tx · ALbafyQFaGSpkuqRPvWjNcaDSSZYHYvpY916UR55TQVv

3NC3GcwFK9knYYKT2SRc7nWxc5SXc2aKBQ6:  -0.07500000 Waves

2023.01.18 17:32 [2410491] smart account 3NC3GcwFK9knYYKT2SRc7nWxc5SXc2aKBQ6 > SELF 0.00000000 Waves

{ "type": 13, "id": "ALbafyQFaGSpkuqRPvWjNcaDSSZYHYvpY916UR55TQVv", "fee": 7500000, "feeAssetId": null, "timestamp": 1674052399642, "version": 2, "chainId": 84, "sender": "3NC3GcwFK9knYYKT2SRc7nWxc5SXc2aKBQ6", "senderPublicKey": "5GAkpjTakesSgVm3A22kYMBvNpM8C1KpqWfyC7YyB84y", "proofs": [ "252NEQ3Cv33MDcJ7eGRYr1KFsGKSL2F28LHio78AeyApJLFg4JeBVZQjcEf9Ly6HhasoiCmsdFwZFWqXoUqyUHu4" ], "script": "base64:BgJ0CAISABIAEgASABIDCgEBEgMKAQESDgoMAQEBAQEBAQEBAQEBEhQKEgEBAQEBAQEICAgIAQEBAQEBARIGCgQBAQEIEgASAwoBARIFCgMBAQQSAwoBCBIAEgASAwoBCBIDCgEBEgASABIDCgEIEgASBAoCCAjGAQAJa19vcmFfa2V5AglrX29yYV9rZXkAD2tfb3JhX2Jsb2NrX2tleQIPa19vcmFfYmxvY2tfa2V5AA5rX29yYV9vcGVuX2tleQIOa19vcmFfb3Blbl9rZXkABWtfb3JhAgVrX29yYQAJa19iYWxhbmNlAglrX2JhbGFuY2UACmtfc2VxdWVuY2UCCmtfc2VxdWVuY2UADmtfcG9zaXRpb25TaXplAg5rX3Bvc2l0aW9uU2l6ZQAQa19wb3NpdGlvbk1hcmdpbgIQa19wb3NpdGlvbk1hcmdpbgAWa19wb3NpdGlvbk9wZW5Ob3Rpb25hbAIWa19wb3NpdGlvbk9wZW5Ob3Rpb25hbAAua19wb3NpdGlvbkxhc3RVcGRhdGVkQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgISa19wb3NpdGlvbkZyYWN0aW9uABJrX3Bvc2l0aW9uU2VxdWVuY2UCEmtfcG9zaXRpb25TZXF1ZW5jZQAPa19wb3NpdGlvbkFzc2V0Ag9rX3Bvc2l0aW9uQXNzZXQADWtfcG9zaXRpb25GZWUCDWtfcG9zaXRpb25GZWUADWtfaW5pdGlhbGl6ZWQCDWtfaW5pdGlhbGl6ZWQACGtfcGF1c2VkAghrX3BhdXNlZAALa19jbG9zZU9ubHkCC2tfY2xvc2VPbmx5AAVrX2ZlZQIFa19mZWUAD2tfZnVuZGluZ1BlcmlvZAIPa19mdW5kaW5nUGVyaW9kABFrX2luaXRNYXJnaW5SYXRpbwIRa19pbml0TWFyZ2luUmF0aW8AGGtfbWFpbnRlbmFuY2VNYXJnaW5SYXRpbwIFa19tbXIAFWtfbGlxdWlkYXRpb25GZWVSYXRpbwIVa19saXF1aWRhdGlvbkZlZVJhdGlvABlrX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAhZrX3BhcnRMaXF1aWRhdGlvblJhdGlvAA1rX3NwcmVhZExpbWl0Ag1rX3NwcmVhZExpbWl0ABBrX21heFByaWNlSW1wYWN0AhBrX21heFByaWNlSW1wYWN0ABBrX21heFByaWNlU3ByZWFkAhBrX21heFByaWNlU3ByZWFkABFrX21heE9wZW5Ob3Rpb25hbAIRa19tYXhPcGVuTm90aW9uYWwAFWtfZmVlVG9TdGFrZXJzUGVyY2VudAIVa19mZWVUb1N0YWtlcnNQZXJjZW50ABBrX21heE9yYWNsZURlbGF5AhBrX21heE9yYWNsZURlbGF5AA1rX2xhc3REYXRhU3RyAg1rX2xhc3REYXRhU3RyAA5rX2xhc3RNaW51dGVJZAIOa19sYXN0TWludXRlSWQAHWtfdHdhcERhdGFMYXN0Q3VtdWxhdGl2ZVByaWNlAh1rX3R3YXBEYXRhTGFzdEN1bXVsYXRpdmVQcmljZQATa190d2FwRGF0YUxhc3RQcmljZQITa190d2FwRGF0YUxhc3RQcmljZQAaa190d2FwRGF0YVByZXZpb3VzTWludXRlSWQCGmtfdHdhcERhdGFQcmV2aW91c01pbnV0ZUlkACVrX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAhtrX2xhdGVzdExvbmdQcmVtaXVtRnJhY3Rpb24AJmtfbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAhxrX2xhdGVzdFNob3J0UHJlbWl1bUZyYWN0aW9uABJrX25leHRGdW5kaW5nQmxvY2sCHmtfbmV4dEZ1bmRpbmdCbG9ja01pblRpbWVzdGFtcAARa19sb25nRnVuZGluZ1JhdGUCEWtfbG9uZ0Z1bmRpbmdSYXRlABJrX3Nob3J0RnVuZGluZ1JhdGUCEmtfc2hvcnRGdW5kaW5nUmF0ZQATa19xdW90ZUFzc2V0UmVzZXJ2ZQIIa19xdEFzdFIAEmtfYmFzZUFzc2V0UmVzZXJ2ZQIIa19ic0FzdFIAEmtfcXVvdGVBc3NldFdlaWdodAIIa19xdEFzdFcAEWtfYmFzZUFzc2V0V2VpZ2h0AghrX2JzQXN0VwATa190b3RhbFBvc2l0aW9uU2l6ZQITa190b3RhbFBvc2l0aW9uU2l6ZQAXa190b3RhbExvbmdQb3NpdGlvblNpemUCF2tfdG90YWxMb25nUG9zaXRpb25TaXplABhrX3RvdGFsU2hvcnRQb3NpdGlvblNpemUCGGtfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAWa19vcGVuSW50ZXJlc3ROb3Rpb25hbAIWa19vcGVuSW50ZXJlc3ROb3Rpb25hbAATa19vcGVuSW50ZXJlc3RTaG9ydAITa19vcGVuSW50ZXJlc3RTaG9ydAASa19vcGVuSW50ZXJlc3RMb25nAhJrX29wZW5JbnRlcmVzdExvbmcAFGtfY29vcmRpbmF0b3JBZGRyZXNzAhRrX2Nvb3JkaW5hdG9yQWRkcmVzcwAPa192YXVsdF9hZGRyZXNzAg9rX3ZhdWx0X2FkZHJlc3MAD2tfYWRtaW5fYWRkcmVzcwIPa19hZG1pbl9hZGRyZXNzABJrX2FkbWluX3B1YmxpY19rZXkCEmtfYWRtaW5fcHVibGljX2tleQANa19xdW90ZV9hc3NldAINa19xdW90ZV9hc3NldAAPa19xdW90ZV9zdGFraW5nAg9rX3F1b3RlX3N0YWtpbmcAEWtfc3Rha2luZ19hZGRyZXNzAhFrX3N0YWtpbmdfYWRkcmVzcwAPa19taW5lcl9hZGRyZXNzAg9rX21pbmVyX2FkZHJlc3MAEGtfb3JkZXJzX2FkZHJlc3MCEGtfb3JkZXJzX2FkZHJlc3MAEmtfcmVmZXJyYWxfYWRkcmVzcwISa19yZWZlcnJhbF9hZGRyZXNzABRrX2NvbGxhdGVyYWxfYWRkcmVzcwIUa19jb2xsYXRlcmFsX2FkZHJlc3MAEmtfZXhjaGFuZ2VfYWRkcmVzcwISa19leGNoYW5nZV9hZGRyZXNzABVrX25mdF9tYW5hZ2VyX2FkZHJlc3MCFWtfbmZ0X21hbmFnZXJfYWRkcmVzcwAga190cmFkZXJfbWFya2V0X2Fzc2V0X2NvbGxhdGVyYWwCIGtfdHJhZGVyX21hcmtldF9hc3NldF9jb2xsYXRlcmFsAQ50b0NvbXBvc2l0ZUtleQIEX2tleQhfYWRkcmVzcwkArAICCQCsAgIFBF9rZXkCAV8FCF9hZGRyZXNzAQtjb29yZGluYXRvcgAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCBQR0aGlzBRRrX2Nvb3JkaW5hdG9yQWRkcmVzcwITQ29vcmRpbmF0b3Igbm90IHNldAEMYWRtaW5BZGRyZXNzAAkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABQ9rX2FkbWluX2FkZHJlc3MBDmFkbWluUHVibGljS2V5AAkA2QQBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABRJrX2FkbWluX3B1YmxpY19rZXkBCnF1b3RlQXNzZXQACQDZBAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFDWtfcXVvdGVfYXNzZXQBEXF1b3RlQXNzZXRTdGFraW5nAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFD2tfcXVvdGVfc3Rha2luZwIbUXVvdGUgYXNzZXQgc3Rha2luZyBub3Qgc2V0AQ5zdGFraW5nQWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABRFrX3N0YWtpbmdfYWRkcmVzcwIPU3Rha2luZyBub3Qgc2V0AQx2YXVsdEFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUPa192YXVsdF9hZGRyZXNzAg1WYXVsdCBub3Qgc2V0AQxtaW5lckFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUPa19taW5lcl9hZGRyZXNzAg1NaW5lciBub3Qgc2V0AQ1vcmRlcnNBZGRyZXNzAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFEGtfb3JkZXJzX2FkZHJlc3MCDk9yZGVycyBub3Qgc2V0AQ9yZWZlcnJhbEFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUSa19yZWZlcnJhbF9hZGRyZXNzAhBSZWZlcnJhbCBub3Qgc2V0ARFuZnRNYW5hZ2VyQWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABRVrX25mdF9tYW5hZ2VyX2FkZHJlc3MCE05GVCBNYW5hZ2VyIG5vdCBzZXQBEWNvbGxhdGVyYWxBZGRyZXNzAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFFGtfY29sbGF0ZXJhbF9hZGRyZXNzAhpDb2xsYXRlcmFsIE1hbmFnZXIgbm90IHNldAELc3dhcEFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIJAQtjb29yZGluYXRvcgAFEmtfZXhjaGFuZ2VfYWRkcmVzcwIPTm8gc3dhcCBhZGRyZXNzAhRJbnZhbGlkIHN3YXAgYWRkcmVzcwARa193aGl0ZWxpc3RfYXNzZXQCEWtfd2hpdGVsaXN0X2Fzc2V0ARBpc1doaXRlbGlzdEFzc2V0AQhfYXNzZXRJZAkBC3ZhbHVlT3JFbHNlAgkAmwgCCQERY29sbGF0ZXJhbEFkZHJlc3MACQEOdG9Db21wb3NpdGVLZXkCBRFrX3doaXRlbGlzdF9hc3NldAUIX2Fzc2V0SWQHAA1rX3Rva2VuX3BhcmFtAg1rX3Rva2VuX3BhcmFtAAxrX3Rva2VuX3R5cGUCDGtfdG9rZW5fdHlwZQAYRkVFX1JFRFVDVElPTl9UT0tFTl9UWVBFAg1mZWVfcmVkdWN0aW9uAAhESVJfTE9ORwABAAlESVJfU0hPUlQAAgANVFdBUF9JTlRFUlZBTAAPAA9PUkFDTEVfSU5URVJWQUwADwAHU0VDT05EUwDoBwAPREVDSU1BTF9OVU1CRVJTAAYADERFQ0lNQUxfVU5JVAkAaAIAAQkAaAIJAGgCCQBoAgkAaAIJAGgCAAoACgAKAAoACgAKAAdPTkVfREFZCQBoAgCAowUFDERFQ0lNQUxfVU5JVAAIQUxMX0ZFRVMAZAAPUE5MX09QVElPTl9TUE9UAAEAEVBOTF9PUFRJT05fT1JBQ0xFAAIBAXMBAl94CQCsAgIJAKQDAQUCX3gCASwBBGRpdmQCAl94Al95CQBuBAUCX3gFDERFQ0lNQUxfVU5JVAUCX3kFCEhBTEZFVkVOAQRtdWxkAgJfeAJfeQkAbgQFAl94BQJfeQUMREVDSU1BTF9VTklUBQhIQUxGRVZFTgEFc3FydGQBAl94CQEEc3FydAQFAl94BQ9ERUNJTUFMX05VTUJFUlMFD0RFQ0lNQUxfTlVNQkVSUwUISEFMRkVWRU4BBHBvd2QCAl94Al95CQBsBgUCX3gFD0RFQ0lNQUxfTlVNQkVSUwUCX3kFD0RFQ0lNQUxfTlVNQkVSUwUPREVDSU1BTF9OVU1CRVJTBQhIQUxGRVZFTgEFYmRpdmQCAl94Al95CQC9AgQFAl94CQC2AgEFDERFQ0lNQUxfVU5JVAUCX3kFCEhBTEZFVkVOAQVibXVsZAICX3gCX3kJAL0CBAUCX3gFAl95CQC2AgEFDERFQ0lNQUxfVU5JVAUISEFMRkVWRU4BBmJzcXJ0ZAECX3gJAQpzcXJ0QmlnSW50BAUCX3gFD0RFQ0lNQUxfTlVNQkVSUwUPREVDSU1BTF9OVU1CRVJTBQhIQUxGRVZFTgEFYnBvd2QCAl94Al95CQB2BgUCX3gFD0RFQ0lNQUxfTlVNQkVSUwUCX3kFD0RFQ0lNQUxfTlVNQkVSUwUPREVDSU1BTF9OVU1CRVJTBQhIQUxGRVZFTgEDYWJzAQJfeAMJAGYCBQJfeAAABQJfeAkBAS0BBQJfeAEEdm1heAICX3gCX3kDCQBnAgUCX3gFAl95BQJfeAUCX3kBCWxpc3RUb1N0cgEFX2xpc3QKAQVfam9pbgILYWNjdW11bGF0b3IDdmFsCQCsAgIJAKwCAgULYWNjdW11bGF0b3IFA3ZhbAIBLAQKbmV3TGlzdFN0cgoAAiRsBQVfbGlzdAoAAiRzCQCQAwEFAiRsCgAFJGFjYzACAAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEFX2pvaW4CBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDIwCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoACwAMAA0ADgAPABAAEQASABMAFAQLbmV3TGlzdFN0clUJALMCAgUKbmV3TGlzdFN0cgABBAtuZXdMaXN0U3RyUgMJAAACCQCvAgIFC25ld0xpc3RTdHJVAAECASwJALACAgULbmV3TGlzdFN0clUAAQULbmV3TGlzdFN0clUFC25ld0xpc3RTdHJSAQlzdHJUb0xpc3QBBF9zdHIJALUJAgUEX3N0cgIBLAELcHVzaFRvUXVldWUDBV9saXN0CF9tYXhTaXplBl92YWx1ZQMJAGYCCQCQAwEFBV9saXN0BQhfbWF4U2l6ZQkAzQgCCQDRCAIFBV9saXN0AAAFBl92YWx1ZQkAzQgCBQVfbGlzdAUGX3ZhbHVlAQNpbnQBAWsJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBQR0aGlzBQFrCQCsAgICDW5vIHZhbHVlIGZvciAFAWsBBWludE9yAgFrA2RlZgkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQFrBQNkZWYBBHN0ckECCF9hZGRyZXNzBF9rZXkEA3ZhbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFCF9hZGRyZXNzBQRfa2V5CQCsAgICEU5vIHZhbHVlIGZvciBrZXkgBQRfa2V5BQN2YWwBBGludEECCF9hZGRyZXNzBF9rZXkEA3ZhbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFCF9hZGRyZXNzBQRfa2V5CQCsAgICEU5vIHZhbHVlIGZvciBrZXkgBQRfa2V5BQN2YWwBCGNiYWxhbmNlAAkBA2ludAEFCWtfYmFsYW5jZQEDZmVlAAkBA2ludAEFBWtfZmVlAQ9pbml0TWFyZ2luUmF0aW8ACQEDaW50AQURa19pbml0TWFyZ2luUmF0aW8BBnF0QXN0UgAJAQNpbnQBBRNrX3F1b3RlQXNzZXRSZXNlcnZlAQZic0FzdFIACQEDaW50AQUSa19iYXNlQXNzZXRSZXNlcnZlAQZxdEFzdFcACQEFaW50T3ICBRJrX3F1b3RlQXNzZXRXZWlnaHQFDERFQ0lNQUxfVU5JVAEGYnNBc3RXAAkBBWludE9yAgURa19iYXNlQXNzZXRXZWlnaHQFDERFQ0lNQUxfVU5JVAERdG90YWxQb3NpdGlvblNpemUACQEDaW50AQUTa190b3RhbFBvc2l0aW9uU2l6ZQEUb3BlbkludGVyZXN0Tm90aW9uYWwACQEDaW50AQUWa19vcGVuSW50ZXJlc3ROb3Rpb25hbAERb3BlbkludGVyZXN0U2hvcnQACQEDaW50AQUTa19vcGVuSW50ZXJlc3RTaG9ydAEQb3BlbkludGVyZXN0TG9uZwAJAQNpbnQBBRJrX29wZW5JbnRlcmVzdExvbmcBGW5leHRGdW5kaW5nQmxvY2tUaW1lc3RhbXAACQEDaW50AQUSa19uZXh0RnVuZGluZ0Jsb2NrARBmdW5kaW5nUGVyaW9kUmF3AAkBA2ludAEFD2tfZnVuZGluZ1BlcmlvZAEUZnVuZGluZ1BlcmlvZERlY2ltYWwACQBoAgkBEGZ1bmRpbmdQZXJpb2RSYXcABQxERUNJTUFMX1VOSVQBFGZ1bmRpbmdQZXJpb2RTZWNvbmRzAAkAaAIJARBmdW5kaW5nUGVyaW9kUmF3AAUHU0VDT05EUwEWbWFpbnRlbmFuY2VNYXJnaW5SYXRpbwAJAQNpbnQBBRhrX21haW50ZW5hbmNlTWFyZ2luUmF0aW8BE2xpcXVpZGF0aW9uRmVlUmF0aW8ACQEDaW50AQUVa19saXF1aWRhdGlvbkZlZVJhdGlvARdwYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwAJAQNpbnQBBRlrX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAQtzcHJlYWRMaW1pdAAJAQNpbnQBBQ1rX3NwcmVhZExpbWl0AQ5tYXhQcmljZUltcGFjdAAJAQNpbnQBBRBrX21heFByaWNlSW1wYWN0AQ5tYXhQcmljZVNwcmVhZAAJAQNpbnQBBRBrX21heFByaWNlU3ByZWFkAQ9tYXhPcGVuTm90aW9uYWwACQEDaW50AQURa19tYXhPcGVuTm90aW9uYWwBI2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAAkBA2ludAEFJWtfbGF0ZXN0TG9uZ0N1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24BJGxhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgAJAQNpbnQBBSZrX2xhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAJAQNpbnQBBRhrX3RvdGFsU2hvcnRQb3NpdGlvblNpemUBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQAJAQNpbnQBBRdrX3RvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQEMbGFzdFNlcXVlbmNlAAkBBWludE9yAgUKa19zZXF1ZW5jZQAAARNmZWVUb1N0YWtlcnNQZXJjZW50AAkBA2ludAEFFWtfZmVlVG9TdGFrZXJzUGVyY2VudAEObWF4T3JhY2xlRGVsYXkACQEDaW50AQUQa19tYXhPcmFjbGVEZWxheQEPZ2V0QWN0dWFsQ2FsbGVyAQFpCQELdmFsdWVPckVsc2UCCQCdCAIJAQ1vcmRlcnNBZGRyZXNzAAIIa19zZW5kZXIJAKUIAQgFAWkGY2FsbGVyARZyZXF1aXJlTW9yZU1hcmdpblJhdGlvAwxfbWFyZ2luUmF0aW8QX2Jhc2VNYXJnaW5SYXRpbxRfbGFyZ2VyVGhhbk9yRXF1YWxUbwQUcmVtYWluaW5nTWFyZ2luUmF0aW8JAGUCBQxfbWFyZ2luUmF0aW8FEF9iYXNlTWFyZ2luUmF0aW8DAwUUX2xhcmdlclRoYW5PckVxdWFsVG8JAGYCAAAFFHJlbWFpbmluZ01hcmdpblJhdGlvBwkAAgEJAKwCAgkArAICCQCsAgICEEludmFsaWQgbWFyZ2luOiAJAKQDAQUMX21hcmdpblJhdGlvAgMgPCAJAKQDAQUQX2Jhc2VNYXJnaW5SYXRpbwMDCQEBIQEFFF9sYXJnZXJUaGFuT3JFcXVhbFRvCQBnAgUUcmVtYWluaW5nTWFyZ2luUmF0aW8AAAcJAAIBCQCsAgIJAKwCAgkArAICAhBJbnZhbGlkIG1hcmdpbjogCQCkAwEFDF9tYXJnaW5SYXRpbwIDID4gCQCkAwEFEF9iYXNlTWFyZ2luUmF0aW8GAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAQ1fcG9zaXRpb25TaXplAwkAAAIFDV9wb3NpdGlvblNpemUAAAkAAgECLFNob3VsZCBub3QgYmUgY2FsbGVkIHdpdGggX3Bvc2l0aW9uU2l6ZSA9PSAwAwkAZgIFDV9wb3NpdGlvblNpemUAAAkBI2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAAkBJGxhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgABC2dldFBvc2l0aW9uAQdfdHJhZGVyBA9wb3NpdGlvblNpemVPcHQJAJoIAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUOa19wb3NpdGlvblNpemUFB190cmFkZXIEByRtYXRjaDAFD3Bvc2l0aW9uU2l6ZU9wdAMJAAECBQckbWF0Y2gwAgNJbnQEDHBvc2l0aW9uU2l6ZQUHJG1hdGNoMAkAlgoEBQxwb3NpdGlvblNpemUJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFEGtfcG9zaXRpb25NYXJnaW4FB190cmFkZXIJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFFmtfcG9zaXRpb25PcGVuTm90aW9uYWwFB190cmFkZXIJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFLmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FB190cmFkZXIJAJYKBAAAAAAAAAAAARBnZXRQb3NpdGlvbkFzc2V0AQdfdHJhZGVyBBBwb3NpdGlvbkFzc2V0T3B0CQCdCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFD2tfcG9zaXRpb25Bc3NldAUHX3RyYWRlcgQHJG1hdGNoMAUQcG9zaXRpb25Bc3NldE9wdAMJAAECBQckbWF0Y2gwAgZTdHJpbmcEDXBvc2l0aW9uQXNzZXQFByRtYXRjaDAFDXBvc2l0aW9uQXNzZXQJANgEAQkBCnF1b3RlQXNzZXQAAQ5nZXRQb3NpdGlvbkZlZQEHX3RyYWRlcgQOcG9zaXRpb25GZWVPcHQJAJoIAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUNa19wb3NpdGlvbkZlZQUHX3RyYWRlcgQHJG1hdGNoMAUOcG9zaXRpb25GZWVPcHQDCQABAgUHJG1hdGNoMAIDSW50BAtwb3NpdGlvbkZlZQUHJG1hdGNoMAULcG9zaXRpb25GZWUJAQNmZWUAARNyZXF1aXJlT3BlblBvc2l0aW9uAQdfdHJhZGVyAwkAAAIICQELZ2V0UG9zaXRpb24BBQdfdHJhZGVyAl8xAAAJAAIBAhBObyBvcGVuIHBvc2l0aW9uBgELaW5pdGlhbGl6ZWQACQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMFDWtfaW5pdGlhbGl6ZWQHAQZwYXVzZWQACQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMFCGtfcGF1c2VkBwEJY2xvc2VPbmx5AAkBC3ZhbHVlT3JFbHNlAgkAmwgCBQR0aGlzBQtrX2Nsb3NlT25seQcBDXVwZGF0ZVJlc2VydmUDBl9pc0FkZBFfcXVvdGVBc3NldEFtb3VudBBfYmFzZUFzc2V0QW1vdW50AwUGX2lzQWRkBAduZXdCYXNlCQBlAgkBBmJzQXN0UgAFEF9iYXNlQXNzZXRBbW91bnQDCQBnAgAABQduZXdCYXNlCQACAQIqVHggbGVhZCB0byBiYXNlIGFzc2V0IHJlc2VydmUgPD0gMCwgcmV2ZXJ0CQCVCgMJAGQCCQEGcXRBc3RSAAURX3F1b3RlQXNzZXRBbW91bnQFB25ld0Jhc2UJAGQCCQERdG90YWxQb3NpdGlvblNpemUABRBfYmFzZUFzc2V0QW1vdW50BAhuZXdRdW90ZQkAZQIJAQZxdEFzdFIABRFfcXVvdGVBc3NldEFtb3VudAMJAGcCAAAFCG5ld1F1b3RlCQACAQIqVHggbGVhZCB0byBiYXNlIHF1b3RlIHJlc2VydmUgPD0gMCwgcmV2ZXJ0CQCVCgMFCG5ld1F1b3RlCQBkAgkBBmJzQXN0UgAFEF9iYXNlQXNzZXRBbW91bnQJAGUCCQERdG90YWxQb3NpdGlvblNpemUABRBfYmFzZUFzc2V0QW1vdW50AQ1jYWxjSW52YXJpYW50AgdfcXRBc3RSB19ic0FzdFIEB2JxdEFzdFIJALYCAQUHX3F0QXN0UgQHYmJzQXN0UgkAtgIBBQdfYnNBc3RSCQEFYm11bGQCBQdicXRBc3RSBQdiYnNBc3RSAQlzd2FwSW5wdXQCBl9pc0FkZBFfcXVvdGVBc3NldEFtb3VudAQHX3F0QXN0UgkBBnF0QXN0UgAEB19ic0FzdFIJAQZic0FzdFIABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAEGHF1b3RlQXNzZXRBbW91bnRBZGp1c3RlZAkBBGRpdmQCBRFfcXVvdGVBc3NldEFtb3VudAUHX3F0QXN0VwQBawkBDWNhbGNJbnZhcmlhbnQCBQdfcXRBc3RSBQdfYnNBc3RSBBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyAwUGX2lzQWRkCQBkAgUHX3F0QXN0UgUYcXVvdGVBc3NldEFtb3VudEFkanVzdGVkCQBlAgUHX3F0QXN0UgUYcXVvdGVBc3NldEFtb3VudEFkanVzdGVkBBViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIJAKADAQkBBWJkaXZkAgUBawkAtgIBBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBBhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMJAQNhYnMBCQBlAgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBQdfYnNBc3RSBBVhbW91bnRCYXNlQXNzZXRCb3VnaHQDBQZfaXNBZGQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwkBAS0BBRhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMEDSR0MDE3MTM4MTczMDgJAQ11cGRhdGVSZXNlcnZlAwUGX2lzQWRkBRhxdW90ZUFzc2V0QW1vdW50QWRqdXN0ZWQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwQXcXVvdGVBc3NldFJlc2VydmVBZnRlcjEIBQ0kdDAxNzEzODE3MzA4Al8xBBZiYXNlQXNzZXRSZXNlcnZlQWZ0ZXIxCAUNJHQwMTcxMzgxNzMwOAJfMgQXdG90YWxQb3NpdGlvblNpemVBZnRlcjEIBQ0kdDAxNzEzODE3MzA4Al8zBAtwcmljZUJlZm9yZQkBBGRpdmQCCQEEbXVsZAIFB19xdEFzdFIFB19xdEFzdFcJAQRtdWxkAgUHX2JzQXN0UgUHX2JzQXN0VwQLbWFya2V0UHJpY2UJAQRkaXZkAgURX3F1b3RlQXNzZXRBbW91bnQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwQJcHJpY2VEaWZmCQEDYWJzAQkAZQIFC3ByaWNlQmVmb3JlBQttYXJrZXRQcmljZQQLcHJpY2VJbXBhY3QJAGUCBQxERUNJTUFMX1VOSVQJAQRkaXZkAgULcHJpY2VCZWZvcmUJAGQCBQtwcmljZUJlZm9yZQUJcHJpY2VEaWZmBBNtYXhQcmljZUltcGFjdFZhbHVlCQEObWF4UHJpY2VJbXBhY3QAAwkAZgIFC3ByaWNlSW1wYWN0BRNtYXhQcmljZUltcGFjdFZhbHVlCQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICAg1QcmljZSBpbXBhY3QgCQCkAwEFC3ByaWNlSW1wYWN0AhQgPiBtYXggcHJpY2UgaW1wYWN0IAkApAMBBRNtYXhQcmljZUltcGFjdFZhbHVlAhUgYmVmb3JlIHF1b3RlIGFzc2V0OiAJAKQDAQUHX3F0QXN0UgIUIGJlZm9yZSBiYXNlIGFzc2V0OiAJAKQDAQUHX2JzQXN0UgIhIHF1b3RlIGFzc2V0IGFtb3VudCB0byBleGNoYW5nZTogCQCkAwEFEV9xdW90ZUFzc2V0QW1vdW50Ag8gcHJpY2UgYmVmb3JlOiAJAKQDAQULcHJpY2VCZWZvcmUCDiBtYXJrZXRQcmljZTogCQCkAwEFC21hcmtldFByaWNlCQCWCgQFFWFtb3VudEJhc2VBc3NldEJvdWdodAUXcXVvdGVBc3NldFJlc2VydmVBZnRlcjEFFmJhc2VBc3NldFJlc2VydmVBZnRlcjEFF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxASJjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50BBBfb2xkUG9zaXRpb25TaXplEl9vbGRQb3NpdGlvbk1hcmdpbiVfb2xkUG9zaXRpb25DdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uDF9tYXJnaW5EZWx0YQQOZnVuZGluZ1BheW1lbnQDCQECIT0CBRBfb2xkUG9zaXRpb25TaXplAAAEIF9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uCQEfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEFEF9vbGRQb3NpdGlvblNpemUJAQRtdWxkAgkAZQIFIF9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBSVfb2xkUG9zaXRpb25DdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBRBfb2xkUG9zaXRpb25TaXplAAAEDHNpZ25lZE1hcmdpbgkAZAIJAGUCBQxfbWFyZ2luRGVsdGEFDmZ1bmRpbmdQYXltZW50BRJfb2xkUG9zaXRpb25NYXJnaW4EDSR0MDE4Nzk1MTg5MjIDCQBmAgAABQxzaWduZWRNYXJnaW4JAJQKAgAACQEDYWJzAQUMc2lnbmVkTWFyZ2luCQCUCgIJAQNhYnMBBQxzaWduZWRNYXJnaW4AAAQMcmVtYWluTWFyZ2luCAUNJHQwMTg3OTUxODkyMgJfMQQHYmFkRGVidAgFDSR0MDE4Nzk1MTg5MjICXzIJAJUKAwUMcmVtYWluTWFyZ2luBQdiYWREZWJ0BQ5mdW5kaW5nUGF5bWVudAEWc3dhcE91dHB1dFdpdGhSZXNlcnZlcwcGX2lzQWRkEF9iYXNlQXNzZXRBbW91bnQUX2NoZWNrTWF4UHJpY2VJbXBhY3QSX3F1b3RlQXNzZXRSZXNlcnZlEV9xdW90ZUFzc2V0V2VpZ2h0EV9iYXNlQXNzZXRSZXNlcnZlEF9iYXNlQXNzZXRXZWlnaHQEC3ByaWNlQmVmb3JlCQEEZGl2ZAIJAQRtdWxkAgUSX3F1b3RlQXNzZXRSZXNlcnZlBRFfcXVvdGVBc3NldFdlaWdodAkBBG11bGQCBRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldFdlaWdodAMJAAACBRBfYmFzZUFzc2V0QW1vdW50AAAJAAIBAhlJbnZhbGlkIGJhc2UgYXNzZXQgYW1vdW50BAFrCQENY2FsY0ludmFyaWFudAIFEl9xdW90ZUFzc2V0UmVzZXJ2ZQURX2Jhc2VBc3NldFJlc2VydmUEGGJhc2VBc3NldFBvb2xBbW91bnRBZnRlcgMFBl9pc0FkZAkAZAIFEV9iYXNlQXNzZXRSZXNlcnZlBRBfYmFzZUFzc2V0QW1vdW50CQBlAgURX2Jhc2VBc3NldFJlc2VydmUFEF9iYXNlQXNzZXRBbW91bnQED3F1b3RlQXNzZXRBZnRlcgkAoAMBCQEFYmRpdmQCBQFrCQC2AgEFGGJhc2VBc3NldFBvb2xBbW91bnRBZnRlcgQPcXVvdGVBc3NldERlbHRhCQEDYWJzAQkAZQIFD3F1b3RlQXNzZXRBZnRlcgUSX3F1b3RlQXNzZXRSZXNlcnZlBA5xdW90ZUFzc2V0U29sZAkBBG11bGQCBQ9xdW90ZUFzc2V0RGVsdGEFEV9xdW90ZUFzc2V0V2VpZ2h0BBNtYXhQcmljZUltcGFjdFZhbHVlCQEObWF4UHJpY2VJbXBhY3QABA0kdDAyMDA5MjIwMjU0CQENdXBkYXRlUmVzZXJ2ZQMJAQEhAQUGX2lzQWRkBQ9xdW90ZUFzc2V0RGVsdGEFEF9iYXNlQXNzZXRBbW91bnQEF3F1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIxCAUNJHQwMjAwOTIyMDI1NAJfMQQWYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyMQgFDSR0MDIwMDkyMjAyNTQCXzIEF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxCAUNJHQwMjAwOTIyMDI1NAJfMwQLbWFya2V0UHJpY2UJAQRkaXZkAgUOcXVvdGVBc3NldFNvbGQFEF9iYXNlQXNzZXRBbW91bnQECXByaWNlRGlmZgkBA2FicwEJAGUCBQtwcmljZUJlZm9yZQULbWFya2V0UHJpY2UEC3ByaWNlSW1wYWN0CQBlAgUMREVDSU1BTF9VTklUCQEEZGl2ZAIFC3ByaWNlQmVmb3JlCQBkAgULcHJpY2VCZWZvcmUFCXByaWNlRGlmZgMDCQBmAgULcHJpY2VJbXBhY3QFE21heFByaWNlSW1wYWN0VmFsdWUFFF9jaGVja01heFByaWNlSW1wYWN0BwkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgINUHJpY2UgaW1wYWN0IAkApAMBBQtwcmljZUltcGFjdAIUID4gbWF4IHByaWNlIGltcGFjdCAJAKQDAQUTbWF4UHJpY2VJbXBhY3RWYWx1ZQIVIGJlZm9yZSBxdW90ZSBhc3NldDogCQCkAwEFEl9xdW90ZUFzc2V0UmVzZXJ2ZQIUIGJlZm9yZSBiYXNlIGFzc2V0OiAJAKQDAQURX2Jhc2VBc3NldFJlc2VydmUCICBiYXNlIGFzc2V0IGFtb3VudCB0byBleGNoYW5nZTogCQCkAwEFEF9iYXNlQXNzZXRBbW91bnQCDyBwcmljZSBiZWZvcmU6IAkApAMBBQtwcmljZUJlZm9yZQIPIG1hcmtldCBwcmljZTogCQCkAwEFC21hcmtldFByaWNlCQCZCgcFDnF1b3RlQXNzZXRTb2xkBRdxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyMQUWYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyMQUXdG90YWxQb3NpdGlvblNpemVBZnRlcjEJAGUCCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAMFBl9pc0FkZAkBA2FicwEFEF9iYXNlQXNzZXRBbW91bnQAAAkAZQIJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAMJAQEhAQUGX2lzQWRkCQEDYWJzAQUQX2Jhc2VBc3NldEFtb3VudAAABQtwcmljZUltcGFjdAEKc3dhcE91dHB1dAMGX2lzQWRkEF9iYXNlQXNzZXRBbW91bnQUX2NoZWNrTWF4UHJpY2VJbXBhY3QJARZzd2FwT3V0cHV0V2l0aFJlc2VydmVzBwUGX2lzQWRkBRBfYmFzZUFzc2V0QW1vdW50BRRfY2hlY2tNYXhQcmljZUltcGFjdAkBBnF0QXN0UgAJAQZxdEFzdFcACQEGYnNBc3RSAAkBBmJzQXN0VwABDmdldE9yYWNsZVByaWNlAAQGb3JhY2xlCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgUEdGhpcwUFa19vcmECAAQIcHJpY2VLZXkJARFAZXh0ck5hdGl2ZSgxMDUzKQIFBHRoaXMFCWtfb3JhX2tleQQJbGFzdFZhbHVlCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUGb3JhY2xlBQhwcmljZUtleQkArAICCQCsAgIJAKwCAgIiQ2FuIG5vdCBnZXQgb3JhY2xlIHByaWNlLiBPcmFjbGU6IAkApQgBBQZvcmFjbGUCBiBrZXk6IAUIcHJpY2VLZXkECGJsb2NrS2V5CQELdmFsdWVPckVsc2UCCQCdCAIFBHRoaXMFD2tfb3JhX2Jsb2NrX2tleQIAAwkBAiE9AgUIYmxvY2tLZXkCAAQMY3VycmVudEJsb2NrCAUJbGFzdEJsb2NrBmhlaWdodAQPbGFzdE9yYWNsZUJsb2NrCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUGb3JhY2xlBQhibG9ja0tleQkArAICCQCsAgIJAKwCAgIiQ2FuIG5vdCBnZXQgb3JhY2xlIGJsb2NrLiBPcmFjbGU6IAkApQgBBQZvcmFjbGUCBiBrZXk6IAUIYmxvY2tLZXkDCQBmAgkAZQIFDGN1cnJlbnRCbG9jawUPbGFzdE9yYWNsZUJsb2NrCQEObWF4T3JhY2xlRGVsYXkACQACAQkArAICCQCsAgIJAKwCAgImT3JhY2xlIHN0YWxlIGRhdGEuIExhc3Qgb3JhY2xlIGJsb2NrOiAJAKQDAQUPbGFzdE9yYWNsZUJsb2NrAhAgY3VycmVudCBibG9jazogCQCkAwEFDGN1cnJlbnRCbG9jawUJbGFzdFZhbHVlBQlsYXN0VmFsdWUBDmlzTWFya2V0Q2xvc2VkAAQGb3JhY2xlCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgUEdGhpcwUFa19vcmECAAQHb3BlbktleQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzBQ5rX29yYV9vcGVuX2tleQIAAwkBAiE9AgUHb3BlbktleQIABAZpc09wZW4JARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmwgCBQZvcmFjbGUFB29wZW5LZXkJAKwCAgkArAICCQCsAgICK0NhbiBub3QgZ2V0IG9yYWNsZSBpcyBvcGVuL2Nsb3NlZC4gT3JhY2xlOiAJAKUIAQUGb3JhY2xlAgYga2V5OiAFB29wZW5LZXkJAQEhAQUGaXNPcGVuBwEMYWJzUHJpY2VEaWZmBQxfb3JhY2xlUHJpY2USX3F1b3RlQXNzZXRSZXNlcnZlEV9iYXNlQXNzZXRSZXNlcnZlB19xdEFzdFcHX2JzQXN0VwQKcHJpY2VBZnRlcgkBBGRpdmQCCQEEbXVsZAIFEl9xdW90ZUFzc2V0UmVzZXJ2ZQUHX3F0QXN0VwkBBG11bGQCBRFfYmFzZUFzc2V0UmVzZXJ2ZQUHX2JzQXN0VwQMYXZlcmFnZVByaWNlCQEEZGl2ZAIJAGQCBQxfb3JhY2xlUHJpY2UFCnByaWNlQWZ0ZXIJAGgCAAIFDERFQ0lNQUxfVU5JVAQMYWJzUHJpY2VEaWZmCQEEZGl2ZAIJAQNhYnMBCQBlAgUMX29yYWNsZVByaWNlBQpwcmljZUFmdGVyBQxhdmVyYWdlUHJpY2UFDGFic1ByaWNlRGlmZgEZcmVxdWlyZU5vdE92ZXJTcHJlYWRMaW1pdAISX3F1b3RlQXNzZXRSZXNlcnZlEV9iYXNlQXNzZXRSZXNlcnZlBAtvcmFjbGVQcmljZQkBDmdldE9yYWNsZVByaWNlAAQHX3F0QXN0VwkBBnF0QXN0VwAEB19ic0FzdFcJAQZic0FzdFcABBJhYnNQcmljZURpZmZCZWZvcmUJAQxhYnNQcmljZURpZmYFBQtvcmFjbGVQcmljZQkBBnF0QXN0UgAJAQZic0FzdFIABQdfcXRBc3RXBQdfYnNBc3RXBBFhYnNQcmljZURpZmZBZnRlcgkBDGFic1ByaWNlRGlmZgUFC29yYWNsZVByaWNlBRJfcXVvdGVBc3NldFJlc2VydmUFEV9iYXNlQXNzZXRSZXNlcnZlBQdfcXRBc3RXBQdfYnNBc3RXAwMJAGYCBRFhYnNQcmljZURpZmZBZnRlcgkBDm1heFByaWNlU3ByZWFkAAkAZgIFEWFic1ByaWNlRGlmZkFmdGVyBRJhYnNQcmljZURpZmZCZWZvcmUHCQACAQkArAICCQCsAgIJAKwCAgINUHJpY2Ugc3ByZWFkIAkApAMBBRFhYnNQcmljZURpZmZBZnRlcgIUID4gbWF4IHByaWNlIHNwcmVhZCAJAKQDAQkBDm1heFByaWNlU3ByZWFkAAYBHXJlcXVpcmVOb3RPdmVyTWF4T3Blbk5vdGlvbmFsAhFfbG9uZ09wZW5Ob3Rpb25hbBJfc2hvcnRPcGVuTm90aW9uYWwEEF9tYXhPcGVuTm90aW9uYWwJAQ9tYXhPcGVuTm90aW9uYWwAAwkAZgIFEV9sb25nT3Blbk5vdGlvbmFsBRBfbWF4T3Blbk5vdGlvbmFsCQACAQkArAICCQCsAgIJAKwCAgITTG9uZyBvcGVuIG5vdGlvbmFsIAkApAMBBRFfbG9uZ09wZW5Ob3Rpb25hbAIVID4gbWF4IG9wZW4gbm90aW9uYWwgCQCkAwEFEF9tYXhPcGVuTm90aW9uYWwDCQBmAgUSX3Nob3J0T3Blbk5vdGlvbmFsBRBfbWF4T3Blbk5vdGlvbmFsCQACAQkArAICCQCsAgIJAKwCAgIUU2hvcnQgb3BlbiBub3Rpb25hbCAJAKQDAQUSX3Nob3J0T3Blbk5vdGlvbmFsAhUgPiBtYXggb3BlbiBub3Rpb25hbCAJAKQDAQUQX21heE9wZW5Ob3Rpb25hbAYBDGdldFNwb3RQcmljZQAEEl9xdW90ZUFzc2V0UmVzZXJ2ZQkBBnF0QXN0UgAEEV9iYXNlQXNzZXRSZXNlcnZlCQEGYnNBc3RSAAQHX3F0QXN0VwkBBnF0QXN0VwAEB19ic0FzdFcJAQZic0FzdFcACQEEZGl2ZAIJAQRtdWxkAgUSX3F1b3RlQXNzZXRSZXNlcnZlBQdfcXRBc3RXCQEEbXVsZAIFEV9iYXNlQXNzZXRSZXNlcnZlBQdfYnNBc3RXARZpc092ZXJGbHVjdHVhdGlvbkxpbWl0AAQLb3JhY2xlUHJpY2UJAQ5nZXRPcmFjbGVQcmljZQAEDGN1cnJlbnRQcmljZQkBDGdldFNwb3RQcmljZQAJAGYCCQEEZGl2ZAIJAQNhYnMBCQBlAgULb3JhY2xlUHJpY2UFDGN1cnJlbnRQcmljZQULb3JhY2xlUHJpY2UJAQtzcHJlYWRMaW1pdAABH2dldFBvc2l0aW9uQWRqdXN0ZWRPcGVuTm90aW9uYWwGDV9wb3NpdGlvblNpemUHX29wdGlvbhJfcXVvdGVBc3NldFJlc2VydmURX3F1b3RlQXNzZXRXZWlnaHQRX2Jhc2VBc3NldFJlc2VydmUQX2Jhc2VBc3NldFdlaWdodAQPcG9zaXRpb25TaXplQWJzCQEDYWJzAQUNX3Bvc2l0aW9uU2l6ZQQHaXNTaG9ydAkAZgIAAAUNX3Bvc2l0aW9uU2l6ZQQQcG9zaXRpb25Ob3Rpb25hbAMJAAACBQdfb3B0aW9uBQ9QTkxfT1BUSU9OX1NQT1QEDSR0MDI1MjA1MjU0MjUJARZzd2FwT3V0cHV0V2l0aFJlc2VydmVzBwkBASEBBQdpc1Nob3J0BQ9wb3NpdGlvblNpemVBYnMHBRJfcXVvdGVBc3NldFJlc2VydmUFEV9xdW90ZUFzc2V0V2VpZ2h0BRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldFdlaWdodAQTb3V0UG9zaXRpb25Ob3Rpb25hbAgFDSR0MDI1MjA1MjU0MjUCXzEEAngxCAUNJHQwMjUyMDUyNTQyNQJfMgQCeDIIBQ0kdDAyNTIwNTI1NDI1Al8zBAJ4MwgFDSR0MDI1MjA1MjU0MjUCXzQFE291dFBvc2l0aW9uTm90aW9uYWwJAQRtdWxkAgUPcG9zaXRpb25TaXplQWJzCQEOZ2V0T3JhY2xlUHJpY2UABRBwb3NpdGlvbk5vdGlvbmFsAStnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubEJ5VmFsdWVzBw1fcG9zaXRpb25TaXplFV9wb3NpdGlvbk9wZW5Ob3Rpb25hbBJfcXVvdGVBc3NldFJlc2VydmURX3F1b3RlQXNzZXRXZWlnaHQRX2Jhc2VBc3NldFJlc2VydmUQX2Jhc2VBc3NldFdlaWdodAdfb3B0aW9uAwkAAAIFDV9wb3NpdGlvblNpemUAAAkAAgECFUludmFsaWQgcG9zaXRpb24gc2l6ZQQHaXNTaG9ydAkAZgIAAAUNX3Bvc2l0aW9uU2l6ZQQQcG9zaXRpb25Ob3Rpb25hbAkBH2dldFBvc2l0aW9uQWRqdXN0ZWRPcGVuTm90aW9uYWwGBQ1fcG9zaXRpb25TaXplBQdfb3B0aW9uBRJfcXVvdGVBc3NldFJlc2VydmUFEV9xdW90ZUFzc2V0V2VpZ2h0BRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldFdlaWdodAQNdW5yZWFsaXplZFBubAMFB2lzU2hvcnQJAGUCBRVfcG9zaXRpb25PcGVuTm90aW9uYWwFEHBvc2l0aW9uTm90aW9uYWwJAGUCBRBwb3NpdGlvbk5vdGlvbmFsBRVfcG9zaXRpb25PcGVuTm90aW9uYWwJAJQKAgUQcG9zaXRpb25Ob3Rpb25hbAUNdW5yZWFsaXplZFBubAEjZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmwCB190cmFkZXIHX29wdGlvbgQNJHQwMjY4NDYyNjk3NAkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgQMcG9zaXRpb25TaXplCAUNJHQwMjY4NDYyNjk3NAJfMQQOcG9zaXRpb25NYXJnaW4IBQ0kdDAyNjg0NjI2OTc0Al8yBBRwb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDI2ODQ2MjY5NzQCXzMEEXBvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwMjY4NDYyNjk3NAJfNAkBK2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sQnlWYWx1ZXMHBQxwb3NpdGlvblNpemUFFHBvc2l0aW9uT3Blbk5vdGlvbmFsCQEGcXRBc3RSAAkBBnF0QXN0VwAJAQZic0FzdFIACQEGYnNBc3RXAAUHX29wdGlvbgEPY2FsY01hcmdpblJhdGlvAw1fcmVtYWluTWFyZ2luCF9iYWREZWJ0EV9wb3NpdGlvbk5vdGlvbmFsCQEEZGl2ZAIJAGUCBQ1fcmVtYWluTWFyZ2luBQhfYmFkRGVidAURX3Bvc2l0aW9uTm90aW9uYWwBFmdldE1hcmdpblJhdGlvQnlPcHRpb24CB190cmFkZXIHX29wdGlvbgQNJHQwMjc0ODcyNzU5OAkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgQMcG9zaXRpb25TaXplCAUNJHQwMjc0ODcyNzU5OAJfMQQOcG9zaXRpb25NYXJnaW4IBQ0kdDAyNzQ4NzI3NTk4Al8yBANwb24IBQ0kdDAyNzQ4NzI3NTk4Al8zBBFwb3NpdGlvbkxzdFVwZENQRggFDSR0MDI3NDg3Mjc1OTgCXzQEDSR0MDI3NjA0Mjc2OTcJASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAIFB190cmFkZXIFB19vcHRpb24EEHBvc2l0aW9uTm90aW9uYWwIBQ0kdDAyNzYwNDI3Njk3Al8xBA11bnJlYWxpemVkUG5sCAUNJHQwMjc2MDQyNzY5NwJfMgQNJHQwMjc3MDIyNzg2OAkBImNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnQEBQxwb3NpdGlvblNpemUFDnBvc2l0aW9uTWFyZ2luBRFwb3NpdGlvbkxzdFVwZENQRgUNdW5yZWFsaXplZFBubAQMcmVtYWluTWFyZ2luCAUNJHQwMjc3MDIyNzg2OAJfMQQHYmFkRGVidAgFDSR0MDI3NzAyMjc4NjgCXzIJAQ9jYWxjTWFyZ2luUmF0aW8DBQxyZW1haW5NYXJnaW4FB2JhZERlYnQFEHBvc2l0aW9uTm90aW9uYWwBDmdldE1hcmdpblJhdGlvAQdfdHJhZGVyCQEWZ2V0TWFyZ2luUmF0aW9CeU9wdGlvbgIFB190cmFkZXIFD1BOTF9PUFRJT05fU1BPVAEbZ2V0UGFydGlhbExpcXVpZGF0aW9uQW1vdW50AgdfdHJhZGVyDV9wb3NpdGlvblNpemUEDG1heGltdW1SYXRpbwkBBHZtYXgCCQEXcGFydGlhbExpcXVpZGF0aW9uUmF0aW8ACQBlAgUMREVDSU1BTF9VTklUCQEEZGl2ZAIJAQ5nZXRNYXJnaW5SYXRpbwEFB190cmFkZXIJARZtYWludGVuYW5jZU1hcmdpblJhdGlvAAQYbWF4RXhjaGFuZ2VkUG9zaXRpb25TaXplCQEEbXVsZAIJAQNhYnMBBQ1fcG9zaXRpb25TaXplBQxtYXhpbXVtUmF0aW8ECnN3YXBSZXN1bHQJAQpzd2FwT3V0cHV0AwkAZgIFDV9wb3NpdGlvblNpemUAAAUYbWF4RXhjaGFuZ2VkUG9zaXRpb25TaXplBwQcbWF4RXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAgFCnN3YXBSZXN1bHQCXzEEC3ByaWNlSW1wYWN0CAUKc3dhcFJlc3VsdAJfNwMJAGYCCQEObWF4UHJpY2VJbXBhY3QABQtwcmljZUltcGFjdAUcbWF4RXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAQVZXhjaGFuZ2VkUG9zaXRpb25TaXplCQEEbXVsZAIJAQNhYnMBBQ1fcG9zaXRpb25TaXplCQEXcGFydGlhbExpcXVpZGF0aW9uUmF0aW8ABBlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50CAkBCnN3YXBPdXRwdXQDCQBmAgUNX3Bvc2l0aW9uU2l6ZQAABRVleGNoYW5nZWRQb3NpdGlvblNpemUHAl8xBRlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50ARVpbnRlcm5hbENsb3NlUG9zaXRpb24CB190cmFkZXIUX2NoZWNrTWF4UHJpY2VJbXBhY3QEDSR0MDI5MTA4MjkyMzYJAQtnZXRQb3NpdGlvbgEFB190cmFkZXIEDHBvc2l0aW9uU2l6ZQgFDSR0MDI5MTA4MjkyMzYCXzEEDnBvc2l0aW9uTWFyZ2luCAUNJHQwMjkxMDgyOTIzNgJfMgQUcG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDAyOTEwODI5MjM2Al8zBBFwb3NpdGlvbkxzdFVwZENQRggFDSR0MDI5MTA4MjkyMzYCXzQEDXVucmVhbGl6ZWRQbmwICQEjZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmwCBQdfdHJhZGVyBQ9QTkxfT1BUSU9OX1NQT1QCXzIEDSR0MDI5MzMxMjk0OTkJASJjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50BAUMcG9zaXRpb25TaXplBQ5wb3NpdGlvbk1hcmdpbgURcG9zaXRpb25Mc3RVcGRDUEYFDXVucmVhbGl6ZWRQbmwEDHJlbWFpbk1hcmdpbggFDSR0MDI5MzMxMjk0OTkCXzEEB2JhZERlYnQIBQ0kdDAyOTMzMTI5NDk5Al8yBBVleGNoYW5nZWRQb3NpdGlvblNpemUJAQEtAQUMcG9zaXRpb25TaXplBAtyZWFsaXplZFBubAUNdW5yZWFsaXplZFBubAQNbWFyZ2luVG9WYXVsdAkBAS0BBQxyZW1haW5NYXJnaW4EDSR0MDI5NjI2Mjk5MDAJAQpzd2FwT3V0cHV0AwkAZgIFDHBvc2l0aW9uU2l6ZQAACQEDYWJzAQUMcG9zaXRpb25TaXplBRRfY2hlY2tNYXhQcmljZUltcGFjdAQZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAgFDSR0MDI5NjI2Mjk5MDACXzEEFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDAyOTYyNjI5OTAwAl8yBBViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDAyOTYyNjI5OTAwAl8zBBZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCAUNJHQwMjk2MjYyOTkwMAJfNAQOdG90YWxMb25nQWZ0ZXIIBQ0kdDAyOTYyNjI5OTAwAl81BA90b3RhbFNob3J0QWZ0ZXIIBQ0kdDAyOTYyNjI5OTAwAl82BBlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyCQBlAgkBFG9wZW5JbnRlcmVzdE5vdGlvbmFsAAUUcG9zaXRpb25PcGVuTm90aW9uYWwJAJ8KDQUVZXhjaGFuZ2VkUG9zaXRpb25TaXplBQdiYWREZWJ0BQtyZWFsaXplZFBubAUNbWFyZ2luVG9WYXVsdAUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBRZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyBRlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyBRlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50BQ50b3RhbExvbmdBZnRlcgUPdG90YWxTaG9ydEFmdGVyCQBlAgkBEG9wZW5JbnRlcmVzdExvbmcAAwkAZgIFDHBvc2l0aW9uU2l6ZQAABRRwb3NpdGlvbk9wZW5Ob3Rpb25hbAAACQBlAgkBEW9wZW5JbnRlcmVzdFNob3J0AAMJAGYCAAAFDHBvc2l0aW9uU2l6ZQUUcG9zaXRpb25PcGVuTm90aW9uYWwAAAEQZ2V0VHdhcFNwb3RQcmljZQAECG1pbnV0ZUlkCQBpAgkAaQIIBQlsYXN0QmxvY2sJdGltZXN0YW1wAOgHADwEDXN0YXJ0TWludXRlSWQJAGUCBQhtaW51dGVJZAUNVFdBUF9JTlRFUlZBTAQHbGlzdFN0cgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzBQ1rX2xhc3REYXRhU3RyAgAEBGxpc3QJALUJAgUHbGlzdFN0cgIBLAoBCGZpbHRlckZuAgthY2N1bXVsYXRvcgRuZXh0AwkAZwIFDXN0YXJ0TWludXRlSWQJAQ1wYXJzZUludFZhbHVlAQUEbmV4dAkAzQgCBQthY2N1bXVsYXRvcgkBDXBhcnNlSW50VmFsdWUBBQRuZXh0BQthY2N1bXVsYXRvcgQFbGlzdEYKAAIkbAUEbGlzdAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEIZmlsdGVyRm4CBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDIwCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoACwAMAA0ADgAPABAAEQASABMAFAQIbWF4SW5kZXgDCQBmAgkAkAMBBQVsaXN0RgAACQCWAwEFBWxpc3RGCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUEbGlzdAAABAxsYXN0TWludXRlSWQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwUOa19sYXN0TWludXRlSWQAAAQWZW5kTGFzdEN1bXVsYXRpdmVQcmljZQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQCsAgIJAKwCAgUda190d2FwRGF0YUxhc3RDdW11bGF0aXZlUHJpY2UCAV8JAKQDAQUMbGFzdE1pbnV0ZUlkAAAEDGVuZExhc3RQcmljZQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQCsAgIJAKwCAgUTa190d2FwRGF0YUxhc3RQcmljZQIBXwkApAMBBQxsYXN0TWludXRlSWQAAAQSbm93Q3VtdWxhdGl2ZVByaWNlCQBkAgUWZW5kTGFzdEN1bXVsYXRpdmVQcmljZQkAaAIJAGUCBQhtaW51dGVJZAUMbGFzdE1pbnV0ZUlkBQxlbmRMYXN0UHJpY2UEGHN0YXJ0TGFzdEN1bXVsYXRpdmVQcmljZQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQCsAgIJAKwCAgUda190d2FwRGF0YUxhc3RDdW11bGF0aXZlUHJpY2UCAV8JAKQDAQUIbWF4SW5kZXgAAAQOc3RhcnRMYXN0UHJpY2UJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkArAICCQCsAgIFE2tfdHdhcERhdGFMYXN0UHJpY2UCAV8JAKQDAQUIbWF4SW5kZXgAAAQUc3RhcnRDdW11bGF0aXZlUHJpY2UJAGQCBRhzdGFydExhc3RDdW11bGF0aXZlUHJpY2UJAGgCCQBlAgUNc3RhcnRNaW51dGVJZAUIbWF4SW5kZXgFDnN0YXJ0TGFzdFByaWNlCQBpAgkAZQIFEm5vd0N1bXVsYXRpdmVQcmljZQUUc3RhcnRDdW11bGF0aXZlUHJpY2UFDVRXQVBfSU5URVJWQUwBE2dldFRlcm1pbmFsQW1tU3RhdGUABA1fcG9zaXRpb25TaXplCQERdG90YWxQb3NpdGlvblNpemUAAwkAAAIFDV9wb3NpdGlvblNpemUAAAkAlAoCCQEGcXRBc3RSAAkBBmJzQXN0UgAECWRpcmVjdGlvbgkAZgIFDV9wb3NpdGlvblNpemUAAAQNJHQwMzIwMjMzMjIwMgkBCnN3YXBPdXRwdXQDBQlkaXJlY3Rpb24JAQNhYnMBBQ1fcG9zaXRpb25TaXplBwQVY3VycmVudE5ldE1hcmtldFZhbHVlCAUNJHQwMzIwMjMzMjIwMgJfMQQZdGVybWluYWxRdW90ZUFzc2V0UmVzZXJ2ZQgFDSR0MDMyMDIzMzIyMDICXzIEGHRlcm1pbmFsQmFzZUFzc2V0UmVzZXJ2ZQgFDSR0MDMyMDIzMzIyMDICXzMJAJQKAgUZdGVybWluYWxRdW90ZUFzc2V0UmVzZXJ2ZQUYdGVybWluYWxCYXNlQXNzZXRSZXNlcnZlARNnZXRRdW90ZUFzc2V0V2VpZ2h0BBBiYXNlQXNzZXRSZXNlcnZlEXRvdGFsUG9zaXRpb25TaXplEXF1b3RlQXNzZXRSZXNlcnZlC3RhcmdldFByaWNlBAFiCQC2AgEFEGJhc2VBc3NldFJlc2VydmUEAnN6CQC2AgEFEXRvdGFsUG9zaXRpb25TaXplBAFxCQC2AgEFEXF1b3RlQXNzZXRSZXNlcnZlBAFwCQC2AgEFC3RhcmdldFByaWNlBAFrCQEFYm11bGQCBQFxBQFiBARuZXdCCQC3AgIFAWIFAnN6BARuZXdRCQEFYmRpdmQCBQFrBQRuZXdCBAF6CQEFYmRpdmQCBQRuZXdRBQRuZXdCBAZyZXN1bHQJAQViZGl2ZAIFAXAFAXoJAKADAQUGcmVzdWx0ARRnZXRTeW5jVGVybWluYWxQcmljZQMOX3Rlcm1pbmFsUHJpY2UHX3F0QXN0UgdfYnNBc3RSBA1fcG9zaXRpb25TaXplCQERdG90YWxQb3NpdGlvblNpemUAAwkAAAIFDV9wb3NpdGlvblNpemUAAAQJbmV3UXRBc3RXCQEEZGl2ZAIJAQRtdWxkAgUOX3Rlcm1pbmFsUHJpY2UFB19ic0FzdFIFB19xdEFzdFIJAJUKAwUJbmV3UXRBc3RXBQxERUNJTUFMX1VOSVQAAAQJZGlyZWN0aW9uCQBmAgUNX3Bvc2l0aW9uU2l6ZQAABBVjdXJyZW50TmV0TWFya2V0VmFsdWUICQEKc3dhcE91dHB1dAMFCWRpcmVjdGlvbgkBA2FicwEFDV9wb3NpdGlvblNpemUHAl8xBAluZXdRdEFzdFcJARNnZXRRdW90ZUFzc2V0V2VpZ2h0BAUHX2JzQXN0UgUNX3Bvc2l0aW9uU2l6ZQUHX3F0QXN0UgUOX3Rlcm1pbmFsUHJpY2UECW5ld0JzQXN0VwUMREVDSU1BTF9VTklUBA1tYXJnaW5Ub1ZhdWx0CAkBK2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sQnlWYWx1ZXMHBQ1fcG9zaXRpb25TaXplBRVjdXJyZW50TmV0TWFya2V0VmFsdWUFB19xdEFzdFIFCW5ld1F0QXN0VwUHX2JzQXN0UgUJbmV3QnNBc3RXBQ9QTkxfT1BUSU9OX1NQT1QCXzIJAJUKAwUJbmV3UXRBc3RXBQluZXdCc0FzdFcFDW1hcmdpblRvVmF1bHQBCmdldEZ1bmRpbmcABA91bmRlcmx5aW5nUHJpY2UJAQ5nZXRPcmFjbGVQcmljZQAEDXNwb3RUd2FwUHJpY2UJARBnZXRUd2FwU3BvdFByaWNlAAQHcHJlbWl1bQkAZQIFDXNwb3RUd2FwUHJpY2UFD3VuZGVybHlpbmdQcmljZQMDAwkAAAIJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAAABgkAAAIJARV0b3RhbExvbmdQb3NpdGlvblNpemUAAAAGCQEOaXNNYXJrZXRDbG9zZWQACQCUCgIAAAAAAwkAZgIAAAUHcHJlbWl1bQQUc2hvcnRQcmVtaXVtRnJhY3Rpb24JAQRkaXZkAgkBBG11bGQCBQdwcmVtaXVtCQEUZnVuZGluZ1BlcmlvZERlY2ltYWwABQdPTkVfREFZBBNsb25nUHJlbWl1bUZyYWN0aW9uCQEEZGl2ZAIJAQRtdWxkAgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24JARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQAJAJQKAgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24FE2xvbmdQcmVtaXVtRnJhY3Rpb24EE2xvbmdQcmVtaXVtRnJhY3Rpb24JAQRkaXZkAgkBBG11bGQCBQdwcmVtaXVtCQEUZnVuZGluZ1BlcmlvZERlY2ltYWwABQdPTkVfREFZBBRzaG9ydFByZW1pdW1GcmFjdGlvbgkBBGRpdmQCCQEEbXVsZAIFE2xvbmdQcmVtaXVtRnJhY3Rpb24JARV0b3RhbExvbmdQb3NpdGlvblNpemUACQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAJAJQKAgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24FE2xvbmdQcmVtaXVtRnJhY3Rpb24BDmdldEFkanVzdGVkRmVlAgtfYXJ0aWZhY3RJZBBfYmFzZUZlZURpc2NvdW50BApiYXNlRmVlUmF3CQEDZmVlAAQHYmFzZUZlZQkBBG11bGQCBQpiYXNlRmVlUmF3BRBfYmFzZUZlZURpc2NvdW50BA0kdDAzNTA2MzM1NTU4AwkBAiE9AgULX2FydGlmYWN0SWQCAAQMYXJ0aWZhY3RLaW5kCQEEc3RyQQIJARFuZnRNYW5hZ2VyQWRkcmVzcwAJAQ50b0NvbXBvc2l0ZUtleQIFDGtfdG9rZW5fdHlwZQULX2FydGlmYWN0SWQDCQAAAgUMYXJ0aWZhY3RLaW5kBRhGRUVfUkVEVUNUSU9OX1RPS0VOX1RZUEUECXJlZHVjdGlvbgkBBGludEECCQERbmZ0TWFuYWdlckFkZHJlc3MACQEOdG9Db21wb3NpdGVLZXkCBQ1rX3Rva2VuX3BhcmFtBQtfYXJ0aWZhY3RJZAQLYWRqdXN0ZWRGZWUJAQRtdWxkAgUHYmFzZUZlZQUJcmVkdWN0aW9uCQCUCgIFC2FkanVzdGVkRmVlBgkAAgECGUludmFsaWQgYXR0YWNoZWQgYXJ0aWZhY3QJAJQKAgUHYmFzZUZlZQcEC2FkanVzdGVkRmVlCAUNJHQwMzUwNjMzNTU1OAJfMQQMYnVybkFydGlmYWN0CAUNJHQwMzUwNjMzNTU1OAJfMgkAlAoCBQthZGp1c3RlZEZlZQUMYnVybkFydGlmYWN0ARdpc1NhbWVBc3NldE9yTm9Qb3NpdGlvbgIHX3RyYWRlcghfYXNzZXRJZAQPb2xkUG9zaXRpb25TaXplCAkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgJfMQMJAAACBQ9vbGRQb3NpdGlvblNpemUAAAYJAAACCQEQZ2V0UG9zaXRpb25Bc3NldAEFB190cmFkZXIFCF9hc3NldElkAQtpc1NhbWVBc3NldAIHX3RyYWRlcghfYXNzZXRJZAkAAAIJARBnZXRQb3NpdGlvbkFzc2V0AQUHX3RyYWRlcgUIX2Fzc2V0SWQBHmdldEJvcnJvd2VkQnlUcmFkZXJJbk1hcmtldEtleQMEX2FtbQhfYXNzZXRJZAdfdHJhZGVyCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICBSBrX3RyYWRlcl9tYXJrZXRfYXNzZXRfY29sbGF0ZXJhbAIBXwUEX2FtbQIBXwUIX2Fzc2V0SWQCAV8FB190cmFkZXIBE2dldEJvcnJvd2VkQnlUcmFkZXIBB190cmFkZXIEDXBvc2l0aW9uQXNzZXQJARBnZXRQb3NpdGlvbkFzc2V0AQUHX3RyYWRlcgMJAAACBQ1wb3NpdGlvbkFzc2V0CQDYBAEJAQpxdW90ZUFzc2V0AAkAlAoCAAAFDXBvc2l0aW9uQXNzZXQEA2tleQkBHmdldEJvcnJvd2VkQnlUcmFkZXJJbk1hcmtldEtleQMJAKUIAQUEdGhpcwUNcG9zaXRpb25Bc3NldAUHX3RyYWRlcgQGYm9ycm93CQELdmFsdWVPckVsc2UCCQCaCAIJARFjb2xsYXRlcmFsQWRkcmVzcwAFA2tleQAACQCUCgIFBmJvcnJvdwUNcG9zaXRpb25Bc3NldAEYZ2V0Rm9yVHJhZGVyV2l0aEFydGlmYWN0AgdfdHJhZGVyC19hcnRpZmFjdElkBBBkb0dldEZlZURpc2NvdW50CQD8BwQJAQxtaW5lckFkZHJlc3MAAhJjb21wdXRlRmVlRGlzY291bnQJAMwIAgUHX3RyYWRlcgUDbmlsBQNuaWwDCQAAAgUQZG9HZXRGZWVEaXNjb3VudAUQZG9HZXRGZWVEaXNjb3VudAQLZmVlRGlzY291bnQEByRtYXRjaDAFEGRvR2V0RmVlRGlzY291bnQDCQABAgUHJG1hdGNoMAIDSW50BAF4BQckbWF0Y2gwBQF4CQACAQIhSW52YWxpZCBjb21wdXRlRmVlRGlzY291bnQgcmVzdWx0BA0kdDAzNjc4OTM2ODYzCQEOZ2V0QWRqdXN0ZWRGZWUCBQtfYXJ0aWZhY3RJZAULZmVlRGlzY291bnQEC2FkanVzdGVkRmVlCAUNJHQwMzY3ODkzNjg2MwJfMQQMYnVybkFydGlmYWN0CAUNJHQwMzY3ODkzNjg2MwJfMgkAlAoCBQthZGp1c3RlZEZlZQUMYnVybkFydGlmYWN0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAQ1nZXRBcnRpZmFjdElkAQFpBAphcnRpZmFjdElkAwkAZgIJAJADAQgFAWkIcGF5bWVudHMAAQkA2AQBCQETdmFsdWVPckVycm9yTWVzc2FnZQIICQCRAwIIBQFpCHBheW1lbnRzAAEHYXNzZXRJZAISSW52YWxpZCBhcnRpZmFjdElkAgAFCmFydGlmYWN0SWQBDWRpc3RyaWJ1dGVGZWUBCl9mZWVBbW91bnQEDGZlZVRvU3Rha2VycwkBBG11bGQCBQpfZmVlQW1vdW50CQETZmVlVG9TdGFrZXJzUGVyY2VudAAECmZlZVRvVmF1bHQJAGUCBQpfZmVlQW1vdW50BQxmZWVUb1N0YWtlcnMJAJQKAgUMZmVlVG9TdGFrZXJzBQpmZWVUb1ZhdWx0AQ51cGRhdGVTZXR0aW5ncwwQX2luaXRNYXJnaW5SYXRpbwRfbW1yFF9saXF1aWRhdGlvbkZlZVJhdGlvDl9mdW5kaW5nUGVyaW9kBF9mZWUMX3NwcmVhZExpbWl0D19tYXhQcmljZUltcGFjdBhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8PX21heFByaWNlU3ByZWFkEF9tYXhPcGVuTm90aW9uYWwUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQPX21heE9yYWNsZURlbGF5CQDMCAIJAQxJbnRlZ2VyRW50cnkCBRFrX2luaXRNYXJnaW5SYXRpbwUQX2luaXRNYXJnaW5SYXRpbwkAzAgCCQEMSW50ZWdlckVudHJ5AgUYa19tYWludGVuYW5jZU1hcmdpblJhdGlvBQRfbW1yCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRVrX2xpcXVpZGF0aW9uRmVlUmF0aW8FFF9saXF1aWRhdGlvbkZlZVJhdGlvCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ9rX2Z1bmRpbmdQZXJpb2QFDl9mdW5kaW5nUGVyaW9kCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQVrX2ZlZQUEX2ZlZQkAzAgCCQEMSW50ZWdlckVudHJ5AgUNa19zcHJlYWRMaW1pdAUMX3NwcmVhZExpbWl0CQDMCAIJAQxJbnRlZ2VyRW50cnkCBRBrX21heFByaWNlSW1wYWN0BQ9fbWF4UHJpY2VJbXBhY3QJAMwIAgkBDEludGVnZXJFbnRyeQIFGWtfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8FGF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwkAzAgCCQEMSW50ZWdlckVudHJ5AgUQa19tYXhQcmljZVNwcmVhZAUPX21heFByaWNlU3ByZWFkCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRFrX21heE9wZW5Ob3Rpb25hbAUQX21heE9wZW5Ob3Rpb25hbAkAzAgCCQEMSW50ZWdlckVudHJ5AgUVa19mZWVUb1N0YWtlcnNQZXJjZW50BRRfZmVlVG9TdGFrZXJzUGVyY2VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgUQa19tYXhPcmFjbGVEZWxheQUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQFA25pbAENdXBkYXRlRnVuZGluZwURX25leHRGdW5kaW5nQmxvY2skX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uJV9sYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24QX2xvbmdGdW5kaW5nUmF0ZRFfc2hvcnRGdW5kaW5nUmF0ZQkAzAgCCQEMSW50ZWdlckVudHJ5AgUSa19uZXh0RnVuZGluZ0Jsb2NrBRFfbmV4dEZ1bmRpbmdCbG9jawkAzAgCCQEMSW50ZWdlckVudHJ5AgUla19sYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUkX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uCQDMCAIJAQxJbnRlZ2VyRW50cnkCBSZrX2xhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUlX2xhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkAzAgCCQEMSW50ZWdlckVudHJ5AgURa19sb25nRnVuZGluZ1JhdGUFEF9sb25nRnVuZGluZ1JhdGUJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfc2hvcnRGdW5kaW5nUmF0ZQURX3Nob3J0RnVuZGluZ1JhdGUFA25pbAETdXBkYXRlUG9zaXRpb25Bc3NldAIIX2FkZHJlc3MIX2Fzc2V0SWQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUPa19wb3NpdGlvbkFzc2V0BQhfYWRkcmVzcwUIX2Fzc2V0SWQFA25pbAEfaW5jcmVtZW50UG9zaXRpb25TZXF1ZW5jZU51bWJlcgIOX2lzTmV3UG9zaXRpb24IX2FkZHJlc3MDBQ5faXNOZXdQb3NpdGlvbgQPY3VycmVudFNlcXVlbmNlCQEMbGFzdFNlcXVlbmNlAAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUSa19wb3NpdGlvblNlcXVlbmNlBQhfYWRkcmVzcwkAZAIFD2N1cnJlbnRTZXF1ZW5jZQABCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQprX3NlcXVlbmNlCQBkAgUPY3VycmVudFNlcXVlbmNlAAEFA25pbAUDbmlsARF1cGRhdGVQb3NpdGlvbkZlZQMOX2lzTmV3UG9zaXRpb24IX2FkZHJlc3MEX2ZlZQMFDl9pc05ld1Bvc2l0aW9uCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBQ1rX3Bvc2l0aW9uRmVlBQhfYWRkcmVzcwUEX2ZlZQUDbmlsBQNuaWwBDnVwZGF0ZVBvc2l0aW9uBQhfYWRkcmVzcwVfc2l6ZQdfbWFyZ2luDV9vcGVuTm90aW9uYWwgX2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24JAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFDmtfcG9zaXRpb25TaXplBQhfYWRkcmVzcwUFX3NpemUJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFEGtfcG9zaXRpb25NYXJnaW4FCF9hZGRyZXNzBQdfbWFyZ2luCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBRZrX3Bvc2l0aW9uT3Blbk5vdGlvbmFsBQhfYWRkcmVzcwUNX29wZW5Ob3Rpb25hbAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUua19wb3NpdGlvbkxhc3RVcGRhdGVkQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUIX2FkZHJlc3MFIF9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQNuaWwBCmFwcGVuZFR3YXABBl9wcmljZQQIbWludXRlSWQJAGkCCQBpAggFCWxhc3RCbG9jawl0aW1lc3RhbXAA6AcAPAQQcHJldmlvdXNNaW51dGVJZAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQ5rX2xhc3RNaW51dGVJZAAAAwkAZgIFEHByZXZpb3VzTWludXRlSWQFCG1pbnV0ZUlkCQACAQIRVFdBUCBvdXQtb2Ytb3JkZXIEDGxhc3RNaW51dGVJZAMJAAACBRBwcmV2aW91c01pbnV0ZUlkAAAFCG1pbnV0ZUlkBRBwcmV2aW91c01pbnV0ZUlkAwkAZgIFCG1pbnV0ZUlkBRBwcmV2aW91c01pbnV0ZUlkBBNwcmV2Q3VtdWxhdGl2ZVByaWNlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAKwCAgkArAICBR1rX3R3YXBEYXRhTGFzdEN1bXVsYXRpdmVQcmljZQIBXwkApAMBBRBwcmV2aW91c01pbnV0ZUlkAAAECXByZXZQcmljZQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQCsAgIJAKwCAgUTa190d2FwRGF0YUxhc3RQcmljZQIBXwkApAMBBRBwcmV2aW91c01pbnV0ZUlkBQZfcHJpY2UEE2xhc3RDdW11bGF0aXZlUHJpY2UJAGQCBRNwcmV2Q3VtdWxhdGl2ZVByaWNlCQBoAgkAZQIFCG1pbnV0ZUlkBQxsYXN0TWludXRlSWQFCXByZXZQcmljZQQEbGlzdAkBC3B1c2hUb1F1ZXVlAwkBCXN0clRvTGlzdAEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwUNa19sYXN0RGF0YVN0cgIABQ1UV0FQX0lOVEVSVkFMCQCkAwEFCG1pbnV0ZUlkCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBR1rX3R3YXBEYXRhTGFzdEN1bXVsYXRpdmVQcmljZQkApAMBBQhtaW51dGVJZAUTbGFzdEN1bXVsYXRpdmVQcmljZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUTa190d2FwRGF0YUxhc3RQcmljZQkApAMBBQhtaW51dGVJZAUGX3ByaWNlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBRprX3R3YXBEYXRhUHJldmlvdXNNaW51dGVJZAkApAMBBQhtaW51dGVJZAUQcHJldmlvdXNNaW51dGVJZAkAzAgCCQEMSW50ZWdlckVudHJ5AgUOa19sYXN0TWludXRlSWQFCG1pbnV0ZUlkCQDMCAIJAQtTdHJpbmdFbnRyeQIFDWtfbGFzdERhdGFTdHIJAQlsaXN0VG9TdHIBBQRsaXN0BQNuaWwEGHR3YXBEYXRhUHJldmlvdXNNaW51dGVJZAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBRprX3R3YXBEYXRhUHJldmlvdXNNaW51dGVJZAkApAMBBQhtaW51dGVJZAAABBNwcmV2Q3VtdWxhdGl2ZVByaWNlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFHWtfdHdhcERhdGFMYXN0Q3VtdWxhdGl2ZVByaWNlCQCkAwEFGHR3YXBEYXRhUHJldmlvdXNNaW51dGVJZAAABAlwcmV2UHJpY2UJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUTa190d2FwRGF0YUxhc3RQcmljZQkApAMBBRh0d2FwRGF0YVByZXZpb3VzTWludXRlSWQFBl9wcmljZQQTbGFzdEN1bXVsYXRpdmVQcmljZQkAZAIFE3ByZXZDdW11bGF0aXZlUHJpY2UJAGgCCQBlAgUIbWludXRlSWQFGHR3YXBEYXRhUHJldmlvdXNNaW51dGVJZAUJcHJldlByaWNlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBR1rX3R3YXBEYXRhTGFzdEN1bXVsYXRpdmVQcmljZQkApAMBBQhtaW51dGVJZAUTbGFzdEN1bXVsYXRpdmVQcmljZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUTa190d2FwRGF0YUxhc3RQcmljZQkApAMBBQhtaW51dGVJZAUGX3ByaWNlBQNuaWwBEXVwZGF0ZUFtbVJlc2VydmVzAgdfcXRBc3RSB19ic0FzdFIJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tfcXVvdGVBc3NldFJlc2VydmUFB19xdEFzdFIJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfYmFzZUFzc2V0UmVzZXJ2ZQUHX2JzQXN0UgUDbmlsARB1cGRhdGVBbW1XZWlnaHRzAgdfcXRBc3RXB19ic0FzdFcJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfcXVvdGVBc3NldFdlaWdodAUHX3F0QXN0VwkAzAgCCQEMSW50ZWdlckVudHJ5AgURa19iYXNlQXNzZXRXZWlnaHQFB19ic0FzdFcFA25pbAEJdXBkYXRlQW1tCAdfcXRBc3RSB19ic0FzdFIXX3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIVX29wZW5JbnRlcmVzdE5vdGlvbmFsFl90b3RhbExvbmdQb3NpdGlvblNpemUXX3RvdGFsU2hvcnRQb3NpdGlvblNpemUWX3RvdGFsTG9uZ09wZW5Ob3Rpb25hbBdfdG90YWxTaG9ydE9wZW5Ob3Rpb25hbAQHX3F0QXN0VwkBBnF0QXN0VwAEB19ic0FzdFcJAQZic0FzdFcAAwkBAiE9AgkAZQIFFl90b3RhbExvbmdQb3NpdGlvblNpemUFF190b3RhbFNob3J0UG9zaXRpb25TaXplBRdfdG90YWxQb3NpdGlvblNpemVBZnRlcgkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICAhhJbnZhbGlkIEFNTSBzdGF0ZSBkYXRhOiAJAKQDAQUWX3RvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQIEICsgIAkApAMBBRdfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQIEICE9IAkApAMBBRdfdG90YWxQb3NpdGlvblNpemVBZnRlcgkAzggCCQDOCAIJARF1cGRhdGVBbW1SZXNlcnZlcwIFB19xdEFzdFIFB19ic0FzdFIJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tfdG90YWxQb3NpdGlvblNpemUFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRZrX29wZW5JbnRlcmVzdE5vdGlvbmFsBRVfb3BlbkludGVyZXN0Tm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFF2tfdG90YWxMb25nUG9zaXRpb25TaXplBRZfdG90YWxMb25nUG9zaXRpb25TaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRhrX3RvdGFsU2hvcnRQb3NpdGlvblNpemUFF190b3RhbFNob3J0UG9zaXRpb25TaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRJrX29wZW5JbnRlcmVzdExvbmcFFl90b3RhbExvbmdPcGVuTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tfb3BlbkludGVyZXN0U2hvcnQFF190b3RhbFNob3J0T3Blbk5vdGlvbmFsBQNuaWwJAQphcHBlbmRUd2FwAQkBBGRpdmQCCQEEbXVsZAIFB19xdEFzdFIFB19xdEFzdFcJAQRtdWxkAgUHX2JzQXN0UgUHX2JzQXN0VwEOZGVsZXRlUG9zaXRpb24BCF9hZGRyZXNzCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFDmtfcG9zaXRpb25TaXplBQhfYWRkcmVzcwkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBRBrX3Bvc2l0aW9uTWFyZ2luBQhfYWRkcmVzcwkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBRZrX3Bvc2l0aW9uT3Blbk5vdGlvbmFsBQhfYWRkcmVzcwkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQhfYWRkcmVzcwkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBQ9rX3Bvc2l0aW9uQXNzZXQFCF9hZGRyZXNzBQNuaWwBCHdpdGhkcmF3AghfYWRkcmVzcwdfYW1vdW50BAdiYWxhbmNlCQDwBwIFBHRoaXMJAQpxdW90ZUFzc2V0AAMJAGYCBQdfYW1vdW50BQdiYWxhbmNlCQACAQkArAICCQCsAgIJAKwCAgITVW5hYmxlIHRvIHdpdGhkcmF3IAkApAMBBQdfYW1vdW50AhcgZnJvbSBjb250cmFjdCBiYWxhbmNlIAkApAMBBQdiYWxhbmNlCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMFCF9hZGRyZXNzBQdfYW1vdW50CQEKcXVvdGVBc3NldAAFA25pbAENdXBkYXRlQmFsYW5jZQEBaQMJAGYCAAAFAWkJAAIBAgdCYWxhbmNlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQlrX2JhbGFuY2UFAWkFA25pbAELdHJhbnNmZXJGZWUBAWkJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwkBDnN0YWtpbmdBZGRyZXNzAAUBaQkBCnF1b3RlQXNzZXQABQNuaWwBDmRvQnVybkFydGlmYWN0Ag1fYnVybkFydGlmYWN0AWkDBQ1fYnVybkFydGlmYWN0CQDMCAIJAQRCdXJuAgkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCAkAkQMCCAUBaQhwYXltZW50cwABB2Fzc2V0SWQCEEludmFsaWQgYXJ0aWZhY3QAAQUDbmlsBQNuaWwWAWkBBXBhdXNlAAMJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAJAAIBAhRJbnZhbGlkIHBhdXNlIHBhcmFtcwkAzAgCCQEMQm9vbGVhbkVudHJ5AgUIa19wYXVzZWQGBQNuaWwBaQEHdW5wYXVzZQADCQECIT0CCAUBaQZjYWxsZXIJAQxhZG1pbkFkZHJlc3MACQACAQIWSW52YWxpZCB1bnBhdXNlIHBhcmFtcwkAzAgCCQEMQm9vbGVhbkVudHJ5AgUIa19wYXVzZWQHBQNuaWwBaQEMc2V0Q2xvc2VPbmx5AAMJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAJAAIBAhtJbnZhbGlkIHNldENsb3NlT25seSBwYXJhbXMJAMwIAgkBDEJvb2xlYW5FbnRyeQIFC2tfY2xvc2VPbmx5BgUDbmlsAWkBDnVuc2V0Q2xvc2VPbmx5AAMJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAJAAIBAh1JbnZhbGlkIHVuc2V0Q2xvc2VPbmx5IHBhcmFtcwkAzAgCCQEMQm9vbGVhbkVudHJ5AgULa19jbG9zZU9ubHkHBQNuaWwBaQEMYWRkTGlxdWlkaXR5ARFfcXVvdGVBc3NldEFtb3VudAMDCQECIT0CCAUBaQZjYWxsZXIJAQxhZG1pbkFkZHJlc3MABgkAZwIAAAURX3F1b3RlQXNzZXRBbW91bnQJAAIBAhtJbnZhbGlkIGFkZExpcXVpZGl0eSBwYXJhbXMEB19xdEFzdFIJAQZxdEFzdFIABAdfYnNBc3RSCQEGYnNBc3RSAAQHX3F0QXN0VwkBBnF0QXN0VwAEB19ic0FzdFcJAQZic0FzdFcABAVwcmljZQkBBGRpdmQCCQEEbXVsZAIFB19xdEFzdFIFB19xdEFzdFcJAQRtdWxkAgUHX2JzQXN0UgUHX2JzQXN0VwQLcXRBc3RSQWZ0ZXIJAGQCBQdfcXRBc3RSBRFfcXVvdGVBc3NldEFtb3VudAQUYmFzZUFzc2V0QW1vdW50VG9BZGQJAGUCCQEEZGl2ZAIJAQRtdWxkAgULcXRBc3RSQWZ0ZXIFB19xdEFzdFcFBXByaWNlBQdfYnNBc3RSBAtic0FzdFJBZnRlcgkAZAIFB19ic0FzdFIFFGJhc2VBc3NldEFtb3VudFRvQWRkBA0kdDA0NjEwNzQ2MjU4CQEUZ2V0U3luY1Rlcm1pbmFsUHJpY2UDCQEOZ2V0T3JhY2xlUHJpY2UABQtxdEFzdFJBZnRlcgULYnNBc3RSQWZ0ZXIEE25ld1F1b3RlQXNzZXRXZWlnaHQIBQ0kdDA0NjEwNzQ2MjU4Al8xBBJuZXdCYXNlQXNzZXRXZWlnaHQIBQ0kdDA0NjEwNzQ2MjU4Al8yBA1tYXJnaW5Ub1ZhdWx0CAUNJHQwNDYxMDc0NjI1OAJfMwQNZG9FeGNoYW5nZVBuTAMJAQIhPQIFDW1hcmdpblRvVmF1bHQAAAQNZG9FeGNoYW5nZVBuTAkA/AcECQEMdmF1bHRBZGRyZXNzAAIVZXhjaGFuZ2VGcmVlQW5kTG9ja2VkCQDMCAIFDW1hcmdpblRvVmF1bHQFA25pbAUDbmlsAwkAAAIFDWRvRXhjaGFuZ2VQbkwFDWRvRXhjaGFuZ2VQbkwFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFDWRvRXhjaGFuZ2VQbkwFDWRvRXhjaGFuZ2VQbkwJAM4IAgkBEXVwZGF0ZUFtbVJlc2VydmVzAgULcXRBc3RSQWZ0ZXIFC2JzQXN0UkFmdGVyCQEQdXBkYXRlQW1tV2VpZ2h0cwIFE25ld1F1b3RlQXNzZXRXZWlnaHQFEm5ld0Jhc2VBc3NldFdlaWdodAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ9yZW1vdmVMaXF1aWRpdHkBEV9xdW90ZUFzc2V0QW1vdW50AwMJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAGCQBnAgURX3F1b3RlQXNzZXRBbW91bnQAAAkAAgECHkludmFsaWQgcmVtb3ZlTGlxdWlkaXR5IHBhcmFtcwQHX3F0QXN0UgkBBnF0QXN0UgAEB19ic0FzdFIJAQZic0FzdFIABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAEBXByaWNlCQEEZGl2ZAIJAQRtdWxkAgUHX3F0QXN0UgUHX3F0QXN0VwkBBG11bGQCBQdfYnNBc3RSBQdfYnNBc3RXBAtxdEFzdFJBZnRlcgkAZQIFB19xdEFzdFIFEV9xdW90ZUFzc2V0QW1vdW50BBdiYXNlQXNzZXRBbW91bnRUb1JlbW92ZQkBA2FicwEJAGUCCQEEZGl2ZAIJAQRtdWxkAgULcXRBc3RSQWZ0ZXIFB19xdEFzdFcFBXByaWNlBQdfYnNBc3RSBAtic0FzdFJBZnRlcgkAZQIFB19ic0FzdFIFF2Jhc2VBc3NldEFtb3VudFRvUmVtb3ZlBA0kdDA0NzE5MDQ3MzQxCQEUZ2V0U3luY1Rlcm1pbmFsUHJpY2UDCQEOZ2V0T3JhY2xlUHJpY2UABQtxdEFzdFJBZnRlcgULYnNBc3RSQWZ0ZXIEE25ld1F1b3RlQXNzZXRXZWlnaHQIBQ0kdDA0NzE5MDQ3MzQxAl8xBBJuZXdCYXNlQXNzZXRXZWlnaHQIBQ0kdDA0NzE5MDQ3MzQxAl8yBA1tYXJnaW5Ub1ZhdWx0CAUNJHQwNDcxOTA0NzM0MQJfMwQNZG9FeGNoYW5nZVBuTAMJAQIhPQIFDW1hcmdpblRvVmF1bHQAAAQNZG9FeGNoYW5nZVBuTAkA/AcECQEMdmF1bHRBZGRyZXNzAAIVZXhjaGFuZ2VGcmVlQW5kTG9ja2VkCQDMCAIFDW1hcmdpblRvVmF1bHQFA25pbAUDbmlsAwkAAAIFDWRvRXhjaGFuZ2VQbkwFDWRvRXhjaGFuZ2VQbkwFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFDWRvRXhjaGFuZ2VQbkwFDWRvRXhjaGFuZ2VQbkwJAM4IAgkBEXVwZGF0ZUFtbVJlc2VydmVzAgULcXRBc3RSQWZ0ZXIFC2JzQXN0UkFmdGVyCQEQdXBkYXRlQW1tV2VpZ2h0cwIFE25ld1F1b3RlQXNzZXRXZWlnaHQFEm5ld0Jhc2VBc3NldFdlaWdodAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ5jaGFuZ2VTZXR0aW5ncwwQX2luaXRNYXJnaW5SYXRpbwRfbW1yFF9saXF1aWRhdGlvbkZlZVJhdGlvDl9mdW5kaW5nUGVyaW9kBF9mZWUMX3NwcmVhZExpbWl0D19tYXhQcmljZUltcGFjdBhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8PX21heFByaWNlU3ByZWFkEF9tYXhPcGVuTm90aW9uYWwUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQPX21heE9yYWNsZURlbGF5AwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECHUludmFsaWQgY2hhbmdlU2V0dGluZ3MgcGFyYW1zCQEOdXBkYXRlU2V0dGluZ3MMBRBfaW5pdE1hcmdpblJhdGlvBQRfbW1yBRRfbGlxdWlkYXRpb25GZWVSYXRpbwUOX2Z1bmRpbmdQZXJpb2QFBF9mZWUFDF9zcHJlYWRMaW1pdAUPX21heFByaWNlSW1wYWN0BRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8FD19tYXhQcmljZVNwcmVhZAUQX21heE9wZW5Ob3Rpb25hbAUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQFD19tYXhPcmFjbGVEZWxheQFpAQppbml0aWFsaXplEgdfcXRBc3RSB19ic0FzdFIOX2Z1bmRpbmdQZXJpb2QQX2luaXRNYXJnaW5SYXRpbwRfbW1yFF9saXF1aWRhdGlvbkZlZVJhdGlvBF9mZWUHX29yYWNsZQpfb3JhY2xlS2V5D19vcmFjbGVCbG9ja0tleQxfY29vcmRpbmF0b3IMX3NwcmVhZExpbWl0D19tYXhQcmljZUltcGFjdBhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8PX21heFByaWNlU3ByZWFkEF9tYXhPcGVuTm90aW9uYWwUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQPX21heE9yYWNsZURlbGF5AwMDAwMDAwMDAwMDAwMDAwkAZwIAAAUHX3F0QXN0UgYJAGcCAAAFB19ic0FzdFIGCQBnAgAABQ5fZnVuZGluZ1BlcmlvZAYJAGcCAAAFEF9pbml0TWFyZ2luUmF0aW8GCQBnAgAABQRfbW1yBgkAZwIAAAUUX2xpcXVpZGF0aW9uRmVlUmF0aW8GCQBnAgAABQRfZmVlBgkAZwIAAAUMX3NwcmVhZExpbWl0BgkAZwIAAAUPX21heFByaWNlSW1wYWN0BgkAZwIAAAUYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvBgkAZwIAAAUPX21heFByaWNlU3ByZWFkBgkAZwIAAAUQX21heE9wZW5Ob3Rpb25hbAYJAGcCAAAFFF9mZWVUb1N0YWtlcnNQZXJjZW50BgkAZgIFFF9mZWVUb1N0YWtlcnNQZXJjZW50BQxERUNJTUFMX1VOSVQGCQBnAgAABQ9fbWF4T3JhY2xlRGVsYXkGCQELaW5pdGlhbGl6ZWQACQACAQIdSW52YWxpZCBpbml0aWFsaXplIHBhcmFtZXRlcnMJAM4IAgkAzggCCQDOCAIJAM4IAgkBCXVwZGF0ZUFtbQgFB19xdEFzdFIFB19ic0FzdFIAAAAAAAAAAAAAAAAJAQ51cGRhdGVTZXR0aW5ncwwFEF9pbml0TWFyZ2luUmF0aW8FBF9tbXIFFF9saXF1aWRhdGlvbkZlZVJhdGlvBQ5fZnVuZGluZ1BlcmlvZAUEX2ZlZQUMX3NwcmVhZExpbWl0BQ9fbWF4UHJpY2VJbXBhY3QFGF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwUPX21heFByaWNlU3ByZWFkBRBfbWF4T3Blbk5vdGlvbmFsBRRfZmVlVG9TdGFrZXJzUGVyY2VudAUPX21heE9yYWNsZURlbGF5CQENdXBkYXRlRnVuZGluZwUJAGQCCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAUOX2Z1bmRpbmdQZXJpb2QAAAAAAAAAAAkBDXVwZGF0ZUJhbGFuY2UBAAAJAMwIAgkBDEJvb2xlYW5FbnRyeQIFDWtfaW5pdGlhbGl6ZWQGCQDMCAIJAQtTdHJpbmdFbnRyeQIFBWtfb3JhBQdfb3JhY2xlCQDMCAIJAQtTdHJpbmdFbnRyeQIFCWtfb3JhX2tleQUKX29yYWNsZUtleQkAzAgCCQELU3RyaW5nRW50cnkCBQ9rX29yYV9ibG9ja19rZXkFD19vcmFjbGVCbG9ja0tleQkAzAgCCQELU3RyaW5nRW50cnkCBRRrX2Nvb3JkaW5hdG9yQWRkcmVzcwUMX2Nvb3JkaW5hdG9yBQNuaWwBaQEQaW5jcmVhc2VQb3NpdGlvbgQKX2RpcmVjdGlvbglfbGV2ZXJhZ2UTX21pbkJhc2VBc3NldEFtb3VudAhfcmVmTGluawQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBAdfdHJhZGVyCQEPZ2V0QWN0dWFsQ2FsbGVyAQUBaQQKX3Jhd0Ftb3VudAgJAJEDAggFAWkIcGF5bWVudHMAAAZhbW91bnQECF9hc3NldElkCAkAkQMCCAUBaQhwYXltZW50cwAAB2Fzc2V0SWQEC19hc3NldElkU3RyCQDYBAEJAQV2YWx1ZQEFCF9hc3NldElkBAxpc1F1b3RlQXNzZXQJAAACBQhfYXNzZXRJZAkBCnF1b3RlQXNzZXQABBFpc0NvbGxhdGVyYWxBc3NldAkBEGlzV2hpdGVsaXN0QXNzZXQBBQtfYXNzZXRJZFN0cgMDAwMDAwMDAwMJAQIhPQIFCl9kaXJlY3Rpb24FCERJUl9MT05HCQECIT0CBQpfZGlyZWN0aW9uBQlESVJfU0hPUlQHBgkAZwIAAAUKX3Jhd0Ftb3VudAYJAQEhAQkBC2luaXRpYWxpemVkAAYDCQEBIQEFDGlzUXVvdGVBc3NldAkBASEBBRFpc0NvbGxhdGVyYWxBc3NldAcGCQEBIQEJARdpc1NhbWVBc3NldE9yTm9Qb3NpdGlvbgIFB190cmFkZXIFC19hc3NldElkU3RyBgkBASEBCQEWcmVxdWlyZU1vcmVNYXJnaW5SYXRpbwMJAQRkaXZkAgUMREVDSU1BTF9VTklUBQlfbGV2ZXJhZ2UJAQ9pbml0TWFyZ2luUmF0aW8ABgYJAQZwYXVzZWQABgkBCWNsb3NlT25seQAGCQEOaXNNYXJrZXRDbG9zZWQACQACAQIjSW52YWxpZCBpbmNyZWFzZVBvc2l0aW9uIHBhcmFtZXRlcnMEDSR0MDUxMDA5NTExNTgJARhnZXRGb3JUcmFkZXJXaXRoQXJ0aWZhY3QCBQdfdHJhZGVyCQENZ2V0QXJ0aWZhY3RJZAEFAWkEC2FkanVzdGVkRmVlCAUNJHQwNTEwMDk1MTE1OAJfMQQMYnVybkFydGlmYWN0CAUNJHQwNTEwMDk1MTE1OAJfMgQHX2Ftb3VudAkBBGRpdmQCBQpfcmF3QW1vdW50CQBkAgkBBG11bGQCBQthZGp1c3RlZEZlZQUJX2xldmVyYWdlBQxERUNJTUFMX1VOSVQEDHJhd0ZlZUFtb3VudAkAZQIFCl9yYXdBbW91bnQFB19hbW91bnQEE2Rpc3RyaWJ1dGVGZWVBbW91bnQDBRFpc0NvbGxhdGVyYWxBc3NldAQIZG9Cb3Jyb3cJAPwHBAkBEWNvbGxhdGVyYWxBZGRyZXNzAAIGYm9ycm93CQDMCAIFB190cmFkZXIFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgUIX2Fzc2V0SWQFB19hbW91bnQFA25pbAMJAAACBQhkb0JvcnJvdwUIZG9Cb3Jyb3cEDWJhbGFuY2VCZWZvcmUJAPAHAgUEdGhpcwkBCnF1b3RlQXNzZXQAAwkAAAIFDWJhbGFuY2VCZWZvcmUFDWJhbGFuY2VCZWZvcmUEBmRvU3dhcAkA/AcECQELc3dhcEFkZHJlc3MAAgRzd2FwCQDMCAIJANgEAQkBCnF1b3RlQXNzZXQACQDMCAIAAAUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCBQhfYXNzZXRJZAUMcmF3RmVlQW1vdW50BQNuaWwDCQAAAgUGZG9Td2FwBQZkb1N3YXAEDGJhbGFuY2VBZnRlcgkA8AcCBQR0aGlzCQEKcXVvdGVBc3NldAADCQAAAgUMYmFsYW5jZUFmdGVyBQxiYWxhbmNlQWZ0ZXIED2V4Y2hhbmdlZEFtb3VudAkAZQIFDGJhbGFuY2VBZnRlcgUNYmFsYW5jZUJlZm9yZQMJAAACBQ9leGNoYW5nZWRBbW91bnQFD2V4Y2hhbmdlZEFtb3VudAUPZXhjaGFuZ2VkQW1vdW50CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQxyYXdGZWVBbW91bnQDCQAAAgUTZGlzdHJpYnV0ZUZlZUFtb3VudAUTZGlzdHJpYnV0ZUZlZUFtb3VudAQOcmVmZXJyZXJGZWVBbnkJAPwHBAkBD3JlZmVycmFsQWRkcmVzcwACFWFjY2VwdFBheW1lbnRXaXRoTGluawkAzAgCBQdfdHJhZGVyCQDMCAIFCF9yZWZMaW5rBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUTZGlzdHJpYnV0ZUZlZUFtb3VudAUDbmlsAwkAAAIFDnJlZmVycmVyRmVlQW55BQ5yZWZlcnJlckZlZUFueQQLcmVmZXJyZXJGZWUEByRtYXRjaDAFDnJlZmVycmVyRmVlQW55AwkAAQIFByRtYXRjaDACA0ludAQBeAUHJG1hdGNoMAUBeAkAAgECE0ludmFsaWQgcmVmZXJyZXJGZWUECWZlZUFtb3VudAkAZQIFE2Rpc3RyaWJ1dGVGZWVBbW91bnQFC3JlZmVycmVyRmVlBA0kdDA1MjUwMDUyNjQwCQELZ2V0UG9zaXRpb24BBQdfdHJhZGVyBA9vbGRQb3NpdGlvblNpemUIBQ0kdDA1MjUwMDUyNjQwAl8xBBFvbGRQb3NpdGlvbk1hcmdpbggFDSR0MDUyNTAwNTI2NDACXzIEF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNTI1MDA1MjY0MAJfMwQUb2xkUG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA1MjUwMDUyNjQwAl80BA1pc05ld1Bvc2l0aW9uCQAAAgUPb2xkUG9zaXRpb25TaXplAAAED2lzU2FtZURpcmVjdGlvbgMJAGYCBQ9vbGRQb3NpdGlvblNpemUAAAkAAAIFCl9kaXJlY3Rpb24FCERJUl9MT05HCQAAAgUKX2RpcmVjdGlvbgUJRElSX1NIT1JUBA5leHBhbmRFeGlzdGluZwMJAQEhAQUNaXNOZXdQb3NpdGlvbgUPaXNTYW1lRGlyZWN0aW9uBwQFaXNBZGQJAAACBQpfZGlyZWN0aW9uBQhESVJfTE9ORwQNJHQwNTI5Mjk1NTg5MQMDBQ1pc05ld1Bvc2l0aW9uBgUOZXhwYW5kRXhpc3RpbmcEDG9wZW5Ob3Rpb25hbAkBBG11bGQCBQdfYW1vdW50BQlfbGV2ZXJhZ2UEDSR0MDUzMzkxNTM1NjQJAQlzd2FwSW5wdXQCBQVpc0FkZAUMb3Blbk5vdGlvbmFsBBVhbW91bnRCYXNlQXNzZXRCb3VnaHQIBQ0kdDA1MzM5MTUzNTY0Al8xBBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNTMzOTE1MzU2NAJfMgQVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNTMzOTE1MzU2NAJfMwQWdG90YWxQb3NpdGlvblNpemVBZnRlcggFDSR0MDUzMzkxNTM1NjQCXzQDAwkBAiE9AgUTX21pbkJhc2VBc3NldEFtb3VudAAACQBmAgUTX21pbkJhc2VBc3NldEFtb3VudAkBA2FicwEFFWFtb3VudEJhc2VBc3NldEJvdWdodAcJAAIBCQCsAgIJAKwCAgkArAICAg1MaW1pdCBlcnJvcjogCQCkAwEJAQNhYnMBBRVhbW91bnRCYXNlQXNzZXRCb3VnaHQCAyA8IAkApAMBBRNfbWluQmFzZUFzc2V0QW1vdW50BA9uZXdQb3NpdGlvblNpemUJAGQCBQ9vbGRQb3NpdGlvblNpemUFFWFtb3VudEJhc2VBc3NldEJvdWdodAQadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIJAGQCCQEQb3BlbkludGVyZXN0TG9uZwADCQBmAgUPbmV3UG9zaXRpb25TaXplAAAFDG9wZW5Ob3Rpb25hbAAABBt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIJAGQCCQERb3BlbkludGVyZXN0U2hvcnQAAwkAZgIAAAUPbmV3UG9zaXRpb25TaXplBQxvcGVuTm90aW9uYWwAAAQNJHQwNTQxMTA1NDMzMQkBImNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnQEBQ9vbGRQb3NpdGlvblNpemUFEW9sZFBvc2l0aW9uTWFyZ2luBRRvbGRQb3NpdGlvbkxzdFVwZENQRgUHX2Ftb3VudAQMcmVtYWluTWFyZ2luCAUNJHQwNTQxMTA1NDMzMQJfMQQCeDEIBQ0kdDA1NDExMDU0MzMxAl8yBAJ4MggFDSR0MDU0MTEwNTQzMzECXzMDCQEBIQEJARlyZXF1aXJlTm90T3ZlclNwcmVhZExpbWl0AgUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCQACAQIVT3ZlciBtYXggc3ByZWFkIGxpbWl0AwkBASEBCQEdcmVxdWlyZU5vdE92ZXJNYXhPcGVuTm90aW9uYWwCBRp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcgUbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCQACAQIWT3ZlciBtYXggb3BlbiBub3Rpb25hbAkAngoMBQ9uZXdQb3NpdGlvblNpemUFDHJlbWFpbk1hcmdpbgkAZAIFF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsBQxvcGVuTm90aW9uYWwJAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAQUPbmV3UG9zaXRpb25TaXplBRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIJAGQCCQEUb3BlbkludGVyZXN0Tm90aW9uYWwABQxvcGVuTm90aW9uYWwJAGQCCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAMJAGYCBQ9uZXdQb3NpdGlvblNpemUAAAkBA2FicwEFFWFtb3VudEJhc2VBc3NldEJvdWdodAAACQBkAgkBFnRvdGFsU2hvcnRQb3NpdGlvblNpemUAAwkAZgIAAAUPbmV3UG9zaXRpb25TaXplCQEDYWJzAQUVYW1vdW50QmFzZUFzc2V0Qm91Z2h0AAAFGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyBRt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIEDG9wZW5Ob3Rpb25hbAkBBG11bGQCBQdfYW1vdW50BQlfbGV2ZXJhZ2UEDSR0MDU1NTkxNTU3MDcJASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAIJAKUIAQgFAWkGY2FsbGVyBQ9QTkxfT1BUSU9OX1NQT1QEE29sZFBvc2l0aW9uTm90aW9uYWwIBQ0kdDA1NTU5MTU1NzA3Al8xBA11bnJlYWxpemVkUG5sCAUNJHQwNTU1OTE1NTcwNwJfMgMJAGYCBRNvbGRQb3NpdGlvbk5vdGlvbmFsBQxvcGVuTm90aW9uYWwJAAIBAi5Vc2UgZGVjcmVhc2VQb3NpdGlvbiB0byBkZWNyZWFzZSBwb3NpdGlvbiBzaXplCQACAQIUQ2xvc2UgcG9zaXRpb24gZmlyc3QED25ld1Bvc2l0aW9uU2l6ZQgFDSR0MDUyOTI5NTU4OTECXzEEF25ld1Bvc2l0aW9uUmVtYWluTWFyZ2luCAUNJHQwNTI5Mjk1NTg5MQJfMgQXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDA1MjkyOTU1ODkxAl8zBBRuZXdQb3NpdGlvbkxhdGVzdENQRggFDSR0MDUyOTI5NTU4OTECXzQEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDUyOTI5NTU4OTECXzUEFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA1MjkyOTU1ODkxAl82BBZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCAUNJHQwNTI5Mjk1NTg5MQJfNwQZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcggFDSR0MDUyOTI5NTU4OTECXzgEDnRvdGFsTG9uZ0FmdGVyCAUNJHQwNTI5Mjk1NTg5MQJfOQQPdG90YWxTaG9ydEFmdGVyCAUNJHQwNTI5Mjk1NTg5MQNfMTAEGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyCAUNJHQwNTI5Mjk1NTg5MQNfMTEEG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcggFDSR0MDUyOTI5NTU4OTEDXzEyBA0kdDA1NTg5NzU1OTU0CQENZGlzdHJpYnV0ZUZlZQEFCWZlZUFtb3VudAQMZmVlVG9TdGFrZXJzCAUNJHQwNTU4OTc1NTk1NAJfMQQKZmVlVG9WYXVsdAgFDSR0MDU1ODk3NTU5NTQCXzIEBXN0YWtlAwUMaXNRdW90ZUFzc2V0BAVzdGFrZQkA/AcECQEMdmF1bHRBZGRyZXNzAAIJYWRkTG9ja2VkCQDMCAIHBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUHX2Ftb3VudAUDbmlsAwkAAAIFBXN0YWtlBQVzdGFrZQUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUFc3Rha2UFBXN0YWtlBAxkZXBvc2l0VmF1bHQJAPwHBAkBDHZhdWx0QWRkcmVzcwACB2FkZEZyZWUFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQpmZWVUb1ZhdWx0BQNuaWwDCQAAAgUMZGVwb3NpdFZhdWx0BQxkZXBvc2l0VmF1bHQECW5vdGlmeUZlZQkA/AcECQEMbWluZXJBZGRyZXNzAAIKbm90aWZ5RmVlcwkAzAgCBQdfdHJhZGVyCQDMCAIFCWZlZUFtb3VudAUDbmlsBQNuaWwDCQAAAgUJbm90aWZ5RmVlBQlub3RpZnlGZWUEDm5vdGlmeU5vdGlvbmFsCQD8BwQJAQxtaW5lckFkZHJlc3MAAg5ub3RpZnlOb3Rpb25hbAkAzAgCBQdfdHJhZGVyCQDMCAIFF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBQNuaWwFA25pbAMJAAACBQ5ub3RpZnlOb3Rpb25hbAUObm90aWZ5Tm90aW9uYWwJAM4IAgkAzggCCQDOCAIJAM4IAgkAzggCCQDOCAIJAM4IAgkBDnVwZGF0ZVBvc2l0aW9uBQUHX3RyYWRlcgUPbmV3UG9zaXRpb25TaXplBRduZXdQb3NpdGlvblJlbWFpbk1hcmdpbgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFFG5ld1Bvc2l0aW9uTGF0ZXN0Q1BGCQEfaW5jcmVtZW50UG9zaXRpb25TZXF1ZW5jZU51bWJlcgIFDWlzTmV3UG9zaXRpb24FB190cmFkZXIJARF1cGRhdGVQb3NpdGlvbkZlZQMFDWlzTmV3UG9zaXRpb24FB190cmFkZXIFC2FkanVzdGVkRmVlCQETdXBkYXRlUG9zaXRpb25Bc3NldAIFB190cmFkZXIFC19hc3NldElkU3RyCQEJdXBkYXRlQW1tCAUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBRZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyBRlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyBQ50b3RhbExvbmdBZnRlcgUPdG90YWxTaG9ydEFmdGVyBRp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcgUbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCQELdHJhbnNmZXJGZWUBBQxmZWVUb1N0YWtlcnMJAQ11cGRhdGVCYWxhbmNlAQkAZAIJAQhjYmFsYW5jZQAFB19hbW91bnQJAQ5kb0J1cm5BcnRpZmFjdAIFDGJ1cm5BcnRpZmFjdAUBaQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQlhZGRNYXJnaW4ABARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEB190cmFkZXIJAKUIAQgFAWkGY2FsbGVyBAdfYW1vdW50CAkAkQMCCAUBaQhwYXltZW50cwAABmFtb3VudAQIX2Fzc2V0SWQICQCRAwIIBQFpCHBheW1lbnRzAAAHYXNzZXRJZAQLX2Fzc2V0SWRTdHIJANgEAQkBBXZhbHVlAQUIX2Fzc2V0SWQEDGlzUXVvdGVBc3NldAkAAAIFCF9hc3NldElkCQEKcXVvdGVBc3NldAAEEWlzQ29sbGF0ZXJhbEFzc2V0CQEQaXNXaGl0ZWxpc3RBc3NldAEFC19hc3NldElkU3RyAwMDAwMDAwMJAQEhAQUMaXNRdW90ZUFzc2V0CQEBIQEFEWlzQ29sbGF0ZXJhbEFzc2V0BwYJAQEhAQkBE3JlcXVpcmVPcGVuUG9zaXRpb24BCQClCAEIBQFpBmNhbGxlcgYJAQEhAQkBC2lzU2FtZUFzc2V0AgUHX3RyYWRlcgULX2Fzc2V0SWRTdHIGCQEBIQEJAQtpbml0aWFsaXplZAAGCQEGcGF1c2VkAAYJAQljbG9zZU9ubHkABgkBDmlzTWFya2V0Q2xvc2VkAAkAAgECHEludmFsaWQgYWRkTWFyZ2luIHBhcmFtZXRlcnMEDSR0MDU3OTg1NTgxMjUJAQtnZXRQb3NpdGlvbgEFB190cmFkZXIED29sZFBvc2l0aW9uU2l6ZQgFDSR0MDU3OTg1NTgxMjUCXzEEEW9sZFBvc2l0aW9uTWFyZ2luCAUNJHQwNTc5ODU1ODEyNQJfMgQXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDA1Nzk4NTU4MTI1Al8zBBRvbGRQb3NpdGlvbkxzdFVwZENQRggFDSR0MDU3OTg1NTgxMjUCXzQEBXN0YWtlAwUMaXNRdW90ZUFzc2V0BAVzdGFrZQkA/AcECQEMdmF1bHRBZGRyZXNzAAIJYWRkTG9ja2VkCQDMCAIHBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUHX2Ftb3VudAUDbmlsAwkAAAIFBXN0YWtlBQVzdGFrZQUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUFc3Rha2UFBXN0YWtlCQDOCAIJAQ51cGRhdGVQb3NpdGlvbgUFB190cmFkZXIFD29sZFBvc2l0aW9uU2l6ZQkAZAIFEW9sZFBvc2l0aW9uTWFyZ2luBQdfYW1vdW50BRdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAUUb2xkUG9zaXRpb25Mc3RVcGRDUEYJAQ11cGRhdGVCYWxhbmNlAQkAZAIJAQhjYmFsYW5jZQAFB19hbW91bnQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEMcmVtb3ZlTWFyZ2luAQdfYW1vdW50BARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEB190cmFkZXIJAKUIAQgFAWkGY2FsbGVyAwMDAwMJAGcCAAAFB19hbW91bnQGCQEBIQEJARNyZXF1aXJlT3BlblBvc2l0aW9uAQUHX3RyYWRlcgYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQZwYXVzZWQABgkBDmlzTWFya2V0Q2xvc2VkAAkAAgECH0ludmFsaWQgcmVtb3ZlTWFyZ2luIHBhcmFtZXRlcnMEDSR0MDU4OTIwNTkwNjAJAQtnZXRQb3NpdGlvbgEFB190cmFkZXIED29sZFBvc2l0aW9uU2l6ZQgFDSR0MDU4OTIwNTkwNjACXzEEEW9sZFBvc2l0aW9uTWFyZ2luCAUNJHQwNTg5MjA1OTA2MAJfMgQXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDA1ODkyMDU5MDYwAl8zBBRvbGRQb3NpdGlvbkxzdFVwZENQRggFDSR0MDU4OTIwNTkwNjACXzQEC21hcmdpbkRlbHRhCQEBLQEFB19hbW91bnQEDSR0MDU5MDk3NTkyNzYJASJjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50BAUPb2xkUG9zaXRpb25TaXplBRFvbGRQb3NpdGlvbk1hcmdpbgUUb2xkUG9zaXRpb25Mc3RVcGRDUEYFC21hcmdpbkRlbHRhBAxyZW1haW5NYXJnaW4IBQ0kdDA1OTA5NzU5Mjc2Al8xBAdiYWREZWJ0CAUNJHQwNTkwOTc1OTI3NgJfMgMJAQIhPQIFB2JhZERlYnQAAAkAAgECHUludmFsaWQgcmVtb3ZlZCBtYXJnaW4gYW1vdW50BAttYXJnaW5SYXRpbwkBD2NhbGNNYXJnaW5SYXRpbwMFDHJlbWFpbk1hcmdpbgUHYmFkRGVidAUXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwDCQEBIQEJARZyZXF1aXJlTW9yZU1hcmdpblJhdGlvAwULbWFyZ2luUmF0aW8JAQ9pbml0TWFyZ2luUmF0aW8ABgkAAgEJAKwCAgkArAICCQCsAgICGVRvbyBtdWNoIG1hcmdpbiByZW1vdmVkOiAJAKQDAQULbWFyZ2luUmF0aW8CAyA8IAkApAMBCQEPaW5pdE1hcmdpblJhdGlvAAQNcXVvdGVBc3NldFN0cgkA2AQBCQEKcXVvdGVBc3NldAAEDSR0MDU5NzIwNTk3NzQJARNnZXRCb3Jyb3dlZEJ5VHJhZGVyAQUHX3RyYWRlcgQIYm9ycm93ZWQIBQ0kdDA1OTcyMDU5Nzc0Al8xBAdhc3NldElkCAUNJHQwNTk3MjA1OTc3NAJfMgQHdG9SZXBheQMJAGYCBQdfYW1vdW50BQhib3Jyb3dlZAUIYm9ycm93ZWQFB19hbW91bnQECnRvV2l0aGRyYXcDCQBmAgUIYm9ycm93ZWQFB19hbW91bnQAAAkAZQIFB19hbW91bnQFCGJvcnJvd2VkBAtmaW5hbEJvcnJvdwkAZQIFCGJvcnJvd2VkBQd0b1JlcGF5BBVzd2l0Y2hQb3NpdGlvblRvUXVvdGUDCQBmAgULZmluYWxCb3Jyb3cAAAUDbmlsCQETdXBkYXRlUG9zaXRpb25Bc3NldAIFB190cmFkZXIFDXF1b3RlQXNzZXRTdHIEDWRvU2FuaXR5Q2hlY2sDCQECIT0CCQBkAgUHdG9SZXBheQUKdG9XaXRoZHJhdwUHX2Ftb3VudAkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICAgh0b1JlcGF5PQkApAMBBQd0b1JlcGF5Ag4gKyB0b1dpdGhkcmF3PQkApAMBBQp0b1dpdGhkcmF3AgQgIT0gCQCkAwEFB19hbW91bnQFA25pbAMJAAACBQ1kb1Nhbml0eUNoZWNrBQ1kb1Nhbml0eUNoZWNrBAlkb1Vuc3Rha2UDCQBmAgUKdG9XaXRoZHJhdwAABAlkb1Vuc3Rha2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACDndpdGhkcmF3TG9ja2VkCQDMCAIFCnRvV2l0aGRyYXcFA25pbAUDbmlsAwkAAAIFCWRvVW5zdGFrZQUJZG9VbnN0YWtlBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBQlkb1Vuc3Rha2UFCWRvVW5zdGFrZQQWcmV0dXJuQ29sbGF0ZXJhbEFjdGlvbgMJAGYCBQd0b1JlcGF5AAAEB2RvUmVwYXkJAPwHBAkBEWNvbGxhdGVyYWxBZGRyZXNzAAIFcmVwYXkJAMwIAgUHX3RyYWRlcgkAzAgCBQd0b1JlcGF5CQDMCAIFB2Fzc2V0SWQFA25pbAUDbmlsAwkAAAIFB2RvUmVwYXkFB2RvUmVwYXkJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwgFAWkGY2FsbGVyBQd0b1JlcGF5CQDZBAEFB2Fzc2V0SWQFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFFnJldHVybkNvbGxhdGVyYWxBY3Rpb24FFnJldHVybkNvbGxhdGVyYWxBY3Rpb24JAM4IAgkAzggCCQDOCAIJAM4IAgkBDnVwZGF0ZVBvc2l0aW9uBQUHX3RyYWRlcgUPb2xkUG9zaXRpb25TaXplBQxyZW1haW5NYXJnaW4FF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCQEfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEFD29sZFBvc2l0aW9uU2l6ZQMJAGYCBQp0b1dpdGhkcmF3AAAJAQh3aXRoZHJhdwIIBQFpBmNhbGxlcgUKdG9XaXRoZHJhdwUDbmlsCQENdXBkYXRlQmFsYW5jZQEJAGUCCQEIY2JhbGFuY2UABQdfYW1vdW50BRVzd2l0Y2hQb3NpdGlvblRvUXVvdGUFFnJldHVybkNvbGxhdGVyYWxBY3Rpb24JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQENY2xvc2VQb3NpdGlvbgMFX3NpemUUX21pblF1b3RlQXNzZXRBbW91bnQMX2FkZFRvTWFyZ2luBARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEB190cmFkZXIJAQ9nZXRBY3R1YWxDYWxsZXIBBQFpBA5fdHJhZGVyQWRkcmVzcwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEFB190cmFkZXICDkludmFsaWQgY2FsbGVyBAtwb3NpdGlvbkZlZQkBDmdldFBvc2l0aW9uRmVlAQUHX3RyYWRlcgMDAwMDAwkBASEBCQETcmVxdWlyZU9wZW5Qb3NpdGlvbgEFB190cmFkZXIGCQEBIQEJAQtpbml0aWFsaXplZAAGCQEGcGF1c2VkAAYJAGcCAAAFBV9zaXplBgkAZgIAAAUUX21pblF1b3RlQXNzZXRBbW91bnQGCQEOaXNNYXJrZXRDbG9zZWQACQACAQIgSW52YWxpZCBjbG9zZVBvc2l0aW9uIHBhcmFtZXRlcnMEDSR0MDYyMDExNjIxNTEJAQtnZXRQb3NpdGlvbgEFB190cmFkZXIED29sZFBvc2l0aW9uU2l6ZQgFDSR0MDYyMDExNjIxNTECXzEEEW9sZFBvc2l0aW9uTWFyZ2luCAUNJHQwNjIwMTE2MjE1MQJfMgQXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDA2MjAxMTYyMTUxAl8zBBRvbGRQb3NpdGlvbkxzdFVwZENQRggFDSR0MDYyMDExNjIxNTECXzQEDSR0MDYyMTU3Njc5MTYDCQBmAgkBA2FicwEFD29sZFBvc2l0aW9uU2l6ZQUFX3NpemUEDSR0MDYyNjQ5NjI4NzEJAQpzd2FwT3V0cHV0AwkAZgIFD29sZFBvc2l0aW9uU2l6ZQAABQVfc2l6ZQYEGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQIBQ0kdDA2MjY0OTYyODcxAl8xBBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNjI2NDk2Mjg3MQJfMgQVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNjI2NDk2Mjg3MQJfMwQWdG90YWxQb3NpdGlvblNpemVBZnRlcggFDSR0MDYyNjQ5NjI4NzECXzQEFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQMJAGYCBQ9vbGRQb3NpdGlvblNpemUAAAkBAS0BBQVfc2l6ZQUFX3NpemUEDSR0MDYyOTYyNjMxMTYJASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAIFB190cmFkZXIFD1BOTF9PUFRJT05fU1BPVAQTb2xkUG9zaXRpb25Ob3Rpb25hbAgFDSR0MDYyOTYyNjMxMTYCXzEEDXVucmVhbGl6ZWRQbmwIBQ0kdDA2Mjk2MjYzMTE2Al8yBAJtcgkBFmdldE1hcmdpblJhdGlvQnlPcHRpb24CBQdfdHJhZGVyBQ9QTkxfT1BUSU9OX1NQT1QEDXJlYWxpemVkUmF0aW8JAQRkaXZkAgkBA2FicwEFFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQkBA2FicwEFD29sZFBvc2l0aW9uU2l6ZQQLcmVhbGl6ZWRQbmwJAQRtdWxkAgUNdW5yZWFsaXplZFBubAUNcmVhbGl6ZWRSYXRpbwQLcmVhbGl6ZWRGZWUJAQRtdWxkAgkBBG11bGQCBRNvbGRQb3NpdGlvbk5vdGlvbmFsBQ1yZWFsaXplZFJhdGlvBQtwb3NpdGlvbkZlZQQScmVtYWluTWFyZ2luQmVmb3JlCAkBImNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnQEBQ9vbGRQb3NpdGlvblNpemUFEW9sZFBvc2l0aW9uTWFyZ2luBRRvbGRQb3NpdGlvbkxzdFVwZENQRgUNdW5yZWFsaXplZFBubAJfMQQPcG9zaXRpb25CYWREZWJ0CAkBImNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnQEBQ9vbGRQb3NpdGlvblNpemUFEW9sZFBvc2l0aW9uTWFyZ2luBRRvbGRQb3NpdGlvbkxzdFVwZENQRgULcmVhbGl6ZWRQbmwCXzIEEnVucmVhbGl6ZWRQbmxBZnRlcgkAZQIFDXVucmVhbGl6ZWRQbmwFC3JlYWxpemVkUG5sBBJyZW1haW5PcGVuTm90aW9uYWwDCQBmAgUPb2xkUG9zaXRpb25TaXplAAAJAGUCCQBlAgUTb2xkUG9zaXRpb25Ob3Rpb25hbAUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAUSdW5yZWFsaXplZFBubEFmdGVyCQBlAgkAZAIFEnVucmVhbGl6ZWRQbmxBZnRlcgUTb2xkUG9zaXRpb25Ob3Rpb25hbAUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAQXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwJAQNhYnMBBRJyZW1haW5PcGVuTm90aW9uYWwED25ld1Bvc2l0aW9uU2l6ZQkAZAIFD29sZFBvc2l0aW9uU2l6ZQUVZXhjaGFuZ2VkUG9zaXRpb25TaXplBBRuZXdQb3NpdGlvbkxzdFVwZENQRgkBH2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24BBQ9uZXdQb3NpdGlvblNpemUEEW9wZW5Ob3Rpb25hbERlbHRhCQBlAgUXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwFF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBBlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyCQBlAgkBFG9wZW5JbnRlcmVzdE5vdGlvbmFsAAURb3Blbk5vdGlvbmFsRGVsdGEEEW5ld1Bvc2l0aW9uTWFyZ2luAwkAZgIFD29sZFBvc2l0aW9uU2l6ZQAACQBlAgkBBG11bGQCCQBkAgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFEnVucmVhbGl6ZWRQbmxBZnRlcgUCbXIFEnVucmVhbGl6ZWRQbmxBZnRlcgkAZQIJAQRtdWxkAgkAZQIFF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBRJ1bnJlYWxpemVkUG5sQWZ0ZXIFAm1yBRJ1bnJlYWxpemVkUG5sQWZ0ZXIEEW1hcmdpblRvVHJhZGVyUmF3CQBlAgkAZQIFEnJlbWFpbk1hcmdpbkJlZm9yZQkAZAIFEW5ld1Bvc2l0aW9uTWFyZ2luBRJ1bnJlYWxpemVkUG5sQWZ0ZXIFC3JlYWxpemVkRmVlBA5tYXJnaW5Ub1RyYWRlcgMJAGYCAAAFEW1hcmdpblRvVHJhZGVyUmF3CQACAQIlTWFyZ2luIGVycm9yOiB1bmFibGUgdG8gcGF5IGNsb3NlIGZlZQURbWFyZ2luVG9UcmFkZXJSYXcDAwkBAiE9AgUUX21pblF1b3RlQXNzZXRBbW91bnQAAAkAZgIFFF9taW5RdW90ZUFzc2V0QW1vdW50BRlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50BwkAAgEJAKwCAgkArAICCQCsAgICDUxpbWl0IGVycm9yOiAJAKQDAQUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAIDIDwgCQCkAwEFFF9taW5RdW90ZUFzc2V0QW1vdW50CQCiChAFD25ld1Bvc2l0aW9uU2l6ZQMFDF9hZGRUb01hcmdpbgkAZAIFEW5ld1Bvc2l0aW9uTWFyZ2luBQ5tYXJnaW5Ub1RyYWRlcgURbmV3UG9zaXRpb25NYXJnaW4FF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBRRuZXdQb3NpdGlvbkxzdFVwZENQRgUPcG9zaXRpb25CYWREZWJ0BQtyZWFsaXplZFBubAMFDF9hZGRUb01hcmdpbgAABQ5tYXJnaW5Ub1RyYWRlcgUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBRZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyBRlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyCQBlAgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQADCQBmAgUPbmV3UG9zaXRpb25TaXplAAAJAQNhYnMBBRVleGNoYW5nZWRQb3NpdGlvblNpemUAAAkAZQIJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAMJAGYCAAAFD25ld1Bvc2l0aW9uU2l6ZQkBA2FicwEFFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQAACQBlAgkBEG9wZW5JbnRlcmVzdExvbmcAAwkAZgIFD25ld1Bvc2l0aW9uU2l6ZQAABRFvcGVuTm90aW9uYWxEZWx0YQAACQBlAgkBEW9wZW5JbnRlcmVzdFNob3J0AAMJAGYCAAAFD25ld1Bvc2l0aW9uU2l6ZQURb3Blbk5vdGlvbmFsRGVsdGEAAAULcmVhbGl6ZWRGZWUDCQBmAgUFX3NpemUJAQNhYnMBBQ9vbGRQb3NpdGlvblNpemUJAAIBAiBJbnZhbGlkIGNsb3NlUG9zaXRpb24gcGFyYW1ldGVycwQNJHQwNjYzMzU2Njc2NQkBFWludGVybmFsQ2xvc2VQb3NpdGlvbgIFB190cmFkZXIGBAJ4MggFDSR0MDY2MzM1NjY3NjUCXzEED3Bvc2l0aW9uQmFkRGVidAgFDSR0MDY2MzM1NjY3NjUCXzIEC3JlYWxpemVkUG5sCAUNJHQwNjYzMzU2Njc2NQJfMwQYbWFyZ2luVG9UcmFkZXJXaXRob3V0RmVlCAUNJHQwNjYzMzU2Njc2NQJfNAQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDY2MzM1NjY3NjUCXzUEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDY2MzM1NjY3NjUCXzYEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDA2NjMzNTY2NzY1Al83BBlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyCAUNJHQwNjYzMzU2Njc2NQJfOAQZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAgFDSR0MDY2MzM1NjY3NjUCXzkEDnRvdGFsTG9uZ0FmdGVyCAUNJHQwNjYzMzU2Njc2NQNfMTAED3RvdGFsU2hvcnRBZnRlcggFDSR0MDY2MzM1NjY3NjUDXzExBBp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcggFDSR0MDY2MzM1NjY3NjUDXzEyBBt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA2NjMzNTY2NzY1A18xMwQLcmVhbGl6ZWRGZWUJAQRtdWxkAgUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAULcG9zaXRpb25GZWUEEW1hcmdpblRvVHJhZGVyUmF3CQBlAgkBA2FicwEFGG1hcmdpblRvVHJhZGVyV2l0aG91dEZlZQULcmVhbGl6ZWRGZWUEDm1hcmdpblRvVHJhZGVyAwkAZgIAAAURbWFyZ2luVG9UcmFkZXJSYXcJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgICJ01hcmdpbiBlcnJvcjogdW5hYmxlIHRvIHBheSBjbG9zZSBmZWU6IAkApAMBBQtyZWFsaXplZEZlZQIJIG1hcmdpbjogCQCkAwEFGG1hcmdpblRvVHJhZGVyV2l0aG91dEZlZQIOIGZlZSBwZXJjZW50OiAJAKQDAQULcG9zaXRpb25GZWUCCyBub3Rpb25hbDogCQCkAwEFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQFEW1hcmdpblRvVHJhZGVyUmF3AwMJAQIhPQIFFF9taW5RdW90ZUFzc2V0QW1vdW50AAAJAGYCBRRfbWluUXVvdGVBc3NldEFtb3VudAUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAcJAAIBCQCsAgIJAKwCAgkArAICAg1MaW1pdCBlcnJvcjogCQCkAwEFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQCAyA8IAkApAMBBRRfbWluUXVvdGVBc3NldEFtb3VudAkAogoQAAAAAAAAAAAFD3Bvc2l0aW9uQmFkRGVidAULcmVhbGl6ZWRQbmwFDm1hcmdpblRvVHJhZGVyBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIFGW9wZW5JbnRlcmVzdE5vdGlvbmFsQWZ0ZXIFDnRvdGFsTG9uZ0FmdGVyBQ90b3RhbFNob3J0QWZ0ZXIFGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyBRt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIFC3JlYWxpemVkRmVlBA9uZXdQb3NpdGlvblNpemUIBQ0kdDA2MjE1NzY3OTE2Al8xBBFuZXdQb3NpdGlvbk1hcmdpbggFDSR0MDYyMTU3Njc5MTYCXzIEF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNjIxNTc2NzkxNgJfMwQUbmV3UG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA2MjE1NzY3OTE2Al80BA9wb3NpdGlvbkJhZERlYnQIBQ0kdDA2MjE1NzY3OTE2Al81BAtyZWFsaXplZFBubAgFDSR0MDYyMTU3Njc5MTYCXzYEDm1hcmdpblRvVHJhZGVyCAUNJHQwNjIxNTc2NzkxNgJfNwQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDYyMTU3Njc5MTYCXzgEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDYyMTU3Njc5MTYCXzkEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDA2MjE1NzY3OTE2A18xMAQZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcggFDSR0MDYyMTU3Njc5MTYDXzExBA50b3RhbExvbmdBZnRlcggFDSR0MDYyMTU3Njc5MTYDXzEyBA90b3RhbFNob3J0QWZ0ZXIIBQ0kdDA2MjE1NzY3OTE2A18xMwQadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA2MjE1NzY3OTE2A18xNAQbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCAUNJHQwNjIxNTc2NzkxNgNfMTUEC3JlYWxpemVkRmVlCAUNJHQwNjIxNTc2NzkxNgNfMTYDCQBmAgUPcG9zaXRpb25CYWREZWJ0AAAJAAIBAiZVbmFibGUgdG8gY2xvc2UgcG9zaXRpb24gd2l0aCBiYWQgZGVidAQOaXNQYXJ0aWFsQ2xvc2UJAQIhPQIFD25ld1Bvc2l0aW9uU2l6ZQAABA53aXRoZHJhd0Ftb3VudAkAZAIFDm1hcmdpblRvVHJhZGVyBQtyZWFsaXplZEZlZQQKYW1tQmFsYW5jZQkAZQIJAQhjYmFsYW5jZQAFDndpdGhkcmF3QW1vdW50BA0kdDA2ODE4MzY4MzkwAwkAZgIAAAUKYW1tQmFsYW5jZQkAlAoCAAAJAQNhYnMBBQphbW1CYWxhbmNlCQCUCgIFCmFtbUJhbGFuY2UAAAQNYW1tTmV3QmFsYW5jZQgFDSR0MDY4MTgzNjgzOTACXzEEA3gxMQgFDSR0MDY4MTgzNjgzOTACXzIEDSR0MDY4Mzk3Njg0NTEJARNnZXRCb3Jyb3dlZEJ5VHJhZGVyAQUHX3RyYWRlcgQIYm9ycm93ZWQIBQ0kdDA2ODM5NzY4NDUxAl8xBAdhc3NldElkCAUNJHQwNjgzOTc2ODQ1MQJfMgQNJHQwNjg0NTk2OTMxOQMJAGYCBQhib3Jyb3dlZAAAAwkAZwIFDndpdGhkcmF3QW1vdW50BQhib3Jyb3dlZAQHZG9SZXBheQkA/AcECQERY29sbGF0ZXJhbEFkZHJlc3MAAgVyZXBheQkAzAgCBQdfdHJhZGVyCQDMCAIFCGJvcnJvd2VkCQDMCAIFB2Fzc2V0SWQFA25pbAUDbmlsAwkAAAIFB2RvUmVwYXkFB2RvUmVwYXkJAJUKAwUIYm9ycm93ZWQJAGUCBQ53aXRoZHJhd0Ftb3VudAUIYm9ycm93ZWQFDmlzUGFydGlhbENsb3NlCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBA9yZWFsaXplQW5kQ2xvc2UJAPwHBAkBEWNvbGxhdGVyYWxBZGRyZXNzAAMFDmlzUGFydGlhbENsb3NlAgVyZXBheQIYcmVhbGl6ZVBhcnRpYWxseUFuZENsb3NlCQDMCAIFB190cmFkZXIJAMwIAgUOd2l0aGRyYXdBbW91bnQJAMwIAgUHYXNzZXRJZAUDbmlsBQNuaWwDCQAAAgUPcmVhbGl6ZUFuZENsb3NlBQ9yZWFsaXplQW5kQ2xvc2UJAJUKAwUOd2l0aGRyYXdBbW91bnQAAAcJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAJUKAwAABQ53aXRoZHJhd0Ftb3VudAcDCQAAAgUNJHQwNjg0NTk2OTMxOQUNJHQwNjg0NTk2OTMxOQQNc3dpdGNoVG9RdW90ZQgFDSR0MDY4NDU5NjkzMTkCXzMEHHF1b3RlV2l0aGRyYXdBbW91bnRCZWZvcmVGZWUIBQ0kdDA2ODQ1OTY5MzE5Al8yBBxhc3NldFdpdGhkcmF3QW1vdW50QmVmb3JlRmVlCAUNJHQwNjg0NTk2OTMxOQJfMQQNJHQwNjkzMjc3MDM5NAMJAGcCBRxxdW90ZVdpdGhkcmF3QW1vdW50QmVmb3JlRmVlBQtyZWFsaXplZEZlZQkAlQoDBRxhc3NldFdpdGhkcmF3QW1vdW50QmVmb3JlRmVlCQBlAgUccXVvdGVXaXRoZHJhd0Ftb3VudEJlZm9yZUZlZQULcmVhbGl6ZWRGZWUFC3JlYWxpemVkRmVlBBpmZWVMZWZ0VG9XaXRoZHJhd0Zyb21Bc3NldAkAZQIFC3JlYWxpemVkRmVlBRxxdW90ZVdpdGhkcmF3QW1vdW50QmVmb3JlRmVlBBthc3NldFdpdGhkcmF3QW1vdW50QWZ0ZXJGZWUJAGUCBRxhc3NldFdpdGhkcmF3QW1vdW50QmVmb3JlRmVlBRpmZWVMZWZ0VG9XaXRoZHJhd0Zyb21Bc3NldAQNYmFsYW5jZUJlZm9yZQkA8AcCBQR0aGlzCQEKcXVvdGVBc3NldAADCQAAAgUNYmFsYW5jZUJlZm9yZQUNYmFsYW5jZUJlZm9yZQQGZG9Td2FwCQD8BwQJAQtzd2FwQWRkcmVzcwACBHN3YXAJAMwIAgkA2AQBCQEKcXVvdGVBc3NldAAJAMwIAgAABQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJANkEAQUHYXNzZXRJZAUaZmVlTGVmdFRvV2l0aGRyYXdGcm9tQXNzZXQFA25pbAMJAAACBQZkb1N3YXAFBmRvU3dhcAQMYmFsYW5jZUFmdGVyCQDwBwIFBHRoaXMJAQpxdW90ZUFzc2V0AAMJAAACBQxiYWxhbmNlQWZ0ZXIFDGJhbGFuY2VBZnRlcgQPZXhjaGFuZ2VkQW1vdW50CQBlAgUMYmFsYW5jZUFmdGVyBQ1iYWxhbmNlQmVmb3JlAwkAAAIFD2V4Y2hhbmdlZEFtb3VudAUPZXhjaGFuZ2VkQW1vdW50CQCVCgMFG2Fzc2V0V2l0aGRyYXdBbW91bnRBZnRlckZlZQAACQBkAgUccXVvdGVXaXRoZHJhd0Ftb3VudEJlZm9yZUZlZQUPZXhjaGFuZ2VkQW1vdW50CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAwkAAAIFDSR0MDY5MzI3NzAzOTQFDSR0MDY5MzI3NzAzOTQEFWFjdHVhbEZlZUluUXVvdGVBc3NldAgFDSR0MDY5MzI3NzAzOTQCXzMEG3F1b3RlV2l0aGRyYXdBbW91bnRBZnRlckZlZQgFDSR0MDY5MzI3NzAzOTQCXzIEG2Fzc2V0V2l0aGRyYXdBbW91bnRBZnRlckZlZQgFDSR0MDY5MzI3NzAzOTQCXzEEB3Vuc3Rha2UDCQBmAgUccXVvdGVXaXRoZHJhd0Ftb3VudEJlZm9yZUZlZQAABAd1bnN0YWtlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAg53aXRoZHJhd0xvY2tlZAkAzAgCBRxxdW90ZVdpdGhkcmF3QW1vdW50QmVmb3JlRmVlBQNuaWwFA25pbAMJAAACBQd1bnN0YWtlBQd1bnN0YWtlBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBQd1bnN0YWtlBQd1bnN0YWtlBA0kdDA3MDY2ODcwNzM3CQENZGlzdHJpYnV0ZUZlZQEFFWFjdHVhbEZlZUluUXVvdGVBc3NldAQMZmVlVG9TdGFrZXJzCAUNJHQwNzA2Njg3MDczNwJfMQQKZmVlVG9WYXVsdAgFDSR0MDcwNjY4NzA3MzcCXzIEDGRlcG9zaXRWYXVsdAkA/AcECQEMdmF1bHRBZGRyZXNzAAIHYWRkRnJlZQUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQEKcXVvdGVBc3NldAAFCmZlZVRvVmF1bHQFA25pbAMJAAACBQxkZXBvc2l0VmF1bHQFDGRlcG9zaXRWYXVsdAQJbm90aWZ5RmVlCQD8BwQJAQxtaW5lckFkZHJlc3MAAgpub3RpZnlGZWVzCQDMCAIFB190cmFkZXIJAMwIAgULcmVhbGl6ZWRGZWUFA25pbAUDbmlsAwkAAAIFCW5vdGlmeUZlZQUJbm90aWZ5RmVlBA5ub3RpZnlOb3Rpb25hbAkA/AcECQEMbWluZXJBZGRyZXNzAAIObm90aWZ5Tm90aW9uYWwJAMwIAgUHX3RyYWRlcgkAzAgCBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUDbmlsBQNuaWwDCQAAAgUObm90aWZ5Tm90aW9uYWwFDm5vdGlmeU5vdGlvbmFsCQDOCAIJAM4IAgkAzggCCQDOCAIJAM4IAgkAzggCAwUOaXNQYXJ0aWFsQ2xvc2UJAQ51cGRhdGVQb3NpdGlvbgUFB190cmFkZXIFD25ld1Bvc2l0aW9uU2l6ZQURbmV3UG9zaXRpb25NYXJnaW4FF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBRRuZXdQb3NpdGlvbkxzdFVwZENQRgkBDmRlbGV0ZVBvc2l0aW9uAQUHX3RyYWRlcgMFDXN3aXRjaFRvUXVvdGUEDXF1b3RlQXNzZXRTdHIJANgEAQkBCnF1b3RlQXNzZXQACQETdXBkYXRlUG9zaXRpb25Bc3NldAIFB190cmFkZXIFDXF1b3RlQXNzZXRTdHIFA25pbAkBCXVwZGF0ZUFtbQgFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgUWdG90YWxQb3NpdGlvblNpemVBZnRlcgUZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcgUOdG90YWxMb25nQWZ0ZXIFD3RvdGFsU2hvcnRBZnRlcgUadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIFG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcgkBC3RyYW5zZmVyRmVlAQUMZmVlVG9TdGFrZXJzAwkAZgIFG3F1b3RlV2l0aGRyYXdBbW91bnRBZnRlckZlZQAACQEId2l0aGRyYXcCBQ5fdHJhZGVyQWRkcmVzcwUbcXVvdGVXaXRoZHJhd0Ftb3VudEFmdGVyRmVlBQNuaWwJAQ11cGRhdGVCYWxhbmNlAQUNYW1tTmV3QmFsYW5jZQMJAGYCBRthc3NldFdpdGhkcmF3QW1vdW50QWZ0ZXJGZWUAAAkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDBQ5fdHJhZGVyQWRkcmVzcwUbYXNzZXRXaXRoZHJhd0Ftb3VudEFmdGVyRmVlCQDZBAEFB2Fzc2V0SWQFA25pbAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCWxpcXVpZGF0ZQEHX3RyYWRlcgQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBA9zcG90TWFyZ2luUmF0aW8JARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAgUHX3RyYWRlcgUPUE5MX09QVElPTl9TUE9UBAttYXJnaW5SYXRpbwMJARZpc092ZXJGbHVjdHVhdGlvbkxpbWl0AAQRb3JhY2xlTWFyZ2luUmF0aW8JARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAgUHX3RyYWRlcgURUE5MX09QVElPTl9PUkFDTEUJAQR2bWF4AgUPc3BvdE1hcmdpblJhdGlvBRFvcmFjbGVNYXJnaW5SYXRpbwUPc3BvdE1hcmdpblJhdGlvAwMDAwMJAQEhAQkBFnJlcXVpcmVNb3JlTWFyZ2luUmF0aW8DBQttYXJnaW5SYXRpbwkBFm1haW50ZW5hbmNlTWFyZ2luUmF0aW8ABwYJAQEhAQkBE3JlcXVpcmVPcGVuUG9zaXRpb24BBQdfdHJhZGVyBgkBASEBCQELaW5pdGlhbGl6ZWQABgkBBnBhdXNlZAAGCQEOaXNNYXJrZXRDbG9zZWQACQACAQITVW5hYmxlIHRvIGxpcXVpZGF0ZQMDAwkAZgIFD3Nwb3RNYXJnaW5SYXRpbwkBE2xpcXVpZGF0aW9uRmVlUmF0aW8ACQBmAgkBF3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAAAABwkAZgIFDERFQ0lNQUxfVU5JVAkBF3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAAcEDSR0MDczNDkwNzM2NDAJAQtnZXRQb3NpdGlvbgEFB190cmFkZXIED29sZFBvc2l0aW9uU2l6ZQgFDSR0MDczNDkwNzM2NDACXzEEEW9sZFBvc2l0aW9uTWFyZ2luCAUNJHQwNzM0OTA3MzY0MAJfMgQXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDA3MzQ5MDczNjQwAl8zBBRvbGRQb3NpdGlvbkxzdFVwZENQRggFDSR0MDczNDkwNzM2NDACXzQECl9kaXJlY3Rpb24DCQBmAgUPb2xkUG9zaXRpb25TaXplAAAFCURJUl9TSE9SVAUIRElSX0xPTkcEBWlzQWRkCQAAAgUKX2RpcmVjdGlvbgUIRElSX0xPTkcEGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQJARtnZXRQYXJ0aWFsTGlxdWlkYXRpb25BbW91bnQCBQdfdHJhZGVyBQ9vbGRQb3NpdGlvblNpemUEDSR0MDczODY1NzM5NjkJASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAIFB190cmFkZXIFD1BOTF9PUFRJT05fU1BPVAQTb2xkUG9zaXRpb25Ob3Rpb25hbAgFDSR0MDczODY1NzM5NjkCXzEEDXVucmVhbGl6ZWRQbmwIBQ0kdDA3Mzg2NTczOTY5Al8yBA0kdDA3Mzk3Nzc0MTY0CQEJc3dhcElucHV0AgUFaXNBZGQFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQEFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQgFDSR0MDczOTc3NzQxNjQCXzEEFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA3Mzk3Nzc0MTY0Al8yBBViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA3Mzk3Nzc0MTY0Al8zBBZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCAUNJHQwNzM5Nzc3NDE2NAJfNAQQbGlxdWlkYXRpb25SYXRpbwkBBGRpdmQCCQEDYWJzAQUVZXhjaGFuZ2VkUG9zaXRpb25TaXplCQEDYWJzAQUPb2xkUG9zaXRpb25TaXplBAtyZWFsaXplZFBubAkBBG11bGQCBQ11bnJlYWxpemVkUG5sBRBsaXF1aWRhdGlvblJhdGlvBA0kdDA3NDQ1Mzc0Njg2CQEiY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudAQFD29sZFBvc2l0aW9uU2l6ZQURb2xkUG9zaXRpb25NYXJnaW4FFG9sZFBvc2l0aW9uTHN0VXBkQ1BGBQtyZWFsaXplZFBubAQMcmVtYWluTWFyZ2luCAUNJHQwNzQ0NTM3NDY4NgJfMQQHYmFkRGVidAgFDSR0MDc0NDUzNzQ2ODYCXzIEDmZ1bmRpbmdQYXltZW50CAUNJHQwNzQ0NTM3NDY4NgJfMwQSdW5yZWFsaXplZFBubEFmdGVyCQBlAgUNdW5yZWFsaXplZFBubAULcmVhbGl6ZWRQbmwEEnJlbWFpbk9wZW5Ob3Rpb25hbAMJAGYCBQ9vbGRQb3NpdGlvblNpemUAAAkAZQIJAGUCBRNvbGRQb3NpdGlvbk5vdGlvbmFsBRlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50BRJ1bnJlYWxpemVkUG5sQWZ0ZXIJAGUCCQBkAgUSdW5yZWFsaXplZFBubEFmdGVyBRNvbGRQb3NpdGlvbk5vdGlvbmFsBRlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50BBJsaXF1aWRhdGlvblBlbmFsdHkJAQRtdWxkAgUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAkBE2xpcXVpZGF0aW9uRmVlUmF0aW8ABA9mZWVUb0xpcXVpZGF0b3IJAGkCBRJsaXF1aWRhdGlvblBlbmFsdHkAAgQKZmVlVG9WYXVsdAkAZQIFEmxpcXVpZGF0aW9uUGVuYWx0eQUPZmVlVG9MaXF1aWRhdG9yBBFuZXdQb3NpdGlvbk1hcmdpbgkAZQIFDHJlbWFpbk1hcmdpbgUSbGlxdWlkYXRpb25QZW5hbHR5BA9uZXdQb3NpdGlvblNpemUJAGQCBQ9vbGRQb3NpdGlvblNpemUFFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQQXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwJAQNhYnMBBRJyZW1haW5PcGVuTm90aW9uYWwEEW9wZW5Ob3Rpb25hbERlbHRhCQBlAgUXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwFF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBBRuZXdQb3NpdGlvbkxzdFVwZENQRgkBH2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24BBQ9uZXdQb3NpdGlvblNpemUEGW9wZW5JbnRlcmVzdE5vdGlvbmFsQWZ0ZXIJAGUCCQEUb3BlbkludGVyZXN0Tm90aW9uYWwABRFvcGVuTm90aW9uYWxEZWx0YQQKYW1tQmFsYW5jZQkAZQIJAQhjYmFsYW5jZQAFEmxpcXVpZGF0aW9uUGVuYWx0eQQNJHQwNzU5Mjc3NjA1NgMJAGYCAAAFCmFtbUJhbGFuY2UJAJQKAgAACQEDYWJzAQUKYW1tQmFsYW5jZQkAlAoCBQphbW1CYWxhbmNlAAAEDW5ld0FtbUJhbGFuY2UIBQ0kdDA3NTkyNzc2MDU2Al8xBAN4MTEIBQ0kdDA3NTkyNzc2MDU2Al8yBA0kdDA3NjA2NDc2MTE4CQETZ2V0Qm9ycm93ZWRCeVRyYWRlcgEFB190cmFkZXIECGJvcnJvd2VkCAUNJHQwNzYwNjQ3NjExOAJfMQQHYXNzZXRJZAgFDSR0MDc2MDY0NzYxMTgCXzIEFWRvTGlxdWlkYXRlQ29sbGF0ZXJhbAMJAGYCBQhib3Jyb3dlZAAABBBjb2xsYXRlcmFsVG9TZWxsCQEEbXVsZAIFCGJvcnJvd2VkBRBsaXF1aWRhdGlvblJhdGlvBA9yZWFsaXplQW5kQ2xvc2UJAPwHBAkBEWNvbGxhdGVyYWxBZGRyZXNzAAIQcmVhbGl6ZVBhcnRpYWxseQkAzAgCBQdfdHJhZGVyCQDMCAIFB2Fzc2V0SWQJAMwIAgUQY29sbGF0ZXJhbFRvU2VsbAUDbmlsBQNuaWwDCQAAAgUPcmVhbGl6ZUFuZENsb3NlBQ9yZWFsaXplQW5kQ2xvc2UFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFFWRvTGlxdWlkYXRlQ29sbGF0ZXJhbAUVZG9MaXF1aWRhdGVDb2xsYXRlcmFsBAd1bnN0YWtlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAg53aXRoZHJhd0xvY2tlZAkAzAgCBRJsaXF1aWRhdGlvblBlbmFsdHkFA25pbAUDbmlsAwkAAAIFB3Vuc3Rha2UFB3Vuc3Rha2UEEGRlcG9zaXRJbnN1cmFuY2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACB2FkZEZyZWUFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQpmZWVUb1ZhdWx0BQNuaWwDCQAAAgUQZGVwb3NpdEluc3VyYW5jZQUQZGVwb3NpdEluc3VyYW5jZQQObm90aWZ5Tm90aW9uYWwJAPwHBAkBDG1pbmVyQWRkcmVzcwACDm5vdGlmeU5vdGlvbmFsCQDMCAIFB190cmFkZXIJAMwIAgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFA25pbAUDbmlsAwkAAAIFDm5vdGlmeU5vdGlvbmFsBQ5ub3RpZnlOb3Rpb25hbAkAzggCCQDOCAIJAM4IAgkBDnVwZGF0ZVBvc2l0aW9uBQUHX3RyYWRlcgUPbmV3UG9zaXRpb25TaXplBRFuZXdQb3NpdGlvbk1hcmdpbgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFFG5ld1Bvc2l0aW9uTHN0VXBkQ1BGCQEJdXBkYXRlQW1tCAUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBRZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyBRlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyCQBlAgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQADCQBmAgUPbmV3UG9zaXRpb25TaXplAAAJAQNhYnMBBRVleGNoYW5nZWRQb3NpdGlvblNpemUAAAkAZQIJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAMJAGYCAAAFD25ld1Bvc2l0aW9uU2l6ZQkBA2FicwEFFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQAACQBlAgkBEG9wZW5JbnRlcmVzdExvbmcAAwkAZgIFD25ld1Bvc2l0aW9uU2l6ZQAABRFvcGVuTm90aW9uYWxEZWx0YQAACQBlAgkBEW9wZW5JbnRlcmVzdFNob3J0AAMJAGYCAAAFD25ld1Bvc2l0aW9uU2l6ZQURb3Blbk5vdGlvbmFsRGVsdGEAAAkBCHdpdGhkcmF3AggFAWkGY2FsbGVyBQ9mZWVUb0xpcXVpZGF0b3IJAQ11cGRhdGVCYWxhbmNlAQUNbmV3QW1tQmFsYW5jZQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgQNJHQwNzc3OTc3ODI5MgkBFWludGVybmFsQ2xvc2VQb3NpdGlvbgIFB190cmFkZXIHBAJ4MQgFDSR0MDc3Nzk3NzgyOTICXzEEB2JhZERlYnQIBQ0kdDA3Nzc5Nzc4MjkyAl8yBAJ4MggFDSR0MDc3Nzk3NzgyOTICXzMEAngzCAUNJHQwNzc3OTc3ODI5MgJfNAQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDc3Nzk3NzgyOTICXzUEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDc3Nzk3NzgyOTICXzYEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDA3Nzc5Nzc4MjkyAl83BBlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyCAUNJHQwNzc3OTc3ODI5MgJfOAQZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAgFDSR0MDc3Nzk3NzgyOTICXzkEDnRvdGFsTG9uZ0FmdGVyCAUNJHQwNzc3OTc3ODI5MgNfMTAED3RvdGFsU2hvcnRBZnRlcggFDSR0MDc3Nzk3NzgyOTIDXzExBBp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcggFDSR0MDc3Nzk3NzgyOTIDXzEyBBt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA3Nzc5Nzc4MjkyA18xMwQSbGlxdWlkYXRpb25QZW5hbHR5CQEEbXVsZAIFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQJARNsaXF1aWRhdGlvbkZlZVJhdGlvAAQPZmVlVG9MaXF1aWRhdG9yCQBpAgUSbGlxdWlkYXRpb25QZW5hbHR5AAIECmZlZVRvVmF1bHQJAGUCBRJsaXF1aWRhdGlvblBlbmFsdHkFD2ZlZVRvTGlxdWlkYXRvcgQKYW1tQmFsYW5jZQkAZQIJAQhjYmFsYW5jZQAFEmxpcXVpZGF0aW9uUGVuYWx0eQQNJHQwNzg3MDA3ODgyOQMJAGYCAAAFCmFtbUJhbGFuY2UJAJQKAgAACQEDYWJzAQUKYW1tQmFsYW5jZQkAlAoCBQphbW1CYWxhbmNlAAAEDW5ld0FtbUJhbGFuY2UIBQ0kdDA3ODcwMDc4ODI5Al8xBAN4MTEIBQ0kdDA3ODcwMDc4ODI5Al8yBA0kdDA3ODgzNzc4ODkxCQETZ2V0Qm9ycm93ZWRCeVRyYWRlcgEFB190cmFkZXIECGJvcnJvd2VkCAUNJHQwNzg4Mzc3ODg5MQJfMQQHYXNzZXRJZAgFDSR0MDc4ODM3Nzg4OTECXzIEFWRvTGlxdWlkYXRlQ29sbGF0ZXJhbAMJAGYCBQhib3Jyb3dlZAAABA9yZWFsaXplQW5kQ2xvc2UJAPwHBAkBEWNvbGxhdGVyYWxBZGRyZXNzAAIYcmVhbGl6ZVBhcnRpYWxseUFuZENsb3NlCQDMCAIFB190cmFkZXIJAMwIAgAACQDMCAIFB2Fzc2V0SWQFA25pbAUDbmlsAwkAAAIFD3JlYWxpemVBbmRDbG9zZQUPcmVhbGl6ZUFuZENsb3NlBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBRVkb0xpcXVpZGF0ZUNvbGxhdGVyYWwFFWRvTGlxdWlkYXRlQ29sbGF0ZXJhbAQBeAMJAGYCBQdiYWREZWJ0AAAEC2xvY2tCYWREZWJ0CQD8BwQJAQx2YXVsdEFkZHJlc3MAAhVleGNoYW5nZUZyZWVBbmRMb2NrZWQJAMwIAgUHYmFkRGVidAUDbmlsBQNuaWwDCQAAAgULbG9ja0JhZERlYnQFC2xvY2tCYWREZWJ0BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBQF4BQF4BAd1bnN0YWtlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAg53aXRoZHJhd0xvY2tlZAkAzAgCBRJsaXF1aWRhdGlvblBlbmFsdHkFA25pbAUDbmlsAwkAAAIFB3Vuc3Rha2UFB3Vuc3Rha2UEEGRlcG9zaXRJbnN1cmFuY2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACB2FkZEZyZWUFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQpmZWVUb1ZhdWx0BQNuaWwDCQAAAgUQZGVwb3NpdEluc3VyYW5jZQUQZGVwb3NpdEluc3VyYW5jZQQObm90aWZ5Tm90aW9uYWwJAPwHBAkBDG1pbmVyQWRkcmVzcwACDm5vdGlmeU5vdGlvbmFsCQDMCAIFB190cmFkZXIJAMwIAgAABQNuaWwFA25pbAMJAAACBQ5ub3RpZnlOb3Rpb25hbAUObm90aWZ5Tm90aW9uYWwJAM4IAgkAzggCCQDOCAIJAQ5kZWxldGVQb3NpdGlvbgEFB190cmFkZXIJAQl1cGRhdGVBbW0IBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIFGW9wZW5JbnRlcmVzdE5vdGlvbmFsQWZ0ZXIFDnRvdGFsTG9uZ0FmdGVyBQ90b3RhbFNob3J0QWZ0ZXIFGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyBRt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIJAQh3aXRoZHJhdwIIBQFpBmNhbGxlcgUPZmVlVG9MaXF1aWRhdG9yCQENdXBkYXRlQmFsYW5jZQEFDW5ld0FtbUJhbGFuY2UJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEKcGF5RnVuZGluZwAEBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQVZnVuZGluZ0Jsb2NrVGltZXN0YW1wCQEZbmV4dEZ1bmRpbmdCbG9ja1RpbWVzdGFtcAADAwMJAGYCBRVmdW5kaW5nQmxvY2tUaW1lc3RhbXAIBQlsYXN0QmxvY2sJdGltZXN0YW1wBgkBASEBCQELaW5pdGlhbGl6ZWQABgkBBnBhdXNlZAAJAAIBCQCsAgIJAKwCAgkArAICAiFJbnZhbGlkIGZ1bmRpbmcgYmxvY2sgdGltZXN0YW1wOiAJAKQDAQgFCWxhc3RCbG9jawl0aW1lc3RhbXACAyA8IAkApAMBBRVmdW5kaW5nQmxvY2tUaW1lc3RhbXAED3VuZGVybHlpbmdQcmljZQkBDmdldE9yYWNsZVByaWNlAAQNJHQwODA3NjM4MDgyNQkBCmdldEZ1bmRpbmcABBRzaG9ydFByZW1pdW1GcmFjdGlvbggFDSR0MDgwNzYzODA4MjUCXzEEE2xvbmdQcmVtaXVtRnJhY3Rpb24IBQ0kdDA4MDc2MzgwODI1Al8yCQENdXBkYXRlRnVuZGluZwUJAGQCBRVmdW5kaW5nQmxvY2tUaW1lc3RhbXAJARRmdW5kaW5nUGVyaW9kU2Vjb25kcwAJAGQCCQEjbGF0ZXN0TG9uZ0N1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24ABRNsb25nUHJlbWl1bUZyYWN0aW9uCQBkAgkBJGxhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgAFFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEEZGl2ZAIFE2xvbmdQcmVtaXVtRnJhY3Rpb24FD3VuZGVybHlpbmdQcmljZQkBBGRpdmQCBRRzaG9ydFByZW1pdW1GcmFjdGlvbgUPdW5kZXJseWluZ1ByaWNlCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUABAdfcXRBc3RSCQEGcXRBc3RSAAQHX2JzQXN0UgkBBmJzQXN0UgAEDSR0MDgxMjU3ODEzOTIJARRnZXRTeW5jVGVybWluYWxQcmljZQMJAQ5nZXRPcmFjbGVQcmljZQAFB19xdEFzdFIFB19ic0FzdFIEE25ld1F1b3RlQXNzZXRXZWlnaHQIBQ0kdDA4MTI1NzgxMzkyAl8xBBJuZXdCYXNlQXNzZXRXZWlnaHQIBQ0kdDA4MTI1NzgxMzkyAl8yBA1tYXJnaW5Ub1ZhdWx0CAUNJHQwODEyNTc4MTM5MgJfMwQNZG9FeGNoYW5nZVBuTAMJAQIhPQIFDW1hcmdpblRvVmF1bHQAAAQNZG9FeGNoYW5nZVBuTAkA/AcECQEMdmF1bHRBZGRyZXNzAAIVZXhjaGFuZ2VGcmVlQW5kTG9ja2VkCQDMCAIFDW1hcmdpblRvVmF1bHQFA25pbAUDbmlsAwkAAAIFDWRvRXhjaGFuZ2VQbkwFDWRvRXhjaGFuZ2VQbkwFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFDWRvRXhjaGFuZ2VQbkwFDWRvRXhjaGFuZ2VQbkwJAM4IAgkBEHVwZGF0ZUFtbVdlaWdodHMCBRNuZXdRdW90ZUFzc2V0V2VpZ2h0BRJuZXdCYXNlQXNzZXRXZWlnaHQJAQphcHBlbmRUd2FwAQkBBGRpdmQCCQEEbXVsZAIFB19xdEFzdFIFE25ld1F1b3RlQXNzZXRXZWlnaHQJAQRtdWxkAgUHX2JzQXN0UgUSbmV3QmFzZUFzc2V0V2VpZ2h0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBJ3ZpZXdfY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudAEHX3RyYWRlcgQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBA0kdDA4MTk2MTgyMDYyCQELZ2V0UG9zaXRpb24BBQdfdHJhZGVyBAxwb3NpdGlvblNpemUIBQ0kdDA4MTk2MTgyMDYyAl8xBA5wb3NpdGlvbk1hcmdpbggFDSR0MDgxOTYxODIwNjICXzIEA3BvbggFDSR0MDgxOTYxODIwNjICXzMEEXBvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwODE5NjE4MjA2MgJfNAQNJHQwODIwNjU4MjE2NgkBI2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sAgUHX3RyYWRlcgUPUE5MX09QVElPTl9TUE9UBBBwb3NpdGlvbk5vdGlvbmFsCAUNJHQwODIwNjU4MjE2NgJfMQQNdW5yZWFsaXplZFBubAgFDSR0MDgyMDY1ODIxNjYCXzIEDSR0MDgyMTY5ODIzNDEJASJjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50BAUMcG9zaXRpb25TaXplBQ5wb3NpdGlvbk1hcmdpbgURcG9zaXRpb25Mc3RVcGRDUEYFDXVucmVhbGl6ZWRQbmwEDHJlbWFpbk1hcmdpbggFDSR0MDgyMTY5ODIzNDECXzEEB2JhZERlYnQIBQ0kdDA4MjE2OTgyMzQxAl8yBA5mdW5kaW5nUGF5bWVudAgFDSR0MDgyMTY5ODIzNDECXzMJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkBAXMBBQxyZW1haW5NYXJnaW4JAQFzAQUOZnVuZGluZ1BheW1lbnQJAQFzAQkBDmdldE1hcmdpblJhdGlvAQUHX3RyYWRlcgkBAXMBBQ11bnJlYWxpemVkUG5sCQEBcwEFB2JhZERlYnQJAQFzAQUQcG9zaXRpb25Ob3Rpb25hbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARV2aWV3X2dldFBlZ0FkanVzdENvc3QBBl9wcmljZQQHX3F0QXN0UgkBBnF0QXN0UgAEB19ic0FzdFIJAQZic0FzdFIABAZyZXN1bHQJARRnZXRTeW5jVGVybWluYWxQcmljZQMFBl9wcmljZQUHX3F0QXN0UgUHX2JzQXN0UgkAAgEJAKQDAQgFBnJlc3VsdAJfMwFpARh2aWV3X2dldFRlcm1pbmFsQW1tUHJpY2UABA0kdDA4Mjc1NzgyODM4CQETZ2V0VGVybWluYWxBbW1TdGF0ZQAEGXRlcm1pbmFsUXVvdGVBc3NldFJlc2VydmUIBQ0kdDA4Mjc1NzgyODM4Al8xBBh0ZXJtaW5hbEJhc2VBc3NldFJlc2VydmUIBQ0kdDA4Mjc1NzgyODM4Al8yBAVwcmljZQkBBGRpdmQCCQEEbXVsZAIFGXRlcm1pbmFsUXVvdGVBc3NldFJlc2VydmUJAQZxdEFzdFcACQEEbXVsZAIFGHRlcm1pbmFsQmFzZUFzc2V0UmVzZXJ2ZQkBBmJzQXN0VwAJAAIBCQCkAwEFBXByaWNlAWkBD3ZpZXdfZ2V0RnVuZGluZwAED3VuZGVybHlpbmdQcmljZQkBDmdldE9yYWNsZVByaWNlAAQNJHQwODMwNTM4MzExNQkBCmdldEZ1bmRpbmcABBRzaG9ydFByZW1pdW1GcmFjdGlvbggFDSR0MDgzMDUzODMxMTUCXzEEE2xvbmdQcmVtaXVtRnJhY3Rpb24IBQ0kdDA4MzA1MzgzMTE1Al8yBAtsb25nRnVuZGluZwkBBGRpdmQCBRNsb25nUHJlbWl1bUZyYWN0aW9uBQ91bmRlcmx5aW5nUHJpY2UEDHNob3J0RnVuZGluZwkBBGRpdmQCBRRzaG9ydFByZW1pdW1GcmFjdGlvbgUPdW5kZXJseWluZ1ByaWNlCQACAQkArAICCQCsAgIJAKwCAgkBAXMBBQtsb25nRnVuZGluZwkBAXMBBQxzaG9ydEZ1bmRpbmcJAQFzAQkBEGdldFR3YXBTcG90UHJpY2UACQEBcwEJAQ5nZXRPcmFjbGVQcmljZQABaQEYdmlld19nZXRCb3Jyb3dlZEJ5VHJhZGVyAQdfdHJhZGVyBA0kdDA4MzQwMTgzNDU1CQETZ2V0Qm9ycm93ZWRCeVRyYWRlcgEFB190cmFkZXIECGJvcnJvd2VkCAUNJHQwODM0MDE4MzQ1NQJfMQQHYXNzZXRJZAgFDSR0MDgzNDAxODM0NTUCXzIJAAIBCQCsAgIJAQFzAQUIYm9ycm93ZWQFB2Fzc2V0SWQBaQEQY29tcHV0ZVNwb3RQcmljZQAEBnJlc3VsdAkBDGdldFNwb3RQcmljZQAJAJQKAgUDbmlsBQZyZXN1bHQBaQEfY29tcHV0ZUZlZUZvclRyYWRlcldpdGhBcnRpZmFjdAIHX3RyYWRlcgtfYXJ0aWZhY3RJZAQGcmVzdWx0CQEYZ2V0Rm9yVHJhZGVyV2l0aEFydGlmYWN0AgUHX3RyYWRlcgULX2FydGlmYWN0SWQJAJQKAgUDbmlsBQZyZXN1bHQBAnR4AQZ2ZXJpZnkACQD0AwMIBQJ0eAlib2R5Qnl0ZXMJAJEDAggFAnR4BnByb29mcwAACQEOYWRtaW5QdWJsaWNLZXkAI/MSvA==", "height": 2410491, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: AhGER8w5c4Pcd3ASemMyeoCk6Wed59h5CYtCawnEtM1g Next: 55a9BMiBtVZw1LcNSVCNgmPnqSwbnVDoS2VJij6DDpUd Diff:
OldNewDifferences
55
66 let k_ora_block_key = "k_ora_block_key"
77
8+let k_ora_open_key = "k_ora_open_key"
9+
810 let k_ora = "k_ora"
911
1012 let k_balance = "k_balance"
2224 let k_positionSequence = "k_positionSequence"
2325
2426 let k_positionAsset = "k_positionAsset"
27+
28+let k_positionFee = "k_positionFee"
2529
2630 let k_initialized = "k_initialized"
2731
379383 if (if (_largerThanOrEqualTo)
380384 then (0 > remainingMarginRatio)
381385 else false)
382- then throw("Invalid margin")
386+ then throw(((("Invalid margin: " + toString(_marginRatio)) + " < ") + toString(_baseMarginRatio)))
383387 else if (if (!(_largerThanOrEqualTo))
384388 then (remainingMarginRatio >= 0)
385389 else false)
386- then throw("Invalid margin")
390+ then throw(((("Invalid margin: " + toString(_marginRatio)) + " > ") + toString(_baseMarginRatio)))
387391 else true
388392 }
389393
413417 positionAsset
414418 case _ =>
415419 toBase58String(quoteAsset())
420+ }
421+ }
422+
423+
424+func getPositionFee (_trader) = {
425+ let positionFeeOpt = getInteger(this, toCompositeKey(k_positionFee, _trader))
426+ match positionFeeOpt {
427+ case positionFee: Int =>
428+ positionFee
429+ case _ =>
430+ fee()
416431 }
417432 }
418433
446461 }
447462
448463
449-func calcInvariant (_qtAstR,_qtAstW,_bsAstR,_bsAstW) = {
464+func calcInvariant (_qtAstR,_bsAstR) = {
450465 let bqtAstR = toBigInt(_qtAstR)
451- let bqtAstW = toBigInt(_qtAstW)
452466 let bbsAstR = toBigInt(_bsAstR)
453- let bbsAstW = toBigInt(_bsAstW)
454- bmuld(bmuld(bqtAstR, bqtAstW), bmuld(bbsAstR, bbsAstW))
467+ bmuld(bqtAstR, bbsAstR)
455468 }
456469
457470
460473 let _bsAstR = bsAstR()
461474 let _qtAstW = qtAstW()
462475 let _bsAstW = bsAstW()
463- let k = calcInvariant(_qtAstR, _qtAstW, _bsAstR, _bsAstW)
476+ let quoteAssetAmountAdjusted = divd(_quoteAssetAmount, _qtAstW)
477+ let k = calcInvariant(_qtAstR, _bsAstR)
464478 let quoteAssetReserveAfter = if (_isAdd)
465- then (_qtAstR + _quoteAssetAmount)
466- else (_qtAstR - _quoteAssetAmount)
467- let baseAssetReserveAfter = toInt(bdivd(k, toBigInt(muld(quoteAssetReserveAfter, _qtAstW))))
468- let amountBaseAssetBoughtAbs = divd(abs((baseAssetReserveAfter - _bsAstR)), _qtAstW)
479+ then (_qtAstR + quoteAssetAmountAdjusted)
480+ else (_qtAstR - quoteAssetAmountAdjusted)
481+ let baseAssetReserveAfter = toInt(bdivd(k, toBigInt(quoteAssetReserveAfter)))
482+ let amountBaseAssetBoughtAbs = abs((baseAssetReserveAfter - _bsAstR))
469483 let amountBaseAssetBought = if (_isAdd)
470484 then amountBaseAssetBoughtAbs
471485 else -(amountBaseAssetBoughtAbs)
472- let $t01694617109 = updateReserve(_isAdd, _quoteAssetAmount, amountBaseAssetBoughtAbs)
473- let quoteAssetReserveAfter1 = $t01694617109._1
474- let baseAssetReserveAfter1 = $t01694617109._2
475- let totalPositionSizeAfter1 = $t01694617109._3
486+ let $t01713817308 = updateReserve(_isAdd, quoteAssetAmountAdjusted, amountBaseAssetBoughtAbs)
487+ let quoteAssetReserveAfter1 = $t01713817308._1
488+ let baseAssetReserveAfter1 = $t01713817308._2
489+ let totalPositionSizeAfter1 = $t01713817308._3
476490 let priceBefore = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
477491 let marketPrice = divd(_quoteAssetAmount, amountBaseAssetBoughtAbs)
478492 let priceDiff = abs((priceBefore - marketPrice))
492506 }
493507 else 0
494508 let signedMargin = ((_marginDelta - fundingPayment) + _oldPositionMargin)
495- let $t01859618723 = if ((0 > signedMargin))
509+ let $t01879518922 = if ((0 > signedMargin))
496510 then $Tuple2(0, abs(signedMargin))
497511 else $Tuple2(abs(signedMargin), 0)
498- let remainMargin = $t01859618723._1
499- let badDebt = $t01859618723._2
512+ let remainMargin = $t01879518922._1
513+ let badDebt = $t01879518922._2
500514 $Tuple3(remainMargin, badDebt, fundingPayment)
501515 }
502516
506520 if ((_baseAssetAmount == 0))
507521 then throw("Invalid base asset amount")
508522 else {
509- let k = calcInvariant(_quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)
523+ let k = calcInvariant(_quoteAssetReserve, _baseAssetReserve)
510524 let baseAssetPoolAmountAfter = if (_isAdd)
511525 then (_baseAssetReserve + _baseAssetAmount)
512526 else (_baseAssetReserve - _baseAssetAmount)
513- let quoteAssetAfter = toInt(bdivd(k, toBigInt(muld(baseAssetPoolAmountAfter, _baseAssetWeight))))
514- let quoteAssetSold = abs((quoteAssetAfter - muld(_quoteAssetReserve, _quoteAssetWeight)))
527+ let quoteAssetAfter = toInt(bdivd(k, toBigInt(baseAssetPoolAmountAfter)))
528+ let quoteAssetDelta = abs((quoteAssetAfter - _quoteAssetReserve))
529+ let quoteAssetSold = muld(quoteAssetDelta, _quoteAssetWeight)
515530 let maxPriceImpactValue = maxPriceImpact()
516- let $t01991120072 = updateReserve(!(_isAdd), quoteAssetSold, _baseAssetAmount)
517- let quoteAssetReserveAfter1 = $t01991120072._1
518- let baseAssetReserveAfter1 = $t01991120072._2
519- let totalPositionSizeAfter1 = $t01991120072._3
531+ let $t02009220254 = updateReserve(!(_isAdd), quoteAssetDelta, _baseAssetAmount)
532+ let quoteAssetReserveAfter1 = $t02009220254._1
533+ let baseAssetReserveAfter1 = $t02009220254._2
534+ let totalPositionSizeAfter1 = $t02009220254._3
520535 let marketPrice = divd(quoteAssetSold, _baseAssetAmount)
521536 let priceDiff = abs((priceBefore - marketPrice))
522537 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
536551 func swapOutput (_isAdd,_baseAssetAmount,_checkMaxPriceImpact) = swapOutputWithReserves(_isAdd, _baseAssetAmount, _checkMaxPriceImpact, qtAstR(), qtAstW(), bsAstR(), bsAstW())
537552
538553
539-func getOracleTwapPrice () = {
554+func getOraclePrice () = {
540555 let oracle = valueOrErrorMessage(addressFromString(getStringValue(this, k_ora)), "")
541556 let priceKey = getStringValue(this, k_ora_key)
542557 let lastValue = valueOrErrorMessage(getInteger(oracle, priceKey), ((("Can not get oracle price. Oracle: " + toString(oracle)) + " key: ") + priceKey))
544559 if ((blockKey != ""))
545560 then {
546561 let currentBlock = lastBlock.height
547- let lastOracleBlock = valueOrErrorMessage(getInteger(oracle, k_ora_block_key), ((("Can not get oracle block. Oracle: " + toString(oracle)) + " key: ") + blockKey))
562+ let lastOracleBlock = valueOrErrorMessage(getInteger(oracle, blockKey), ((("Can not get oracle block. Oracle: " + toString(oracle)) + " key: ") + blockKey))
548563 if (((currentBlock - lastOracleBlock) > maxOracleDelay()))
549564 then throw(((("Oracle stale data. Last oracle block: " + toString(lastOracleBlock)) + " current block: ") + toString(currentBlock)))
550565 else lastValue
553568 }
554569
555570
571+func isMarketClosed () = {
572+ let oracle = valueOrErrorMessage(addressFromString(getStringValue(this, k_ora)), "")
573+ let openKey = valueOrElse(getString(this, k_ora_open_key), "")
574+ if ((openKey != ""))
575+ then {
576+ let isOpen = valueOrErrorMessage(getBoolean(oracle, openKey), ((("Can not get oracle is open/closed. Oracle: " + toString(oracle)) + " key: ") + openKey))
577+ !(isOpen)
578+ }
579+ else false
580+ }
581+
582+
583+func absPriceDiff (_oraclePrice,_quoteAssetReserve,_baseAssetReserve,_qtAstW,_bsAstW) = {
584+ let priceAfter = divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW))
585+ let averagePrice = divd((_oraclePrice + priceAfter), (2 * DECIMAL_UNIT))
586+ let absPriceDiff = divd(abs((_oraclePrice - priceAfter)), averagePrice)
587+ absPriceDiff
588+ }
589+
590+
556591 func requireNotOverSpreadLimit (_quoteAssetReserve,_baseAssetReserve) = {
557- let oraclePrice = getOracleTwapPrice()
592+ let oraclePrice = getOraclePrice()
558593 let _qtAstW = qtAstW()
559594 let _bsAstW = bsAstW()
560- let priceAfter = divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW))
561- let averagePrice = divd((oraclePrice + priceAfter), (2 * DECIMAL_UNIT))
562- let absPriceDiff = divd(abs((oraclePrice - priceAfter)), averagePrice)
563- if ((absPriceDiff > maxPriceSpread()))
564- then throw(((("Price spread " + toString(absPriceDiff)) + " > max price spread ") + toString(maxPriceSpread())))
595+ let absPriceDiffBefore = absPriceDiff(oraclePrice, qtAstR(), bsAstR(), _qtAstW, _bsAstW)
596+ let absPriceDiffAfter = absPriceDiff(oraclePrice, _quoteAssetReserve, _baseAssetReserve, _qtAstW, _bsAstW)
597+ if (if ((absPriceDiffAfter > maxPriceSpread()))
598+ then (absPriceDiffAfter > absPriceDiffBefore)
599+ else false)
600+ then throw(((("Price spread " + toString(absPriceDiffAfter)) + " > max price spread ") + toString(maxPriceSpread())))
565601 else true
566602 }
567603
586622
587623
588624 func isOverFluctuationLimit () = {
589- let oraclePrice = getOracleTwapPrice()
625+ let oraclePrice = getOraclePrice()
590626 let currentPrice = getSpotPrice()
591627 (divd(abs((oraclePrice - currentPrice)), oraclePrice) > spreadLimit())
592628 }
597633 let isShort = (0 > _positionSize)
598634 let positionNotional = if ((_option == PNL_OPTION_SPOT))
599635 then {
600- let $t02423824458 = swapOutputWithReserves(!(isShort), positionSizeAbs, false, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)
601- let outPositionNotional = $t02423824458._1
602- let x1 = $t02423824458._2
603- let x2 = $t02423824458._3
604- let x3 = $t02423824458._4
636+ let $t02520525425 = swapOutputWithReserves(!(isShort), positionSizeAbs, false, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)
637+ let outPositionNotional = $t02520525425._1
638+ let x1 = $t02520525425._2
639+ let x2 = $t02520525425._3
640+ let x3 = $t02520525425._4
605641 outPositionNotional
606642 }
607- else muld(positionSizeAbs, getOracleTwapPrice())
643+ else muld(positionSizeAbs, getOraclePrice())
608644 positionNotional
609645 }
610646
622658
623659
624660 func getPositionNotionalAndUnrealizedPnl (_trader,_option) = {
625- let $t02588326011 = getPosition(_trader)
626- let positionSize = $t02588326011._1
627- let positionMargin = $t02588326011._2
628- let positionOpenNotional = $t02588326011._3
629- let positionLstUpdCPF = $t02588326011._4
661+ let $t02684626974 = getPosition(_trader)
662+ let positionSize = $t02684626974._1
663+ let positionMargin = $t02684626974._2
664+ let positionOpenNotional = $t02684626974._3
665+ let positionLstUpdCPF = $t02684626974._4
630666 getPositionNotionalAndUnrealizedPnlByValues(positionSize, positionOpenNotional, qtAstR(), qtAstW(), bsAstR(), bsAstW(), _option)
631667 }
632668
635671
636672
637673 func getMarginRatioByOption (_trader,_option) = {
638- let $t02652426635 = getPosition(_trader)
639- let positionSize = $t02652426635._1
640- let positionMargin = $t02652426635._2
641- let pon = $t02652426635._3
642- let positionLstUpdCPF = $t02652426635._4
643- let $t02664126734 = getPositionNotionalAndUnrealizedPnl(_trader, _option)
644- let positionNotional = $t02664126734._1
645- let unrealizedPnl = $t02664126734._2
646- let $t02673926905 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
647- let remainMargin = $t02673926905._1
648- let badDebt = $t02673926905._2
674+ let $t02748727598 = getPosition(_trader)
675+ let positionSize = $t02748727598._1
676+ let positionMargin = $t02748727598._2
677+ let pon = $t02748727598._3
678+ let positionLstUpdCPF = $t02748727598._4
679+ let $t02760427697 = getPositionNotionalAndUnrealizedPnl(_trader, _option)
680+ let positionNotional = $t02760427697._1
681+ let unrealizedPnl = $t02760427697._2
682+ let $t02770227868 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
683+ let remainMargin = $t02770227868._1
684+ let badDebt = $t02770227868._2
649685 calcMarginRatio(remainMargin, badDebt, positionNotional)
650686 }
651687
670706
671707
672708 func internalClosePosition (_trader,_checkMaxPriceImpact) = {
673- let $t02814528273 = getPosition(_trader)
674- let positionSize = $t02814528273._1
675- let positionMargin = $t02814528273._2
676- let positionOpenNotional = $t02814528273._3
677- let positionLstUpdCPF = $t02814528273._4
709+ let $t02910829236 = getPosition(_trader)
710+ let positionSize = $t02910829236._1
711+ let positionMargin = $t02910829236._2
712+ let positionOpenNotional = $t02910829236._3
713+ let positionLstUpdCPF = $t02910829236._4
678714 let unrealizedPnl = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)._2
679- let $t02836828536 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
680- let remainMargin = $t02836828536._1
681- let badDebt = $t02836828536._2
715+ let $t02933129499 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
716+ let remainMargin = $t02933129499._1
717+ let badDebt = $t02933129499._2
682718 let exchangedPositionSize = -(positionSize)
683719 let realizedPnl = unrealizedPnl
684720 let marginToVault = -(remainMargin)
685- let $t02866328937 = swapOutput((positionSize > 0), abs(positionSize), _checkMaxPriceImpact)
686- let exchangedQuoteAssetAmount = $t02866328937._1
687- let quoteAssetReserveAfter = $t02866328937._2
688- let baseAssetReserveAfter = $t02866328937._3
689- let totalPositionSizeAfter = $t02866328937._4
690- let totalLongAfter = $t02866328937._5
691- let totalShortAfter = $t02866328937._6
721+ let $t02962629900 = swapOutput((positionSize > 0), abs(positionSize), _checkMaxPriceImpact)
722+ let exchangedQuoteAssetAmount = $t02962629900._1
723+ let quoteAssetReserveAfter = $t02962629900._2
724+ let baseAssetReserveAfter = $t02962629900._3
725+ let totalPositionSizeAfter = $t02962629900._4
726+ let totalLongAfter = $t02962629900._5
727+ let totalShortAfter = $t02962629900._6
692728 let openInterestNotionalAfter = (openInterestNotional() - positionOpenNotional)
693729 $Tuple13(exchangedPositionSize, badDebt, realizedPnl, marginToVault, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, exchangedQuoteAssetAmount, totalLongAfter, totalShortAfter, (openInterestLong() - (if ((positionSize > 0))
694730 then positionOpenNotional
741777 then $Tuple2(qtAstR(), bsAstR())
742778 else {
743779 let direction = (_positionSize > 0)
744- let $t03106031239 = swapOutput(direction, abs(_positionSize), false)
745- let currentNetMarketValue = $t03106031239._1
746- let terminalQuoteAssetReserve = $t03106031239._2
747- let terminalBaseAssetReserve = $t03106031239._3
780+ let $t03202332202 = swapOutput(direction, abs(_positionSize), false)
781+ let currentNetMarketValue = $t03202332202._1
782+ let terminalQuoteAssetReserve = $t03202332202._2
783+ let terminalBaseAssetReserve = $t03202332202._3
748784 $Tuple2(terminalQuoteAssetReserve, terminalBaseAssetReserve)
749785 }
750786 }
755791 let sz = toBigInt(totalPositionSize)
756792 let q = toBigInt(quoteAssetReserve)
757793 let p = toBigInt(targetPrice)
758- let bs2 = bpowd((b + sz), toBigInt((2 * DECIMAL_UNIT)))
759- let qbs2 = bmuld(q, bs2)
760- let ps4 = (toBigInt(4) * bmuld(p, sz))
761- let sqr = bsqrtd(bmuld(qbs2, (q - ps4)))
762- let bq = bmuld(b, q)
763- let qs = bmuld(q, sz)
764- let top = ((-(sqr) + bq) + qs)
765- let bot = (toBigInt(2) * bmuld(q, sz))
766- let result = bdivd(top, bot)
794+ let k = bmuld(q, b)
795+ let newB = (b + sz)
796+ let newQ = bdivd(k, newB)
797+ let z = bdivd(newQ, newB)
798+ let result = bdivd(p, z)
767799 toInt(result)
768800 }
769801
770802
771-func getSyncTerminalPrice (_terminalPrice) = {
803+func getSyncTerminalPrice (_terminalPrice,_qtAstR,_bsAstR) = {
772804 let _positionSize = totalPositionSize()
773805 if ((_positionSize == 0))
774806 then {
775- let _qtAstR = qtAstR()
776- let _bsAstR = bsAstR()
777807 let newQtAstW = divd(muld(_terminalPrice, _bsAstR), _qtAstR)
778808 $Tuple3(newQtAstW, DECIMAL_UNIT, 0)
779809 }
780810 else {
781811 let direction = (_positionSize > 0)
782812 let currentNetMarketValue = swapOutput(direction, abs(_positionSize), false)._1
783- let _qtAstR = qtAstR()
784- let _bsAstR = bsAstR()
785813 let newQtAstW = getQuoteAssetWeight(_bsAstR, _positionSize, _qtAstR, _terminalPrice)
786814 let newBsAstW = DECIMAL_UNIT
787815 let marginToVault = getPositionNotionalAndUnrealizedPnlByValues(_positionSize, currentNetMarketValue, _qtAstR, newQtAstW, _bsAstR, newBsAstW, PNL_OPTION_SPOT)._2
791819
792820
793821 func getFunding () = {
794- let underlyingPrice = getOracleTwapPrice()
822+ let underlyingPrice = getOraclePrice()
795823 let spotTwapPrice = getTwapSpotPrice()
796824 let premium = (spotTwapPrice - underlyingPrice)
797- if (if ((totalShortPositionSize() == 0))
825+ if (if (if ((totalShortPositionSize() == 0))
798826 then true
799827 else (totalLongPositionSize() == 0))
828+ then true
829+ else isMarketClosed())
800830 then $Tuple2(0, 0)
801831 else if ((0 > premium))
802832 then {
815845 func getAdjustedFee (_artifactId,_baseFeeDiscount) = {
816846 let baseFeeRaw = fee()
817847 let baseFee = muld(baseFeeRaw, _baseFeeDiscount)
818- let $t03433834833 = if ((_artifactId != ""))
848+ let $t03506335558 = if ((_artifactId != ""))
819849 then {
820850 let artifactKind = strA(nftManagerAddress(), toCompositeKey(k_token_type, _artifactId))
821851 if ((artifactKind == FEE_REDUCTION_TOKEN_TYPE))
827857 else throw("Invalid attached artifact")
828858 }
829859 else $Tuple2(baseFee, false)
830- let adjustedFee = $t03433834833._1
831- let burnArtifact = $t03433834833._2
860+ let adjustedFee = $t03506335558._1
861+ let burnArtifact = $t03506335558._2
832862 $Tuple2(adjustedFee, burnArtifact)
833863 }
834864
869899 case _ =>
870900 throw("Invalid computeFeeDiscount result")
871901 }
872- let $t03606436138 = getAdjustedFee(_artifactId, feeDiscount)
873- let adjustedFee = $t03606436138._1
874- let burnArtifact = $t03606436138._2
902+ let $t03678936863 = getAdjustedFee(_artifactId, feeDiscount)
903+ let adjustedFee = $t03678936863._1
904+ let burnArtifact = $t03678936863._2
875905 $Tuple2(adjustedFee, burnArtifact)
876906 }
877907 else throw("Strict value is not equal to itself.")
902932 func updatePositionAsset (_address,_assetId) = [StringEntry(toCompositeKey(k_positionAsset, _address), _assetId)]
903933
904934
905-func incrementPositionSequenceNumber (isNewPosition,_address) = if (isNewPosition)
935+func incrementPositionSequenceNumber (_isNewPosition,_address) = if (_isNewPosition)
906936 then {
907937 let currentSequence = lastSequence()
908938 [IntegerEntry(toCompositeKey(k_positionSequence, _address), (currentSequence + 1)), IntegerEntry(k_sequence, (currentSequence + 1))]
909939 }
940+ else nil
941+
942+
943+func updatePositionFee (_isNewPosition,_address,_fee) = if (_isNewPosition)
944+ then [IntegerEntry(toCompositeKey(k_positionFee, _address), _fee)]
910945 else nil
911946
912947
10191054 let _qtAstW = qtAstW()
10201055 let _bsAstW = bsAstW()
10211056 let price = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
1022- let baseAssetAmountToAdd = divd(_quoteAssetAmount, price)
10231057 let qtAstRAfter = (_qtAstR + _quoteAssetAmount)
1058+ let baseAssetAmountToAdd = (divd(muld(qtAstRAfter, _qtAstW), price) - _bsAstR)
10241059 let bsAstRAfter = (_bsAstR + baseAssetAmountToAdd)
1025- updateAmmReserves(qtAstRAfter, bsAstRAfter)
1060+ let $t04610746258 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1061+ let newQuoteAssetWeight = $t04610746258._1
1062+ let newBaseAssetWeight = $t04610746258._2
1063+ let marginToVault = $t04610746258._3
1064+ let doExchangePnL = if ((marginToVault != 0))
1065+ then {
1066+ let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
1067+ if ((doExchangePnL == doExchangePnL))
1068+ then nil
1069+ else throw("Strict value is not equal to itself.")
1070+ }
1071+ else nil
1072+ if ((doExchangePnL == doExchangePnL))
1073+ then (updateAmmReserves(qtAstRAfter, bsAstRAfter) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
1074+ else throw("Strict value is not equal to itself.")
10261075 }
10271076
10281077
10301079 @Callable(i)
10311080 func removeLiquidity (_quoteAssetAmount) = if (if ((i.caller != adminAddress()))
10321081 then true
1033- else (0 >= _quoteAssetAmount))
1082+ else (_quoteAssetAmount >= 0))
10341083 then throw("Invalid removeLiquidity params")
10351084 else {
10361085 let _qtAstR = qtAstR()
10381087 let _qtAstW = qtAstW()
10391088 let _bsAstW = bsAstW()
10401089 let price = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
1041- let baseAssetAmountToRemove = divd(_quoteAssetAmount, price)
10421090 let qtAstRAfter = (_qtAstR - _quoteAssetAmount)
1091+ let baseAssetAmountToRemove = abs((divd(muld(qtAstRAfter, _qtAstW), price) - _bsAstR))
10431092 let bsAstRAfter = (_bsAstR - baseAssetAmountToRemove)
1044- updateAmmReserves(qtAstRAfter, bsAstRAfter)
1093+ let $t04719047341 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1094+ let newQuoteAssetWeight = $t04719047341._1
1095+ let newBaseAssetWeight = $t04719047341._2
1096+ let marginToVault = $t04719047341._3
1097+ let doExchangePnL = if ((marginToVault != 0))
1098+ then {
1099+ let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
1100+ if ((doExchangePnL == doExchangePnL))
1101+ then nil
1102+ else throw("Strict value is not equal to itself.")
1103+ }
1104+ else nil
1105+ if ((doExchangePnL == doExchangePnL))
1106+ then (updateAmmReserves(qtAstRAfter, bsAstRAfter) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
1107+ else throw("Strict value is not equal to itself.")
10451108 }
10461109
10471110
10911154
10921155
10931156 @Callable(i)
1094-func decreasePosition (_amount,_leverage,_minBaseAssetAmount) = {
1095- let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
1096- if ((sync == sync))
1097- then {
1098- let _trader = getActualCaller(i)
1099- if (if (if (if (if ((0 >= _amount))
1100- then true
1101- else !(initialized()))
1102- then true
1103- else !(requireMoreMarginRatio(divd(DECIMAL_UNIT, _leverage), initMarginRatio(), true)))
1104- then true
1105- else !(requireOpenPosition(_trader)))
1106- then true
1107- else paused())
1108- then throw("Invalid decreasePosition parameters")
1109- else {
1110- let $t04867748817 = getPosition(_trader)
1111- let oldPositionSize = $t04867748817._1
1112- let oldPositionMargin = $t04867748817._2
1113- let oldPositionOpenNotional = $t04867748817._3
1114- let oldPositionLstUpdCPF = $t04867748817._4
1115- let _direction = if ((oldPositionSize > 0))
1116- then DIR_SHORT
1117- else DIR_LONG
1118- let isAdd = (_direction == DIR_LONG)
1119- let openNotional = muld(_amount, _leverage)
1120- let $t04899049094 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1121- let oldPositionNotional = $t04899049094._1
1122- let unrealizedPnl = $t04899049094._2
1123- let $t04910051758 = if ((oldPositionNotional > openNotional))
1124- then {
1125- let $t04951549699 = swapInput(isAdd, openNotional)
1126- let exchangedPositionSize = $t04951549699._1
1127- let quoteAssetReserveAfter = $t04951549699._2
1128- let baseAssetReserveAfter = $t04951549699._3
1129- let totalPositionSizeAfter = $t04951549699._4
1130- let exchangedPositionSizeAbs = abs(exchangedPositionSize)
1131- if (if ((_minBaseAssetAmount != 0))
1132- then (_minBaseAssetAmount > exchangedPositionSizeAbs)
1133- else false)
1134- then throw(((("Too little base asset exchanged, got " + toString(exchangedPositionSizeAbs)) + " expected ") + toString(_minBaseAssetAmount)))
1135- else {
1136- let realizedPnl = divd(muld(unrealizedPnl, exchangedPositionSizeAbs), abs(oldPositionSize))
1137- let $t05013650381 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl)
1138- let remainMargin = $t05013650381._1
1139- let badDebt = $t05013650381._2
1140- let fundingPayment = $t05013650381._3
1141- let exchangedQuoteAssetAmount = openNotional
1142- let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
1143- let remainOpenNotional = if ((oldPositionSize > 0))
1144- then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
1145- else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
1146- let newPositionSize = (oldPositionSize + exchangedPositionSize)
1147- $Tuple12(newPositionSize, remainMargin, abs(remainOpenNotional), latestCumulativePremiumFraction(newPositionSize), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() - openNotional), (totalLongPositionSize() - (if ((newPositionSize > 0))
1148- then abs(exchangedPositionSize)
1149- else 0)), (totalShortPositionSize() - (if ((0 > newPositionSize))
1150- then abs(exchangedPositionSize)
1151- else 0)), (openInterestLong() - (if ((newPositionSize > 0))
1152- then openNotional
1153- else 0)), (openInterestShort() - (if ((0 > newPositionSize))
1154- then openNotional
1155- else 0)))
1156- }
1157- }
1158- else throw("Close position first")
1159- let newPositionSize = $t04910051758._1
1160- let newPositionRemainMargin = $t04910051758._2
1161- let newPositionOpenNotional = $t04910051758._3
1162- let newPositionLatestCPF = $t04910051758._4
1163- let baseAssetReserveAfter = $t04910051758._5
1164- let quoteAssetReserveAfter = $t04910051758._6
1165- let totalPositionSizeAfter = $t04910051758._7
1166- let openInterestNotionalAfter = $t04910051758._8
1167- let totalLongAfter = $t04910051758._9
1168- let totalShortAfter = $t04910051758._10
1169- let totalLongOpenInterestAfter = $t04910051758._11
1170- let totalShortOpenInterestAfter = $t04910051758._12
1171- let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
1172- if ((notifyNotional == notifyNotional))
1173- then (updatePosition(_trader, newPositionSize, newPositionRemainMargin, newPositionOpenNotional, newPositionLatestCPF) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter))
1174- else throw("Strict value is not equal to itself.")
1175- }
1176- }
1177- else throw("Strict value is not equal to itself.")
1178- }
1179-
1180-
1181-
1182-@Callable(i)
11831157 func increasePosition (_direction,_leverage,_minBaseAssetAmount,_refLink) = {
11841158 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
11851159 if ((sync == sync))
11901164 let _assetIdStr = toBase58String(value(_assetId))
11911165 let isQuoteAsset = (_assetId == quoteAsset())
11921166 let isCollateralAsset = isWhitelistAsset(_assetIdStr)
1193- if (if (if (if (if (if (if (if (if ((_direction != DIR_LONG))
1167+ if (if (if (if (if (if (if (if (if (if ((_direction != DIR_LONG))
11941168 then (_direction != DIR_SHORT)
11951169 else false)
11961170 then true
12091183 else paused())
12101184 then true
12111185 else closeOnly())
1186+ then true
1187+ else isMarketClosed())
12121188 then throw("Invalid increasePosition parameters")
12131189 else {
1214- let $t05319653281 = getForTraderWithArtifact(_trader, getArtifactId(i))
1215- let adjustedFee = $t05319653281._1
1216- let burnArtifact = $t05319653281._2
1217- let rawFeeAmount = muld(_rawAmount, adjustedFee)
1218- let _amount = (_rawAmount - rawFeeAmount)
1190+ let $t05100951158 = getForTraderWithArtifact(_trader, getArtifactId(i))
1191+ let adjustedFee = $t05100951158._1
1192+ let burnArtifact = $t05100951158._2
1193+ let _amount = divd(_rawAmount, (muld(adjustedFee, _leverage) + DECIMAL_UNIT))
1194+ let rawFeeAmount = (_rawAmount - _amount)
12191195 let distributeFeeAmount = if (isCollateralAsset)
12201196 then {
12211197 let doBorrow = invoke(collateralAddress(), "borrow", [_trader], [AttachedPayment(_assetId, _amount)])
12561232 throw("Invalid referrerFee")
12571233 }
12581234 let feeAmount = (distributeFeeAmount - referrerFee)
1259- let $t05459754737 = getPosition(_trader)
1260- let oldPositionSize = $t05459754737._1
1261- let oldPositionMargin = $t05459754737._2
1262- let oldPositionOpenNotional = $t05459754737._3
1263- let oldPositionLstUpdCPF = $t05459754737._4
1235+ let $t05250052640 = getPosition(_trader)
1236+ let oldPositionSize = $t05250052640._1
1237+ let oldPositionMargin = $t05250052640._2
1238+ let oldPositionOpenNotional = $t05250052640._3
1239+ let oldPositionLstUpdCPF = $t05250052640._4
12641240 let isNewPosition = (oldPositionSize == 0)
12651241 let isSameDirection = if ((oldPositionSize > 0))
12661242 then (_direction == DIR_LONG)
12691245 then isSameDirection
12701246 else false
12711247 let isAdd = (_direction == DIR_LONG)
1272- let $t05502658067 = if (if (isNewPosition)
1248+ let $t05292955891 = if (if (isNewPosition)
12731249 then true
12741250 else expandExisting)
12751251 then {
12761252 let openNotional = muld(_amount, _leverage)
1277- let $t05548855661 = swapInput(isAdd, openNotional)
1278- let amountBaseAssetBought = $t05548855661._1
1279- let quoteAssetReserveAfter = $t05548855661._2
1280- let baseAssetReserveAfter = $t05548855661._3
1281- let totalPositionSizeAfter = $t05548855661._4
1253+ let $t05339153564 = swapInput(isAdd, openNotional)
1254+ let amountBaseAssetBought = $t05339153564._1
1255+ let quoteAssetReserveAfter = $t05339153564._2
1256+ let baseAssetReserveAfter = $t05339153564._3
1257+ let totalPositionSizeAfter = $t05339153564._4
12821258 if (if ((_minBaseAssetAmount != 0))
12831259 then (_minBaseAssetAmount > abs(amountBaseAssetBought))
12841260 else false)
12911267 let totalShortOpenInterestAfter = (openInterestShort() + (if ((0 > newPositionSize))
12921268 then openNotional
12931269 else 0))
1294- let increaseMarginRequirement = divd(openNotional, _leverage)
1295- let $t05626956508 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, increaseMarginRequirement)
1296- let remainMargin = $t05626956508._1
1297- let x1 = $t05626956508._2
1298- let x2 = $t05626956508._3
1270+ let $t05411054331 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, _amount)
1271+ let remainMargin = $t05411054331._1
1272+ let x1 = $t05411054331._2
1273+ let x2 = $t05411054331._3
12991274 if (!(requireNotOverSpreadLimit(quoteAssetReserveAfter, baseAssetReserveAfter)))
13001275 then throw("Over max spread limit")
13011276 else if (!(requireNotOverMaxOpenNotional(totalLongOpenInterestAfter, totalShortOpenInterestAfter)))
13091284 }
13101285 else {
13111286 let openNotional = muld(_amount, _leverage)
1312- let $t05776757883 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
1313- let oldPositionNotional = $t05776757883._1
1314- let unrealizedPnl = $t05776757883._2
1287+ let $t05559155707 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
1288+ let oldPositionNotional = $t05559155707._1
1289+ let unrealizedPnl = $t05559155707._2
13151290 if ((oldPositionNotional > openNotional))
13161291 then throw("Use decreasePosition to decrease position size")
13171292 else throw("Close position first")
13181293 }
1319- let newPositionSize = $t05502658067._1
1320- let newPositionRemainMargin = $t05502658067._2
1321- let newPositionOpenNotional = $t05502658067._3
1322- let newPositionLatestCPF = $t05502658067._4
1323- let baseAssetReserveAfter = $t05502658067._5
1324- let quoteAssetReserveAfter = $t05502658067._6
1325- let totalPositionSizeAfter = $t05502658067._7
1326- let openInterestNotionalAfter = $t05502658067._8
1327- let totalLongAfter = $t05502658067._9
1328- let totalShortAfter = $t05502658067._10
1329- let totalLongOpenInterestAfter = $t05502658067._11
1330- let totalShortOpenInterestAfter = $t05502658067._12
1331- let $t05807358130 = distributeFee(feeAmount)
1332- let feeToStakers = $t05807358130._1
1333- let feeToVault = $t05807358130._2
1294+ let newPositionSize = $t05292955891._1
1295+ let newPositionRemainMargin = $t05292955891._2
1296+ let newPositionOpenNotional = $t05292955891._3
1297+ let newPositionLatestCPF = $t05292955891._4
1298+ let baseAssetReserveAfter = $t05292955891._5
1299+ let quoteAssetReserveAfter = $t05292955891._6
1300+ let totalPositionSizeAfter = $t05292955891._7
1301+ let openInterestNotionalAfter = $t05292955891._8
1302+ let totalLongAfter = $t05292955891._9
1303+ let totalShortAfter = $t05292955891._10
1304+ let totalLongOpenInterestAfter = $t05292955891._11
1305+ let totalShortOpenInterestAfter = $t05292955891._12
1306+ let $t05589755954 = distributeFee(feeAmount)
1307+ let feeToStakers = $t05589755954._1
1308+ let feeToVault = $t05589755954._2
13341309 let stake = if (isQuoteAsset)
13351310 then {
13361311 let stake = invoke(vaultAddress(), "addLocked", [false], [AttachedPayment(quoteAsset(), _amount)])
13411316 else nil
13421317 if ((stake == stake))
13431318 then {
1344- let depositInsurance = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1345- if ((depositInsurance == depositInsurance))
1319+ let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1320+ if ((depositVault == depositVault))
13461321 then {
13471322 let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, feeAmount], nil)
13481323 if ((notifyFee == notifyFee))
13491324 then {
13501325 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
13511326 if ((notifyNotional == notifyNotional))
1352- then ((((((updatePosition(_trader, newPositionSize, newPositionRemainMargin, newPositionOpenNotional, newPositionLatestCPF) ++ incrementPositionSequenceNumber(isNewPosition, _trader)) ++ updatePositionAsset(_trader, _assetIdStr)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ transferFee(feeToStakers)) ++ updateBalance((cbalance() + _amount))) ++ doBurnArtifact(burnArtifact, i))
1327+ then (((((((updatePosition(_trader, newPositionSize, newPositionRemainMargin, newPositionOpenNotional, newPositionLatestCPF) ++ incrementPositionSequenceNumber(isNewPosition, _trader)) ++ updatePositionFee(isNewPosition, _trader, adjustedFee)) ++ updatePositionAsset(_trader, _assetIdStr)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ transferFee(feeToStakers)) ++ updateBalance((cbalance() + _amount))) ++ doBurnArtifact(burnArtifact, i))
13531328 else throw("Strict value is not equal to itself.")
13541329 }
13551330 else throw("Strict value is not equal to itself.")
13741349 if ((sync == sync))
13751350 then {
13761351 let _trader = toString(i.caller)
1377- let _rawAmount = i.payments[0].amount
1352+ let _amount = i.payments[0].amount
13781353 let _assetId = i.payments[0].assetId
13791354 let _assetIdStr = toBase58String(value(_assetId))
13801355 let isQuoteAsset = (_assetId == quoteAsset())
13811356 let isCollateralAsset = isWhitelistAsset(_assetIdStr)
1382- if (if (if (if (if (if (if (!(isQuoteAsset))
1357+ if (if (if (if (if (if (if (if (!(isQuoteAsset))
13831358 then !(isCollateralAsset)
13841359 else false)
13851360 then true
13921367 else paused())
13931368 then true
13941369 else closeOnly())
1370+ then true
1371+ else isMarketClosed())
13951372 then throw("Invalid addMargin parameters")
13961373 else {
1397- let $t06007860163 = getForTraderWithArtifact(_trader, getArtifactId(i))
1398- let adjustedFee = $t06007860163._1
1399- let burnArtifact = $t06007860163._2
1400- let rawFeeAmount = muld(_rawAmount, adjustedFee)
1401- let _amount = (_rawAmount - rawFeeAmount)
1402- let distributeFeeAmount = if (isCollateralAsset)
1374+ let $t05798558125 = getPosition(_trader)
1375+ let oldPositionSize = $t05798558125._1
1376+ let oldPositionMargin = $t05798558125._2
1377+ let oldPositionOpenNotional = $t05798558125._3
1378+ let oldPositionLstUpdCPF = $t05798558125._4
1379+ let stake = if (isQuoteAsset)
14031380 then {
1404- let doBorrow = invoke(collateralAddress(), "borrow", [_trader], [AttachedPayment(_assetId, _amount)])
1405- if ((doBorrow == doBorrow))
1406- then {
1407- let balanceBefore = assetBalance(this, quoteAsset())
1408- if ((balanceBefore == balanceBefore))
1409- then {
1410- let doSwap = invoke(swapAddress(), "swap", [toBase58String(quoteAsset()), 0], [AttachedPayment(_assetId, rawFeeAmount)])
1411- if ((doSwap == doSwap))
1412- then {
1413- let balanceAfter = assetBalance(this, quoteAsset())
1414- if ((balanceAfter == balanceAfter))
1415- then {
1416- let exchangedAmount = (balanceAfter - balanceBefore)
1417- if ((exchangedAmount == exchangedAmount))
1418- then exchangedAmount
1419- else throw("Strict value is not equal to itself.")
1420- }
1421- else throw("Strict value is not equal to itself.")
1422- }
1423- else throw("Strict value is not equal to itself.")
1424- }
1425- else throw("Strict value is not equal to itself.")
1426- }
1381+ let stake = invoke(vaultAddress(), "addLocked", [false], [AttachedPayment(quoteAsset(), _amount)])
1382+ if ((stake == stake))
1383+ then nil
14271384 else throw("Strict value is not equal to itself.")
14281385 }
1429- else rawFeeAmount
1430- if ((distributeFeeAmount == distributeFeeAmount))
1431- then {
1432- let referrerFeeAny = invoke(referralAddress(), "acceptPayment", [_trader], [AttachedPayment(quoteAsset(), distributeFeeAmount)])
1433- if ((referrerFeeAny == referrerFeeAny))
1434- then {
1435- let referrerFee = match referrerFeeAny {
1436- case x: Int =>
1437- x
1438- case _ =>
1439- throw("Invalid referrerFee")
1440- }
1441- let feeAmount = (distributeFeeAmount - referrerFee)
1442- let $t06146261602 = getPosition(_trader)
1443- let oldPositionSize = $t06146261602._1
1444- let oldPositionMargin = $t06146261602._2
1445- let oldPositionOpenNotional = $t06146261602._3
1446- let oldPositionLstUpdCPF = $t06146261602._4
1447- let $t06160861665 = distributeFee(feeAmount)
1448- let feeToStakers = $t06160861665._1
1449- let feeToVault = $t06160861665._2
1450- let stake = if (isQuoteAsset)
1451- then {
1452- let stake = invoke(vaultAddress(), "addLocked", [false], [AttachedPayment(quoteAsset(), _amount)])
1453- if ((stake == stake))
1454- then nil
1455- else throw("Strict value is not equal to itself.")
1456- }
1457- else nil
1458- if ((stake == stake))
1459- then {
1460- let depositInsurance = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1461- if ((depositInsurance == depositInsurance))
1462- then {
1463- let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, feeAmount], nil)
1464- if ((notifyFee == notifyFee))
1465- then (((updatePosition(_trader, oldPositionSize, (oldPositionMargin + _amount), oldPositionOpenNotional, oldPositionLstUpdCPF) ++ transferFee(feeToStakers)) ++ updateBalance((cbalance() + _amount))) ++ doBurnArtifact(burnArtifact, i))
1466- else throw("Strict value is not equal to itself.")
1467- }
1468- else throw("Strict value is not equal to itself.")
1469- }
1470- else throw("Strict value is not equal to itself.")
1471- }
1472- else throw("Strict value is not equal to itself.")
1473- }
1386+ else nil
1387+ if ((stake == stake))
1388+ then (updatePosition(_trader, oldPositionSize, (oldPositionMargin + _amount), oldPositionOpenNotional, oldPositionLstUpdCPF) ++ updateBalance((cbalance() + _amount)))
14741389 else throw("Strict value is not equal to itself.")
14751390 }
14761391 }
14851400 if ((sync == sync))
14861401 then {
14871402 let _trader = toString(i.caller)
1488- if (if (if (if ((0 >= _amount))
1403+ if (if (if (if (if ((0 >= _amount))
14891404 then true
14901405 else !(requireOpenPosition(_trader)))
14911406 then true
14921407 else !(initialized()))
14931408 then true
14941409 else paused())
1410+ then true
1411+ else isMarketClosed())
14951412 then throw("Invalid removeMargin parameters")
14961413 else {
1497- let $t06277762917 = getPosition(_trader)
1498- let oldPositionSize = $t06277762917._1
1499- let oldPositionMargin = $t06277762917._2
1500- let oldPositionOpenNotional = $t06277762917._3
1501- let oldPositionLstUpdCPF = $t06277762917._4
1414+ let $t05892059060 = getPosition(_trader)
1415+ let oldPositionSize = $t05892059060._1
1416+ let oldPositionMargin = $t05892059060._2
1417+ let oldPositionOpenNotional = $t05892059060._3
1418+ let oldPositionLstUpdCPF = $t05892059060._4
15021419 let marginDelta = -(_amount)
1503- let $t06295463133 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, marginDelta)
1504- let remainMargin = $t06295463133._1
1505- let badDebt = $t06295463133._2
1420+ let $t05909759276 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, marginDelta)
1421+ let remainMargin = $t05909759276._1
1422+ let badDebt = $t05909759276._2
15061423 if ((badDebt != 0))
15071424 then throw("Invalid removed margin amount")
15081425 else {
15111428 then throw(((("Too much margin removed: " + toString(marginRatio)) + " < ") + toString(initMarginRatio())))
15121429 else {
15131430 let quoteAssetStr = toBase58String(quoteAsset())
1514- let $t06357763631 = getBorrowedByTrader(_trader)
1515- let borrowed = $t06357763631._1
1516- let assetId = $t06357763631._2
1431+ let $t05972059774 = getBorrowedByTrader(_trader)
1432+ let borrowed = $t05972059774._1
1433+ let assetId = $t05972059774._2
15171434 let toRepay = if ((_amount > borrowed))
15181435 then borrowed
15191436 else _amount
15661483
15671484
15681485 @Callable(i)
1569-func closePosition (_size,_minQuoteAssetAmount) = {
1486+func closePosition (_size,_minQuoteAssetAmount,_addToMargin) = {
15701487 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
15711488 if ((sync == sync))
15721489 then {
15731490 let _trader = getActualCaller(i)
15741491 let _traderAddress = valueOrErrorMessage(addressFromString(_trader), "Invalid caller")
1575- if (if (if (if (if (!(requireOpenPosition(_trader)))
1492+ let positionFee = getPositionFee(_trader)
1493+ if (if (if (if (if (if (!(requireOpenPosition(_trader)))
15761494 then true
15771495 else !(initialized()))
15781496 then true
15811499 else (0 >= _size))
15821500 then true
15831501 else (0 > _minQuoteAssetAmount))
1502+ then true
1503+ else isMarketClosed())
15841504 then throw("Invalid closePosition parameters")
15851505 else {
1586- let $t06578965929 = getPosition(_trader)
1587- let oldPositionSize = $t06578965929._1
1588- let oldPositionMargin = $t06578965929._2
1589- let oldPositionOpenNotional = $t06578965929._3
1590- let oldPositionLstUpdCPF = $t06578965929._4
1591- let $t06593570372 = if ((abs(oldPositionSize) > _size))
1506+ let $t06201162151 = getPosition(_trader)
1507+ let oldPositionSize = $t06201162151._1
1508+ let oldPositionMargin = $t06201162151._2
1509+ let oldPositionOpenNotional = $t06201162151._3
1510+ let oldPositionLstUpdCPF = $t06201162151._4
1511+ let $t06215767916 = if ((abs(oldPositionSize) > _size))
15921512 then {
1593- let _direction = if ((oldPositionSize > 0))
1594- then DIR_SHORT
1595- else DIR_LONG
1596- let isAdd = (_direction == DIR_LONG)
1597- let $t06652666748 = swapOutput((oldPositionSize > 0), _size, true)
1598- let exchangedQuoteAssetAmount = $t06652666748._1
1599- let quoteAssetReserveAfter = $t06652666748._2
1600- let baseAssetReserveAfter = $t06652666748._3
1601- let totalPositionSizeAfter = $t06652666748._4
1513+ let $t06264962871 = swapOutput((oldPositionSize > 0), _size, true)
1514+ let exchangedQuoteAssetAmount = $t06264962871._1
1515+ let quoteAssetReserveAfter = $t06264962871._2
1516+ let baseAssetReserveAfter = $t06264962871._3
1517+ let totalPositionSizeAfter = $t06264962871._4
16021518 let exchangedPositionSize = if ((oldPositionSize > 0))
16031519 then -(_size)
16041520 else _size
1605- let $t06683966993 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1606- let oldPositionNotional = $t06683966993._1
1607- let unrealizedPnl = $t06683966993._2
1521+ let $t06296263116 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1522+ let oldPositionNotional = $t06296263116._1
1523+ let unrealizedPnl = $t06296263116._2
16081524 let mr = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
16091525 let realizedRatio = divd(abs(exchangedPositionSize), abs(oldPositionSize))
16101526 let realizedPnl = muld(unrealizedPnl, realizedRatio)
1611- let $t06727267510 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl)
1612- let remainMargin = $t06727267510._1
1613- let positionBadDebt = $t06727267510._2
1614- let fundingPayment = $t06727267510._3
1527+ let realizedFee = muld(muld(oldPositionNotional, realizedRatio), positionFee)
1528+ let remainMarginBefore = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, unrealizedPnl)._1
1529+ let positionBadDebt = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl)._2
16151530 let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
16161531 let remainOpenNotional = if ((oldPositionSize > 0))
16171532 then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
16181533 else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
16191534 let newPositionOpenNotional = abs(remainOpenNotional)
1620- let newPositionMargin = muld(newPositionOpenNotional, mr)
16211535 let newPositionSize = (oldPositionSize + exchangedPositionSize)
16221536 let newPositionLstUpdCPF = latestCumulativePremiumFraction(newPositionSize)
1623- let openInterestNotionalAfter = (openInterestNotional() - exchangedQuoteAssetAmount)
1537+ let openNotionalDelta = (oldPositionOpenNotional - newPositionOpenNotional)
1538+ let openInterestNotionalAfter = (openInterestNotional() - openNotionalDelta)
1539+ let newPositionMargin = if ((oldPositionSize > 0))
1540+ then (muld((newPositionOpenNotional + unrealizedPnlAfter), mr) - unrealizedPnlAfter)
1541+ else (muld((newPositionOpenNotional - unrealizedPnlAfter), mr) - unrealizedPnlAfter)
1542+ let marginToTraderRaw = ((remainMarginBefore - (newPositionMargin + unrealizedPnlAfter)) - realizedFee)
1543+ let marginToTrader = if ((0 > marginToTraderRaw))
1544+ then throw("Margin error: unable to pay close fee")
1545+ else marginToTraderRaw
16241546 if (if ((_minQuoteAssetAmount != 0))
16251547 then (_minQuoteAssetAmount > exchangedQuoteAssetAmount)
16261548 else false)
16271549 then throw(((("Limit error: " + toString(exchangedQuoteAssetAmount)) + " < ") + toString(_minQuoteAssetAmount)))
1628- else $Tuple15(newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, positionBadDebt, realizedPnl, (abs((remainMargin - newPositionMargin)) + realizedPnl), quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, (totalLongPositionSize() - (if ((newPositionSize > 0))
1550+ else $Tuple16(newPositionSize, if (_addToMargin)
1551+ then (newPositionMargin + marginToTrader)
1552+ else newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, positionBadDebt, realizedPnl, if (_addToMargin)
1553+ then 0
1554+ else marginToTrader, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, (totalLongPositionSize() - (if ((newPositionSize > 0))
16291555 then abs(exchangedPositionSize)
16301556 else 0)), (totalShortPositionSize() - (if ((0 > newPositionSize))
16311557 then abs(exchangedPositionSize)
16321558 else 0)), (openInterestLong() - (if ((newPositionSize > 0))
1633- then exchangedQuoteAssetAmount
1559+ then openNotionalDelta
16341560 else 0)), (openInterestShort() - (if ((0 > newPositionSize))
1635- then exchangedQuoteAssetAmount
1636- else 0)))
1561+ then openNotionalDelta
1562+ else 0)), realizedFee)
16371563 }
16381564 else if ((_size > abs(oldPositionSize)))
16391565 then throw("Invalid closePosition parameters")
16401566 else {
1641- let $t06931369732 = internalClosePosition(_trader, true)
1642- let exchangedQuoteAssetAmount = $t06931369732._1
1643- let positionBadDebt = $t06931369732._2
1644- let realizedPnl = $t06931369732._3
1645- let marginToVault = $t06931369732._4
1646- let quoteAssetReserveAfter = $t06931369732._5
1647- let baseAssetReserveAfter = $t06931369732._6
1648- let totalPositionSizeAfter = $t06931369732._7
1649- let openInterestNotionalAfter = $t06931369732._8
1650- let x2 = $t06931369732._9
1651- let totalLongAfter = $t06931369732._10
1652- let totalShortAfter = $t06931369732._11
1653- let totalLongOpenInterestAfter = $t06931369732._12
1654- let totalShortOpenInterestAfter = $t06931369732._13
1567+ let $t06633566765 = internalClosePosition(_trader, true)
1568+ let x2 = $t06633566765._1
1569+ let positionBadDebt = $t06633566765._2
1570+ let realizedPnl = $t06633566765._3
1571+ let marginToTraderWithoutFee = $t06633566765._4
1572+ let quoteAssetReserveAfter = $t06633566765._5
1573+ let baseAssetReserveAfter = $t06633566765._6
1574+ let totalPositionSizeAfter = $t06633566765._7
1575+ let openInterestNotionalAfter = $t06633566765._8
1576+ let exchangedQuoteAssetAmount = $t06633566765._9
1577+ let totalLongAfter = $t06633566765._10
1578+ let totalShortAfter = $t06633566765._11
1579+ let totalLongOpenInterestAfter = $t06633566765._12
1580+ let totalShortOpenInterestAfter = $t06633566765._13
1581+ let realizedFee = muld(exchangedQuoteAssetAmount, positionFee)
1582+ let marginToTraderRaw = (abs(marginToTraderWithoutFee) - realizedFee)
1583+ let marginToTrader = if ((0 > marginToTraderRaw))
1584+ then throw(((((((("Margin error: unable to pay close fee: " + toString(realizedFee)) + " margin: ") + toString(marginToTraderWithoutFee)) + " fee percent: ") + toString(positionFee)) + " notional: ") + toString(exchangedQuoteAssetAmount)))
1585+ else marginToTraderRaw
16551586 if (if ((_minQuoteAssetAmount != 0))
16561587 then (_minQuoteAssetAmount > exchangedQuoteAssetAmount)
16571588 else false)
16581589 then throw(((("Limit error: " + toString(exchangedQuoteAssetAmount)) + " < ") + toString(_minQuoteAssetAmount)))
1659- else $Tuple15(0, 0, 0, 0, positionBadDebt, realizedPnl, marginToVault, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)
1590+ else $Tuple16(0, 0, 0, 0, positionBadDebt, realizedPnl, marginToTrader, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter, realizedFee)
16601591 }
1661- let newPositionSize = $t06593570372._1
1662- let newPositionMargin = $t06593570372._2
1663- let newPositionOpenNotional = $t06593570372._3
1664- let newPositionLstUpdCPF = $t06593570372._4
1665- let positionBadDebt = $t06593570372._5
1666- let realizedPnl = $t06593570372._6
1667- let marginToVault = $t06593570372._7
1668- let quoteAssetReserveAfter = $t06593570372._8
1669- let baseAssetReserveAfter = $t06593570372._9
1670- let totalPositionSizeAfter = $t06593570372._10
1671- let openInterestNotionalAfter = $t06593570372._11
1672- let totalLongAfter = $t06593570372._12
1673- let totalShortAfter = $t06593570372._13
1674- let totalLongOpenInterestAfter = $t06593570372._14
1675- let totalShortOpenInterestAfter = $t06593570372._15
1592+ let newPositionSize = $t06215767916._1
1593+ let newPositionMargin = $t06215767916._2
1594+ let newPositionOpenNotional = $t06215767916._3
1595+ let newPositionLstUpdCPF = $t06215767916._4
1596+ let positionBadDebt = $t06215767916._5
1597+ let realizedPnl = $t06215767916._6
1598+ let marginToTrader = $t06215767916._7
1599+ let quoteAssetReserveAfter = $t06215767916._8
1600+ let baseAssetReserveAfter = $t06215767916._9
1601+ let totalPositionSizeAfter = $t06215767916._10
1602+ let openInterestNotionalAfter = $t06215767916._11
1603+ let totalLongAfter = $t06215767916._12
1604+ let totalShortAfter = $t06215767916._13
1605+ let totalLongOpenInterestAfter = $t06215767916._14
1606+ let totalShortOpenInterestAfter = $t06215767916._15
1607+ let realizedFee = $t06215767916._16
16761608 if ((positionBadDebt > 0))
16771609 then throw("Unable to close position with bad debt")
16781610 else {
1679- let withdrawAmount = abs(marginToVault)
1611+ let isPartialClose = (newPositionSize != 0)
1612+ let withdrawAmount = (marginToTrader + realizedFee)
16801613 let ammBalance = (cbalance() - withdrawAmount)
1681- let $t07058170788 = if ((0 > ammBalance))
1614+ let $t06818368390 = if ((0 > ammBalance))
16821615 then $Tuple2(0, abs(ammBalance))
16831616 else $Tuple2(ammBalance, 0)
1684- let ammNewBalance = $t07058170788._1
1685- let x11 = $t07058170788._2
1686- let $t07079570849 = getBorrowedByTrader(_trader)
1687- let borrowed = $t07079570849._1
1688- let assetId = $t07079570849._2
1689- let $t07086471723 = if ((borrowed > 0))
1617+ let ammNewBalance = $t06818368390._1
1618+ let x11 = $t06818368390._2
1619+ let $t06839768451 = getBorrowedByTrader(_trader)
1620+ let borrowed = $t06839768451._1
1621+ let assetId = $t06839768451._2
1622+ let $t06845969319 = if ((borrowed > 0))
16901623 then if ((withdrawAmount >= borrowed))
16911624 then {
16921625 let doRepay = invoke(collateralAddress(), "repay", [_trader, borrowed, assetId], nil)
16931626 if ((doRepay == doRepay))
1694- then $Tuple2([ScriptTransfer(_traderAddress, borrowed, fromBase58String(assetId))], (withdrawAmount - borrowed))
1627+ then $Tuple3(borrowed, (withdrawAmount - borrowed), isPartialClose)
16951628 else throw("Strict value is not equal to itself.")
16961629 }
16971630 else {
1698- let realizeAndClose = invoke(collateralAddress(), "realizePartiallyAndClose", [_trader, withdrawAmount, assetId], nil)
1631+ let realizeAndClose = invoke(collateralAddress(), if (isPartialClose)
1632+ then "repay"
1633+ else "realizePartiallyAndClose", [_trader, withdrawAmount, assetId], nil)
16991634 if ((realizeAndClose == realizeAndClose))
1700- then $Tuple2([ScriptTransfer(_traderAddress, withdrawAmount, fromBase58String(assetId))], 0)
1635+ then $Tuple3(withdrawAmount, 0, false)
17011636 else throw("Strict value is not equal to itself.")
17021637 }
1703- else $Tuple2(nil, withdrawAmount)
1704- if (($t07086471723 == $t07086471723))
1638+ else $Tuple3(0, withdrawAmount, false)
1639+ if (($t06845969319 == $t06845969319))
17051640 then {
1706- let quoteWithdrawAmount = $t07086471723._2
1707- let sendCollateralAction = $t07086471723._1
1708- let unstake = if ((quoteWithdrawAmount > 0))
1709- then {
1710- let unstake = invoke(vaultAddress(), "withdrawLocked", [quoteWithdrawAmount], nil)
1711- if ((unstake == unstake))
1712- then nil
1641+ let switchToQuote = $t06845969319._3
1642+ let quoteWithdrawAmountBeforeFee = $t06845969319._2
1643+ let assetWithdrawAmountBeforeFee = $t06845969319._1
1644+ let $t06932770394 = if ((quoteWithdrawAmountBeforeFee >= realizedFee))
1645+ then $Tuple3(assetWithdrawAmountBeforeFee, (quoteWithdrawAmountBeforeFee - realizedFee), realizedFee)
1646+ else {
1647+ let feeLeftToWithdrawFromAsset = (realizedFee - quoteWithdrawAmountBeforeFee)
1648+ let assetWithdrawAmountAfterFee = (assetWithdrawAmountBeforeFee - feeLeftToWithdrawFromAsset)
1649+ let balanceBefore = assetBalance(this, quoteAsset())
1650+ if ((balanceBefore == balanceBefore))
1651+ then {
1652+ let doSwap = invoke(swapAddress(), "swap", [toBase58String(quoteAsset()), 0], [AttachedPayment(fromBase58String(assetId), feeLeftToWithdrawFromAsset)])
1653+ if ((doSwap == doSwap))
1654+ then {
1655+ let balanceAfter = assetBalance(this, quoteAsset())
1656+ if ((balanceAfter == balanceAfter))
1657+ then {
1658+ let exchangedAmount = (balanceAfter - balanceBefore)
1659+ if ((exchangedAmount == exchangedAmount))
1660+ then $Tuple3(assetWithdrawAmountAfterFee, 0, (quoteWithdrawAmountBeforeFee + exchangedAmount))
1661+ else throw("Strict value is not equal to itself.")
1662+ }
1663+ else throw("Strict value is not equal to itself.")
1664+ }
1665+ else throw("Strict value is not equal to itself.")
1666+ }
17131667 else throw("Strict value is not equal to itself.")
17141668 }
1715- else nil
1716- if ((unstake == unstake))
1669+ if (($t06932770394 == $t06932770394))
17171670 then {
1718- let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, 0], nil)
1719- if ((notifyNotional == notifyNotional))
1720- then (((((if ((newPositionSize == 0))
1721- then deletePosition(_trader)
1722- else updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ (if ((quoteWithdrawAmount > 0))
1723- then withdraw(_traderAddress, quoteWithdrawAmount)
1724- else nil)) ++ updateBalance(ammNewBalance)) ++ sendCollateralAction)
1671+ let actualFeeInQuoteAsset = $t06932770394._3
1672+ let quoteWithdrawAmountAfterFee = $t06932770394._2
1673+ let assetWithdrawAmountAfterFee = $t06932770394._1
1674+ let unstake = if ((quoteWithdrawAmountBeforeFee > 0))
1675+ then {
1676+ let unstake = invoke(vaultAddress(), "withdrawLocked", [quoteWithdrawAmountBeforeFee], nil)
1677+ if ((unstake == unstake))
1678+ then nil
1679+ else throw("Strict value is not equal to itself.")
1680+ }
1681+ else nil
1682+ if ((unstake == unstake))
1683+ then {
1684+ let $t07066870737 = distributeFee(actualFeeInQuoteAsset)
1685+ let feeToStakers = $t07066870737._1
1686+ let feeToVault = $t07066870737._2
1687+ let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1688+ if ((depositVault == depositVault))
1689+ then {
1690+ let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, realizedFee], nil)
1691+ if ((notifyFee == notifyFee))
1692+ then {
1693+ let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
1694+ if ((notifyNotional == notifyNotional))
1695+ then (((((((if (isPartialClose)
1696+ then updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF)
1697+ else deletePosition(_trader)) ++ (if (switchToQuote)
1698+ then {
1699+ let quoteAssetStr = toBase58String(quoteAsset())
1700+ updatePositionAsset(_trader, quoteAssetStr)
1701+ }
1702+ else nil)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ transferFee(feeToStakers)) ++ (if ((quoteWithdrawAmountAfterFee > 0))
1703+ then withdraw(_traderAddress, quoteWithdrawAmountAfterFee)
1704+ else nil)) ++ updateBalance(ammNewBalance)) ++ (if ((assetWithdrawAmountAfterFee > 0))
1705+ then [ScriptTransfer(_traderAddress, assetWithdrawAmountAfterFee, fromBase58String(assetId))]
1706+ else nil))
1707+ else throw("Strict value is not equal to itself.")
1708+ }
1709+ else throw("Strict value is not equal to itself.")
1710+ }
1711+ else throw("Strict value is not equal to itself.")
1712+ }
17251713 else throw("Strict value is not equal to itself.")
17261714 }
17271715 else throw("Strict value is not equal to itself.")
17471735 vmax(spotMarginRatio, oracleMarginRatio)
17481736 }
17491737 else spotMarginRatio
1750- if (if (if (if (!(requireMoreMarginRatio(marginRatio, maintenanceMarginRatio(), false)))
1738+ if (if (if (if (if (!(requireMoreMarginRatio(marginRatio, maintenanceMarginRatio(), false)))
17511739 then true
17521740 else !(requireOpenPosition(_trader)))
17531741 then true
17541742 else !(initialized()))
17551743 then true
17561744 else paused())
1745+ then true
1746+ else isMarketClosed())
17571747 then throw("Unable to liquidate")
17581748 else if (if (if ((spotMarginRatio > liquidationFeeRatio()))
17591749 then (partialLiquidationRatio() > 0)
17611751 then (DECIMAL_UNIT > partialLiquidationRatio())
17621752 else false)
17631753 then {
1764- let $t07402074170 = getPosition(_trader)
1765- let oldPositionSize = $t07402074170._1
1766- let oldPositionMargin = $t07402074170._2
1767- let oldPositionOpenNotional = $t07402074170._3
1768- let oldPositionLstUpdCPF = $t07402074170._4
1754+ let $t07349073640 = getPosition(_trader)
1755+ let oldPositionSize = $t07349073640._1
1756+ let oldPositionMargin = $t07349073640._2
1757+ let oldPositionOpenNotional = $t07349073640._3
1758+ let oldPositionLstUpdCPF = $t07349073640._4
17691759 let _direction = if ((oldPositionSize > 0))
17701760 then DIR_SHORT
17711761 else DIR_LONG
17721762 let isAdd = (_direction == DIR_LONG)
17731763 let exchangedQuoteAssetAmount = getPartialLiquidationAmount(_trader, oldPositionSize)
1774- let $t07439574499 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1775- let oldPositionNotional = $t07439574499._1
1776- let unrealizedPnl = $t07439574499._2
1777- let $t07450774694 = swapInput(isAdd, exchangedQuoteAssetAmount)
1778- let exchangedPositionSize = $t07450774694._1
1779- let quoteAssetReserveAfter = $t07450774694._2
1780- let baseAssetReserveAfter = $t07450774694._3
1781- let totalPositionSizeAfter = $t07450774694._4
1764+ let $t07386573969 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1765+ let oldPositionNotional = $t07386573969._1
1766+ let unrealizedPnl = $t07386573969._2
1767+ let $t07397774164 = swapInput(isAdd, exchangedQuoteAssetAmount)
1768+ let exchangedPositionSize = $t07397774164._1
1769+ let quoteAssetReserveAfter = $t07397774164._2
1770+ let baseAssetReserveAfter = $t07397774164._3
1771+ let totalPositionSizeAfter = $t07397774164._4
17821772 let liquidationRatio = divd(abs(exchangedPositionSize), abs(oldPositionSize))
17831773 let realizedPnl = muld(unrealizedPnl, liquidationRatio)
1784- let $t07498375216 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl)
1785- let remainMargin = $t07498375216._1
1786- let badDebt = $t07498375216._2
1787- let fundingPayment = $t07498375216._3
1774+ let $t07445374686 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl)
1775+ let remainMargin = $t07445374686._1
1776+ let badDebt = $t07445374686._2
1777+ let fundingPayment = $t07445374686._3
17881778 let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
17891779 let remainOpenNotional = if ((oldPositionSize > 0))
17901780 then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
17951785 let newPositionMargin = (remainMargin - liquidationPenalty)
17961786 let newPositionSize = (oldPositionSize + exchangedPositionSize)
17971787 let newPositionOpenNotional = abs(remainOpenNotional)
1788+ let openNotionalDelta = (oldPositionOpenNotional - newPositionOpenNotional)
17981789 let newPositionLstUpdCPF = latestCumulativePremiumFraction(newPositionSize)
1799- let openInterestNotionalAfter = (openInterestNotional() - exchangedQuoteAssetAmount)
1790+ let openInterestNotionalAfter = (openInterestNotional() - openNotionalDelta)
18001791 let ammBalance = (cbalance() - liquidationPenalty)
1801- let $t07638576514 = if ((0 > ammBalance))
1792+ let $t07592776056 = if ((0 > ammBalance))
18021793 then $Tuple2(0, abs(ammBalance))
18031794 else $Tuple2(ammBalance, 0)
1804- let newAmmBalance = $t07638576514._1
1805- let x11 = $t07638576514._2
1806- let $t07652276576 = getBorrowedByTrader(_trader)
1807- let borrowed = $t07652276576._1
1808- let assetId = $t07652276576._2
1795+ let newAmmBalance = $t07592776056._1
1796+ let x11 = $t07592776056._2
1797+ let $t07606476118 = getBorrowedByTrader(_trader)
1798+ let borrowed = $t07606476118._1
1799+ let assetId = $t07606476118._2
18091800 let doLiquidateCollateral = if ((borrowed > 0))
18101801 then {
18111802 let collateralToSell = muld(borrowed, liquidationRatio)
18301821 else 0)), (totalShortPositionSize() - (if ((0 > newPositionSize))
18311822 then abs(exchangedPositionSize)
18321823 else 0)), (openInterestLong() - (if ((newPositionSize > 0))
1833- then exchangedQuoteAssetAmount
1824+ then openNotionalDelta
18341825 else 0)), (openInterestShort() - (if ((0 > newPositionSize))
1835- then exchangedQuoteAssetAmount
1826+ then openNotionalDelta
18361827 else 0)))) ++ withdraw(i.caller, feeToLiquidator)) ++ updateBalance(newAmmBalance))
18371828 else throw("Strict value is not equal to itself.")
18381829 }
18431834 else throw("Strict value is not equal to itself.")
18441835 }
18451836 else {
1846- let $t07827178766 = internalClosePosition(_trader, false)
1847- let x1 = $t07827178766._1
1848- let badDebt = $t07827178766._2
1849- let x2 = $t07827178766._3
1850- let x3 = $t07827178766._4
1851- let quoteAssetReserveAfter = $t07827178766._5
1852- let baseAssetReserveAfter = $t07827178766._6
1853- let totalPositionSizeAfter = $t07827178766._7
1854- let openInterestNotionalAfter = $t07827178766._8
1855- let exchangedQuoteAssetAmount = $t07827178766._9
1856- let totalLongAfter = $t07827178766._10
1857- let totalShortAfter = $t07827178766._11
1858- let totalLongOpenInterestAfter = $t07827178766._12
1859- let totalShortOpenInterestAfter = $t07827178766._13
1837+ let $t07779778292 = internalClosePosition(_trader, false)
1838+ let x1 = $t07779778292._1
1839+ let badDebt = $t07779778292._2
1840+ let x2 = $t07779778292._3
1841+ let x3 = $t07779778292._4
1842+ let quoteAssetReserveAfter = $t07779778292._5
1843+ let baseAssetReserveAfter = $t07779778292._6
1844+ let totalPositionSizeAfter = $t07779778292._7
1845+ let openInterestNotionalAfter = $t07779778292._8
1846+ let exchangedQuoteAssetAmount = $t07779778292._9
1847+ let totalLongAfter = $t07779778292._10
1848+ let totalShortAfter = $t07779778292._11
1849+ let totalLongOpenInterestAfter = $t07779778292._12
1850+ let totalShortOpenInterestAfter = $t07779778292._13
18601851 let liquidationPenalty = muld(exchangedQuoteAssetAmount, liquidationFeeRatio())
18611852 let feeToLiquidator = (liquidationPenalty / 2)
18621853 let feeToVault = (liquidationPenalty - feeToLiquidator)
18631854 let ammBalance = (cbalance() - liquidationPenalty)
1864- let $t07917479303 = if ((0 > ammBalance))
1855+ let $t07870078829 = if ((0 > ammBalance))
18651856 then $Tuple2(0, abs(ammBalance))
18661857 else $Tuple2(ammBalance, 0)
1867- let newAmmBalance = $t07917479303._1
1868- let x11 = $t07917479303._2
1869- let $t07931179365 = getBorrowedByTrader(_trader)
1870- let borrowed = $t07931179365._1
1871- let assetId = $t07931179365._2
1858+ let newAmmBalance = $t07870078829._1
1859+ let x11 = $t07870078829._2
1860+ let $t07883778891 = getBorrowedByTrader(_trader)
1861+ let borrowed = $t07883778891._1
1862+ let assetId = $t07883778891._2
18721863 let doLiquidateCollateral = if ((borrowed > 0))
18731864 then {
18741865 let realizeAndClose = invoke(collateralAddress(), "realizePartiallyAndClose", [_trader, 0, assetId], nil)
19161907
19171908 @Callable(i)
19181909 func payFunding () = {
1919- let fundingBlockTimestamp = nextFundingBlockTimestamp()
1920- if (if (if ((fundingBlockTimestamp > lastBlock.timestamp))
1921- then true
1922- else !(initialized()))
1923- then true
1924- else paused())
1925- then throw(((("Invalid funding block timestamp: " + toString(lastBlock.timestamp)) + " < ") + toString(fundingBlockTimestamp)))
1926- else {
1927- let underlyingPrice = getOracleTwapPrice()
1928- let $t08117281234 = getFunding()
1929- let shortPremiumFraction = $t08117281234._1
1930- let longPremiumFraction = $t08117281234._2
1931- updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice))
1932- }
1910+ let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
1911+ if ((sync == sync))
1912+ then {
1913+ let fundingBlockTimestamp = nextFundingBlockTimestamp()
1914+ if (if (if ((fundingBlockTimestamp > lastBlock.timestamp))
1915+ then true
1916+ else !(initialized()))
1917+ then true
1918+ else paused())
1919+ then throw(((("Invalid funding block timestamp: " + toString(lastBlock.timestamp)) + " < ") + toString(fundingBlockTimestamp)))
1920+ else {
1921+ let underlyingPrice = getOraclePrice()
1922+ let $t08076380825 = getFunding()
1923+ let shortPremiumFraction = $t08076380825._1
1924+ let longPremiumFraction = $t08076380825._2
1925+ updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice))
1926+ }
1927+ }
1928+ else throw("Strict value is not equal to itself.")
19331929 }
19341930
19351931
19361932
19371933 @Callable(i)
19381934 func syncTerminalPriceToOracle () = {
1939- let $t08161681737 = getSyncTerminalPrice(getOracleTwapPrice())
1940- let newQuoteAssetWeight = $t08161681737._1
1941- let newBaseAssetWeight = $t08161681737._2
1942- let marginToVault = $t08161681737._3
1935+ let _qtAstR = qtAstR()
1936+ let _bsAstR = bsAstR()
1937+ let $t08125781392 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1938+ let newQuoteAssetWeight = $t08125781392._1
1939+ let newBaseAssetWeight = $t08125781392._2
1940+ let marginToVault = $t08125781392._3
19431941 let doExchangePnL = if ((marginToVault != 0))
19441942 then {
19451943 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
19491947 }
19501948 else nil
19511949 if ((doExchangePnL == doExchangePnL))
1952- then updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight)
1950+ then (updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight) ++ appendTwap(divd(muld(_qtAstR, newQuoteAssetWeight), muld(_bsAstR, newBaseAssetWeight))))
19531951 else throw("Strict value is not equal to itself.")
19541952 }
19551953
19601958 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
19611959 if ((sync == sync))
19621960 then {
1963- let $t08221382314 = getPosition(_trader)
1964- let positionSize = $t08221382314._1
1965- let positionMargin = $t08221382314._2
1966- let pon = $t08221382314._3
1967- let positionLstUpdCPF = $t08221382314._4
1968- let $t08231782418 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1969- let positionNotional = $t08231782418._1
1970- let unrealizedPnl = $t08231782418._2
1971- let $t08242182593 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
1972- let remainMargin = $t08242182593._1
1973- let badDebt = $t08242182593._2
1974- let fundingPayment = $t08242182593._3
1961+ let $t08196182062 = getPosition(_trader)
1962+ let positionSize = $t08196182062._1
1963+ let positionMargin = $t08196182062._2
1964+ let pon = $t08196182062._3
1965+ let positionLstUpdCPF = $t08196182062._4
1966+ let $t08206582166 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1967+ let positionNotional = $t08206582166._1
1968+ let unrealizedPnl = $t08206582166._2
1969+ let $t08216982341 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
1970+ let remainMargin = $t08216982341._1
1971+ let badDebt = $t08216982341._2
1972+ let fundingPayment = $t08216982341._3
19751973 throw((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)))
19761974 }
19771975 else throw("Strict value is not equal to itself.")
19811979
19821980 @Callable(i)
19831981 func view_getPegAdjustCost (_price) = {
1984- let result = getSyncTerminalPrice(_price)
1982+ let _qtAstR = qtAstR()
1983+ let _bsAstR = bsAstR()
1984+ let result = getSyncTerminalPrice(_price, _qtAstR, _bsAstR)
19851985 throw(toString(result._3))
19861986 }
19871987
19891989
19901990 @Callable(i)
19911991 func view_getTerminalAmmPrice () = {
1992- let $t08294083021 = getTerminalAmmState()
1993- let terminalQuoteAssetReserve = $t08294083021._1
1994- let terminalBaseAssetReserve = $t08294083021._2
1992+ let $t08275782838 = getTerminalAmmState()
1993+ let terminalQuoteAssetReserve = $t08275782838._1
1994+ let terminalBaseAssetReserve = $t08275782838._2
19951995 let price = divd(muld(terminalQuoteAssetReserve, qtAstW()), muld(terminalBaseAssetReserve, bsAstW()))
19961996 throw(toString(price))
19971997 }
20002000
20012001 @Callable(i)
20022002 func view_getFunding () = {
2003- let underlyingPrice = getOracleTwapPrice()
2004- let $t08324083302 = getFunding()
2005- let shortPremiumFraction = $t08324083302._1
2006- let longPremiumFraction = $t08324083302._2
2003+ let underlyingPrice = getOraclePrice()
2004+ let $t08305383115 = getFunding()
2005+ let shortPremiumFraction = $t08305383115._1
2006+ let longPremiumFraction = $t08305383115._2
20072007 let longFunding = divd(longPremiumFraction, underlyingPrice)
20082008 let shortFunding = divd(shortPremiumFraction, underlyingPrice)
2009- throw((((s(longFunding) + s(shortFunding)) + s(getTwapSpotPrice())) + s(getOracleTwapPrice())))
2009+ throw((((s(longFunding) + s(shortFunding)) + s(getTwapSpotPrice())) + s(getOraclePrice())))
20102010 }
20112011
20122012
20132013
20142014 @Callable(i)
20152015 func view_getBorrowedByTrader (_trader) = {
2016- let $t08359283646 = getBorrowedByTrader(_trader)
2017- let borrowed = $t08359283646._1
2018- let assetId = $t08359283646._2
2016+ let $t08340183455 = getBorrowedByTrader(_trader)
2017+ let borrowed = $t08340183455._1
2018+ let assetId = $t08340183455._2
20192019 throw((s(borrowed) + assetId))
20202020 }
20212021
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let k_ora_key = "k_ora_key"
55
66 let k_ora_block_key = "k_ora_block_key"
77
8+let k_ora_open_key = "k_ora_open_key"
9+
810 let k_ora = "k_ora"
911
1012 let k_balance = "k_balance"
1113
1214 let k_sequence = "k_sequence"
1315
1416 let k_positionSize = "k_positionSize"
1517
1618 let k_positionMargin = "k_positionMargin"
1719
1820 let k_positionOpenNotional = "k_positionOpenNotional"
1921
2022 let k_positionLastUpdatedCumulativePremiumFraction = "k_positionFraction"
2123
2224 let k_positionSequence = "k_positionSequence"
2325
2426 let k_positionAsset = "k_positionAsset"
27+
28+let k_positionFee = "k_positionFee"
2529
2630 let k_initialized = "k_initialized"
2731
2832 let k_paused = "k_paused"
2933
3034 let k_closeOnly = "k_closeOnly"
3135
3236 let k_fee = "k_fee"
3337
3438 let k_fundingPeriod = "k_fundingPeriod"
3539
3640 let k_initMarginRatio = "k_initMarginRatio"
3741
3842 let k_maintenanceMarginRatio = "k_mmr"
3943
4044 let k_liquidationFeeRatio = "k_liquidationFeeRatio"
4145
4246 let k_partialLiquidationRatio = "k_partLiquidationRatio"
4347
4448 let k_spreadLimit = "k_spreadLimit"
4549
4650 let k_maxPriceImpact = "k_maxPriceImpact"
4751
4852 let k_maxPriceSpread = "k_maxPriceSpread"
4953
5054 let k_maxOpenNotional = "k_maxOpenNotional"
5155
5256 let k_feeToStakersPercent = "k_feeToStakersPercent"
5357
5458 let k_maxOracleDelay = "k_maxOracleDelay"
5559
5660 let k_lastDataStr = "k_lastDataStr"
5761
5862 let k_lastMinuteId = "k_lastMinuteId"
5963
6064 let k_twapDataLastCumulativePrice = "k_twapDataLastCumulativePrice"
6165
6266 let k_twapDataLastPrice = "k_twapDataLastPrice"
6367
6468 let k_twapDataPreviousMinuteId = "k_twapDataPreviousMinuteId"
6569
6670 let k_latestLongCumulativePremiumFraction = "k_latestLongPremiumFraction"
6771
6872 let k_latestShortCumulativePremiumFraction = "k_latestShortPremiumFraction"
6973
7074 let k_nextFundingBlock = "k_nextFundingBlockMinTimestamp"
7175
7276 let k_longFundingRate = "k_longFundingRate"
7377
7478 let k_shortFundingRate = "k_shortFundingRate"
7579
7680 let k_quoteAssetReserve = "k_qtAstR"
7781
7882 let k_baseAssetReserve = "k_bsAstR"
7983
8084 let k_quoteAssetWeight = "k_qtAstW"
8185
8286 let k_baseAssetWeight = "k_bsAstW"
8387
8488 let k_totalPositionSize = "k_totalPositionSize"
8589
8690 let k_totalLongPositionSize = "k_totalLongPositionSize"
8791
8892 let k_totalShortPositionSize = "k_totalShortPositionSize"
8993
9094 let k_openInterestNotional = "k_openInterestNotional"
9195
9296 let k_openInterestShort = "k_openInterestShort"
9397
9498 let k_openInterestLong = "k_openInterestLong"
9599
96100 let k_coordinatorAddress = "k_coordinatorAddress"
97101
98102 let k_vault_address = "k_vault_address"
99103
100104 let k_admin_address = "k_admin_address"
101105
102106 let k_admin_public_key = "k_admin_public_key"
103107
104108 let k_quote_asset = "k_quote_asset"
105109
106110 let k_quote_staking = "k_quote_staking"
107111
108112 let k_staking_address = "k_staking_address"
109113
110114 let k_miner_address = "k_miner_address"
111115
112116 let k_orders_address = "k_orders_address"
113117
114118 let k_referral_address = "k_referral_address"
115119
116120 let k_collateral_address = "k_collateral_address"
117121
118122 let k_exchange_address = "k_exchange_address"
119123
120124 let k_nft_manager_address = "k_nft_manager_address"
121125
122126 let k_trader_market_asset_collateral = "k_trader_market_asset_collateral"
123127
124128 func toCompositeKey (_key,_address) = ((_key + "_") + _address)
125129
126130
127131 func coordinator () = valueOrErrorMessage(addressFromString(getStringValue(this, k_coordinatorAddress)), "Coordinator not set")
128132
129133
130134 func adminAddress () = addressFromString(getStringValue(coordinator(), k_admin_address))
131135
132136
133137 func adminPublicKey () = fromBase58String(getStringValue(coordinator(), k_admin_public_key))
134138
135139
136140 func quoteAsset () = fromBase58String(getStringValue(coordinator(), k_quote_asset))
137141
138142
139143 func quoteAssetStaking () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_quote_staking)), "Quote asset staking not set")
140144
141145
142146 func stakingAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_staking_address)), "Staking not set")
143147
144148
145149 func vaultAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_vault_address)), "Vault not set")
146150
147151
148152 func minerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_miner_address)), "Miner not set")
149153
150154
151155 func ordersAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_orders_address)), "Orders not set")
152156
153157
154158 func referralAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_referral_address)), "Referral not set")
155159
156160
157161 func nftManagerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_nft_manager_address)), "NFT Manager not set")
158162
159163
160164 func collateralAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_collateral_address)), "Collateral Manager not set")
161165
162166
163167 func swapAddress () = valueOrErrorMessage(addressFromString(valueOrErrorMessage(getString(coordinator(), k_exchange_address), "No swap address")), "Invalid swap address")
164168
165169
166170 let k_whitelist_asset = "k_whitelist_asset"
167171
168172 func isWhitelistAsset (_assetId) = valueOrElse(getBoolean(collateralAddress(), toCompositeKey(k_whitelist_asset, _assetId)), false)
169173
170174
171175 let k_token_param = "k_token_param"
172176
173177 let k_token_type = "k_token_type"
174178
175179 let FEE_REDUCTION_TOKEN_TYPE = "fee_reduction"
176180
177181 let DIR_LONG = 1
178182
179183 let DIR_SHORT = 2
180184
181185 let TWAP_INTERVAL = 15
182186
183187 let ORACLE_INTERVAL = 15
184188
185189 let SECONDS = 1000
186190
187191 let DECIMAL_NUMBERS = 6
188192
189193 let DECIMAL_UNIT = (1 * (((((10 * 10) * 10) * 10) * 10) * 10))
190194
191195 let ONE_DAY = (86400 * DECIMAL_UNIT)
192196
193197 let ALL_FEES = 100
194198
195199 let PNL_OPTION_SPOT = 1
196200
197201 let PNL_OPTION_ORACLE = 2
198202
199203 func s (_x) = (toString(_x) + ",")
200204
201205
202206 func divd (_x,_y) = fraction(_x, DECIMAL_UNIT, _y, HALFEVEN)
203207
204208
205209 func muld (_x,_y) = fraction(_x, _y, DECIMAL_UNIT, HALFEVEN)
206210
207211
208212 func sqrtd (_x) = sqrt(_x, DECIMAL_NUMBERS, DECIMAL_NUMBERS, HALFEVEN)
209213
210214
211215 func powd (_x,_y) = pow(_x, DECIMAL_NUMBERS, _y, DECIMAL_NUMBERS, DECIMAL_NUMBERS, HALFEVEN)
212216
213217
214218 func bdivd (_x,_y) = fraction(_x, toBigInt(DECIMAL_UNIT), _y, HALFEVEN)
215219
216220
217221 func bmuld (_x,_y) = fraction(_x, _y, toBigInt(DECIMAL_UNIT), HALFEVEN)
218222
219223
220224 func bsqrtd (_x) = sqrtBigInt(_x, DECIMAL_NUMBERS, DECIMAL_NUMBERS, HALFEVEN)
221225
222226
223227 func bpowd (_x,_y) = pow(_x, DECIMAL_NUMBERS, _y, DECIMAL_NUMBERS, DECIMAL_NUMBERS, HALFEVEN)
224228
225229
226230 func abs (_x) = if ((_x > 0))
227231 then _x
228232 else -(_x)
229233
230234
231235 func vmax (_x,_y) = if ((_x >= _y))
232236 then _x
233237 else _y
234238
235239
236240 func listToStr (_list) = {
237241 func _join (accumulator,val) = ((accumulator + val) + ",")
238242
239243 let newListStr = {
240244 let $l = _list
241245 let $s = size($l)
242246 let $acc0 = ""
243247 func $f0_1 ($a,$i) = if (($i >= $s))
244248 then $a
245249 else _join($a, $l[$i])
246250
247251 func $f0_2 ($a,$i) = if (($i >= $s))
248252 then $a
249253 else throw("List size exceeds 20")
250254
251255 $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20)
252256 }
253257 let newListStrU = dropRight(newListStr, 1)
254258 let newListStrR = if ((take(newListStrU, 1) == ","))
255259 then drop(newListStrU, 1)
256260 else newListStrU
257261 newListStrR
258262 }
259263
260264
261265 func strToList (_str) = split(_str, ",")
262266
263267
264268 func pushToQueue (_list,_maxSize,_value) = if ((size(_list) > _maxSize))
265269 then (removeByIndex(_list, 0) :+ _value)
266270 else (_list :+ _value)
267271
268272
269273 func int (k) = valueOrErrorMessage(getInteger(this, k), ("no value for " + k))
270274
271275
272276 func intOr (k,def) = valueOrElse(getInteger(this, k), def)
273277
274278
275279 func strA (_address,_key) = {
276280 let val = valueOrErrorMessage(getString(_address, _key), ("No value for key " + _key))
277281 val
278282 }
279283
280284
281285 func intA (_address,_key) = {
282286 let val = valueOrErrorMessage(getInteger(_address, _key), ("No value for key " + _key))
283287 val
284288 }
285289
286290
287291 func cbalance () = int(k_balance)
288292
289293
290294 func fee () = int(k_fee)
291295
292296
293297 func initMarginRatio () = int(k_initMarginRatio)
294298
295299
296300 func qtAstR () = int(k_quoteAssetReserve)
297301
298302
299303 func bsAstR () = int(k_baseAssetReserve)
300304
301305
302306 func qtAstW () = intOr(k_quoteAssetWeight, DECIMAL_UNIT)
303307
304308
305309 func bsAstW () = intOr(k_baseAssetWeight, DECIMAL_UNIT)
306310
307311
308312 func totalPositionSize () = int(k_totalPositionSize)
309313
310314
311315 func openInterestNotional () = int(k_openInterestNotional)
312316
313317
314318 func openInterestShort () = int(k_openInterestShort)
315319
316320
317321 func openInterestLong () = int(k_openInterestLong)
318322
319323
320324 func nextFundingBlockTimestamp () = int(k_nextFundingBlock)
321325
322326
323327 func fundingPeriodRaw () = int(k_fundingPeriod)
324328
325329
326330 func fundingPeriodDecimal () = (fundingPeriodRaw() * DECIMAL_UNIT)
327331
328332
329333 func fundingPeriodSeconds () = (fundingPeriodRaw() * SECONDS)
330334
331335
332336 func maintenanceMarginRatio () = int(k_maintenanceMarginRatio)
333337
334338
335339 func liquidationFeeRatio () = int(k_liquidationFeeRatio)
336340
337341
338342 func partialLiquidationRatio () = int(k_partialLiquidationRatio)
339343
340344
341345 func spreadLimit () = int(k_spreadLimit)
342346
343347
344348 func maxPriceImpact () = int(k_maxPriceImpact)
345349
346350
347351 func maxPriceSpread () = int(k_maxPriceSpread)
348352
349353
350354 func maxOpenNotional () = int(k_maxOpenNotional)
351355
352356
353357 func latestLongCumulativePremiumFraction () = int(k_latestLongCumulativePremiumFraction)
354358
355359
356360 func latestShortCumulativePremiumFraction () = int(k_latestShortCumulativePremiumFraction)
357361
358362
359363 func totalShortPositionSize () = int(k_totalShortPositionSize)
360364
361365
362366 func totalLongPositionSize () = int(k_totalLongPositionSize)
363367
364368
365369 func lastSequence () = intOr(k_sequence, 0)
366370
367371
368372 func feeToStakersPercent () = int(k_feeToStakersPercent)
369373
370374
371375 func maxOracleDelay () = int(k_maxOracleDelay)
372376
373377
374378 func getActualCaller (i) = valueOrElse(getString(ordersAddress(), "k_sender"), toString(i.caller))
375379
376380
377381 func requireMoreMarginRatio (_marginRatio,_baseMarginRatio,_largerThanOrEqualTo) = {
378382 let remainingMarginRatio = (_marginRatio - _baseMarginRatio)
379383 if (if (_largerThanOrEqualTo)
380384 then (0 > remainingMarginRatio)
381385 else false)
382- then throw("Invalid margin")
386+ then throw(((("Invalid margin: " + toString(_marginRatio)) + " < ") + toString(_baseMarginRatio)))
383387 else if (if (!(_largerThanOrEqualTo))
384388 then (remainingMarginRatio >= 0)
385389 else false)
386- then throw("Invalid margin")
390+ then throw(((("Invalid margin: " + toString(_marginRatio)) + " > ") + toString(_baseMarginRatio)))
387391 else true
388392 }
389393
390394
391395 func latestCumulativePremiumFraction (_positionSize) = if ((_positionSize == 0))
392396 then throw("Should not be called with _positionSize == 0")
393397 else if ((_positionSize > 0))
394398 then latestLongCumulativePremiumFraction()
395399 else latestShortCumulativePremiumFraction()
396400
397401
398402 func getPosition (_trader) = {
399403 let positionSizeOpt = getInteger(this, toCompositeKey(k_positionSize, _trader))
400404 match positionSizeOpt {
401405 case positionSize: Int =>
402406 $Tuple4(positionSize, getIntegerValue(this, toCompositeKey(k_positionMargin, _trader)), getIntegerValue(this, toCompositeKey(k_positionOpenNotional, _trader)), getIntegerValue(this, toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _trader)))
403407 case _ =>
404408 $Tuple4(0, 0, 0, 0)
405409 }
406410 }
407411
408412
409413 func getPositionAsset (_trader) = {
410414 let positionAssetOpt = getString(this, toCompositeKey(k_positionAsset, _trader))
411415 match positionAssetOpt {
412416 case positionAsset: String =>
413417 positionAsset
414418 case _ =>
415419 toBase58String(quoteAsset())
420+ }
421+ }
422+
423+
424+func getPositionFee (_trader) = {
425+ let positionFeeOpt = getInteger(this, toCompositeKey(k_positionFee, _trader))
426+ match positionFeeOpt {
427+ case positionFee: Int =>
428+ positionFee
429+ case _ =>
430+ fee()
416431 }
417432 }
418433
419434
420435 func requireOpenPosition (_trader) = if ((getPosition(_trader)._1 == 0))
421436 then throw("No open position")
422437 else true
423438
424439
425440 func initialized () = valueOrElse(getBoolean(this, k_initialized), false)
426441
427442
428443 func paused () = valueOrElse(getBoolean(this, k_paused), false)
429444
430445
431446 func closeOnly () = valueOrElse(getBoolean(this, k_closeOnly), false)
432447
433448
434449 func updateReserve (_isAdd,_quoteAssetAmount,_baseAssetAmount) = if (_isAdd)
435450 then {
436451 let newBase = (bsAstR() - _baseAssetAmount)
437452 if ((0 >= newBase))
438453 then throw("Tx lead to base asset reserve <= 0, revert")
439454 else $Tuple3((qtAstR() + _quoteAssetAmount), newBase, (totalPositionSize() + _baseAssetAmount))
440455 }
441456 else {
442457 let newQuote = (qtAstR() - _quoteAssetAmount)
443458 if ((0 >= newQuote))
444459 then throw("Tx lead to base quote reserve <= 0, revert")
445460 else $Tuple3(newQuote, (bsAstR() + _baseAssetAmount), (totalPositionSize() - _baseAssetAmount))
446461 }
447462
448463
449-func calcInvariant (_qtAstR,_qtAstW,_bsAstR,_bsAstW) = {
464+func calcInvariant (_qtAstR,_bsAstR) = {
450465 let bqtAstR = toBigInt(_qtAstR)
451- let bqtAstW = toBigInt(_qtAstW)
452466 let bbsAstR = toBigInt(_bsAstR)
453- let bbsAstW = toBigInt(_bsAstW)
454- bmuld(bmuld(bqtAstR, bqtAstW), bmuld(bbsAstR, bbsAstW))
467+ bmuld(bqtAstR, bbsAstR)
455468 }
456469
457470
458471 func swapInput (_isAdd,_quoteAssetAmount) = {
459472 let _qtAstR = qtAstR()
460473 let _bsAstR = bsAstR()
461474 let _qtAstW = qtAstW()
462475 let _bsAstW = bsAstW()
463- let k = calcInvariant(_qtAstR, _qtAstW, _bsAstR, _bsAstW)
476+ let quoteAssetAmountAdjusted = divd(_quoteAssetAmount, _qtAstW)
477+ let k = calcInvariant(_qtAstR, _bsAstR)
464478 let quoteAssetReserveAfter = if (_isAdd)
465- then (_qtAstR + _quoteAssetAmount)
466- else (_qtAstR - _quoteAssetAmount)
467- let baseAssetReserveAfter = toInt(bdivd(k, toBigInt(muld(quoteAssetReserveAfter, _qtAstW))))
468- let amountBaseAssetBoughtAbs = divd(abs((baseAssetReserveAfter - _bsAstR)), _qtAstW)
479+ then (_qtAstR + quoteAssetAmountAdjusted)
480+ else (_qtAstR - quoteAssetAmountAdjusted)
481+ let baseAssetReserveAfter = toInt(bdivd(k, toBigInt(quoteAssetReserveAfter)))
482+ let amountBaseAssetBoughtAbs = abs((baseAssetReserveAfter - _bsAstR))
469483 let amountBaseAssetBought = if (_isAdd)
470484 then amountBaseAssetBoughtAbs
471485 else -(amountBaseAssetBoughtAbs)
472- let $t01694617109 = updateReserve(_isAdd, _quoteAssetAmount, amountBaseAssetBoughtAbs)
473- let quoteAssetReserveAfter1 = $t01694617109._1
474- let baseAssetReserveAfter1 = $t01694617109._2
475- let totalPositionSizeAfter1 = $t01694617109._3
486+ let $t01713817308 = updateReserve(_isAdd, quoteAssetAmountAdjusted, amountBaseAssetBoughtAbs)
487+ let quoteAssetReserveAfter1 = $t01713817308._1
488+ let baseAssetReserveAfter1 = $t01713817308._2
489+ let totalPositionSizeAfter1 = $t01713817308._3
476490 let priceBefore = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
477491 let marketPrice = divd(_quoteAssetAmount, amountBaseAssetBoughtAbs)
478492 let priceDiff = abs((priceBefore - marketPrice))
479493 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
480494 let maxPriceImpactValue = maxPriceImpact()
481495 if ((priceImpact > maxPriceImpactValue))
482496 then throw(((((((((((((("Price impact " + toString(priceImpact)) + " > max price impact ") + toString(maxPriceImpactValue)) + " before quote asset: ") + toString(_qtAstR)) + " before base asset: ") + toString(_bsAstR)) + " quote asset amount to exchange: ") + toString(_quoteAssetAmount)) + " price before: ") + toString(priceBefore)) + " marketPrice: ") + toString(marketPrice)))
483497 else $Tuple4(amountBaseAssetBought, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1)
484498 }
485499
486500
487501 func calcRemainMarginWithFundingPayment (_oldPositionSize,_oldPositionMargin,_oldPositionCumulativePremiumFraction,_marginDelta) = {
488502 let fundingPayment = if ((_oldPositionSize != 0))
489503 then {
490504 let _latestCumulativePremiumFraction = latestCumulativePremiumFraction(_oldPositionSize)
491505 muld((_latestCumulativePremiumFraction - _oldPositionCumulativePremiumFraction), _oldPositionSize)
492506 }
493507 else 0
494508 let signedMargin = ((_marginDelta - fundingPayment) + _oldPositionMargin)
495- let $t01859618723 = if ((0 > signedMargin))
509+ let $t01879518922 = if ((0 > signedMargin))
496510 then $Tuple2(0, abs(signedMargin))
497511 else $Tuple2(abs(signedMargin), 0)
498- let remainMargin = $t01859618723._1
499- let badDebt = $t01859618723._2
512+ let remainMargin = $t01879518922._1
513+ let badDebt = $t01879518922._2
500514 $Tuple3(remainMargin, badDebt, fundingPayment)
501515 }
502516
503517
504518 func swapOutputWithReserves (_isAdd,_baseAssetAmount,_checkMaxPriceImpact,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight) = {
505519 let priceBefore = divd(muld(_quoteAssetReserve, _quoteAssetWeight), muld(_baseAssetReserve, _baseAssetWeight))
506520 if ((_baseAssetAmount == 0))
507521 then throw("Invalid base asset amount")
508522 else {
509- let k = calcInvariant(_quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)
523+ let k = calcInvariant(_quoteAssetReserve, _baseAssetReserve)
510524 let baseAssetPoolAmountAfter = if (_isAdd)
511525 then (_baseAssetReserve + _baseAssetAmount)
512526 else (_baseAssetReserve - _baseAssetAmount)
513- let quoteAssetAfter = toInt(bdivd(k, toBigInt(muld(baseAssetPoolAmountAfter, _baseAssetWeight))))
514- let quoteAssetSold = abs((quoteAssetAfter - muld(_quoteAssetReserve, _quoteAssetWeight)))
527+ let quoteAssetAfter = toInt(bdivd(k, toBigInt(baseAssetPoolAmountAfter)))
528+ let quoteAssetDelta = abs((quoteAssetAfter - _quoteAssetReserve))
529+ let quoteAssetSold = muld(quoteAssetDelta, _quoteAssetWeight)
515530 let maxPriceImpactValue = maxPriceImpact()
516- let $t01991120072 = updateReserve(!(_isAdd), quoteAssetSold, _baseAssetAmount)
517- let quoteAssetReserveAfter1 = $t01991120072._1
518- let baseAssetReserveAfter1 = $t01991120072._2
519- let totalPositionSizeAfter1 = $t01991120072._3
531+ let $t02009220254 = updateReserve(!(_isAdd), quoteAssetDelta, _baseAssetAmount)
532+ let quoteAssetReserveAfter1 = $t02009220254._1
533+ let baseAssetReserveAfter1 = $t02009220254._2
534+ let totalPositionSizeAfter1 = $t02009220254._3
520535 let marketPrice = divd(quoteAssetSold, _baseAssetAmount)
521536 let priceDiff = abs((priceBefore - marketPrice))
522537 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
523538 if (if ((priceImpact > maxPriceImpactValue))
524539 then _checkMaxPriceImpact
525540 else false)
526541 then throw(((((((((((((("Price impact " + toString(priceImpact)) + " > max price impact ") + toString(maxPriceImpactValue)) + " before quote asset: ") + toString(_quoteAssetReserve)) + " before base asset: ") + toString(_baseAssetReserve)) + " base asset amount to exchange: ") + toString(_baseAssetAmount)) + " price before: ") + toString(priceBefore)) + " market price: ") + toString(marketPrice)))
527542 else $Tuple7(quoteAssetSold, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1, (totalLongPositionSize() - (if (_isAdd)
528543 then abs(_baseAssetAmount)
529544 else 0)), (totalShortPositionSize() - (if (!(_isAdd))
530545 then abs(_baseAssetAmount)
531546 else 0)), priceImpact)
532547 }
533548 }
534549
535550
536551 func swapOutput (_isAdd,_baseAssetAmount,_checkMaxPriceImpact) = swapOutputWithReserves(_isAdd, _baseAssetAmount, _checkMaxPriceImpact, qtAstR(), qtAstW(), bsAstR(), bsAstW())
537552
538553
539-func getOracleTwapPrice () = {
554+func getOraclePrice () = {
540555 let oracle = valueOrErrorMessage(addressFromString(getStringValue(this, k_ora)), "")
541556 let priceKey = getStringValue(this, k_ora_key)
542557 let lastValue = valueOrErrorMessage(getInteger(oracle, priceKey), ((("Can not get oracle price. Oracle: " + toString(oracle)) + " key: ") + priceKey))
543558 let blockKey = valueOrElse(getString(this, k_ora_block_key), "")
544559 if ((blockKey != ""))
545560 then {
546561 let currentBlock = lastBlock.height
547- let lastOracleBlock = valueOrErrorMessage(getInteger(oracle, k_ora_block_key), ((("Can not get oracle block. Oracle: " + toString(oracle)) + " key: ") + blockKey))
562+ let lastOracleBlock = valueOrErrorMessage(getInteger(oracle, blockKey), ((("Can not get oracle block. Oracle: " + toString(oracle)) + " key: ") + blockKey))
548563 if (((currentBlock - lastOracleBlock) > maxOracleDelay()))
549564 then throw(((("Oracle stale data. Last oracle block: " + toString(lastOracleBlock)) + " current block: ") + toString(currentBlock)))
550565 else lastValue
551566 }
552567 else lastValue
553568 }
554569
555570
571+func isMarketClosed () = {
572+ let oracle = valueOrErrorMessage(addressFromString(getStringValue(this, k_ora)), "")
573+ let openKey = valueOrElse(getString(this, k_ora_open_key), "")
574+ if ((openKey != ""))
575+ then {
576+ let isOpen = valueOrErrorMessage(getBoolean(oracle, openKey), ((("Can not get oracle is open/closed. Oracle: " + toString(oracle)) + " key: ") + openKey))
577+ !(isOpen)
578+ }
579+ else false
580+ }
581+
582+
583+func absPriceDiff (_oraclePrice,_quoteAssetReserve,_baseAssetReserve,_qtAstW,_bsAstW) = {
584+ let priceAfter = divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW))
585+ let averagePrice = divd((_oraclePrice + priceAfter), (2 * DECIMAL_UNIT))
586+ let absPriceDiff = divd(abs((_oraclePrice - priceAfter)), averagePrice)
587+ absPriceDiff
588+ }
589+
590+
556591 func requireNotOverSpreadLimit (_quoteAssetReserve,_baseAssetReserve) = {
557- let oraclePrice = getOracleTwapPrice()
592+ let oraclePrice = getOraclePrice()
558593 let _qtAstW = qtAstW()
559594 let _bsAstW = bsAstW()
560- let priceAfter = divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW))
561- let averagePrice = divd((oraclePrice + priceAfter), (2 * DECIMAL_UNIT))
562- let absPriceDiff = divd(abs((oraclePrice - priceAfter)), averagePrice)
563- if ((absPriceDiff > maxPriceSpread()))
564- then throw(((("Price spread " + toString(absPriceDiff)) + " > max price spread ") + toString(maxPriceSpread())))
595+ let absPriceDiffBefore = absPriceDiff(oraclePrice, qtAstR(), bsAstR(), _qtAstW, _bsAstW)
596+ let absPriceDiffAfter = absPriceDiff(oraclePrice, _quoteAssetReserve, _baseAssetReserve, _qtAstW, _bsAstW)
597+ if (if ((absPriceDiffAfter > maxPriceSpread()))
598+ then (absPriceDiffAfter > absPriceDiffBefore)
599+ else false)
600+ then throw(((("Price spread " + toString(absPriceDiffAfter)) + " > max price spread ") + toString(maxPriceSpread())))
565601 else true
566602 }
567603
568604
569605 func requireNotOverMaxOpenNotional (_longOpenNotional,_shortOpenNotional) = {
570606 let _maxOpenNotional = maxOpenNotional()
571607 if ((_longOpenNotional > _maxOpenNotional))
572608 then throw(((("Long open notional " + toString(_longOpenNotional)) + " > max open notional ") + toString(_maxOpenNotional)))
573609 else if ((_shortOpenNotional > _maxOpenNotional))
574610 then throw(((("Short open notional " + toString(_shortOpenNotional)) + " > max open notional ") + toString(_maxOpenNotional)))
575611 else true
576612 }
577613
578614
579615 func getSpotPrice () = {
580616 let _quoteAssetReserve = qtAstR()
581617 let _baseAssetReserve = bsAstR()
582618 let _qtAstW = qtAstW()
583619 let _bsAstW = bsAstW()
584620 divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW))
585621 }
586622
587623
588624 func isOverFluctuationLimit () = {
589- let oraclePrice = getOracleTwapPrice()
625+ let oraclePrice = getOraclePrice()
590626 let currentPrice = getSpotPrice()
591627 (divd(abs((oraclePrice - currentPrice)), oraclePrice) > spreadLimit())
592628 }
593629
594630
595631 func getPositionAdjustedOpenNotional (_positionSize,_option,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight) = {
596632 let positionSizeAbs = abs(_positionSize)
597633 let isShort = (0 > _positionSize)
598634 let positionNotional = if ((_option == PNL_OPTION_SPOT))
599635 then {
600- let $t02423824458 = swapOutputWithReserves(!(isShort), positionSizeAbs, false, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)
601- let outPositionNotional = $t02423824458._1
602- let x1 = $t02423824458._2
603- let x2 = $t02423824458._3
604- let x3 = $t02423824458._4
636+ let $t02520525425 = swapOutputWithReserves(!(isShort), positionSizeAbs, false, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)
637+ let outPositionNotional = $t02520525425._1
638+ let x1 = $t02520525425._2
639+ let x2 = $t02520525425._3
640+ let x3 = $t02520525425._4
605641 outPositionNotional
606642 }
607- else muld(positionSizeAbs, getOracleTwapPrice())
643+ else muld(positionSizeAbs, getOraclePrice())
608644 positionNotional
609645 }
610646
611647
612648 func getPositionNotionalAndUnrealizedPnlByValues (_positionSize,_positionOpenNotional,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight,_option) = if ((_positionSize == 0))
613649 then throw("Invalid position size")
614650 else {
615651 let isShort = (0 > _positionSize)
616652 let positionNotional = getPositionAdjustedOpenNotional(_positionSize, _option, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)
617653 let unrealizedPnl = if (isShort)
618654 then (_positionOpenNotional - positionNotional)
619655 else (positionNotional - _positionOpenNotional)
620656 $Tuple2(positionNotional, unrealizedPnl)
621657 }
622658
623659
624660 func getPositionNotionalAndUnrealizedPnl (_trader,_option) = {
625- let $t02588326011 = getPosition(_trader)
626- let positionSize = $t02588326011._1
627- let positionMargin = $t02588326011._2
628- let positionOpenNotional = $t02588326011._3
629- let positionLstUpdCPF = $t02588326011._4
661+ let $t02684626974 = getPosition(_trader)
662+ let positionSize = $t02684626974._1
663+ let positionMargin = $t02684626974._2
664+ let positionOpenNotional = $t02684626974._3
665+ let positionLstUpdCPF = $t02684626974._4
630666 getPositionNotionalAndUnrealizedPnlByValues(positionSize, positionOpenNotional, qtAstR(), qtAstW(), bsAstR(), bsAstW(), _option)
631667 }
632668
633669
634670 func calcMarginRatio (_remainMargin,_badDebt,_positionNotional) = divd((_remainMargin - _badDebt), _positionNotional)
635671
636672
637673 func getMarginRatioByOption (_trader,_option) = {
638- let $t02652426635 = getPosition(_trader)
639- let positionSize = $t02652426635._1
640- let positionMargin = $t02652426635._2
641- let pon = $t02652426635._3
642- let positionLstUpdCPF = $t02652426635._4
643- let $t02664126734 = getPositionNotionalAndUnrealizedPnl(_trader, _option)
644- let positionNotional = $t02664126734._1
645- let unrealizedPnl = $t02664126734._2
646- let $t02673926905 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
647- let remainMargin = $t02673926905._1
648- let badDebt = $t02673926905._2
674+ let $t02748727598 = getPosition(_trader)
675+ let positionSize = $t02748727598._1
676+ let positionMargin = $t02748727598._2
677+ let pon = $t02748727598._3
678+ let positionLstUpdCPF = $t02748727598._4
679+ let $t02760427697 = getPositionNotionalAndUnrealizedPnl(_trader, _option)
680+ let positionNotional = $t02760427697._1
681+ let unrealizedPnl = $t02760427697._2
682+ let $t02770227868 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
683+ let remainMargin = $t02770227868._1
684+ let badDebt = $t02770227868._2
649685 calcMarginRatio(remainMargin, badDebt, positionNotional)
650686 }
651687
652688
653689 func getMarginRatio (_trader) = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
654690
655691
656692 func getPartialLiquidationAmount (_trader,_positionSize) = {
657693 let maximumRatio = vmax(partialLiquidationRatio(), (DECIMAL_UNIT - divd(getMarginRatio(_trader), maintenanceMarginRatio())))
658694 let maxExchangedPositionSize = muld(abs(_positionSize), maximumRatio)
659695 let swapResult = swapOutput((_positionSize > 0), maxExchangedPositionSize, false)
660696 let maxExchangedQuoteAssetAmount = swapResult._1
661697 let priceImpact = swapResult._7
662698 if ((maxPriceImpact() > priceImpact))
663699 then maxExchangedQuoteAssetAmount
664700 else {
665701 let exchangedPositionSize = muld(abs(_positionSize), partialLiquidationRatio())
666702 let exchangedQuoteAssetAmount = swapOutput((_positionSize > 0), exchangedPositionSize, false)._1
667703 exchangedQuoteAssetAmount
668704 }
669705 }
670706
671707
672708 func internalClosePosition (_trader,_checkMaxPriceImpact) = {
673- let $t02814528273 = getPosition(_trader)
674- let positionSize = $t02814528273._1
675- let positionMargin = $t02814528273._2
676- let positionOpenNotional = $t02814528273._3
677- let positionLstUpdCPF = $t02814528273._4
709+ let $t02910829236 = getPosition(_trader)
710+ let positionSize = $t02910829236._1
711+ let positionMargin = $t02910829236._2
712+ let positionOpenNotional = $t02910829236._3
713+ let positionLstUpdCPF = $t02910829236._4
678714 let unrealizedPnl = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)._2
679- let $t02836828536 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
680- let remainMargin = $t02836828536._1
681- let badDebt = $t02836828536._2
715+ let $t02933129499 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
716+ let remainMargin = $t02933129499._1
717+ let badDebt = $t02933129499._2
682718 let exchangedPositionSize = -(positionSize)
683719 let realizedPnl = unrealizedPnl
684720 let marginToVault = -(remainMargin)
685- let $t02866328937 = swapOutput((positionSize > 0), abs(positionSize), _checkMaxPriceImpact)
686- let exchangedQuoteAssetAmount = $t02866328937._1
687- let quoteAssetReserveAfter = $t02866328937._2
688- let baseAssetReserveAfter = $t02866328937._3
689- let totalPositionSizeAfter = $t02866328937._4
690- let totalLongAfter = $t02866328937._5
691- let totalShortAfter = $t02866328937._6
721+ let $t02962629900 = swapOutput((positionSize > 0), abs(positionSize), _checkMaxPriceImpact)
722+ let exchangedQuoteAssetAmount = $t02962629900._1
723+ let quoteAssetReserveAfter = $t02962629900._2
724+ let baseAssetReserveAfter = $t02962629900._3
725+ let totalPositionSizeAfter = $t02962629900._4
726+ let totalLongAfter = $t02962629900._5
727+ let totalShortAfter = $t02962629900._6
692728 let openInterestNotionalAfter = (openInterestNotional() - positionOpenNotional)
693729 $Tuple13(exchangedPositionSize, badDebt, realizedPnl, marginToVault, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, exchangedQuoteAssetAmount, totalLongAfter, totalShortAfter, (openInterestLong() - (if ((positionSize > 0))
694730 then positionOpenNotional
695731 else 0)), (openInterestShort() - (if ((0 > positionSize))
696732 then positionOpenNotional
697733 else 0)))
698734 }
699735
700736
701737 func getTwapSpotPrice () = {
702738 let minuteId = ((lastBlock.timestamp / 1000) / 60)
703739 let startMinuteId = (minuteId - TWAP_INTERVAL)
704740 let listStr = valueOrElse(getString(this, k_lastDataStr), "")
705741 let list = split(listStr, ",")
706742 func filterFn (accumulator,next) = if ((startMinuteId >= parseIntValue(next)))
707743 then (accumulator :+ parseIntValue(next))
708744 else accumulator
709745
710746 let listF = {
711747 let $l = list
712748 let $s = size($l)
713749 let $acc0 = nil
714750 func $f0_1 ($a,$i) = if (($i >= $s))
715751 then $a
716752 else filterFn($a, $l[$i])
717753
718754 func $f0_2 ($a,$i) = if (($i >= $s))
719755 then $a
720756 else throw("List size exceeds 20")
721757
722758 $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20)
723759 }
724760 let maxIndex = if ((size(listF) > 0))
725761 then max(listF)
726762 else parseIntValue(list[0])
727763 let lastMinuteId = valueOrElse(getInteger(this, k_lastMinuteId), 0)
728764 let endLastCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(lastMinuteId))), 0)
729765 let endLastPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(lastMinuteId))), 0)
730766 let nowCumulativePrice = (endLastCumulativePrice + ((minuteId - lastMinuteId) * endLastPrice))
731767 let startLastCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(maxIndex))), 0)
732768 let startLastPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(maxIndex))), 0)
733769 let startCumulativePrice = (startLastCumulativePrice + ((startMinuteId - maxIndex) * startLastPrice))
734770 ((nowCumulativePrice - startCumulativePrice) / TWAP_INTERVAL)
735771 }
736772
737773
738774 func getTerminalAmmState () = {
739775 let _positionSize = totalPositionSize()
740776 if ((_positionSize == 0))
741777 then $Tuple2(qtAstR(), bsAstR())
742778 else {
743779 let direction = (_positionSize > 0)
744- let $t03106031239 = swapOutput(direction, abs(_positionSize), false)
745- let currentNetMarketValue = $t03106031239._1
746- let terminalQuoteAssetReserve = $t03106031239._2
747- let terminalBaseAssetReserve = $t03106031239._3
780+ let $t03202332202 = swapOutput(direction, abs(_positionSize), false)
781+ let currentNetMarketValue = $t03202332202._1
782+ let terminalQuoteAssetReserve = $t03202332202._2
783+ let terminalBaseAssetReserve = $t03202332202._3
748784 $Tuple2(terminalQuoteAssetReserve, terminalBaseAssetReserve)
749785 }
750786 }
751787
752788
753789 func getQuoteAssetWeight (baseAssetReserve,totalPositionSize,quoteAssetReserve,targetPrice) = {
754790 let b = toBigInt(baseAssetReserve)
755791 let sz = toBigInt(totalPositionSize)
756792 let q = toBigInt(quoteAssetReserve)
757793 let p = toBigInt(targetPrice)
758- let bs2 = bpowd((b + sz), toBigInt((2 * DECIMAL_UNIT)))
759- let qbs2 = bmuld(q, bs2)
760- let ps4 = (toBigInt(4) * bmuld(p, sz))
761- let sqr = bsqrtd(bmuld(qbs2, (q - ps4)))
762- let bq = bmuld(b, q)
763- let qs = bmuld(q, sz)
764- let top = ((-(sqr) + bq) + qs)
765- let bot = (toBigInt(2) * bmuld(q, sz))
766- let result = bdivd(top, bot)
794+ let k = bmuld(q, b)
795+ let newB = (b + sz)
796+ let newQ = bdivd(k, newB)
797+ let z = bdivd(newQ, newB)
798+ let result = bdivd(p, z)
767799 toInt(result)
768800 }
769801
770802
771-func getSyncTerminalPrice (_terminalPrice) = {
803+func getSyncTerminalPrice (_terminalPrice,_qtAstR,_bsAstR) = {
772804 let _positionSize = totalPositionSize()
773805 if ((_positionSize == 0))
774806 then {
775- let _qtAstR = qtAstR()
776- let _bsAstR = bsAstR()
777807 let newQtAstW = divd(muld(_terminalPrice, _bsAstR), _qtAstR)
778808 $Tuple3(newQtAstW, DECIMAL_UNIT, 0)
779809 }
780810 else {
781811 let direction = (_positionSize > 0)
782812 let currentNetMarketValue = swapOutput(direction, abs(_positionSize), false)._1
783- let _qtAstR = qtAstR()
784- let _bsAstR = bsAstR()
785813 let newQtAstW = getQuoteAssetWeight(_bsAstR, _positionSize, _qtAstR, _terminalPrice)
786814 let newBsAstW = DECIMAL_UNIT
787815 let marginToVault = getPositionNotionalAndUnrealizedPnlByValues(_positionSize, currentNetMarketValue, _qtAstR, newQtAstW, _bsAstR, newBsAstW, PNL_OPTION_SPOT)._2
788816 $Tuple3(newQtAstW, newBsAstW, marginToVault)
789817 }
790818 }
791819
792820
793821 func getFunding () = {
794- let underlyingPrice = getOracleTwapPrice()
822+ let underlyingPrice = getOraclePrice()
795823 let spotTwapPrice = getTwapSpotPrice()
796824 let premium = (spotTwapPrice - underlyingPrice)
797- if (if ((totalShortPositionSize() == 0))
825+ if (if (if ((totalShortPositionSize() == 0))
798826 then true
799827 else (totalLongPositionSize() == 0))
828+ then true
829+ else isMarketClosed())
800830 then $Tuple2(0, 0)
801831 else if ((0 > premium))
802832 then {
803833 let shortPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY)
804834 let longPremiumFraction = divd(muld(shortPremiumFraction, totalShortPositionSize()), totalLongPositionSize())
805835 $Tuple2(shortPremiumFraction, longPremiumFraction)
806836 }
807837 else {
808838 let longPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY)
809839 let shortPremiumFraction = divd(muld(longPremiumFraction, totalLongPositionSize()), totalShortPositionSize())
810840 $Tuple2(shortPremiumFraction, longPremiumFraction)
811841 }
812842 }
813843
814844
815845 func getAdjustedFee (_artifactId,_baseFeeDiscount) = {
816846 let baseFeeRaw = fee()
817847 let baseFee = muld(baseFeeRaw, _baseFeeDiscount)
818- let $t03433834833 = if ((_artifactId != ""))
848+ let $t03506335558 = if ((_artifactId != ""))
819849 then {
820850 let artifactKind = strA(nftManagerAddress(), toCompositeKey(k_token_type, _artifactId))
821851 if ((artifactKind == FEE_REDUCTION_TOKEN_TYPE))
822852 then {
823853 let reduction = intA(nftManagerAddress(), toCompositeKey(k_token_param, _artifactId))
824854 let adjustedFee = muld(baseFee, reduction)
825855 $Tuple2(adjustedFee, true)
826856 }
827857 else throw("Invalid attached artifact")
828858 }
829859 else $Tuple2(baseFee, false)
830- let adjustedFee = $t03433834833._1
831- let burnArtifact = $t03433834833._2
860+ let adjustedFee = $t03506335558._1
861+ let burnArtifact = $t03506335558._2
832862 $Tuple2(adjustedFee, burnArtifact)
833863 }
834864
835865
836866 func isSameAssetOrNoPosition (_trader,_assetId) = {
837867 let oldPositionSize = getPosition(_trader)._1
838868 if ((oldPositionSize == 0))
839869 then true
840870 else (getPositionAsset(_trader) == _assetId)
841871 }
842872
843873
844874 func isSameAsset (_trader,_assetId) = (getPositionAsset(_trader) == _assetId)
845875
846876
847877 func getBorrowedByTraderInMarketKey (_amm,_assetId,_trader) = ((((((k_trader_market_asset_collateral + "_") + _amm) + "_") + _assetId) + "_") + _trader)
848878
849879
850880 func getBorrowedByTrader (_trader) = {
851881 let positionAsset = getPositionAsset(_trader)
852882 if ((positionAsset == toBase58String(quoteAsset())))
853883 then $Tuple2(0, positionAsset)
854884 else {
855885 let key = getBorrowedByTraderInMarketKey(toString(this), positionAsset, _trader)
856886 let borrow = valueOrElse(getInteger(collateralAddress(), key), 0)
857887 $Tuple2(borrow, positionAsset)
858888 }
859889 }
860890
861891
862892 func getForTraderWithArtifact (_trader,_artifactId) = {
863893 let doGetFeeDiscount = invoke(minerAddress(), "computeFeeDiscount", [_trader], nil)
864894 if ((doGetFeeDiscount == doGetFeeDiscount))
865895 then {
866896 let feeDiscount = match doGetFeeDiscount {
867897 case x: Int =>
868898 x
869899 case _ =>
870900 throw("Invalid computeFeeDiscount result")
871901 }
872- let $t03606436138 = getAdjustedFee(_artifactId, feeDiscount)
873- let adjustedFee = $t03606436138._1
874- let burnArtifact = $t03606436138._2
902+ let $t03678936863 = getAdjustedFee(_artifactId, feeDiscount)
903+ let adjustedFee = $t03678936863._1
904+ let burnArtifact = $t03678936863._2
875905 $Tuple2(adjustedFee, burnArtifact)
876906 }
877907 else throw("Strict value is not equal to itself.")
878908 }
879909
880910
881911 func getArtifactId (i) = {
882912 let artifactId = if ((size(i.payments) > 1))
883913 then toBase58String(valueOrErrorMessage(i.payments[1].assetId, "Invalid artifactId"))
884914 else ""
885915 artifactId
886916 }
887917
888918
889919 func distributeFee (_feeAmount) = {
890920 let feeToStakers = muld(_feeAmount, feeToStakersPercent())
891921 let feeToVault = (_feeAmount - feeToStakers)
892922 $Tuple2(feeToStakers, feeToVault)
893923 }
894924
895925
896926 func updateSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay) = [IntegerEntry(k_initMarginRatio, _initMarginRatio), IntegerEntry(k_maintenanceMarginRatio, _mmr), IntegerEntry(k_liquidationFeeRatio, _liquidationFeeRatio), IntegerEntry(k_fundingPeriod, _fundingPeriod), IntegerEntry(k_fee, _fee), IntegerEntry(k_spreadLimit, _spreadLimit), IntegerEntry(k_maxPriceImpact, _maxPriceImpact), IntegerEntry(k_partialLiquidationRatio, _partialLiquidationRatio), IntegerEntry(k_maxPriceSpread, _maxPriceSpread), IntegerEntry(k_maxOpenNotional, _maxOpenNotional), IntegerEntry(k_feeToStakersPercent, _feeToStakersPercent), IntegerEntry(k_maxOracleDelay, _feeToStakersPercent)]
897927
898928
899929 func updateFunding (_nextFundingBlock,_latestLongCumulativePremiumFraction,_latestShortCumulativePremiumFraction,_longFundingRate,_shortFundingRate) = [IntegerEntry(k_nextFundingBlock, _nextFundingBlock), IntegerEntry(k_latestLongCumulativePremiumFraction, _latestLongCumulativePremiumFraction), IntegerEntry(k_latestShortCumulativePremiumFraction, _latestShortCumulativePremiumFraction), IntegerEntry(k_longFundingRate, _longFundingRate), IntegerEntry(k_shortFundingRate, _shortFundingRate)]
900930
901931
902932 func updatePositionAsset (_address,_assetId) = [StringEntry(toCompositeKey(k_positionAsset, _address), _assetId)]
903933
904934
905-func incrementPositionSequenceNumber (isNewPosition,_address) = if (isNewPosition)
935+func incrementPositionSequenceNumber (_isNewPosition,_address) = if (_isNewPosition)
906936 then {
907937 let currentSequence = lastSequence()
908938 [IntegerEntry(toCompositeKey(k_positionSequence, _address), (currentSequence + 1)), IntegerEntry(k_sequence, (currentSequence + 1))]
909939 }
940+ else nil
941+
942+
943+func updatePositionFee (_isNewPosition,_address,_fee) = if (_isNewPosition)
944+ then [IntegerEntry(toCompositeKey(k_positionFee, _address), _fee)]
910945 else nil
911946
912947
913948 func updatePosition (_address,_size,_margin,_openNotional,_latestCumulativePremiumFraction) = [IntegerEntry(toCompositeKey(k_positionSize, _address), _size), IntegerEntry(toCompositeKey(k_positionMargin, _address), _margin), IntegerEntry(toCompositeKey(k_positionOpenNotional, _address), _openNotional), IntegerEntry(toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _address), _latestCumulativePremiumFraction)]
914949
915950
916951 func appendTwap (_price) = {
917952 let minuteId = ((lastBlock.timestamp / 1000) / 60)
918953 let previousMinuteId = valueOrElse(getInteger(this, k_lastMinuteId), 0)
919954 if ((previousMinuteId > minuteId))
920955 then throw("TWAP out-of-order")
921956 else {
922957 let lastMinuteId = if ((previousMinuteId == 0))
923958 then minuteId
924959 else previousMinuteId
925960 if ((minuteId > previousMinuteId))
926961 then {
927962 let prevCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(previousMinuteId))), 0)
928963 let prevPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(previousMinuteId))), _price)
929964 let lastCumulativePrice = (prevCumulativePrice + ((minuteId - lastMinuteId) * prevPrice))
930965 let list = pushToQueue(strToList(valueOrElse(getString(this, k_lastDataStr), "")), TWAP_INTERVAL, toString(minuteId))
931966 [IntegerEntry(toCompositeKey(k_twapDataLastCumulativePrice, toString(minuteId)), lastCumulativePrice), IntegerEntry(toCompositeKey(k_twapDataLastPrice, toString(minuteId)), _price), IntegerEntry(toCompositeKey(k_twapDataPreviousMinuteId, toString(minuteId)), previousMinuteId), IntegerEntry(k_lastMinuteId, minuteId), StringEntry(k_lastDataStr, listToStr(list))]
932967 }
933968 else {
934969 let twapDataPreviousMinuteId = valueOrElse(getInteger(this, toCompositeKey(k_twapDataPreviousMinuteId, toString(minuteId))), 0)
935970 let prevCumulativePrice = valueOrElse(getInteger(this, toCompositeKey(k_twapDataLastCumulativePrice, toString(twapDataPreviousMinuteId))), 0)
936971 let prevPrice = valueOrElse(getInteger(this, toCompositeKey(k_twapDataLastPrice, toString(twapDataPreviousMinuteId))), _price)
937972 let lastCumulativePrice = (prevCumulativePrice + ((minuteId - twapDataPreviousMinuteId) * prevPrice))
938973 [IntegerEntry(toCompositeKey(k_twapDataLastCumulativePrice, toString(minuteId)), lastCumulativePrice), IntegerEntry(toCompositeKey(k_twapDataLastPrice, toString(minuteId)), _price)]
939974 }
940975 }
941976 }
942977
943978
944979 func updateAmmReserves (_qtAstR,_bsAstR) = [IntegerEntry(k_quoteAssetReserve, _qtAstR), IntegerEntry(k_baseAssetReserve, _bsAstR)]
945980
946981
947982 func updateAmmWeights (_qtAstW,_bsAstW) = [IntegerEntry(k_quoteAssetWeight, _qtAstW), IntegerEntry(k_baseAssetWeight, _bsAstW)]
948983
949984
950985 func updateAmm (_qtAstR,_bsAstR,_totalPositionSizeAfter,_openInterestNotional,_totalLongPositionSize,_totalShortPositionSize,_totalLongOpenNotional,_totalShortOpenNotional) = {
951986 let _qtAstW = qtAstW()
952987 let _bsAstW = bsAstW()
953988 if (((_totalLongPositionSize - _totalShortPositionSize) != _totalPositionSizeAfter))
954989 then throw(((((("Invalid AMM state data: " + toString(_totalLongPositionSize)) + " + ") + toString(_totalShortPositionSize)) + " != ") + toString(_totalPositionSizeAfter)))
955990 else ((updateAmmReserves(_qtAstR, _bsAstR) ++ [IntegerEntry(k_totalPositionSize, _totalPositionSizeAfter), IntegerEntry(k_openInterestNotional, _openInterestNotional), IntegerEntry(k_totalLongPositionSize, _totalLongPositionSize), IntegerEntry(k_totalShortPositionSize, _totalShortPositionSize), IntegerEntry(k_openInterestLong, _totalLongOpenNotional), IntegerEntry(k_openInterestShort, _totalShortOpenNotional)]) ++ appendTwap(divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))))
956991 }
957992
958993
959994 func deletePosition (_address) = [DeleteEntry(toCompositeKey(k_positionSize, _address)), DeleteEntry(toCompositeKey(k_positionMargin, _address)), DeleteEntry(toCompositeKey(k_positionOpenNotional, _address)), DeleteEntry(toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _address)), DeleteEntry(toCompositeKey(k_positionAsset, _address))]
960995
961996
962997 func withdraw (_address,_amount) = {
963998 let balance = assetBalance(this, quoteAsset())
964999 if ((_amount > balance))
9651000 then throw(((("Unable to withdraw " + toString(_amount)) + " from contract balance ") + toString(balance)))
9661001 else [ScriptTransfer(_address, _amount, quoteAsset())]
9671002 }
9681003
9691004
9701005 func updateBalance (i) = if ((0 > i))
9711006 then throw("Balance")
9721007 else [IntegerEntry(k_balance, i)]
9731008
9741009
9751010 func transferFee (i) = [ScriptTransfer(stakingAddress(), i, quoteAsset())]
9761011
9771012
9781013 func doBurnArtifact (_burnArtifact,i) = if (_burnArtifact)
9791014 then [Burn(valueOrErrorMessage(i.payments[1].assetId, "Invalid artifact"), 1)]
9801015 else nil
9811016
9821017
9831018 @Callable(i)
9841019 func pause () = if ((i.caller != adminAddress()))
9851020 then throw("Invalid pause params")
9861021 else [BooleanEntry(k_paused, true)]
9871022
9881023
9891024
9901025 @Callable(i)
9911026 func unpause () = if ((i.caller != adminAddress()))
9921027 then throw("Invalid unpause params")
9931028 else [BooleanEntry(k_paused, false)]
9941029
9951030
9961031
9971032 @Callable(i)
9981033 func setCloseOnly () = if ((i.caller != adminAddress()))
9991034 then throw("Invalid setCloseOnly params")
10001035 else [BooleanEntry(k_closeOnly, true)]
10011036
10021037
10031038
10041039 @Callable(i)
10051040 func unsetCloseOnly () = if ((i.caller != adminAddress()))
10061041 then throw("Invalid unsetCloseOnly params")
10071042 else [BooleanEntry(k_closeOnly, false)]
10081043
10091044
10101045
10111046 @Callable(i)
10121047 func addLiquidity (_quoteAssetAmount) = if (if ((i.caller != adminAddress()))
10131048 then true
10141049 else (0 >= _quoteAssetAmount))
10151050 then throw("Invalid addLiquidity params")
10161051 else {
10171052 let _qtAstR = qtAstR()
10181053 let _bsAstR = bsAstR()
10191054 let _qtAstW = qtAstW()
10201055 let _bsAstW = bsAstW()
10211056 let price = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
1022- let baseAssetAmountToAdd = divd(_quoteAssetAmount, price)
10231057 let qtAstRAfter = (_qtAstR + _quoteAssetAmount)
1058+ let baseAssetAmountToAdd = (divd(muld(qtAstRAfter, _qtAstW), price) - _bsAstR)
10241059 let bsAstRAfter = (_bsAstR + baseAssetAmountToAdd)
1025- updateAmmReserves(qtAstRAfter, bsAstRAfter)
1060+ let $t04610746258 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1061+ let newQuoteAssetWeight = $t04610746258._1
1062+ let newBaseAssetWeight = $t04610746258._2
1063+ let marginToVault = $t04610746258._3
1064+ let doExchangePnL = if ((marginToVault != 0))
1065+ then {
1066+ let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
1067+ if ((doExchangePnL == doExchangePnL))
1068+ then nil
1069+ else throw("Strict value is not equal to itself.")
1070+ }
1071+ else nil
1072+ if ((doExchangePnL == doExchangePnL))
1073+ then (updateAmmReserves(qtAstRAfter, bsAstRAfter) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
1074+ else throw("Strict value is not equal to itself.")
10261075 }
10271076
10281077
10291078
10301079 @Callable(i)
10311080 func removeLiquidity (_quoteAssetAmount) = if (if ((i.caller != adminAddress()))
10321081 then true
1033- else (0 >= _quoteAssetAmount))
1082+ else (_quoteAssetAmount >= 0))
10341083 then throw("Invalid removeLiquidity params")
10351084 else {
10361085 let _qtAstR = qtAstR()
10371086 let _bsAstR = bsAstR()
10381087 let _qtAstW = qtAstW()
10391088 let _bsAstW = bsAstW()
10401089 let price = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
1041- let baseAssetAmountToRemove = divd(_quoteAssetAmount, price)
10421090 let qtAstRAfter = (_qtAstR - _quoteAssetAmount)
1091+ let baseAssetAmountToRemove = abs((divd(muld(qtAstRAfter, _qtAstW), price) - _bsAstR))
10431092 let bsAstRAfter = (_bsAstR - baseAssetAmountToRemove)
1044- updateAmmReserves(qtAstRAfter, bsAstRAfter)
1093+ let $t04719047341 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1094+ let newQuoteAssetWeight = $t04719047341._1
1095+ let newBaseAssetWeight = $t04719047341._2
1096+ let marginToVault = $t04719047341._3
1097+ let doExchangePnL = if ((marginToVault != 0))
1098+ then {
1099+ let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
1100+ if ((doExchangePnL == doExchangePnL))
1101+ then nil
1102+ else throw("Strict value is not equal to itself.")
1103+ }
1104+ else nil
1105+ if ((doExchangePnL == doExchangePnL))
1106+ then (updateAmmReserves(qtAstRAfter, bsAstRAfter) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
1107+ else throw("Strict value is not equal to itself.")
10451108 }
10461109
10471110
10481111
10491112 @Callable(i)
10501113 func changeSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay) = if ((i.caller != adminAddress()))
10511114 then throw("Invalid changeSettings params")
10521115 else updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread, _maxOpenNotional, _feeToStakersPercent, _maxOracleDelay)
10531116
10541117
10551118
10561119 @Callable(i)
10571120 func initialize (_qtAstR,_bsAstR,_fundingPeriod,_initMarginRatio,_mmr,_liquidationFeeRatio,_fee,_oracle,_oracleKey,_oracleBlockKey,_coordinator,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay) = if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if ((0 >= _qtAstR))
10581121 then true
10591122 else (0 >= _bsAstR))
10601123 then true
10611124 else (0 >= _fundingPeriod))
10621125 then true
10631126 else (0 >= _initMarginRatio))
10641127 then true
10651128 else (0 >= _mmr))
10661129 then true
10671130 else (0 >= _liquidationFeeRatio))
10681131 then true
10691132 else (0 >= _fee))
10701133 then true
10711134 else (0 >= _spreadLimit))
10721135 then true
10731136 else (0 >= _maxPriceImpact))
10741137 then true
10751138 else (0 >= _partialLiquidationRatio))
10761139 then true
10771140 else (0 >= _maxPriceSpread))
10781141 then true
10791142 else (0 >= _maxOpenNotional))
10801143 then true
10811144 else (0 >= _feeToStakersPercent))
10821145 then true
10831146 else (_feeToStakersPercent > DECIMAL_UNIT))
10841147 then true
10851148 else (0 >= _maxOracleDelay))
10861149 then true
10871150 else initialized())
10881151 then throw("Invalid initialize parameters")
10891152 else ((((updateAmm(_qtAstR, _bsAstR, 0, 0, 0, 0, 0, 0) ++ updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread, _maxOpenNotional, _feeToStakersPercent, _maxOracleDelay)) ++ updateFunding((lastBlock.timestamp + _fundingPeriod), 0, 0, 0, 0)) ++ updateBalance(0)) ++ [BooleanEntry(k_initialized, true), StringEntry(k_ora, _oracle), StringEntry(k_ora_key, _oracleKey), StringEntry(k_ora_block_key, _oracleBlockKey), StringEntry(k_coordinatorAddress, _coordinator)])
10901153
10911154
10921155
10931156 @Callable(i)
1094-func decreasePosition (_amount,_leverage,_minBaseAssetAmount) = {
1095- let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
1096- if ((sync == sync))
1097- then {
1098- let _trader = getActualCaller(i)
1099- if (if (if (if (if ((0 >= _amount))
1100- then true
1101- else !(initialized()))
1102- then true
1103- else !(requireMoreMarginRatio(divd(DECIMAL_UNIT, _leverage), initMarginRatio(), true)))
1104- then true
1105- else !(requireOpenPosition(_trader)))
1106- then true
1107- else paused())
1108- then throw("Invalid decreasePosition parameters")
1109- else {
1110- let $t04867748817 = getPosition(_trader)
1111- let oldPositionSize = $t04867748817._1
1112- let oldPositionMargin = $t04867748817._2
1113- let oldPositionOpenNotional = $t04867748817._3
1114- let oldPositionLstUpdCPF = $t04867748817._4
1115- let _direction = if ((oldPositionSize > 0))
1116- then DIR_SHORT
1117- else DIR_LONG
1118- let isAdd = (_direction == DIR_LONG)
1119- let openNotional = muld(_amount, _leverage)
1120- let $t04899049094 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1121- let oldPositionNotional = $t04899049094._1
1122- let unrealizedPnl = $t04899049094._2
1123- let $t04910051758 = if ((oldPositionNotional > openNotional))
1124- then {
1125- let $t04951549699 = swapInput(isAdd, openNotional)
1126- let exchangedPositionSize = $t04951549699._1
1127- let quoteAssetReserveAfter = $t04951549699._2
1128- let baseAssetReserveAfter = $t04951549699._3
1129- let totalPositionSizeAfter = $t04951549699._4
1130- let exchangedPositionSizeAbs = abs(exchangedPositionSize)
1131- if (if ((_minBaseAssetAmount != 0))
1132- then (_minBaseAssetAmount > exchangedPositionSizeAbs)
1133- else false)
1134- then throw(((("Too little base asset exchanged, got " + toString(exchangedPositionSizeAbs)) + " expected ") + toString(_minBaseAssetAmount)))
1135- else {
1136- let realizedPnl = divd(muld(unrealizedPnl, exchangedPositionSizeAbs), abs(oldPositionSize))
1137- let $t05013650381 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl)
1138- let remainMargin = $t05013650381._1
1139- let badDebt = $t05013650381._2
1140- let fundingPayment = $t05013650381._3
1141- let exchangedQuoteAssetAmount = openNotional
1142- let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
1143- let remainOpenNotional = if ((oldPositionSize > 0))
1144- then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
1145- else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
1146- let newPositionSize = (oldPositionSize + exchangedPositionSize)
1147- $Tuple12(newPositionSize, remainMargin, abs(remainOpenNotional), latestCumulativePremiumFraction(newPositionSize), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() - openNotional), (totalLongPositionSize() - (if ((newPositionSize > 0))
1148- then abs(exchangedPositionSize)
1149- else 0)), (totalShortPositionSize() - (if ((0 > newPositionSize))
1150- then abs(exchangedPositionSize)
1151- else 0)), (openInterestLong() - (if ((newPositionSize > 0))
1152- then openNotional
1153- else 0)), (openInterestShort() - (if ((0 > newPositionSize))
1154- then openNotional
1155- else 0)))
1156- }
1157- }
1158- else throw("Close position first")
1159- let newPositionSize = $t04910051758._1
1160- let newPositionRemainMargin = $t04910051758._2
1161- let newPositionOpenNotional = $t04910051758._3
1162- let newPositionLatestCPF = $t04910051758._4
1163- let baseAssetReserveAfter = $t04910051758._5
1164- let quoteAssetReserveAfter = $t04910051758._6
1165- let totalPositionSizeAfter = $t04910051758._7
1166- let openInterestNotionalAfter = $t04910051758._8
1167- let totalLongAfter = $t04910051758._9
1168- let totalShortAfter = $t04910051758._10
1169- let totalLongOpenInterestAfter = $t04910051758._11
1170- let totalShortOpenInterestAfter = $t04910051758._12
1171- let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
1172- if ((notifyNotional == notifyNotional))
1173- then (updatePosition(_trader, newPositionSize, newPositionRemainMargin, newPositionOpenNotional, newPositionLatestCPF) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter))
1174- else throw("Strict value is not equal to itself.")
1175- }
1176- }
1177- else throw("Strict value is not equal to itself.")
1178- }
1179-
1180-
1181-
1182-@Callable(i)
11831157 func increasePosition (_direction,_leverage,_minBaseAssetAmount,_refLink) = {
11841158 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
11851159 if ((sync == sync))
11861160 then {
11871161 let _trader = getActualCaller(i)
11881162 let _rawAmount = i.payments[0].amount
11891163 let _assetId = i.payments[0].assetId
11901164 let _assetIdStr = toBase58String(value(_assetId))
11911165 let isQuoteAsset = (_assetId == quoteAsset())
11921166 let isCollateralAsset = isWhitelistAsset(_assetIdStr)
1193- if (if (if (if (if (if (if (if (if ((_direction != DIR_LONG))
1167+ if (if (if (if (if (if (if (if (if (if ((_direction != DIR_LONG))
11941168 then (_direction != DIR_SHORT)
11951169 else false)
11961170 then true
11971171 else (0 >= _rawAmount))
11981172 then true
11991173 else !(initialized()))
12001174 then true
12011175 else if (!(isQuoteAsset))
12021176 then !(isCollateralAsset)
12031177 else false)
12041178 then true
12051179 else !(isSameAssetOrNoPosition(_trader, _assetIdStr)))
12061180 then true
12071181 else !(requireMoreMarginRatio(divd(DECIMAL_UNIT, _leverage), initMarginRatio(), true)))
12081182 then true
12091183 else paused())
12101184 then true
12111185 else closeOnly())
1186+ then true
1187+ else isMarketClosed())
12121188 then throw("Invalid increasePosition parameters")
12131189 else {
1214- let $t05319653281 = getForTraderWithArtifact(_trader, getArtifactId(i))
1215- let adjustedFee = $t05319653281._1
1216- let burnArtifact = $t05319653281._2
1217- let rawFeeAmount = muld(_rawAmount, adjustedFee)
1218- let _amount = (_rawAmount - rawFeeAmount)
1190+ let $t05100951158 = getForTraderWithArtifact(_trader, getArtifactId(i))
1191+ let adjustedFee = $t05100951158._1
1192+ let burnArtifact = $t05100951158._2
1193+ let _amount = divd(_rawAmount, (muld(adjustedFee, _leverage) + DECIMAL_UNIT))
1194+ let rawFeeAmount = (_rawAmount - _amount)
12191195 let distributeFeeAmount = if (isCollateralAsset)
12201196 then {
12211197 let doBorrow = invoke(collateralAddress(), "borrow", [_trader], [AttachedPayment(_assetId, _amount)])
12221198 if ((doBorrow == doBorrow))
12231199 then {
12241200 let balanceBefore = assetBalance(this, quoteAsset())
12251201 if ((balanceBefore == balanceBefore))
12261202 then {
12271203 let doSwap = invoke(swapAddress(), "swap", [toBase58String(quoteAsset()), 0], [AttachedPayment(_assetId, rawFeeAmount)])
12281204 if ((doSwap == doSwap))
12291205 then {
12301206 let balanceAfter = assetBalance(this, quoteAsset())
12311207 if ((balanceAfter == balanceAfter))
12321208 then {
12331209 let exchangedAmount = (balanceAfter - balanceBefore)
12341210 if ((exchangedAmount == exchangedAmount))
12351211 then exchangedAmount
12361212 else throw("Strict value is not equal to itself.")
12371213 }
12381214 else throw("Strict value is not equal to itself.")
12391215 }
12401216 else throw("Strict value is not equal to itself.")
12411217 }
12421218 else throw("Strict value is not equal to itself.")
12431219 }
12441220 else throw("Strict value is not equal to itself.")
12451221 }
12461222 else rawFeeAmount
12471223 if ((distributeFeeAmount == distributeFeeAmount))
12481224 then {
12491225 let referrerFeeAny = invoke(referralAddress(), "acceptPaymentWithLink", [_trader, _refLink], [AttachedPayment(quoteAsset(), distributeFeeAmount)])
12501226 if ((referrerFeeAny == referrerFeeAny))
12511227 then {
12521228 let referrerFee = match referrerFeeAny {
12531229 case x: Int =>
12541230 x
12551231 case _ =>
12561232 throw("Invalid referrerFee")
12571233 }
12581234 let feeAmount = (distributeFeeAmount - referrerFee)
1259- let $t05459754737 = getPosition(_trader)
1260- let oldPositionSize = $t05459754737._1
1261- let oldPositionMargin = $t05459754737._2
1262- let oldPositionOpenNotional = $t05459754737._3
1263- let oldPositionLstUpdCPF = $t05459754737._4
1235+ let $t05250052640 = getPosition(_trader)
1236+ let oldPositionSize = $t05250052640._1
1237+ let oldPositionMargin = $t05250052640._2
1238+ let oldPositionOpenNotional = $t05250052640._3
1239+ let oldPositionLstUpdCPF = $t05250052640._4
12641240 let isNewPosition = (oldPositionSize == 0)
12651241 let isSameDirection = if ((oldPositionSize > 0))
12661242 then (_direction == DIR_LONG)
12671243 else (_direction == DIR_SHORT)
12681244 let expandExisting = if (!(isNewPosition))
12691245 then isSameDirection
12701246 else false
12711247 let isAdd = (_direction == DIR_LONG)
1272- let $t05502658067 = if (if (isNewPosition)
1248+ let $t05292955891 = if (if (isNewPosition)
12731249 then true
12741250 else expandExisting)
12751251 then {
12761252 let openNotional = muld(_amount, _leverage)
1277- let $t05548855661 = swapInput(isAdd, openNotional)
1278- let amountBaseAssetBought = $t05548855661._1
1279- let quoteAssetReserveAfter = $t05548855661._2
1280- let baseAssetReserveAfter = $t05548855661._3
1281- let totalPositionSizeAfter = $t05548855661._4
1253+ let $t05339153564 = swapInput(isAdd, openNotional)
1254+ let amountBaseAssetBought = $t05339153564._1
1255+ let quoteAssetReserveAfter = $t05339153564._2
1256+ let baseAssetReserveAfter = $t05339153564._3
1257+ let totalPositionSizeAfter = $t05339153564._4
12821258 if (if ((_minBaseAssetAmount != 0))
12831259 then (_minBaseAssetAmount > abs(amountBaseAssetBought))
12841260 else false)
12851261 then throw(((("Limit error: " + toString(abs(amountBaseAssetBought))) + " < ") + toString(_minBaseAssetAmount)))
12861262 else {
12871263 let newPositionSize = (oldPositionSize + amountBaseAssetBought)
12881264 let totalLongOpenInterestAfter = (openInterestLong() + (if ((newPositionSize > 0))
12891265 then openNotional
12901266 else 0))
12911267 let totalShortOpenInterestAfter = (openInterestShort() + (if ((0 > newPositionSize))
12921268 then openNotional
12931269 else 0))
1294- let increaseMarginRequirement = divd(openNotional, _leverage)
1295- let $t05626956508 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, increaseMarginRequirement)
1296- let remainMargin = $t05626956508._1
1297- let x1 = $t05626956508._2
1298- let x2 = $t05626956508._3
1270+ let $t05411054331 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, _amount)
1271+ let remainMargin = $t05411054331._1
1272+ let x1 = $t05411054331._2
1273+ let x2 = $t05411054331._3
12991274 if (!(requireNotOverSpreadLimit(quoteAssetReserveAfter, baseAssetReserveAfter)))
13001275 then throw("Over max spread limit")
13011276 else if (!(requireNotOverMaxOpenNotional(totalLongOpenInterestAfter, totalShortOpenInterestAfter)))
13021277 then throw("Over max open notional")
13031278 else $Tuple12(newPositionSize, remainMargin, (oldPositionOpenNotional + openNotional), latestCumulativePremiumFraction(newPositionSize), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() + openNotional), (totalLongPositionSize() + (if ((newPositionSize > 0))
13041279 then abs(amountBaseAssetBought)
13051280 else 0)), (totalShortPositionSize() + (if ((0 > newPositionSize))
13061281 then abs(amountBaseAssetBought)
13071282 else 0)), totalLongOpenInterestAfter, totalShortOpenInterestAfter)
13081283 }
13091284 }
13101285 else {
13111286 let openNotional = muld(_amount, _leverage)
1312- let $t05776757883 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
1313- let oldPositionNotional = $t05776757883._1
1314- let unrealizedPnl = $t05776757883._2
1287+ let $t05559155707 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
1288+ let oldPositionNotional = $t05559155707._1
1289+ let unrealizedPnl = $t05559155707._2
13151290 if ((oldPositionNotional > openNotional))
13161291 then throw("Use decreasePosition to decrease position size")
13171292 else throw("Close position first")
13181293 }
1319- let newPositionSize = $t05502658067._1
1320- let newPositionRemainMargin = $t05502658067._2
1321- let newPositionOpenNotional = $t05502658067._3
1322- let newPositionLatestCPF = $t05502658067._4
1323- let baseAssetReserveAfter = $t05502658067._5
1324- let quoteAssetReserveAfter = $t05502658067._6
1325- let totalPositionSizeAfter = $t05502658067._7
1326- let openInterestNotionalAfter = $t05502658067._8
1327- let totalLongAfter = $t05502658067._9
1328- let totalShortAfter = $t05502658067._10
1329- let totalLongOpenInterestAfter = $t05502658067._11
1330- let totalShortOpenInterestAfter = $t05502658067._12
1331- let $t05807358130 = distributeFee(feeAmount)
1332- let feeToStakers = $t05807358130._1
1333- let feeToVault = $t05807358130._2
1294+ let newPositionSize = $t05292955891._1
1295+ let newPositionRemainMargin = $t05292955891._2
1296+ let newPositionOpenNotional = $t05292955891._3
1297+ let newPositionLatestCPF = $t05292955891._4
1298+ let baseAssetReserveAfter = $t05292955891._5
1299+ let quoteAssetReserveAfter = $t05292955891._6
1300+ let totalPositionSizeAfter = $t05292955891._7
1301+ let openInterestNotionalAfter = $t05292955891._8
1302+ let totalLongAfter = $t05292955891._9
1303+ let totalShortAfter = $t05292955891._10
1304+ let totalLongOpenInterestAfter = $t05292955891._11
1305+ let totalShortOpenInterestAfter = $t05292955891._12
1306+ let $t05589755954 = distributeFee(feeAmount)
1307+ let feeToStakers = $t05589755954._1
1308+ let feeToVault = $t05589755954._2
13341309 let stake = if (isQuoteAsset)
13351310 then {
13361311 let stake = invoke(vaultAddress(), "addLocked", [false], [AttachedPayment(quoteAsset(), _amount)])
13371312 if ((stake == stake))
13381313 then nil
13391314 else throw("Strict value is not equal to itself.")
13401315 }
13411316 else nil
13421317 if ((stake == stake))
13431318 then {
1344- let depositInsurance = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1345- if ((depositInsurance == depositInsurance))
1319+ let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1320+ if ((depositVault == depositVault))
13461321 then {
13471322 let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, feeAmount], nil)
13481323 if ((notifyFee == notifyFee))
13491324 then {
13501325 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
13511326 if ((notifyNotional == notifyNotional))
1352- then ((((((updatePosition(_trader, newPositionSize, newPositionRemainMargin, newPositionOpenNotional, newPositionLatestCPF) ++ incrementPositionSequenceNumber(isNewPosition, _trader)) ++ updatePositionAsset(_trader, _assetIdStr)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ transferFee(feeToStakers)) ++ updateBalance((cbalance() + _amount))) ++ doBurnArtifact(burnArtifact, i))
1327+ then (((((((updatePosition(_trader, newPositionSize, newPositionRemainMargin, newPositionOpenNotional, newPositionLatestCPF) ++ incrementPositionSequenceNumber(isNewPosition, _trader)) ++ updatePositionFee(isNewPosition, _trader, adjustedFee)) ++ updatePositionAsset(_trader, _assetIdStr)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ transferFee(feeToStakers)) ++ updateBalance((cbalance() + _amount))) ++ doBurnArtifact(burnArtifact, i))
13531328 else throw("Strict value is not equal to itself.")
13541329 }
13551330 else throw("Strict value is not equal to itself.")
13561331 }
13571332 else throw("Strict value is not equal to itself.")
13581333 }
13591334 else throw("Strict value is not equal to itself.")
13601335 }
13611336 else throw("Strict value is not equal to itself.")
13621337 }
13631338 else throw("Strict value is not equal to itself.")
13641339 }
13651340 }
13661341 else throw("Strict value is not equal to itself.")
13671342 }
13681343
13691344
13701345
13711346 @Callable(i)
13721347 func addMargin () = {
13731348 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
13741349 if ((sync == sync))
13751350 then {
13761351 let _trader = toString(i.caller)
1377- let _rawAmount = i.payments[0].amount
1352+ let _amount = i.payments[0].amount
13781353 let _assetId = i.payments[0].assetId
13791354 let _assetIdStr = toBase58String(value(_assetId))
13801355 let isQuoteAsset = (_assetId == quoteAsset())
13811356 let isCollateralAsset = isWhitelistAsset(_assetIdStr)
1382- if (if (if (if (if (if (if (!(isQuoteAsset))
1357+ if (if (if (if (if (if (if (if (!(isQuoteAsset))
13831358 then !(isCollateralAsset)
13841359 else false)
13851360 then true
13861361 else !(requireOpenPosition(toString(i.caller))))
13871362 then true
13881363 else !(isSameAsset(_trader, _assetIdStr)))
13891364 then true
13901365 else !(initialized()))
13911366 then true
13921367 else paused())
13931368 then true
13941369 else closeOnly())
1370+ then true
1371+ else isMarketClosed())
13951372 then throw("Invalid addMargin parameters")
13961373 else {
1397- let $t06007860163 = getForTraderWithArtifact(_trader, getArtifactId(i))
1398- let adjustedFee = $t06007860163._1
1399- let burnArtifact = $t06007860163._2
1400- let rawFeeAmount = muld(_rawAmount, adjustedFee)
1401- let _amount = (_rawAmount - rawFeeAmount)
1402- let distributeFeeAmount = if (isCollateralAsset)
1374+ let $t05798558125 = getPosition(_trader)
1375+ let oldPositionSize = $t05798558125._1
1376+ let oldPositionMargin = $t05798558125._2
1377+ let oldPositionOpenNotional = $t05798558125._3
1378+ let oldPositionLstUpdCPF = $t05798558125._4
1379+ let stake = if (isQuoteAsset)
14031380 then {
1404- let doBorrow = invoke(collateralAddress(), "borrow", [_trader], [AttachedPayment(_assetId, _amount)])
1405- if ((doBorrow == doBorrow))
1406- then {
1407- let balanceBefore = assetBalance(this, quoteAsset())
1408- if ((balanceBefore == balanceBefore))
1409- then {
1410- let doSwap = invoke(swapAddress(), "swap", [toBase58String(quoteAsset()), 0], [AttachedPayment(_assetId, rawFeeAmount)])
1411- if ((doSwap == doSwap))
1412- then {
1413- let balanceAfter = assetBalance(this, quoteAsset())
1414- if ((balanceAfter == balanceAfter))
1415- then {
1416- let exchangedAmount = (balanceAfter - balanceBefore)
1417- if ((exchangedAmount == exchangedAmount))
1418- then exchangedAmount
1419- else throw("Strict value is not equal to itself.")
1420- }
1421- else throw("Strict value is not equal to itself.")
1422- }
1423- else throw("Strict value is not equal to itself.")
1424- }
1425- else throw("Strict value is not equal to itself.")
1426- }
1381+ let stake = invoke(vaultAddress(), "addLocked", [false], [AttachedPayment(quoteAsset(), _amount)])
1382+ if ((stake == stake))
1383+ then nil
14271384 else throw("Strict value is not equal to itself.")
14281385 }
1429- else rawFeeAmount
1430- if ((distributeFeeAmount == distributeFeeAmount))
1431- then {
1432- let referrerFeeAny = invoke(referralAddress(), "acceptPayment", [_trader], [AttachedPayment(quoteAsset(), distributeFeeAmount)])
1433- if ((referrerFeeAny == referrerFeeAny))
1434- then {
1435- let referrerFee = match referrerFeeAny {
1436- case x: Int =>
1437- x
1438- case _ =>
1439- throw("Invalid referrerFee")
1440- }
1441- let feeAmount = (distributeFeeAmount - referrerFee)
1442- let $t06146261602 = getPosition(_trader)
1443- let oldPositionSize = $t06146261602._1
1444- let oldPositionMargin = $t06146261602._2
1445- let oldPositionOpenNotional = $t06146261602._3
1446- let oldPositionLstUpdCPF = $t06146261602._4
1447- let $t06160861665 = distributeFee(feeAmount)
1448- let feeToStakers = $t06160861665._1
1449- let feeToVault = $t06160861665._2
1450- let stake = if (isQuoteAsset)
1451- then {
1452- let stake = invoke(vaultAddress(), "addLocked", [false], [AttachedPayment(quoteAsset(), _amount)])
1453- if ((stake == stake))
1454- then nil
1455- else throw("Strict value is not equal to itself.")
1456- }
1457- else nil
1458- if ((stake == stake))
1459- then {
1460- let depositInsurance = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1461- if ((depositInsurance == depositInsurance))
1462- then {
1463- let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, feeAmount], nil)
1464- if ((notifyFee == notifyFee))
1465- then (((updatePosition(_trader, oldPositionSize, (oldPositionMargin + _amount), oldPositionOpenNotional, oldPositionLstUpdCPF) ++ transferFee(feeToStakers)) ++ updateBalance((cbalance() + _amount))) ++ doBurnArtifact(burnArtifact, i))
1466- else throw("Strict value is not equal to itself.")
1467- }
1468- else throw("Strict value is not equal to itself.")
1469- }
1470- else throw("Strict value is not equal to itself.")
1471- }
1472- else throw("Strict value is not equal to itself.")
1473- }
1386+ else nil
1387+ if ((stake == stake))
1388+ then (updatePosition(_trader, oldPositionSize, (oldPositionMargin + _amount), oldPositionOpenNotional, oldPositionLstUpdCPF) ++ updateBalance((cbalance() + _amount)))
14741389 else throw("Strict value is not equal to itself.")
14751390 }
14761391 }
14771392 else throw("Strict value is not equal to itself.")
14781393 }
14791394
14801395
14811396
14821397 @Callable(i)
14831398 func removeMargin (_amount) = {
14841399 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
14851400 if ((sync == sync))
14861401 then {
14871402 let _trader = toString(i.caller)
1488- if (if (if (if ((0 >= _amount))
1403+ if (if (if (if (if ((0 >= _amount))
14891404 then true
14901405 else !(requireOpenPosition(_trader)))
14911406 then true
14921407 else !(initialized()))
14931408 then true
14941409 else paused())
1410+ then true
1411+ else isMarketClosed())
14951412 then throw("Invalid removeMargin parameters")
14961413 else {
1497- let $t06277762917 = getPosition(_trader)
1498- let oldPositionSize = $t06277762917._1
1499- let oldPositionMargin = $t06277762917._2
1500- let oldPositionOpenNotional = $t06277762917._3
1501- let oldPositionLstUpdCPF = $t06277762917._4
1414+ let $t05892059060 = getPosition(_trader)
1415+ let oldPositionSize = $t05892059060._1
1416+ let oldPositionMargin = $t05892059060._2
1417+ let oldPositionOpenNotional = $t05892059060._3
1418+ let oldPositionLstUpdCPF = $t05892059060._4
15021419 let marginDelta = -(_amount)
1503- let $t06295463133 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, marginDelta)
1504- let remainMargin = $t06295463133._1
1505- let badDebt = $t06295463133._2
1420+ let $t05909759276 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, marginDelta)
1421+ let remainMargin = $t05909759276._1
1422+ let badDebt = $t05909759276._2
15061423 if ((badDebt != 0))
15071424 then throw("Invalid removed margin amount")
15081425 else {
15091426 let marginRatio = calcMarginRatio(remainMargin, badDebt, oldPositionOpenNotional)
15101427 if (!(requireMoreMarginRatio(marginRatio, initMarginRatio(), true)))
15111428 then throw(((("Too much margin removed: " + toString(marginRatio)) + " < ") + toString(initMarginRatio())))
15121429 else {
15131430 let quoteAssetStr = toBase58String(quoteAsset())
1514- let $t06357763631 = getBorrowedByTrader(_trader)
1515- let borrowed = $t06357763631._1
1516- let assetId = $t06357763631._2
1431+ let $t05972059774 = getBorrowedByTrader(_trader)
1432+ let borrowed = $t05972059774._1
1433+ let assetId = $t05972059774._2
15171434 let toRepay = if ((_amount > borrowed))
15181435 then borrowed
15191436 else _amount
15201437 let toWithdraw = if ((borrowed > _amount))
15211438 then 0
15221439 else (_amount - borrowed)
15231440 let finalBorrow = (borrowed - toRepay)
15241441 let switchPositionToQuote = if ((finalBorrow > 0))
15251442 then nil
15261443 else updatePositionAsset(_trader, quoteAssetStr)
15271444 let doSanityCheck = if (((toRepay + toWithdraw) != _amount))
15281445 then throw(((((("toRepay=" + toString(toRepay)) + " + toWithdraw=") + toString(toWithdraw)) + " != ") + toString(_amount)))
15291446 else nil
15301447 if ((doSanityCheck == doSanityCheck))
15311448 then {
15321449 let doUnstake = if ((toWithdraw > 0))
15331450 then {
15341451 let doUnstake = invoke(vaultAddress(), "withdrawLocked", [toWithdraw], nil)
15351452 if ((doUnstake == doUnstake))
15361453 then nil
15371454 else throw("Strict value is not equal to itself.")
15381455 }
15391456 else nil
15401457 if ((doUnstake == doUnstake))
15411458 then {
15421459 let returnCollateralAction = if ((toRepay > 0))
15431460 then {
15441461 let doRepay = invoke(collateralAddress(), "repay", [_trader, toRepay, assetId], nil)
15451462 if ((doRepay == doRepay))
15461463 then [ScriptTransfer(i.caller, toRepay, fromBase58String(assetId))]
15471464 else throw("Strict value is not equal to itself.")
15481465 }
15491466 else nil
15501467 if ((returnCollateralAction == returnCollateralAction))
15511468 then ((((updatePosition(_trader, oldPositionSize, remainMargin, oldPositionOpenNotional, latestCumulativePremiumFraction(oldPositionSize)) ++ (if ((toWithdraw > 0))
15521469 then withdraw(i.caller, toWithdraw)
15531470 else nil)) ++ updateBalance((cbalance() - _amount))) ++ switchPositionToQuote) ++ returnCollateralAction)
15541471 else throw("Strict value is not equal to itself.")
15551472 }
15561473 else throw("Strict value is not equal to itself.")
15571474 }
15581475 else throw("Strict value is not equal to itself.")
15591476 }
15601477 }
15611478 }
15621479 }
15631480 else throw("Strict value is not equal to itself.")
15641481 }
15651482
15661483
15671484
15681485 @Callable(i)
1569-func closePosition (_size,_minQuoteAssetAmount) = {
1486+func closePosition (_size,_minQuoteAssetAmount,_addToMargin) = {
15701487 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
15711488 if ((sync == sync))
15721489 then {
15731490 let _trader = getActualCaller(i)
15741491 let _traderAddress = valueOrErrorMessage(addressFromString(_trader), "Invalid caller")
1575- if (if (if (if (if (!(requireOpenPosition(_trader)))
1492+ let positionFee = getPositionFee(_trader)
1493+ if (if (if (if (if (if (!(requireOpenPosition(_trader)))
15761494 then true
15771495 else !(initialized()))
15781496 then true
15791497 else paused())
15801498 then true
15811499 else (0 >= _size))
15821500 then true
15831501 else (0 > _minQuoteAssetAmount))
1502+ then true
1503+ else isMarketClosed())
15841504 then throw("Invalid closePosition parameters")
15851505 else {
1586- let $t06578965929 = getPosition(_trader)
1587- let oldPositionSize = $t06578965929._1
1588- let oldPositionMargin = $t06578965929._2
1589- let oldPositionOpenNotional = $t06578965929._3
1590- let oldPositionLstUpdCPF = $t06578965929._4
1591- let $t06593570372 = if ((abs(oldPositionSize) > _size))
1506+ let $t06201162151 = getPosition(_trader)
1507+ let oldPositionSize = $t06201162151._1
1508+ let oldPositionMargin = $t06201162151._2
1509+ let oldPositionOpenNotional = $t06201162151._3
1510+ let oldPositionLstUpdCPF = $t06201162151._4
1511+ let $t06215767916 = if ((abs(oldPositionSize) > _size))
15921512 then {
1593- let _direction = if ((oldPositionSize > 0))
1594- then DIR_SHORT
1595- else DIR_LONG
1596- let isAdd = (_direction == DIR_LONG)
1597- let $t06652666748 = swapOutput((oldPositionSize > 0), _size, true)
1598- let exchangedQuoteAssetAmount = $t06652666748._1
1599- let quoteAssetReserveAfter = $t06652666748._2
1600- let baseAssetReserveAfter = $t06652666748._3
1601- let totalPositionSizeAfter = $t06652666748._4
1513+ let $t06264962871 = swapOutput((oldPositionSize > 0), _size, true)
1514+ let exchangedQuoteAssetAmount = $t06264962871._1
1515+ let quoteAssetReserveAfter = $t06264962871._2
1516+ let baseAssetReserveAfter = $t06264962871._3
1517+ let totalPositionSizeAfter = $t06264962871._4
16021518 let exchangedPositionSize = if ((oldPositionSize > 0))
16031519 then -(_size)
16041520 else _size
1605- let $t06683966993 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1606- let oldPositionNotional = $t06683966993._1
1607- let unrealizedPnl = $t06683966993._2
1521+ let $t06296263116 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1522+ let oldPositionNotional = $t06296263116._1
1523+ let unrealizedPnl = $t06296263116._2
16081524 let mr = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
16091525 let realizedRatio = divd(abs(exchangedPositionSize), abs(oldPositionSize))
16101526 let realizedPnl = muld(unrealizedPnl, realizedRatio)
1611- let $t06727267510 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl)
1612- let remainMargin = $t06727267510._1
1613- let positionBadDebt = $t06727267510._2
1614- let fundingPayment = $t06727267510._3
1527+ let realizedFee = muld(muld(oldPositionNotional, realizedRatio), positionFee)
1528+ let remainMarginBefore = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, unrealizedPnl)._1
1529+ let positionBadDebt = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl)._2
16151530 let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
16161531 let remainOpenNotional = if ((oldPositionSize > 0))
16171532 then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
16181533 else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
16191534 let newPositionOpenNotional = abs(remainOpenNotional)
1620- let newPositionMargin = muld(newPositionOpenNotional, mr)
16211535 let newPositionSize = (oldPositionSize + exchangedPositionSize)
16221536 let newPositionLstUpdCPF = latestCumulativePremiumFraction(newPositionSize)
1623- let openInterestNotionalAfter = (openInterestNotional() - exchangedQuoteAssetAmount)
1537+ let openNotionalDelta = (oldPositionOpenNotional - newPositionOpenNotional)
1538+ let openInterestNotionalAfter = (openInterestNotional() - openNotionalDelta)
1539+ let newPositionMargin = if ((oldPositionSize > 0))
1540+ then (muld((newPositionOpenNotional + unrealizedPnlAfter), mr) - unrealizedPnlAfter)
1541+ else (muld((newPositionOpenNotional - unrealizedPnlAfter), mr) - unrealizedPnlAfter)
1542+ let marginToTraderRaw = ((remainMarginBefore - (newPositionMargin + unrealizedPnlAfter)) - realizedFee)
1543+ let marginToTrader = if ((0 > marginToTraderRaw))
1544+ then throw("Margin error: unable to pay close fee")
1545+ else marginToTraderRaw
16241546 if (if ((_minQuoteAssetAmount != 0))
16251547 then (_minQuoteAssetAmount > exchangedQuoteAssetAmount)
16261548 else false)
16271549 then throw(((("Limit error: " + toString(exchangedQuoteAssetAmount)) + " < ") + toString(_minQuoteAssetAmount)))
1628- else $Tuple15(newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, positionBadDebt, realizedPnl, (abs((remainMargin - newPositionMargin)) + realizedPnl), quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, (totalLongPositionSize() - (if ((newPositionSize > 0))
1550+ else $Tuple16(newPositionSize, if (_addToMargin)
1551+ then (newPositionMargin + marginToTrader)
1552+ else newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, positionBadDebt, realizedPnl, if (_addToMargin)
1553+ then 0
1554+ else marginToTrader, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, (totalLongPositionSize() - (if ((newPositionSize > 0))
16291555 then abs(exchangedPositionSize)
16301556 else 0)), (totalShortPositionSize() - (if ((0 > newPositionSize))
16311557 then abs(exchangedPositionSize)
16321558 else 0)), (openInterestLong() - (if ((newPositionSize > 0))
1633- then exchangedQuoteAssetAmount
1559+ then openNotionalDelta
16341560 else 0)), (openInterestShort() - (if ((0 > newPositionSize))
1635- then exchangedQuoteAssetAmount
1636- else 0)))
1561+ then openNotionalDelta
1562+ else 0)), realizedFee)
16371563 }
16381564 else if ((_size > abs(oldPositionSize)))
16391565 then throw("Invalid closePosition parameters")
16401566 else {
1641- let $t06931369732 = internalClosePosition(_trader, true)
1642- let exchangedQuoteAssetAmount = $t06931369732._1
1643- let positionBadDebt = $t06931369732._2
1644- let realizedPnl = $t06931369732._3
1645- let marginToVault = $t06931369732._4
1646- let quoteAssetReserveAfter = $t06931369732._5
1647- let baseAssetReserveAfter = $t06931369732._6
1648- let totalPositionSizeAfter = $t06931369732._7
1649- let openInterestNotionalAfter = $t06931369732._8
1650- let x2 = $t06931369732._9
1651- let totalLongAfter = $t06931369732._10
1652- let totalShortAfter = $t06931369732._11
1653- let totalLongOpenInterestAfter = $t06931369732._12
1654- let totalShortOpenInterestAfter = $t06931369732._13
1567+ let $t06633566765 = internalClosePosition(_trader, true)
1568+ let x2 = $t06633566765._1
1569+ let positionBadDebt = $t06633566765._2
1570+ let realizedPnl = $t06633566765._3
1571+ let marginToTraderWithoutFee = $t06633566765._4
1572+ let quoteAssetReserveAfter = $t06633566765._5
1573+ let baseAssetReserveAfter = $t06633566765._6
1574+ let totalPositionSizeAfter = $t06633566765._7
1575+ let openInterestNotionalAfter = $t06633566765._8
1576+ let exchangedQuoteAssetAmount = $t06633566765._9
1577+ let totalLongAfter = $t06633566765._10
1578+ let totalShortAfter = $t06633566765._11
1579+ let totalLongOpenInterestAfter = $t06633566765._12
1580+ let totalShortOpenInterestAfter = $t06633566765._13
1581+ let realizedFee = muld(exchangedQuoteAssetAmount, positionFee)
1582+ let marginToTraderRaw = (abs(marginToTraderWithoutFee) - realizedFee)
1583+ let marginToTrader = if ((0 > marginToTraderRaw))
1584+ then throw(((((((("Margin error: unable to pay close fee: " + toString(realizedFee)) + " margin: ") + toString(marginToTraderWithoutFee)) + " fee percent: ") + toString(positionFee)) + " notional: ") + toString(exchangedQuoteAssetAmount)))
1585+ else marginToTraderRaw
16551586 if (if ((_minQuoteAssetAmount != 0))
16561587 then (_minQuoteAssetAmount > exchangedQuoteAssetAmount)
16571588 else false)
16581589 then throw(((("Limit error: " + toString(exchangedQuoteAssetAmount)) + " < ") + toString(_minQuoteAssetAmount)))
1659- else $Tuple15(0, 0, 0, 0, positionBadDebt, realizedPnl, marginToVault, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)
1590+ else $Tuple16(0, 0, 0, 0, positionBadDebt, realizedPnl, marginToTrader, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter, realizedFee)
16601591 }
1661- let newPositionSize = $t06593570372._1
1662- let newPositionMargin = $t06593570372._2
1663- let newPositionOpenNotional = $t06593570372._3
1664- let newPositionLstUpdCPF = $t06593570372._4
1665- let positionBadDebt = $t06593570372._5
1666- let realizedPnl = $t06593570372._6
1667- let marginToVault = $t06593570372._7
1668- let quoteAssetReserveAfter = $t06593570372._8
1669- let baseAssetReserveAfter = $t06593570372._9
1670- let totalPositionSizeAfter = $t06593570372._10
1671- let openInterestNotionalAfter = $t06593570372._11
1672- let totalLongAfter = $t06593570372._12
1673- let totalShortAfter = $t06593570372._13
1674- let totalLongOpenInterestAfter = $t06593570372._14
1675- let totalShortOpenInterestAfter = $t06593570372._15
1592+ let newPositionSize = $t06215767916._1
1593+ let newPositionMargin = $t06215767916._2
1594+ let newPositionOpenNotional = $t06215767916._3
1595+ let newPositionLstUpdCPF = $t06215767916._4
1596+ let positionBadDebt = $t06215767916._5
1597+ let realizedPnl = $t06215767916._6
1598+ let marginToTrader = $t06215767916._7
1599+ let quoteAssetReserveAfter = $t06215767916._8
1600+ let baseAssetReserveAfter = $t06215767916._9
1601+ let totalPositionSizeAfter = $t06215767916._10
1602+ let openInterestNotionalAfter = $t06215767916._11
1603+ let totalLongAfter = $t06215767916._12
1604+ let totalShortAfter = $t06215767916._13
1605+ let totalLongOpenInterestAfter = $t06215767916._14
1606+ let totalShortOpenInterestAfter = $t06215767916._15
1607+ let realizedFee = $t06215767916._16
16761608 if ((positionBadDebt > 0))
16771609 then throw("Unable to close position with bad debt")
16781610 else {
1679- let withdrawAmount = abs(marginToVault)
1611+ let isPartialClose = (newPositionSize != 0)
1612+ let withdrawAmount = (marginToTrader + realizedFee)
16801613 let ammBalance = (cbalance() - withdrawAmount)
1681- let $t07058170788 = if ((0 > ammBalance))
1614+ let $t06818368390 = if ((0 > ammBalance))
16821615 then $Tuple2(0, abs(ammBalance))
16831616 else $Tuple2(ammBalance, 0)
1684- let ammNewBalance = $t07058170788._1
1685- let x11 = $t07058170788._2
1686- let $t07079570849 = getBorrowedByTrader(_trader)
1687- let borrowed = $t07079570849._1
1688- let assetId = $t07079570849._2
1689- let $t07086471723 = if ((borrowed > 0))
1617+ let ammNewBalance = $t06818368390._1
1618+ let x11 = $t06818368390._2
1619+ let $t06839768451 = getBorrowedByTrader(_trader)
1620+ let borrowed = $t06839768451._1
1621+ let assetId = $t06839768451._2
1622+ let $t06845969319 = if ((borrowed > 0))
16901623 then if ((withdrawAmount >= borrowed))
16911624 then {
16921625 let doRepay = invoke(collateralAddress(), "repay", [_trader, borrowed, assetId], nil)
16931626 if ((doRepay == doRepay))
1694- then $Tuple2([ScriptTransfer(_traderAddress, borrowed, fromBase58String(assetId))], (withdrawAmount - borrowed))
1627+ then $Tuple3(borrowed, (withdrawAmount - borrowed), isPartialClose)
16951628 else throw("Strict value is not equal to itself.")
16961629 }
16971630 else {
1698- let realizeAndClose = invoke(collateralAddress(), "realizePartiallyAndClose", [_trader, withdrawAmount, assetId], nil)
1631+ let realizeAndClose = invoke(collateralAddress(), if (isPartialClose)
1632+ then "repay"
1633+ else "realizePartiallyAndClose", [_trader, withdrawAmount, assetId], nil)
16991634 if ((realizeAndClose == realizeAndClose))
1700- then $Tuple2([ScriptTransfer(_traderAddress, withdrawAmount, fromBase58String(assetId))], 0)
1635+ then $Tuple3(withdrawAmount, 0, false)
17011636 else throw("Strict value is not equal to itself.")
17021637 }
1703- else $Tuple2(nil, withdrawAmount)
1704- if (($t07086471723 == $t07086471723))
1638+ else $Tuple3(0, withdrawAmount, false)
1639+ if (($t06845969319 == $t06845969319))
17051640 then {
1706- let quoteWithdrawAmount = $t07086471723._2
1707- let sendCollateralAction = $t07086471723._1
1708- let unstake = if ((quoteWithdrawAmount > 0))
1709- then {
1710- let unstake = invoke(vaultAddress(), "withdrawLocked", [quoteWithdrawAmount], nil)
1711- if ((unstake == unstake))
1712- then nil
1641+ let switchToQuote = $t06845969319._3
1642+ let quoteWithdrawAmountBeforeFee = $t06845969319._2
1643+ let assetWithdrawAmountBeforeFee = $t06845969319._1
1644+ let $t06932770394 = if ((quoteWithdrawAmountBeforeFee >= realizedFee))
1645+ then $Tuple3(assetWithdrawAmountBeforeFee, (quoteWithdrawAmountBeforeFee - realizedFee), realizedFee)
1646+ else {
1647+ let feeLeftToWithdrawFromAsset = (realizedFee - quoteWithdrawAmountBeforeFee)
1648+ let assetWithdrawAmountAfterFee = (assetWithdrawAmountBeforeFee - feeLeftToWithdrawFromAsset)
1649+ let balanceBefore = assetBalance(this, quoteAsset())
1650+ if ((balanceBefore == balanceBefore))
1651+ then {
1652+ let doSwap = invoke(swapAddress(), "swap", [toBase58String(quoteAsset()), 0], [AttachedPayment(fromBase58String(assetId), feeLeftToWithdrawFromAsset)])
1653+ if ((doSwap == doSwap))
1654+ then {
1655+ let balanceAfter = assetBalance(this, quoteAsset())
1656+ if ((balanceAfter == balanceAfter))
1657+ then {
1658+ let exchangedAmount = (balanceAfter - balanceBefore)
1659+ if ((exchangedAmount == exchangedAmount))
1660+ then $Tuple3(assetWithdrawAmountAfterFee, 0, (quoteWithdrawAmountBeforeFee + exchangedAmount))
1661+ else throw("Strict value is not equal to itself.")
1662+ }
1663+ else throw("Strict value is not equal to itself.")
1664+ }
1665+ else throw("Strict value is not equal to itself.")
1666+ }
17131667 else throw("Strict value is not equal to itself.")
17141668 }
1715- else nil
1716- if ((unstake == unstake))
1669+ if (($t06932770394 == $t06932770394))
17171670 then {
1718- let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, 0], nil)
1719- if ((notifyNotional == notifyNotional))
1720- then (((((if ((newPositionSize == 0))
1721- then deletePosition(_trader)
1722- else updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ (if ((quoteWithdrawAmount > 0))
1723- then withdraw(_traderAddress, quoteWithdrawAmount)
1724- else nil)) ++ updateBalance(ammNewBalance)) ++ sendCollateralAction)
1671+ let actualFeeInQuoteAsset = $t06932770394._3
1672+ let quoteWithdrawAmountAfterFee = $t06932770394._2
1673+ let assetWithdrawAmountAfterFee = $t06932770394._1
1674+ let unstake = if ((quoteWithdrawAmountBeforeFee > 0))
1675+ then {
1676+ let unstake = invoke(vaultAddress(), "withdrawLocked", [quoteWithdrawAmountBeforeFee], nil)
1677+ if ((unstake == unstake))
1678+ then nil
1679+ else throw("Strict value is not equal to itself.")
1680+ }
1681+ else nil
1682+ if ((unstake == unstake))
1683+ then {
1684+ let $t07066870737 = distributeFee(actualFeeInQuoteAsset)
1685+ let feeToStakers = $t07066870737._1
1686+ let feeToVault = $t07066870737._2
1687+ let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1688+ if ((depositVault == depositVault))
1689+ then {
1690+ let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, realizedFee], nil)
1691+ if ((notifyFee == notifyFee))
1692+ then {
1693+ let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
1694+ if ((notifyNotional == notifyNotional))
1695+ then (((((((if (isPartialClose)
1696+ then updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF)
1697+ else deletePosition(_trader)) ++ (if (switchToQuote)
1698+ then {
1699+ let quoteAssetStr = toBase58String(quoteAsset())
1700+ updatePositionAsset(_trader, quoteAssetStr)
1701+ }
1702+ else nil)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ transferFee(feeToStakers)) ++ (if ((quoteWithdrawAmountAfterFee > 0))
1703+ then withdraw(_traderAddress, quoteWithdrawAmountAfterFee)
1704+ else nil)) ++ updateBalance(ammNewBalance)) ++ (if ((assetWithdrawAmountAfterFee > 0))
1705+ then [ScriptTransfer(_traderAddress, assetWithdrawAmountAfterFee, fromBase58String(assetId))]
1706+ else nil))
1707+ else throw("Strict value is not equal to itself.")
1708+ }
1709+ else throw("Strict value is not equal to itself.")
1710+ }
1711+ else throw("Strict value is not equal to itself.")
1712+ }
17251713 else throw("Strict value is not equal to itself.")
17261714 }
17271715 else throw("Strict value is not equal to itself.")
17281716 }
17291717 else throw("Strict value is not equal to itself.")
17301718 }
17311719 }
17321720 }
17331721 else throw("Strict value is not equal to itself.")
17341722 }
17351723
17361724
17371725
17381726 @Callable(i)
17391727 func liquidate (_trader) = {
17401728 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
17411729 if ((sync == sync))
17421730 then {
17431731 let spotMarginRatio = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
17441732 let marginRatio = if (isOverFluctuationLimit())
17451733 then {
17461734 let oracleMarginRatio = getMarginRatioByOption(_trader, PNL_OPTION_ORACLE)
17471735 vmax(spotMarginRatio, oracleMarginRatio)
17481736 }
17491737 else spotMarginRatio
1750- if (if (if (if (!(requireMoreMarginRatio(marginRatio, maintenanceMarginRatio(), false)))
1738+ if (if (if (if (if (!(requireMoreMarginRatio(marginRatio, maintenanceMarginRatio(), false)))
17511739 then true
17521740 else !(requireOpenPosition(_trader)))
17531741 then true
17541742 else !(initialized()))
17551743 then true
17561744 else paused())
1745+ then true
1746+ else isMarketClosed())
17571747 then throw("Unable to liquidate")
17581748 else if (if (if ((spotMarginRatio > liquidationFeeRatio()))
17591749 then (partialLiquidationRatio() > 0)
17601750 else false)
17611751 then (DECIMAL_UNIT > partialLiquidationRatio())
17621752 else false)
17631753 then {
1764- let $t07402074170 = getPosition(_trader)
1765- let oldPositionSize = $t07402074170._1
1766- let oldPositionMargin = $t07402074170._2
1767- let oldPositionOpenNotional = $t07402074170._3
1768- let oldPositionLstUpdCPF = $t07402074170._4
1754+ let $t07349073640 = getPosition(_trader)
1755+ let oldPositionSize = $t07349073640._1
1756+ let oldPositionMargin = $t07349073640._2
1757+ let oldPositionOpenNotional = $t07349073640._3
1758+ let oldPositionLstUpdCPF = $t07349073640._4
17691759 let _direction = if ((oldPositionSize > 0))
17701760 then DIR_SHORT
17711761 else DIR_LONG
17721762 let isAdd = (_direction == DIR_LONG)
17731763 let exchangedQuoteAssetAmount = getPartialLiquidationAmount(_trader, oldPositionSize)
1774- let $t07439574499 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1775- let oldPositionNotional = $t07439574499._1
1776- let unrealizedPnl = $t07439574499._2
1777- let $t07450774694 = swapInput(isAdd, exchangedQuoteAssetAmount)
1778- let exchangedPositionSize = $t07450774694._1
1779- let quoteAssetReserveAfter = $t07450774694._2
1780- let baseAssetReserveAfter = $t07450774694._3
1781- let totalPositionSizeAfter = $t07450774694._4
1764+ let $t07386573969 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1765+ let oldPositionNotional = $t07386573969._1
1766+ let unrealizedPnl = $t07386573969._2
1767+ let $t07397774164 = swapInput(isAdd, exchangedQuoteAssetAmount)
1768+ let exchangedPositionSize = $t07397774164._1
1769+ let quoteAssetReserveAfter = $t07397774164._2
1770+ let baseAssetReserveAfter = $t07397774164._3
1771+ let totalPositionSizeAfter = $t07397774164._4
17821772 let liquidationRatio = divd(abs(exchangedPositionSize), abs(oldPositionSize))
17831773 let realizedPnl = muld(unrealizedPnl, liquidationRatio)
1784- let $t07498375216 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl)
1785- let remainMargin = $t07498375216._1
1786- let badDebt = $t07498375216._2
1787- let fundingPayment = $t07498375216._3
1774+ let $t07445374686 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl)
1775+ let remainMargin = $t07445374686._1
1776+ let badDebt = $t07445374686._2
1777+ let fundingPayment = $t07445374686._3
17881778 let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
17891779 let remainOpenNotional = if ((oldPositionSize > 0))
17901780 then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
17911781 else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
17921782 let liquidationPenalty = muld(exchangedQuoteAssetAmount, liquidationFeeRatio())
17931783 let feeToLiquidator = (liquidationPenalty / 2)
17941784 let feeToVault = (liquidationPenalty - feeToLiquidator)
17951785 let newPositionMargin = (remainMargin - liquidationPenalty)
17961786 let newPositionSize = (oldPositionSize + exchangedPositionSize)
17971787 let newPositionOpenNotional = abs(remainOpenNotional)
1788+ let openNotionalDelta = (oldPositionOpenNotional - newPositionOpenNotional)
17981789 let newPositionLstUpdCPF = latestCumulativePremiumFraction(newPositionSize)
1799- let openInterestNotionalAfter = (openInterestNotional() - exchangedQuoteAssetAmount)
1790+ let openInterestNotionalAfter = (openInterestNotional() - openNotionalDelta)
18001791 let ammBalance = (cbalance() - liquidationPenalty)
1801- let $t07638576514 = if ((0 > ammBalance))
1792+ let $t07592776056 = if ((0 > ammBalance))
18021793 then $Tuple2(0, abs(ammBalance))
18031794 else $Tuple2(ammBalance, 0)
1804- let newAmmBalance = $t07638576514._1
1805- let x11 = $t07638576514._2
1806- let $t07652276576 = getBorrowedByTrader(_trader)
1807- let borrowed = $t07652276576._1
1808- let assetId = $t07652276576._2
1795+ let newAmmBalance = $t07592776056._1
1796+ let x11 = $t07592776056._2
1797+ let $t07606476118 = getBorrowedByTrader(_trader)
1798+ let borrowed = $t07606476118._1
1799+ let assetId = $t07606476118._2
18091800 let doLiquidateCollateral = if ((borrowed > 0))
18101801 then {
18111802 let collateralToSell = muld(borrowed, liquidationRatio)
18121803 let realizeAndClose = invoke(collateralAddress(), "realizePartially", [_trader, assetId, collateralToSell], nil)
18131804 if ((realizeAndClose == realizeAndClose))
18141805 then nil
18151806 else throw("Strict value is not equal to itself.")
18161807 }
18171808 else nil
18181809 if ((doLiquidateCollateral == doLiquidateCollateral))
18191810 then {
18201811 let unstake = invoke(vaultAddress(), "withdrawLocked", [liquidationPenalty], nil)
18211812 if ((unstake == unstake))
18221813 then {
18231814 let depositInsurance = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
18241815 if ((depositInsurance == depositInsurance))
18251816 then {
18261817 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
18271818 if ((notifyNotional == notifyNotional))
18281819 then (((updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, (totalLongPositionSize() - (if ((newPositionSize > 0))
18291820 then abs(exchangedPositionSize)
18301821 else 0)), (totalShortPositionSize() - (if ((0 > newPositionSize))
18311822 then abs(exchangedPositionSize)
18321823 else 0)), (openInterestLong() - (if ((newPositionSize > 0))
1833- then exchangedQuoteAssetAmount
1824+ then openNotionalDelta
18341825 else 0)), (openInterestShort() - (if ((0 > newPositionSize))
1835- then exchangedQuoteAssetAmount
1826+ then openNotionalDelta
18361827 else 0)))) ++ withdraw(i.caller, feeToLiquidator)) ++ updateBalance(newAmmBalance))
18371828 else throw("Strict value is not equal to itself.")
18381829 }
18391830 else throw("Strict value is not equal to itself.")
18401831 }
18411832 else throw("Strict value is not equal to itself.")
18421833 }
18431834 else throw("Strict value is not equal to itself.")
18441835 }
18451836 else {
1846- let $t07827178766 = internalClosePosition(_trader, false)
1847- let x1 = $t07827178766._1
1848- let badDebt = $t07827178766._2
1849- let x2 = $t07827178766._3
1850- let x3 = $t07827178766._4
1851- let quoteAssetReserveAfter = $t07827178766._5
1852- let baseAssetReserveAfter = $t07827178766._6
1853- let totalPositionSizeAfter = $t07827178766._7
1854- let openInterestNotionalAfter = $t07827178766._8
1855- let exchangedQuoteAssetAmount = $t07827178766._9
1856- let totalLongAfter = $t07827178766._10
1857- let totalShortAfter = $t07827178766._11
1858- let totalLongOpenInterestAfter = $t07827178766._12
1859- let totalShortOpenInterestAfter = $t07827178766._13
1837+ let $t07779778292 = internalClosePosition(_trader, false)
1838+ let x1 = $t07779778292._1
1839+ let badDebt = $t07779778292._2
1840+ let x2 = $t07779778292._3
1841+ let x3 = $t07779778292._4
1842+ let quoteAssetReserveAfter = $t07779778292._5
1843+ let baseAssetReserveAfter = $t07779778292._6
1844+ let totalPositionSizeAfter = $t07779778292._7
1845+ let openInterestNotionalAfter = $t07779778292._8
1846+ let exchangedQuoteAssetAmount = $t07779778292._9
1847+ let totalLongAfter = $t07779778292._10
1848+ let totalShortAfter = $t07779778292._11
1849+ let totalLongOpenInterestAfter = $t07779778292._12
1850+ let totalShortOpenInterestAfter = $t07779778292._13
18601851 let liquidationPenalty = muld(exchangedQuoteAssetAmount, liquidationFeeRatio())
18611852 let feeToLiquidator = (liquidationPenalty / 2)
18621853 let feeToVault = (liquidationPenalty - feeToLiquidator)
18631854 let ammBalance = (cbalance() - liquidationPenalty)
1864- let $t07917479303 = if ((0 > ammBalance))
1855+ let $t07870078829 = if ((0 > ammBalance))
18651856 then $Tuple2(0, abs(ammBalance))
18661857 else $Tuple2(ammBalance, 0)
1867- let newAmmBalance = $t07917479303._1
1868- let x11 = $t07917479303._2
1869- let $t07931179365 = getBorrowedByTrader(_trader)
1870- let borrowed = $t07931179365._1
1871- let assetId = $t07931179365._2
1858+ let newAmmBalance = $t07870078829._1
1859+ let x11 = $t07870078829._2
1860+ let $t07883778891 = getBorrowedByTrader(_trader)
1861+ let borrowed = $t07883778891._1
1862+ let assetId = $t07883778891._2
18721863 let doLiquidateCollateral = if ((borrowed > 0))
18731864 then {
18741865 let realizeAndClose = invoke(collateralAddress(), "realizePartiallyAndClose", [_trader, 0, assetId], nil)
18751866 if ((realizeAndClose == realizeAndClose))
18761867 then nil
18771868 else throw("Strict value is not equal to itself.")
18781869 }
18791870 else nil
18801871 if ((doLiquidateCollateral == doLiquidateCollateral))
18811872 then {
18821873 let x = if ((badDebt > 0))
18831874 then {
18841875 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [badDebt], nil)
18851876 if ((lockBadDebt == lockBadDebt))
18861877 then nil
18871878 else throw("Strict value is not equal to itself.")
18881879 }
18891880 else nil
18901881 if ((x == x))
18911882 then {
18921883 let unstake = invoke(vaultAddress(), "withdrawLocked", [liquidationPenalty], nil)
18931884 if ((unstake == unstake))
18941885 then {
18951886 let depositInsurance = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
18961887 if ((depositInsurance == depositInsurance))
18971888 then {
18981889 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, 0], nil)
18991890 if ((notifyNotional == notifyNotional))
19001891 then (((deletePosition(_trader) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ withdraw(i.caller, feeToLiquidator)) ++ updateBalance(newAmmBalance))
19011892 else throw("Strict value is not equal to itself.")
19021893 }
19031894 else throw("Strict value is not equal to itself.")
19041895 }
19051896 else throw("Strict value is not equal to itself.")
19061897 }
19071898 else throw("Strict value is not equal to itself.")
19081899 }
19091900 else throw("Strict value is not equal to itself.")
19101901 }
19111902 }
19121903 else throw("Strict value is not equal to itself.")
19131904 }
19141905
19151906
19161907
19171908 @Callable(i)
19181909 func payFunding () = {
1919- let fundingBlockTimestamp = nextFundingBlockTimestamp()
1920- if (if (if ((fundingBlockTimestamp > lastBlock.timestamp))
1921- then true
1922- else !(initialized()))
1923- then true
1924- else paused())
1925- then throw(((("Invalid funding block timestamp: " + toString(lastBlock.timestamp)) + " < ") + toString(fundingBlockTimestamp)))
1926- else {
1927- let underlyingPrice = getOracleTwapPrice()
1928- let $t08117281234 = getFunding()
1929- let shortPremiumFraction = $t08117281234._1
1930- let longPremiumFraction = $t08117281234._2
1931- updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice))
1932- }
1910+ let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
1911+ if ((sync == sync))
1912+ then {
1913+ let fundingBlockTimestamp = nextFundingBlockTimestamp()
1914+ if (if (if ((fundingBlockTimestamp > lastBlock.timestamp))
1915+ then true
1916+ else !(initialized()))
1917+ then true
1918+ else paused())
1919+ then throw(((("Invalid funding block timestamp: " + toString(lastBlock.timestamp)) + " < ") + toString(fundingBlockTimestamp)))
1920+ else {
1921+ let underlyingPrice = getOraclePrice()
1922+ let $t08076380825 = getFunding()
1923+ let shortPremiumFraction = $t08076380825._1
1924+ let longPremiumFraction = $t08076380825._2
1925+ updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice))
1926+ }
1927+ }
1928+ else throw("Strict value is not equal to itself.")
19331929 }
19341930
19351931
19361932
19371933 @Callable(i)
19381934 func syncTerminalPriceToOracle () = {
1939- let $t08161681737 = getSyncTerminalPrice(getOracleTwapPrice())
1940- let newQuoteAssetWeight = $t08161681737._1
1941- let newBaseAssetWeight = $t08161681737._2
1942- let marginToVault = $t08161681737._3
1935+ let _qtAstR = qtAstR()
1936+ let _bsAstR = bsAstR()
1937+ let $t08125781392 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1938+ let newQuoteAssetWeight = $t08125781392._1
1939+ let newBaseAssetWeight = $t08125781392._2
1940+ let marginToVault = $t08125781392._3
19431941 let doExchangePnL = if ((marginToVault != 0))
19441942 then {
19451943 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
19461944 if ((doExchangePnL == doExchangePnL))
19471945 then nil
19481946 else throw("Strict value is not equal to itself.")
19491947 }
19501948 else nil
19511949 if ((doExchangePnL == doExchangePnL))
1952- then updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight)
1950+ then (updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight) ++ appendTwap(divd(muld(_qtAstR, newQuoteAssetWeight), muld(_bsAstR, newBaseAssetWeight))))
19531951 else throw("Strict value is not equal to itself.")
19541952 }
19551953
19561954
19571955
19581956 @Callable(i)
19591957 func view_calcRemainMarginWithFundingPayment (_trader) = {
19601958 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
19611959 if ((sync == sync))
19621960 then {
1963- let $t08221382314 = getPosition(_trader)
1964- let positionSize = $t08221382314._1
1965- let positionMargin = $t08221382314._2
1966- let pon = $t08221382314._3
1967- let positionLstUpdCPF = $t08221382314._4
1968- let $t08231782418 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1969- let positionNotional = $t08231782418._1
1970- let unrealizedPnl = $t08231782418._2
1971- let $t08242182593 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
1972- let remainMargin = $t08242182593._1
1973- let badDebt = $t08242182593._2
1974- let fundingPayment = $t08242182593._3
1961+ let $t08196182062 = getPosition(_trader)
1962+ let positionSize = $t08196182062._1
1963+ let positionMargin = $t08196182062._2
1964+ let pon = $t08196182062._3
1965+ let positionLstUpdCPF = $t08196182062._4
1966+ let $t08206582166 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1967+ let positionNotional = $t08206582166._1
1968+ let unrealizedPnl = $t08206582166._2
1969+ let $t08216982341 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
1970+ let remainMargin = $t08216982341._1
1971+ let badDebt = $t08216982341._2
1972+ let fundingPayment = $t08216982341._3
19751973 throw((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)))
19761974 }
19771975 else throw("Strict value is not equal to itself.")
19781976 }
19791977
19801978
19811979
19821980 @Callable(i)
19831981 func view_getPegAdjustCost (_price) = {
1984- let result = getSyncTerminalPrice(_price)
1982+ let _qtAstR = qtAstR()
1983+ let _bsAstR = bsAstR()
1984+ let result = getSyncTerminalPrice(_price, _qtAstR, _bsAstR)
19851985 throw(toString(result._3))
19861986 }
19871987
19881988
19891989
19901990 @Callable(i)
19911991 func view_getTerminalAmmPrice () = {
1992- let $t08294083021 = getTerminalAmmState()
1993- let terminalQuoteAssetReserve = $t08294083021._1
1994- let terminalBaseAssetReserve = $t08294083021._2
1992+ let $t08275782838 = getTerminalAmmState()
1993+ let terminalQuoteAssetReserve = $t08275782838._1
1994+ let terminalBaseAssetReserve = $t08275782838._2
19951995 let price = divd(muld(terminalQuoteAssetReserve, qtAstW()), muld(terminalBaseAssetReserve, bsAstW()))
19961996 throw(toString(price))
19971997 }
19981998
19991999
20002000
20012001 @Callable(i)
20022002 func view_getFunding () = {
2003- let underlyingPrice = getOracleTwapPrice()
2004- let $t08324083302 = getFunding()
2005- let shortPremiumFraction = $t08324083302._1
2006- let longPremiumFraction = $t08324083302._2
2003+ let underlyingPrice = getOraclePrice()
2004+ let $t08305383115 = getFunding()
2005+ let shortPremiumFraction = $t08305383115._1
2006+ let longPremiumFraction = $t08305383115._2
20072007 let longFunding = divd(longPremiumFraction, underlyingPrice)
20082008 let shortFunding = divd(shortPremiumFraction, underlyingPrice)
2009- throw((((s(longFunding) + s(shortFunding)) + s(getTwapSpotPrice())) + s(getOracleTwapPrice())))
2009+ throw((((s(longFunding) + s(shortFunding)) + s(getTwapSpotPrice())) + s(getOraclePrice())))
20102010 }
20112011
20122012
20132013
20142014 @Callable(i)
20152015 func view_getBorrowedByTrader (_trader) = {
2016- let $t08359283646 = getBorrowedByTrader(_trader)
2017- let borrowed = $t08359283646._1
2018- let assetId = $t08359283646._2
2016+ let $t08340183455 = getBorrowedByTrader(_trader)
2017+ let borrowed = $t08340183455._1
2018+ let assetId = $t08340183455._2
20192019 throw((s(borrowed) + assetId))
20202020 }
20212021
20222022
20232023
20242024 @Callable(i)
20252025 func computeSpotPrice () = {
20262026 let result = getSpotPrice()
20272027 $Tuple2(nil, result)
20282028 }
20292029
20302030
20312031
20322032 @Callable(i)
20332033 func computeFeeForTraderWithArtifact (_trader,_artifactId) = {
20342034 let result = getForTraderWithArtifact(_trader, _artifactId)
20352035 $Tuple2(nil, result)
20362036 }
20372037
20382038
20392039 @Verifier(tx)
20402040 func verify () = sigVerify(tx.bodyBytes, tx.proofs[0], adminPublicKey())
20412041

github/deemru/w8io/c3f4982 
301.32 ms