tx · 55a9BMiBtVZw1LcNSVCNgmPnqSwbnVDoS2VJij6DDpUd

3NC3GcwFK9knYYKT2SRc7nWxc5SXc2aKBQ6:  -0.07500000 Waves

2023.01.21 20:05 [2415004] smart account 3NC3GcwFK9knYYKT2SRc7nWxc5SXc2aKBQ6 > SELF 0.00000000 Waves

{ "type": 13, "id": "55a9BMiBtVZw1LcNSVCNgmPnqSwbnVDoS2VJij6DDpUd", "fee": 7500000, "feeAssetId": null, "timestamp": 1674320697045, "version": 2, "chainId": 84, "sender": "3NC3GcwFK9knYYKT2SRc7nWxc5SXc2aKBQ6", "senderPublicKey": "5GAkpjTakesSgVm3A22kYMBvNpM8C1KpqWfyC7YyB84y", "proofs": [ "261QzFJGUBVMbpi2Aam2pBy2jGk2Wmfk33ZAjMtkSB1NYv8dp4DjssMTTn4emKryxSdFGyJfTRrLFKVFifjGvpeC" ], "script": "base64:BgJxCAISABIAEgASABIDCgEBEgMKAQESDwoNAQEBAQEBAQEBAQEBARIVChMBAQEBAQEBCAgICAEBAQEBAQEBEgYKBAEBAQgSABIDCgEBEgUKAwEBBBIDCgEIEgASABIDCgEIEgMKAQESABIAEgASBAoCCAjEAQAJa19vcmFfa2V5AglrX29yYV9rZXkAD2tfb3JhX2Jsb2NrX2tleQIPa19vcmFfYmxvY2tfa2V5AA5rX29yYV9vcGVuX2tleQIOa19vcmFfb3Blbl9rZXkABWtfb3JhAgVrX29yYQAJa19iYWxhbmNlAglrX2JhbGFuY2UACmtfc2VxdWVuY2UCCmtfc2VxdWVuY2UADmtfcG9zaXRpb25TaXplAg5rX3Bvc2l0aW9uU2l6ZQAQa19wb3NpdGlvbk1hcmdpbgIQa19wb3NpdGlvbk1hcmdpbgAWa19wb3NpdGlvbk9wZW5Ob3Rpb25hbAIWa19wb3NpdGlvbk9wZW5Ob3Rpb25hbAAua19wb3NpdGlvbkxhc3RVcGRhdGVkQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgISa19wb3NpdGlvbkZyYWN0aW9uABJrX3Bvc2l0aW9uU2VxdWVuY2UCEmtfcG9zaXRpb25TZXF1ZW5jZQAPa19wb3NpdGlvbkFzc2V0Ag9rX3Bvc2l0aW9uQXNzZXQADWtfcG9zaXRpb25GZWUCDWtfcG9zaXRpb25GZWUAHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAITa19wb3NpdGlvblRpbWVzdGFtcAANa19pbml0aWFsaXplZAINa19pbml0aWFsaXplZAAIa19wYXVzZWQCCGtfcGF1c2VkAAtrX2Nsb3NlT25seQILa19jbG9zZU9ubHkABWtfZmVlAgVrX2ZlZQANa19yb2xsb3ZlckZlZQIOa19yb2xsb3Zlcl9mZWUAD2tfZnVuZGluZ1BlcmlvZAIPa19mdW5kaW5nUGVyaW9kABFrX2luaXRNYXJnaW5SYXRpbwIRa19pbml0TWFyZ2luUmF0aW8AGGtfbWFpbnRlbmFuY2VNYXJnaW5SYXRpbwIFa19tbXIAFWtfbGlxdWlkYXRpb25GZWVSYXRpbwIVa19saXF1aWRhdGlvbkZlZVJhdGlvABlrX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAhZrX3BhcnRMaXF1aWRhdGlvblJhdGlvAA1rX3NwcmVhZExpbWl0Ag1rX3NwcmVhZExpbWl0ABBrX21heFByaWNlSW1wYWN0AhBrX21heFByaWNlSW1wYWN0ABBrX21heFByaWNlU3ByZWFkAhBrX21heFByaWNlU3ByZWFkABFrX21heE9wZW5Ob3Rpb25hbAIRa19tYXhPcGVuTm90aW9uYWwAFWtfZmVlVG9TdGFrZXJzUGVyY2VudAIVa19mZWVUb1N0YWtlcnNQZXJjZW50ABBrX21heE9yYWNsZURlbGF5AhBrX21heE9yYWNsZURlbGF5AA1rX2xhc3REYXRhU3RyAg1rX2xhc3REYXRhU3RyAA5rX2xhc3RNaW51dGVJZAIOa19sYXN0TWludXRlSWQAHWtfdHdhcERhdGFMYXN0Q3VtdWxhdGl2ZVByaWNlAh1rX3R3YXBEYXRhTGFzdEN1bXVsYXRpdmVQcmljZQATa190d2FwRGF0YUxhc3RQcmljZQITa190d2FwRGF0YUxhc3RQcmljZQAaa190d2FwRGF0YVByZXZpb3VzTWludXRlSWQCGmtfdHdhcERhdGFQcmV2aW91c01pbnV0ZUlkACVrX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAhtrX2xhdGVzdExvbmdQcmVtaXVtRnJhY3Rpb24AJmtfbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAhxrX2xhdGVzdFNob3J0UHJlbWl1bUZyYWN0aW9uABJrX25leHRGdW5kaW5nQmxvY2sCHmtfbmV4dEZ1bmRpbmdCbG9ja01pblRpbWVzdGFtcAARa19sb25nRnVuZGluZ1JhdGUCEWtfbG9uZ0Z1bmRpbmdSYXRlABJrX3Nob3J0RnVuZGluZ1JhdGUCEmtfc2hvcnRGdW5kaW5nUmF0ZQATa19xdW90ZUFzc2V0UmVzZXJ2ZQIIa19xdEFzdFIAEmtfYmFzZUFzc2V0UmVzZXJ2ZQIIa19ic0FzdFIAEmtfcXVvdGVBc3NldFdlaWdodAIIa19xdEFzdFcAEWtfYmFzZUFzc2V0V2VpZ2h0AghrX2JzQXN0VwATa190b3RhbFBvc2l0aW9uU2l6ZQITa190b3RhbFBvc2l0aW9uU2l6ZQAXa190b3RhbExvbmdQb3NpdGlvblNpemUCF2tfdG90YWxMb25nUG9zaXRpb25TaXplABhrX3RvdGFsU2hvcnRQb3NpdGlvblNpemUCGGtfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAWa19vcGVuSW50ZXJlc3ROb3Rpb25hbAIWa19vcGVuSW50ZXJlc3ROb3Rpb25hbAATa19vcGVuSW50ZXJlc3RTaG9ydAITa19vcGVuSW50ZXJlc3RTaG9ydAASa19vcGVuSW50ZXJlc3RMb25nAhJrX29wZW5JbnRlcmVzdExvbmcAFGtfY29vcmRpbmF0b3JBZGRyZXNzAhRrX2Nvb3JkaW5hdG9yQWRkcmVzcwAPa192YXVsdF9hZGRyZXNzAg9rX3ZhdWx0X2FkZHJlc3MAD2tfYWRtaW5fYWRkcmVzcwIPa19hZG1pbl9hZGRyZXNzABJrX2FkbWluX3B1YmxpY19rZXkCEmtfYWRtaW5fcHVibGljX2tleQANa19xdW90ZV9hc3NldAINa19xdW90ZV9hc3NldAAPa19xdW90ZV9zdGFraW5nAg9rX3F1b3RlX3N0YWtpbmcAEWtfc3Rha2luZ19hZGRyZXNzAhFrX3N0YWtpbmdfYWRkcmVzcwAPa19taW5lcl9hZGRyZXNzAg9rX21pbmVyX2FkZHJlc3MAEGtfb3JkZXJzX2FkZHJlc3MCEGtfb3JkZXJzX2FkZHJlc3MAEmtfcmVmZXJyYWxfYWRkcmVzcwISa19yZWZlcnJhbF9hZGRyZXNzABJrX2V4Y2hhbmdlX2FkZHJlc3MCEmtfZXhjaGFuZ2VfYWRkcmVzcwAVa19uZnRfbWFuYWdlcl9hZGRyZXNzAhVrX25mdF9tYW5hZ2VyX2FkZHJlc3MBDnRvQ29tcG9zaXRlS2V5AgRfa2V5CF9hZGRyZXNzCQCsAgIJAKwCAgUEX2tleQIBXwUIX2FkZHJlc3MBC2Nvb3JkaW5hdG9yAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIFBHRoaXMFFGtfY29vcmRpbmF0b3JBZGRyZXNzAhNDb29yZGluYXRvciBub3Qgc2V0AQxhZG1pbkFkZHJlc3MACQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFD2tfYWRtaW5fYWRkcmVzcwEOYWRtaW5QdWJsaWNLZXkACQDZBAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFEmtfYWRtaW5fcHVibGljX2tleQEKcXVvdGVBc3NldAAJANkEAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUNa19xdW90ZV9hc3NldAERcXVvdGVBc3NldFN0YWtpbmcACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUPa19xdW90ZV9zdGFraW5nAhtRdW90ZSBhc3NldCBzdGFraW5nIG5vdCBzZXQBDnN0YWtpbmdBZGRyZXNzAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFEWtfc3Rha2luZ19hZGRyZXNzAg9TdGFraW5nIG5vdCBzZXQBDHZhdWx0QWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABQ9rX3ZhdWx0X2FkZHJlc3MCDVZhdWx0IG5vdCBzZXQBDG1pbmVyQWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABQ9rX21pbmVyX2FkZHJlc3MCDU1pbmVyIG5vdCBzZXQBDW9yZGVyc0FkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUQa19vcmRlcnNfYWRkcmVzcwIOT3JkZXJzIG5vdCBzZXQBD3JlZmVycmFsQWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABRJrX3JlZmVycmFsX2FkZHJlc3MCEFJlZmVycmFsIG5vdCBzZXQBEW5mdE1hbmFnZXJBZGRyZXNzAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFFWtfbmZ0X21hbmFnZXJfYWRkcmVzcwITTkZUIE1hbmFnZXIgbm90IHNldAELc3dhcEFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIJAQtjb29yZGluYXRvcgAFEmtfZXhjaGFuZ2VfYWRkcmVzcwIPTm8gc3dhcCBhZGRyZXNzAhRJbnZhbGlkIHN3YXAgYWRkcmVzcwANa190b2tlbl9wYXJhbQINa190b2tlbl9wYXJhbQAMa190b2tlbl90eXBlAgxrX3Rva2VuX3R5cGUAGEZFRV9SRURVQ1RJT05fVE9LRU5fVFlQRQINZmVlX3JlZHVjdGlvbgAIRElSX0xPTkcAAQAJRElSX1NIT1JUAAIADVRXQVBfSU5URVJWQUwADwAPT1JBQ0xFX0lOVEVSVkFMAA8AB1NFQ09ORFMA6AcAD0RFQ0lNQUxfTlVNQkVSUwAGAAxERUNJTUFMX1VOSVQJAGgCAAEJAGgCCQBoAgkAaAIJAGgCCQBoAgAKAAoACgAKAAoACgAPTUlOVVRFU19JTl9ZRUFSCQBoAgCgiiAFDERFQ0lNQUxfVU5JVAAHT05FX0RBWQkAaAIAgKMFBQxERUNJTUFMX1VOSVQACEFMTF9GRUVTAGQAD1BOTF9PUFRJT05fU1BPVAABABFQTkxfT1BUSU9OX09SQUNMRQACAQFzAQJfeAkArAICCQCkAwEFAl94AgEsAQRkaXZkAgJfeAJfeQkAbgQFAl94BQxERUNJTUFMX1VOSVQFAl95BQhIQUxGRVZFTgEEbXVsZAICX3gCX3kJAG4EBQJfeAUCX3kFDERFQ0lNQUxfVU5JVAUISEFMRkVWRU4BBXNxcnRkAQJfeAkBBHNxcnQEBQJfeAUPREVDSU1BTF9OVU1CRVJTBQ9ERUNJTUFMX05VTUJFUlMFCEhBTEZFVkVOAQRwb3dkAgJfeAJfeQkAbAYFAl94BQ9ERUNJTUFMX05VTUJFUlMFAl95BQ9ERUNJTUFMX05VTUJFUlMFD0RFQ0lNQUxfTlVNQkVSUwUISEFMRkVWRU4BBWJkaXZkAgJfeAJfeQkAvQIEBQJfeAkAtgIBBQxERUNJTUFMX1VOSVQFAl95BQhIQUxGRVZFTgEFYm11bGQCAl94Al95CQC9AgQFAl94BQJfeQkAtgIBBQxERUNJTUFMX1VOSVQFCEhBTEZFVkVOAQZic3FydGQBAl94CQEKc3FydEJpZ0ludAQFAl94BQ9ERUNJTUFMX05VTUJFUlMFD0RFQ0lNQUxfTlVNQkVSUwUISEFMRkVWRU4BBWJwb3dkAgJfeAJfeQkAdgYFAl94BQ9ERUNJTUFMX05VTUJFUlMFAl95BQ9ERUNJTUFMX05VTUJFUlMFD0RFQ0lNQUxfTlVNQkVSUwUISEFMRkVWRU4BA2FicwECX3gDCQBmAgUCX3gAAAUCX3gJAQEtAQUCX3gBBHZtYXgCAl94Al95AwkAZwIFAl94BQJfeQUCX3gFAl95AQlsaXN0VG9TdHIBBV9saXN0AwkAAAIJAJADAQUFX2xpc3QAAAIACQC5CQIFBV9saXN0AgEsAQlzdHJUb0xpc3QBBF9zdHIDCQAAAgUEX3N0cgIABQNuaWwJALUJAgUEX3N0cgIBLAELcHVzaFRvUXVldWUDBV9saXN0CF9tYXhTaXplBl92YWx1ZQMJAGYCCQCQAwEFBV9saXN0BQhfbWF4U2l6ZQkAzQgCCQDRCAIFBV9saXN0AAAFBl92YWx1ZQkAzQgCBQVfbGlzdAUGX3ZhbHVlAQNpbnQBAWsJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBQR0aGlzBQFrCQCsAgICDW5vIHZhbHVlIGZvciAFAWsBBWludE9yAgFrA2RlZgkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQFrBQNkZWYBBHN0ckECCF9hZGRyZXNzBF9rZXkEA3ZhbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFCF9hZGRyZXNzBQRfa2V5CQCsAgICEU5vIHZhbHVlIGZvciBrZXkgBQRfa2V5BQN2YWwBBGludEECCF9hZGRyZXNzBF9rZXkEA3ZhbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFCF9hZGRyZXNzBQRfa2V5CQCsAgICEU5vIHZhbHVlIGZvciBrZXkgBQRfa2V5BQN2YWwBCGNiYWxhbmNlAAkBA2ludAEFCWtfYmFsYW5jZQEDZmVlAAkBA2ludAEFBWtfZmVlAQ9yb2xsb3ZlckZlZVJhdGUACQEDaW50AQUNa19yb2xsb3ZlckZlZQEPaW5pdE1hcmdpblJhdGlvAAkBA2ludAEFEWtfaW5pdE1hcmdpblJhdGlvAQZxdEFzdFIACQEDaW50AQUTa19xdW90ZUFzc2V0UmVzZXJ2ZQEGYnNBc3RSAAkBA2ludAEFEmtfYmFzZUFzc2V0UmVzZXJ2ZQEGcXRBc3RXAAkBBWludE9yAgUSa19xdW90ZUFzc2V0V2VpZ2h0BQxERUNJTUFMX1VOSVQBBmJzQXN0VwAJAQVpbnRPcgIFEWtfYmFzZUFzc2V0V2VpZ2h0BQxERUNJTUFMX1VOSVQBEXRvdGFsUG9zaXRpb25TaXplAAkBA2ludAEFE2tfdG90YWxQb3NpdGlvblNpemUBFG9wZW5JbnRlcmVzdE5vdGlvbmFsAAkBA2ludAEFFmtfb3BlbkludGVyZXN0Tm90aW9uYWwBEW9wZW5JbnRlcmVzdFNob3J0AAkBA2ludAEFE2tfb3BlbkludGVyZXN0U2hvcnQBEG9wZW5JbnRlcmVzdExvbmcACQEDaW50AQUSa19vcGVuSW50ZXJlc3RMb25nARluZXh0RnVuZGluZ0Jsb2NrVGltZXN0YW1wAAkBA2ludAEFEmtfbmV4dEZ1bmRpbmdCbG9jawEQZnVuZGluZ1BlcmlvZFJhdwAJAQNpbnQBBQ9rX2Z1bmRpbmdQZXJpb2QBFGZ1bmRpbmdQZXJpb2REZWNpbWFsAAkAaAIJARBmdW5kaW5nUGVyaW9kUmF3AAUMREVDSU1BTF9VTklUARRmdW5kaW5nUGVyaW9kU2Vjb25kcwAJAGgCCQEQZnVuZGluZ1BlcmlvZFJhdwAFB1NFQ09ORFMBFm1haW50ZW5hbmNlTWFyZ2luUmF0aW8ACQEDaW50AQUYa19tYWludGVuYW5jZU1hcmdpblJhdGlvARNsaXF1aWRhdGlvbkZlZVJhdGlvAAkBA2ludAEFFWtfbGlxdWlkYXRpb25GZWVSYXRpbwEXcGFydGlhbExpcXVpZGF0aW9uUmF0aW8ACQEDaW50AQUZa19wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwELc3ByZWFkTGltaXQACQEDaW50AQUNa19zcHJlYWRMaW1pdAEObWF4UHJpY2VJbXBhY3QACQEDaW50AQUQa19tYXhQcmljZUltcGFjdAEObWF4UHJpY2VTcHJlYWQACQEDaW50AQUQa19tYXhQcmljZVNwcmVhZAEPbWF4T3Blbk5vdGlvbmFsAAkBA2ludAEFEWtfbWF4T3Blbk5vdGlvbmFsASNsYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgAJAQNpbnQBBSVrX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uASRsYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24ACQEDaW50AQUma19sYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24BFnRvdGFsU2hvcnRQb3NpdGlvblNpemUACQEDaW50AQUYa190b3RhbFNob3J0UG9zaXRpb25TaXplARV0b3RhbExvbmdQb3NpdGlvblNpemUACQEDaW50AQUXa190b3RhbExvbmdQb3NpdGlvblNpemUBDGxhc3RTZXF1ZW5jZQAJAQVpbnRPcgIFCmtfc2VxdWVuY2UAAAETZmVlVG9TdGFrZXJzUGVyY2VudAAJAQNpbnQBBRVrX2ZlZVRvU3Rha2Vyc1BlcmNlbnQBDm1heE9yYWNsZURlbGF5AAkBA2ludAEFEGtfbWF4T3JhY2xlRGVsYXkBDWxhc3RUaW1lc3RhbXAACAUJbGFzdEJsb2NrCXRpbWVzdGFtcAEPZ2V0QWN0dWFsQ2FsbGVyAQFpCQELdmFsdWVPckVsc2UCCQCdCAIJAQ1vcmRlcnNBZGRyZXNzAAIIa19zZW5kZXIJAKUIAQgFAWkGY2FsbGVyARZyZXF1aXJlTW9yZU1hcmdpblJhdGlvAwxfbWFyZ2luUmF0aW8QX2Jhc2VNYXJnaW5SYXRpbxRfbGFyZ2VyVGhhbk9yRXF1YWxUbwQUcmVtYWluaW5nTWFyZ2luUmF0aW8JAGUCBQxfbWFyZ2luUmF0aW8FEF9iYXNlTWFyZ2luUmF0aW8DAwUUX2xhcmdlclRoYW5PckVxdWFsVG8JAGYCAAAFFHJlbWFpbmluZ01hcmdpblJhdGlvBwkAAgEJAKwCAgkArAICCQCsAgICEEludmFsaWQgbWFyZ2luOiAJAKQDAQUMX21hcmdpblJhdGlvAgMgPCAJAKQDAQUQX2Jhc2VNYXJnaW5SYXRpbwMDCQEBIQEFFF9sYXJnZXJUaGFuT3JFcXVhbFRvCQBnAgUUcmVtYWluaW5nTWFyZ2luUmF0aW8AAAcJAAIBCQCsAgIJAKwCAgkArAICAhBJbnZhbGlkIG1hcmdpbjogCQCkAwEFDF9tYXJnaW5SYXRpbwIDID4gCQCkAwEFEF9iYXNlTWFyZ2luUmF0aW8GAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAQ1fcG9zaXRpb25TaXplAwkAAAIFDV9wb3NpdGlvblNpemUAAAkAAgECLFNob3VsZCBub3QgYmUgY2FsbGVkIHdpdGggX3Bvc2l0aW9uU2l6ZSA9PSAwAwkAZgIFDV9wb3NpdGlvblNpemUAAAkBI2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAAkBJGxhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgABC2dldFBvc2l0aW9uAQdfdHJhZGVyBA9wb3NpdGlvblNpemVPcHQJAJoIAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUOa19wb3NpdGlvblNpemUFB190cmFkZXIEByRtYXRjaDAFD3Bvc2l0aW9uU2l6ZU9wdAMJAAECBQckbWF0Y2gwAgNJbnQEDHBvc2l0aW9uU2l6ZQUHJG1hdGNoMAkAlwoFBQxwb3NpdGlvblNpemUJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFEGtfcG9zaXRpb25NYXJnaW4FB190cmFkZXIJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFFmtfcG9zaXRpb25PcGVuTm90aW9uYWwFB190cmFkZXIJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFLmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FB190cmFkZXIJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAUHX3RyYWRlcgkAlwoFAAAAAAAAAAAAAAEQZ2V0UG9zaXRpb25Bc3NldAEHX3RyYWRlcgQQcG9zaXRpb25Bc3NldE9wdAkAnQgCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBQ9rX3Bvc2l0aW9uQXNzZXQFB190cmFkZXIEByRtYXRjaDAFEHBvc2l0aW9uQXNzZXRPcHQDCQABAgUHJG1hdGNoMAIGU3RyaW5nBA1wb3NpdGlvbkFzc2V0BQckbWF0Y2gwBQ1wb3NpdGlvbkFzc2V0CQDYBAEJAQpxdW90ZUFzc2V0AAEOZ2V0UG9zaXRpb25GZWUBB190cmFkZXIEDnBvc2l0aW9uRmVlT3B0CQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFDWtfcG9zaXRpb25GZWUFB190cmFkZXIEByRtYXRjaDAFDnBvc2l0aW9uRmVlT3B0AwkAAQIFByRtYXRjaDACA0ludAQLcG9zaXRpb25GZWUFByRtYXRjaDAFC3Bvc2l0aW9uRmVlCQEDZmVlAAETcmVxdWlyZU9wZW5Qb3NpdGlvbgEHX3RyYWRlcgMJAAACCAkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgJfMQAACQACAQIQTm8gb3BlbiBwb3NpdGlvbgYBC2luaXRpYWxpemVkAAkBC3ZhbHVlT3JFbHNlAgkAmwgCBQR0aGlzBQ1rX2luaXRpYWxpemVkBwEGcGF1c2VkAAkBC3ZhbHVlT3JFbHNlAgkAmwgCBQR0aGlzBQhrX3BhdXNlZAcBCWNsb3NlT25seQAJAQt2YWx1ZU9yRWxzZQIJAJsIAgUEdGhpcwULa19jbG9zZU9ubHkHAQ11cGRhdGVSZXNlcnZlAwZfaXNBZGQRX3F1b3RlQXNzZXRBbW91bnQQX2Jhc2VBc3NldEFtb3VudAMFBl9pc0FkZAQHbmV3QmFzZQkAZQIJAQZic0FzdFIABRBfYmFzZUFzc2V0QW1vdW50AwkAZwIAAAUHbmV3QmFzZQkAAgECKlR4IGxlYWQgdG8gYmFzZSBhc3NldCByZXNlcnZlIDw9IDAsIHJldmVydAkAlQoDCQBkAgkBBnF0QXN0UgAFEV9xdW90ZUFzc2V0QW1vdW50BQduZXdCYXNlCQBkAgkBEXRvdGFsUG9zaXRpb25TaXplAAUQX2Jhc2VBc3NldEFtb3VudAQIbmV3UXVvdGUJAGUCCQEGcXRBc3RSAAURX3F1b3RlQXNzZXRBbW91bnQDCQBnAgAABQhuZXdRdW90ZQkAAgECKlR4IGxlYWQgdG8gYmFzZSBxdW90ZSByZXNlcnZlIDw9IDAsIHJldmVydAkAlQoDBQhuZXdRdW90ZQkAZAIJAQZic0FzdFIABRBfYmFzZUFzc2V0QW1vdW50CQBlAgkBEXRvdGFsUG9zaXRpb25TaXplAAUQX2Jhc2VBc3NldEFtb3VudAENY2FsY0ludmFyaWFudAIHX3F0QXN0UgdfYnNBc3RSBAdicXRBc3RSCQC2AgEFB19xdEFzdFIEB2Jic0FzdFIJALYCAQUHX2JzQXN0UgkBBWJtdWxkAgUHYnF0QXN0UgUHYmJzQXN0UgEJc3dhcElucHV0AgZfaXNBZGQRX3F1b3RlQXNzZXRBbW91bnQEB19xdEFzdFIJAQZxdEFzdFIABAdfYnNBc3RSCQEGYnNBc3RSAAQHX3F0QXN0VwkBBnF0QXN0VwAEB19ic0FzdFcJAQZic0FzdFcABBhxdW90ZUFzc2V0QW1vdW50QWRqdXN0ZWQJAQRkaXZkAgURX3F1b3RlQXNzZXRBbW91bnQFB19xdEFzdFcEAWsJAQ1jYWxjSW52YXJpYW50AgUHX3F0QXN0UgUHX2JzQXN0UgQWcXVvdGVBc3NldFJlc2VydmVBZnRlcgMFBl9pc0FkZAkAZAIFB19xdEFzdFIFGHF1b3RlQXNzZXRBbW91bnRBZGp1c3RlZAkAZQIFB19xdEFzdFIFGHF1b3RlQXNzZXRBbW91bnRBZGp1c3RlZAQVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCQCgAwEJAQViZGl2ZAIFAWsJALYCAQUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgQYYW1vdW50QmFzZUFzc2V0Qm91Z2h0QWJzCQEDYWJzAQkAZQIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgUHX2JzQXN0UgQVYW1vdW50QmFzZUFzc2V0Qm91Z2h0AwUGX2lzQWRkBRhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMJAQEtAQUYYW1vdW50QmFzZUFzc2V0Qm91Z2h0QWJzBA0kdDAxNzAzNjE3MjA2CQENdXBkYXRlUmVzZXJ2ZQMFBl9pc0FkZAUYcXVvdGVBc3NldEFtb3VudEFkanVzdGVkBRhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMEF3F1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIxCAUNJHQwMTcwMzYxNzIwNgJfMQQWYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyMQgFDSR0MDE3MDM2MTcyMDYCXzIEF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxCAUNJHQwMTcwMzYxNzIwNgJfMwQLcHJpY2VCZWZvcmUJAQRkaXZkAgkBBG11bGQCBQdfcXRBc3RSBQdfcXRBc3RXCQEEbXVsZAIFB19ic0FzdFIFB19ic0FzdFcEC21hcmtldFByaWNlCQEEZGl2ZAIFEV9xdW90ZUFzc2V0QW1vdW50BRhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMECXByaWNlRGlmZgkBA2FicwEJAGUCBQtwcmljZUJlZm9yZQULbWFya2V0UHJpY2UEC3ByaWNlSW1wYWN0CQBlAgUMREVDSU1BTF9VTklUCQEEZGl2ZAIFC3ByaWNlQmVmb3JlCQBkAgULcHJpY2VCZWZvcmUFCXByaWNlRGlmZgQTbWF4UHJpY2VJbXBhY3RWYWx1ZQkBDm1heFByaWNlSW1wYWN0AAMJAGYCBQtwcmljZUltcGFjdAUTbWF4UHJpY2VJbXBhY3RWYWx1ZQkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgINUHJpY2UgaW1wYWN0IAkApAMBBQtwcmljZUltcGFjdAIUID4gbWF4IHByaWNlIGltcGFjdCAJAKQDAQUTbWF4UHJpY2VJbXBhY3RWYWx1ZQIVIGJlZm9yZSBxdW90ZSBhc3NldDogCQCkAwEFB19xdEFzdFICFCBiZWZvcmUgYmFzZSBhc3NldDogCQCkAwEFB19ic0FzdFICISBxdW90ZSBhc3NldCBhbW91bnQgdG8gZXhjaGFuZ2U6IAkApAMBBRFfcXVvdGVBc3NldEFtb3VudAIPIHByaWNlIGJlZm9yZTogCQCkAwEFC3ByaWNlQmVmb3JlAg4gbWFya2V0UHJpY2U6IAkApAMBBQttYXJrZXRQcmljZQkAlgoEBRVhbW91bnRCYXNlQXNzZXRCb3VnaHQFF3F1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIxBRZiYXNlQXNzZXRSZXNlcnZlQWZ0ZXIxBRd0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyMQEPY2FsY1JvbGxvdmVyRmVlAhJfb2xkUG9zaXRpb25NYXJnaW4gX29sZFBvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAED3Bvc2l0aW9uTWludXRlcwkAaAIJAGkCCQBpAgkAZQIJAQ1sYXN0VGltZXN0YW1wAAUgX29sZFBvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAA6AcAPAUMREVDSU1BTF9VTklUBAtyb2xsb3ZlckZlZQkBBGRpdmQCCQEEbXVsZAIJAQRtdWxkAgUSX29sZFBvc2l0aW9uTWFyZ2luBQ9wb3NpdGlvbk1pbnV0ZXMJAQ9yb2xsb3ZlckZlZVJhdGUABQ9NSU5VVEVTX0lOX1lFQVIFC3JvbGxvdmVyRmVlATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFEF9vbGRQb3NpdGlvblNpemUSX29sZFBvc2l0aW9uTWFyZ2luJV9vbGRQb3NpdGlvbkN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24gX29sZFBvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAMX21hcmdpbkRlbHRhBA5mdW5kaW5nUGF5bWVudAMJAQIhPQIFEF9vbGRQb3NpdGlvblNpemUAAAQgX2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24JAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAQUQX29sZFBvc2l0aW9uU2l6ZQkBBG11bGQCCQBlAgUgX2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FJV9vbGRQb3NpdGlvbkN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FEF9vbGRQb3NpdGlvblNpemUAAAQLcm9sbG92ZXJGZWUJAQ9jYWxjUm9sbG92ZXJGZWUCBRJfb2xkUG9zaXRpb25NYXJnaW4FIF9vbGRQb3NpdGlvbkxhc3RVcGRhdGVkVGltZXN0YW1wBAxzaWduZWRNYXJnaW4JAGQCCQBlAgkAZQIFDF9tYXJnaW5EZWx0YQULcm9sbG92ZXJGZWUFDmZ1bmRpbmdQYXltZW50BRJfb2xkUG9zaXRpb25NYXJnaW4EDSR0MDE5NDYxMTk1ODgDCQBmAgAABQxzaWduZWRNYXJnaW4JAJQKAgAACQEDYWJzAQUMc2lnbmVkTWFyZ2luCQCUCgIJAQNhYnMBBQxzaWduZWRNYXJnaW4AAAQMcmVtYWluTWFyZ2luCAUNJHQwMTk0NjExOTU4OAJfMQQHYmFkRGVidAgFDSR0MDE5NDYxMTk1ODgCXzIJAJYKBAUMcmVtYWluTWFyZ2luBQdiYWREZWJ0BQ5mdW5kaW5nUGF5bWVudAULcm9sbG92ZXJGZWUBFnN3YXBPdXRwdXRXaXRoUmVzZXJ2ZXMHBl9pc0FkZBBfYmFzZUFzc2V0QW1vdW50FF9jaGVja01heFByaWNlSW1wYWN0El9xdW90ZUFzc2V0UmVzZXJ2ZRFfcXVvdGVBc3NldFdlaWdodBFfYmFzZUFzc2V0UmVzZXJ2ZRBfYmFzZUFzc2V0V2VpZ2h0BAtwcmljZUJlZm9yZQkBBGRpdmQCCQEEbXVsZAIFEl9xdW90ZUFzc2V0UmVzZXJ2ZQURX3F1b3RlQXNzZXRXZWlnaHQJAQRtdWxkAgURX2Jhc2VBc3NldFJlc2VydmUFEF9iYXNlQXNzZXRXZWlnaHQDCQAAAgUQX2Jhc2VBc3NldEFtb3VudAAACQACAQIZSW52YWxpZCBiYXNlIGFzc2V0IGFtb3VudAQBawkBDWNhbGNJbnZhcmlhbnQCBRJfcXVvdGVBc3NldFJlc2VydmUFEV9iYXNlQXNzZXRSZXNlcnZlBBhiYXNlQXNzZXRQb29sQW1vdW50QWZ0ZXIDBQZfaXNBZGQJAGQCBRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldEFtb3VudAkAZQIFEV9iYXNlQXNzZXRSZXNlcnZlBRBfYmFzZUFzc2V0QW1vdW50BA9xdW90ZUFzc2V0QWZ0ZXIJAKADAQkBBWJkaXZkAgUBawkAtgIBBRhiYXNlQXNzZXRQb29sQW1vdW50QWZ0ZXIED3F1b3RlQXNzZXREZWx0YQkBA2FicwEJAGUCBQ9xdW90ZUFzc2V0QWZ0ZXIFEl9xdW90ZUFzc2V0UmVzZXJ2ZQQOcXVvdGVBc3NldFNvbGQJAQRtdWxkAgUPcXVvdGVBc3NldERlbHRhBRFfcXVvdGVBc3NldFdlaWdodAQTbWF4UHJpY2VJbXBhY3RWYWx1ZQkBDm1heFByaWNlSW1wYWN0AAQNJHQwMjA4NTAyMTAxMgkBDXVwZGF0ZVJlc2VydmUDCQEBIQEFBl9pc0FkZAUPcXVvdGVBc3NldERlbHRhBRBfYmFzZUFzc2V0QW1vdW50BBdxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyMQgFDSR0MDIwODUwMjEwMTICXzEEFmJhc2VBc3NldFJlc2VydmVBZnRlcjEIBQ0kdDAyMDg1MDIxMDEyAl8yBBd0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyMQgFDSR0MDIwODUwMjEwMTICXzMEC21hcmtldFByaWNlCQEEZGl2ZAIFDnF1b3RlQXNzZXRTb2xkBRBfYmFzZUFzc2V0QW1vdW50BAlwcmljZURpZmYJAQNhYnMBCQBlAgULcHJpY2VCZWZvcmUFC21hcmtldFByaWNlBAtwcmljZUltcGFjdAkAZQIFDERFQ0lNQUxfVU5JVAkBBGRpdmQCBQtwcmljZUJlZm9yZQkAZAIFC3ByaWNlQmVmb3JlBQlwcmljZURpZmYDAwkAZgIFC3ByaWNlSW1wYWN0BRNtYXhQcmljZUltcGFjdFZhbHVlBRRfY2hlY2tNYXhQcmljZUltcGFjdAcJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgICDVByaWNlIGltcGFjdCAJAKQDAQULcHJpY2VJbXBhY3QCFCA+IG1heCBwcmljZSBpbXBhY3QgCQCkAwEFE21heFByaWNlSW1wYWN0VmFsdWUCFSBiZWZvcmUgcXVvdGUgYXNzZXQ6IAkApAMBBRJfcXVvdGVBc3NldFJlc2VydmUCFCBiZWZvcmUgYmFzZSBhc3NldDogCQCkAwEFEV9iYXNlQXNzZXRSZXNlcnZlAiAgYmFzZSBhc3NldCBhbW91bnQgdG8gZXhjaGFuZ2U6IAkApAMBBRBfYmFzZUFzc2V0QW1vdW50Ag8gcHJpY2UgYmVmb3JlOiAJAKQDAQULcHJpY2VCZWZvcmUCDyBtYXJrZXQgcHJpY2U6IAkApAMBBQttYXJrZXRQcmljZQkAmQoHBQ5xdW90ZUFzc2V0U29sZAUXcXVvdGVBc3NldFJlc2VydmVBZnRlcjEFFmJhc2VBc3NldFJlc2VydmVBZnRlcjEFF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxCQBlAgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQADBQZfaXNBZGQJAQNhYnMBBRBfYmFzZUFzc2V0QW1vdW50AAAJAGUCCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQADCQEBIQEFBl9pc0FkZAkBA2FicwEFEF9iYXNlQXNzZXRBbW91bnQAAAULcHJpY2VJbXBhY3QBCnN3YXBPdXRwdXQDBl9pc0FkZBBfYmFzZUFzc2V0QW1vdW50FF9jaGVja01heFByaWNlSW1wYWN0CQEWc3dhcE91dHB1dFdpdGhSZXNlcnZlcwcFBl9pc0FkZAUQX2Jhc2VBc3NldEFtb3VudAUUX2NoZWNrTWF4UHJpY2VJbXBhY3QJAQZxdEFzdFIACQEGcXRBc3RXAAkBBmJzQXN0UgAJAQZic0FzdFcAAQ5nZXRPcmFjbGVQcmljZQAEBm9yYWNsZQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBQR0aGlzBQVrX29yYQkArAICAgpObyB2YWx1ZTogBQVrX29yYQIABAhwcmljZUtleQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzBQlrX29yYV9rZXkJAKwCAgIKTm8gdmFsdWU6IAUJa19vcmFfa2V5BAlsYXN0VmFsdWUJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBQZvcmFjbGUFCHByaWNlS2V5CQCsAgIJAKwCAgkArAICAiJDYW4gbm90IGdldCBvcmFjbGUgcHJpY2UuIE9yYWNsZTogCQClCAEFBm9yYWNsZQIGIGtleTogBQhwcmljZUtleQQIYmxvY2tLZXkJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwUPa19vcmFfYmxvY2tfa2V5AgADCQECIT0CBQhibG9ja0tleQIABAxjdXJyZW50QmxvY2sIBQlsYXN0QmxvY2sGaGVpZ2h0BA9sYXN0T3JhY2xlQmxvY2sJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBQZvcmFjbGUFCGJsb2NrS2V5CQCsAgIJAKwCAgkArAICAiJDYW4gbm90IGdldCBvcmFjbGUgYmxvY2suIE9yYWNsZTogCQClCAEFBm9yYWNsZQIGIGtleTogBQhibG9ja0tleQMJAGYCCQBlAgUMY3VycmVudEJsb2NrBQ9sYXN0T3JhY2xlQmxvY2sJAQ5tYXhPcmFjbGVEZWxheQAJAAIBCQCsAgIJAKwCAgkArAICAiZPcmFjbGUgc3RhbGUgZGF0YS4gTGFzdCBvcmFjbGUgYmxvY2s6IAkApAMBBQ9sYXN0T3JhY2xlQmxvY2sCECBjdXJyZW50IGJsb2NrOiAJAKQDAQUMY3VycmVudEJsb2NrBQlsYXN0VmFsdWUFCWxhc3RWYWx1ZQEOaXNNYXJrZXRDbG9zZWQABAZvcmFjbGUJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCBQR0aGlzBQVrX29yYQIABAdvcGVuS2V5CQELdmFsdWVPckVsc2UCCQCdCAIFBHRoaXMFDmtfb3JhX29wZW5fa2V5AgADCQECIT0CBQdvcGVuS2V5AgAEBmlzT3BlbgkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCbCAIFBm9yYWNsZQUHb3BlbktleQkArAICCQCsAgIJAKwCAgIrQ2FuIG5vdCBnZXQgb3JhY2xlIGlzIG9wZW4vY2xvc2VkLiBPcmFjbGU6IAkApQgBBQZvcmFjbGUCBiBrZXk6IAUHb3BlbktleQkBASEBBQZpc09wZW4HAQxhYnNQcmljZURpZmYFDF9vcmFjbGVQcmljZRJfcXVvdGVBc3NldFJlc2VydmURX2Jhc2VBc3NldFJlc2VydmUHX3F0QXN0VwdfYnNBc3RXBApwcmljZUFmdGVyCQEEZGl2ZAIJAQRtdWxkAgUSX3F1b3RlQXNzZXRSZXNlcnZlBQdfcXRBc3RXCQEEbXVsZAIFEV9iYXNlQXNzZXRSZXNlcnZlBQdfYnNBc3RXBAxhdmVyYWdlUHJpY2UJAQRkaXZkAgkAZAIFDF9vcmFjbGVQcmljZQUKcHJpY2VBZnRlcgkAaAIAAgUMREVDSU1BTF9VTklUBAxhYnNQcmljZURpZmYJAQRkaXZkAgkBA2FicwEJAGUCBQxfb3JhY2xlUHJpY2UFCnByaWNlQWZ0ZXIFDGF2ZXJhZ2VQcmljZQUMYWJzUHJpY2VEaWZmARlyZXF1aXJlTm90T3ZlclNwcmVhZExpbWl0AhJfcXVvdGVBc3NldFJlc2VydmURX2Jhc2VBc3NldFJlc2VydmUEC29yYWNsZVByaWNlCQEOZ2V0T3JhY2xlUHJpY2UABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAEEmFic1ByaWNlRGlmZkJlZm9yZQkBDGFic1ByaWNlRGlmZgUFC29yYWNsZVByaWNlCQEGcXRBc3RSAAkBBmJzQXN0UgAFB19xdEFzdFcFB19ic0FzdFcEEWFic1ByaWNlRGlmZkFmdGVyCQEMYWJzUHJpY2VEaWZmBQULb3JhY2xlUHJpY2UFEl9xdW90ZUFzc2V0UmVzZXJ2ZQURX2Jhc2VBc3NldFJlc2VydmUFB19xdEFzdFcFB19ic0FzdFcDAwkAZgIFEWFic1ByaWNlRGlmZkFmdGVyCQEObWF4UHJpY2VTcHJlYWQACQBmAgURYWJzUHJpY2VEaWZmQWZ0ZXIFEmFic1ByaWNlRGlmZkJlZm9yZQcJAAIBCQCsAgIJAKwCAgkArAICAg1QcmljZSBzcHJlYWQgCQCkAwEFEWFic1ByaWNlRGlmZkFmdGVyAhQgPiBtYXggcHJpY2Ugc3ByZWFkIAkApAMBCQEObWF4UHJpY2VTcHJlYWQABgEdcmVxdWlyZU5vdE92ZXJNYXhPcGVuTm90aW9uYWwCEV9sb25nT3Blbk5vdGlvbmFsEl9zaG9ydE9wZW5Ob3Rpb25hbAQQX21heE9wZW5Ob3Rpb25hbAkBD21heE9wZW5Ob3Rpb25hbAADCQBmAgURX2xvbmdPcGVuTm90aW9uYWwFEF9tYXhPcGVuTm90aW9uYWwJAAIBCQCsAgIJAKwCAgkArAICAhNMb25nIG9wZW4gbm90aW9uYWwgCQCkAwEFEV9sb25nT3Blbk5vdGlvbmFsAhUgPiBtYXggb3BlbiBub3Rpb25hbCAJAKQDAQUQX21heE9wZW5Ob3Rpb25hbAMJAGYCBRJfc2hvcnRPcGVuTm90aW9uYWwFEF9tYXhPcGVuTm90aW9uYWwJAAIBCQCsAgIJAKwCAgkArAICAhRTaG9ydCBvcGVuIG5vdGlvbmFsIAkApAMBBRJfc2hvcnRPcGVuTm90aW9uYWwCFSA+IG1heCBvcGVuIG5vdGlvbmFsIAkApAMBBRBfbWF4T3Blbk5vdGlvbmFsBgEMZ2V0U3BvdFByaWNlAAQSX3F1b3RlQXNzZXRSZXNlcnZlCQEGcXRBc3RSAAQRX2Jhc2VBc3NldFJlc2VydmUJAQZic0FzdFIABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAJAQRkaXZkAgkBBG11bGQCBRJfcXVvdGVBc3NldFJlc2VydmUFB19xdEFzdFcJAQRtdWxkAgURX2Jhc2VBc3NldFJlc2VydmUFB19ic0FzdFcBFmlzT3ZlckZsdWN0dWF0aW9uTGltaXQABAtvcmFjbGVQcmljZQkBDmdldE9yYWNsZVByaWNlAAQMY3VycmVudFByaWNlCQEMZ2V0U3BvdFByaWNlAAkAZgIJAQRkaXZkAgkBA2FicwEJAGUCBQtvcmFjbGVQcmljZQUMY3VycmVudFByaWNlBQtvcmFjbGVQcmljZQkBC3NwcmVhZExpbWl0AAEfZ2V0UG9zaXRpb25BZGp1c3RlZE9wZW5Ob3Rpb25hbAYNX3Bvc2l0aW9uU2l6ZQdfb3B0aW9uEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfcXVvdGVBc3NldFdlaWdodBFfYmFzZUFzc2V0UmVzZXJ2ZRBfYmFzZUFzc2V0V2VpZ2h0BA9wb3NpdGlvblNpemVBYnMJAQNhYnMBBQ1fcG9zaXRpb25TaXplBAdpc1Nob3J0CQBmAgAABQ1fcG9zaXRpb25TaXplBBBwb3NpdGlvbk5vdGlvbmFsAwkAAAIFB19vcHRpb24FD1BOTF9PUFRJT05fU1BPVAQTb3V0UG9zaXRpb25Ob3Rpb25hbAgJARZzd2FwT3V0cHV0V2l0aFJlc2VydmVzBwkBASEBBQdpc1Nob3J0BQ9wb3NpdGlvblNpemVBYnMHBRJfcXVvdGVBc3NldFJlc2VydmUFEV9xdW90ZUFzc2V0V2VpZ2h0BRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldFdlaWdodAJfMQUTb3V0UG9zaXRpb25Ob3Rpb25hbAkBBG11bGQCBQ9wb3NpdGlvblNpemVBYnMJAQ5nZXRPcmFjbGVQcmljZQAFEHBvc2l0aW9uTm90aW9uYWwBK2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sQnlWYWx1ZXMHDV9wb3NpdGlvblNpemUVX3Bvc2l0aW9uT3Blbk5vdGlvbmFsEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfcXVvdGVBc3NldFdlaWdodBFfYmFzZUFzc2V0UmVzZXJ2ZRBfYmFzZUFzc2V0V2VpZ2h0B19vcHRpb24DCQAAAgUNX3Bvc2l0aW9uU2l6ZQAACQACAQIVSW52YWxpZCBwb3NpdGlvbiBzaXplBAdpc1Nob3J0CQBmAgAABQ1fcG9zaXRpb25TaXplBBBwb3NpdGlvbk5vdGlvbmFsCQEfZ2V0UG9zaXRpb25BZGp1c3RlZE9wZW5Ob3Rpb25hbAYFDV9wb3NpdGlvblNpemUFB19vcHRpb24FEl9xdW90ZUFzc2V0UmVzZXJ2ZQURX3F1b3RlQXNzZXRXZWlnaHQFEV9iYXNlQXNzZXRSZXNlcnZlBRBfYmFzZUFzc2V0V2VpZ2h0BA11bnJlYWxpemVkUG5sAwUHaXNTaG9ydAkAZQIFFV9wb3NpdGlvbk9wZW5Ob3Rpb25hbAUQcG9zaXRpb25Ob3Rpb25hbAkAZQIFEHBvc2l0aW9uTm90aW9uYWwFFV9wb3NpdGlvbk9wZW5Ob3Rpb25hbAkAlAoCBRBwb3NpdGlvbk5vdGlvbmFsBQ11bnJlYWxpemVkUG5sASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAIHX3RyYWRlcgdfb3B0aW9uBA0kdDAyODU3NzI4NzA1CQELZ2V0UG9zaXRpb24BBQdfdHJhZGVyBAxwb3NpdGlvblNpemUIBQ0kdDAyODU3NzI4NzA1Al8xBA5wb3NpdGlvbk1hcmdpbggFDSR0MDI4NTc3Mjg3MDUCXzIEFHBvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwMjg1NzcyODcwNQJfMwQRcG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDAyODU3NzI4NzA1Al80CQErZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmxCeVZhbHVlcwcFDHBvc2l0aW9uU2l6ZQUUcG9zaXRpb25PcGVuTm90aW9uYWwJAQZxdEFzdFIACQEGcXRBc3RXAAkBBmJzQXN0UgAJAQZic0FzdFcABQdfb3B0aW9uAQ9jYWxjTWFyZ2luUmF0aW8DDV9yZW1haW5NYXJnaW4IX2JhZERlYnQRX3Bvc2l0aW9uTm90aW9uYWwJAQRkaXZkAgkAZQIFDV9yZW1haW5NYXJnaW4FCF9iYWREZWJ0BRFfcG9zaXRpb25Ob3Rpb25hbAEWZ2V0TWFyZ2luUmF0aW9CeU9wdGlvbgIHX3RyYWRlcgdfb3B0aW9uBA0kdDAyOTIyMDI5MzYxCQELZ2V0UG9zaXRpb24BBQdfdHJhZGVyBAxwb3NpdGlvblNpemUIBQ0kdDAyOTIyMDI5MzYxAl8xBA5wb3NpdGlvbk1hcmdpbggFDSR0MDI5MjIwMjkzNjECXzIEA3BvbggFDSR0MDI5MjIwMjkzNjECXzMEFnBvc2l0aW9uTGFzdFVwZGF0ZWRDUEYIBQ0kdDAyOTIyMDI5MzYxAl80BBFwb3NpdGlvblRpbWVzdGFtcAgFDSR0MDI5MjIwMjkzNjECXzUEDSR0MDI5MzY3Mjk0NjAJASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAIFB190cmFkZXIFB19vcHRpb24EEHBvc2l0aW9uTm90aW9uYWwIBQ0kdDAyOTM2NzI5NDYwAl8xBA11bnJlYWxpemVkUG5sCAUNJHQwMjkzNjcyOTQ2MAJfMgQNJHQwMjk0NjUyOTY3NwkBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQUFDHBvc2l0aW9uU2l6ZQUOcG9zaXRpb25NYXJnaW4FFnBvc2l0aW9uTGFzdFVwZGF0ZWRDUEYFEXBvc2l0aW9uVGltZXN0YW1wBQ11bnJlYWxpemVkUG5sBAxyZW1haW5NYXJnaW4IBQ0kdDAyOTQ2NTI5Njc3Al8xBAdiYWREZWJ0CAUNJHQwMjk0NjUyOTY3NwJfMgkBD2NhbGNNYXJnaW5SYXRpbwMFDHJlbWFpbk1hcmdpbgUHYmFkRGVidAUQcG9zaXRpb25Ob3Rpb25hbAEOZ2V0TWFyZ2luUmF0aW8BB190cmFkZXIJARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAgUHX3RyYWRlcgUPUE5MX09QVElPTl9TUE9UARtnZXRQYXJ0aWFsTGlxdWlkYXRpb25BbW91bnQCB190cmFkZXINX3Bvc2l0aW9uU2l6ZQQMbWF4aW11bVJhdGlvCQEEdm1heAIJARdwYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwAJAGUCBQxERUNJTUFMX1VOSVQJAQRkaXZkAgkBDmdldE1hcmdpblJhdGlvAQUHX3RyYWRlcgkBFm1haW50ZW5hbmNlTWFyZ2luUmF0aW8ABBhtYXhFeGNoYW5nZWRQb3NpdGlvblNpemUJAQRtdWxkAgkBA2FicwEFDV9wb3NpdGlvblNpemUFDG1heGltdW1SYXRpbwQKc3dhcFJlc3VsdAkBCnN3YXBPdXRwdXQDCQBmAgUNX3Bvc2l0aW9uU2l6ZQAABRhtYXhFeGNoYW5nZWRQb3NpdGlvblNpemUHBBxtYXhFeGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50CAUKc3dhcFJlc3VsdAJfMQQLcHJpY2VJbXBhY3QIBQpzd2FwUmVzdWx0Al83AwkAZgIJAQ5tYXhQcmljZUltcGFjdAAFC3ByaWNlSW1wYWN0BRhtYXhFeGNoYW5nZWRQb3NpdGlvblNpemUJAQRtdWxkAgkBA2FicwEFDV9wb3NpdGlvblNpemUJARdwYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwABFWludGVybmFsQ2xvc2VQb3NpdGlvbgYHX3RyYWRlcgVfc2l6ZQRfZmVlFF9taW5RdW90ZUFzc2V0QW1vdW50DF9hZGRUb01hcmdpbhRfY2hlY2tNYXhQcmljZUltcGFjdAQNJHQwMzA3MjEzMDg3NwkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgQPb2xkUG9zaXRpb25TaXplCAUNJHQwMzA3MjEzMDg3NwJfMQQRb2xkUG9zaXRpb25NYXJnaW4IBQ0kdDAzMDcyMTMwODc3Al8yBBdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDMwNzIxMzA4NzcCXzMEFG9sZFBvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwMzA3MjEzMDg3NwJfNAQUb2xkUG9zaXRpb25UaW1lc3RhbXAIBQ0kdDAzMDcyMTMwODc3Al81BA5pc0xvbmdQb3NpdGlvbgkAZgIFD29sZFBvc2l0aW9uU2l6ZQAABBJhYnNPbGRQb3NpdGlvblNpemUJAQNhYnMBBQ9vbGRQb3NpdGlvblNpemUDAwkAZwIFEmFic09sZFBvc2l0aW9uU2l6ZQUFX3NpemUJAGYCBQVfc2l6ZQAABwQOaXNQYXJ0aWFsQ2xvc2UJAGYCBRJhYnNPbGRQb3NpdGlvblNpemUFBV9zaXplBA0kdDAzMTE2OTMxNjIwCQEKc3dhcE91dHB1dAMJAGYCBQ9vbGRQb3NpdGlvblNpemUAAAUFX3NpemUFFF9jaGVja01heFByaWNlSW1wYWN0BBlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50CAUNJHQwMzExNjkzMTYyMAJfMQQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDMxMTY5MzE2MjACXzIEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDMxMTY5MzE2MjACXzMEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDAzMTE2OTMxNjIwAl80BBVleGNoYW5nZWRQb3NpdGlvblNpemUDCQBmAgUPb2xkUG9zaXRpb25TaXplAAAJAQEtAQUFX3NpemUFBV9zaXplBA0kdDAzMTgzNTMyMDQyCQEjZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmwCBQdfdHJhZGVyBQ9QTkxfT1BUSU9OX1NQT1QEE29sZFBvc2l0aW9uTm90aW9uYWwIBQ0kdDAzMTgzNTMyMDQyAl8xBA11bnJlYWxpemVkUG5sCAUNJHQwMzE4MzUzMjA0MgJfMgQNcmVhbGl6ZWRSYXRpbwkBBGRpdmQCCQEDYWJzAQUVZXhjaGFuZ2VkUG9zaXRpb25TaXplBRJhYnNPbGRQb3NpdGlvblNpemUEC3JlYWxpemVkUG5sCQEEbXVsZAIFDXVucmVhbGl6ZWRQbmwFDXJlYWxpemVkUmF0aW8EDSR0MDMyMzgzMzI2MjkJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQ9vbGRQb3NpdGlvblNpemUFEW9sZFBvc2l0aW9uTWFyZ2luBRRvbGRQb3NpdGlvbkxzdFVwZENQRgUUb2xkUG9zaXRpb25UaW1lc3RhbXAFDXVucmVhbGl6ZWRQbmwEEnJlbWFpbk1hcmdpbkJlZm9yZQgFDSR0MDMyMzgzMzI2MjkCXzEEAngxCAUNJHQwMzIzODMzMjYyOQJfMgQCeDIIBQ0kdDAzMjM4MzMyNjI5Al8zBAtyb2xsb3ZlckZlZQgFDSR0MDMyMzgzMzI2MjkCXzQED3Bvc2l0aW9uQmFkRGVidAgJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQ9vbGRQb3NpdGlvblNpemUFEW9sZFBvc2l0aW9uTWFyZ2luBRRvbGRQb3NpdGlvbkxzdFVwZENQRgUUb2xkUG9zaXRpb25UaW1lc3RhbXAFC3JlYWxpemVkUG5sAl8yBBByZWFsaXplZENsb3NlRmVlCQEEbXVsZAIJAQRtdWxkAgUTb2xkUG9zaXRpb25Ob3Rpb25hbAUNcmVhbGl6ZWRSYXRpbwUEX2ZlZQQSdW5yZWFsaXplZFBubEFmdGVyCQBlAgUNdW5yZWFsaXplZFBubAULcmVhbGl6ZWRQbmwEEnJlbWFpbk9wZW5Ob3Rpb25hbAMJAGYCBQ9vbGRQb3NpdGlvblNpemUAAAkAZQIJAGUCBRNvbGRQb3NpdGlvbk5vdGlvbmFsBRlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50BRJ1bnJlYWxpemVkUG5sQWZ0ZXIJAGUCCQBkAgUSdW5yZWFsaXplZFBubEFmdGVyBRNvbGRQb3NpdGlvbk5vdGlvbmFsBRlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50BA9uZXdQb3NpdGlvblNpemUJAGQCBQ9vbGRQb3NpdGlvblNpemUFFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQQNJHQwMzQwMzUzNDQyMQMJAAACBQ9uZXdQb3NpdGlvblNpemUAAAkAlAoCAAAAAAkAlAoCCQEDYWJzAQUScmVtYWluT3Blbk5vdGlvbmFsCQEfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEFD25ld1Bvc2l0aW9uU2l6ZQQXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDAzNDAzNTM0NDIxAl8xBBRuZXdQb3NpdGlvbkxzdFVwZENQRggFDSR0MDM0MDM1MzQ0MjECXzIEEW9wZW5Ob3Rpb25hbERlbHRhCQBlAgUXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwFF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBAttYXJnaW5SYXRpbwkBFmdldE1hcmdpblJhdGlvQnlPcHRpb24CBQdfdHJhZGVyBQ9QTkxfT1BUSU9OX1NQT1QEHm5ld1Bvc2l0aW9uTWFyZ2luV2l0aFNhbWVSYXRpbwMJAGYCBQ9vbGRQb3NpdGlvblNpemUAAAkAZQIJAQRtdWxkAgkAZAIFF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBRJ1bnJlYWxpemVkUG5sQWZ0ZXIFC21hcmdpblJhdGlvBRJ1bnJlYWxpemVkUG5sQWZ0ZXIJAGUCCQEEbXVsZAIJAGUCBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUSdW5yZWFsaXplZFBubEFmdGVyBQttYXJnaW5SYXRpbwUSdW5yZWFsaXplZFBubEFmdGVyBBFtYXJnaW5Ub1RyYWRlclJhdwkAZQIJAGUCBRJyZW1haW5NYXJnaW5CZWZvcmUJAGQCBR5uZXdQb3NpdGlvbk1hcmdpbldpdGhTYW1lUmF0aW8FEnVucmVhbGl6ZWRQbmxBZnRlcgUQcmVhbGl6ZWRDbG9zZUZlZQQObWFyZ2luVG9UcmFkZXIDCQBmAgAABRFtYXJnaW5Ub1RyYWRlclJhdwkAAgECN0ludmFsaWQgaW50ZXJuYWxDbG9zZVBvc2l0aW9uIHBhcmFtczogdW5hYmxlIHRvIHBheSBmZWUFEW1hcmdpblRvVHJhZGVyUmF3BBFuZXdQb3NpdGlvbk1hcmdpbgMFDF9hZGRUb01hcmdpbgkAZAIFHm5ld1Bvc2l0aW9uTWFyZ2luV2l0aFNhbWVSYXRpbwUObWFyZ2luVG9UcmFkZXIFHm5ld1Bvc2l0aW9uTWFyZ2luV2l0aFNhbWVSYXRpbwMDCQECIT0CBRRfbWluUXVvdGVBc3NldEFtb3VudAAACQBmAgUUX21pblF1b3RlQXNzZXRBbW91bnQFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQHCQACAQkArAICCQCsAgIJAKwCAgINTGltaXQgZXJyb3I6IAkApAMBBRlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50AgMgPCAJAKQDAQUUX21pblF1b3RlQXNzZXRBbW91bnQJAKMKEQUPbmV3UG9zaXRpb25TaXplBRFuZXdQb3NpdGlvbk1hcmdpbgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFFG5ld1Bvc2l0aW9uTHN0VXBkQ1BGBQ9wb3NpdGlvbkJhZERlYnQFC3JlYWxpemVkUG5sAwMFDF9hZGRUb01hcmdpbgUOaXNQYXJ0aWFsQ2xvc2UHAAAFDm1hcmdpblRvVHJhZGVyBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIJAGUCCQEUb3BlbkludGVyZXN0Tm90aW9uYWwABRFvcGVuTm90aW9uYWxEZWx0YQkAZQIJARV0b3RhbExvbmdQb3NpdGlvblNpemUAAwUOaXNMb25nUG9zaXRpb24JAQNhYnMBBRVleGNoYW5nZWRQb3NpdGlvblNpemUAAAkAZQIJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAMJAQEhAQUOaXNMb25nUG9zaXRpb24JAQNhYnMBBRVleGNoYW5nZWRQb3NpdGlvblNpemUAAAkAZQIJARBvcGVuSW50ZXJlc3RMb25nAAMFDmlzTG9uZ1Bvc2l0aW9uBRFvcGVuTm90aW9uYWxEZWx0YQAACQBlAgkBEW9wZW5JbnRlcmVzdFNob3J0AAMJAQEhAQUOaXNMb25nUG9zaXRpb24FEW9wZW5Ob3Rpb25hbERlbHRhAAAJAGQCBRByZWFsaXplZENsb3NlRmVlBQtyb2xsb3ZlckZlZQUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAkAAgECO0ludmFsaWQgaW50ZXJuYWxDbG9zZVBvc2l0aW9uIHBhcmFtczogaW52YWxpZCBwb3NpdGlvbiBzaXplARBnZXRUd2FwU3BvdFByaWNlAAQIbWludXRlSWQJAGkCCQBpAgkBDWxhc3RUaW1lc3RhbXAAAOgHADwEDXN0YXJ0TWludXRlSWQJAGUCBQhtaW51dGVJZAUNVFdBUF9JTlRFUlZBTAQHbGlzdFN0cgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzBQ1rX2xhc3REYXRhU3RyAgAEBGxpc3QJALUJAgUHbGlzdFN0cgIBLAoBCGZpbHRlckZuAgthY2N1bXVsYXRvcgRuZXh0AwkAZwIFDXN0YXJ0TWludXRlSWQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAtgkBBQRuZXh0CQCsAgICH2dldFR3YXBTcG90UHJpY2U6IGludmFsaWQgaW50OiAFB2xpc3RTdHIJAM0IAgULYWNjdW11bGF0b3IJAQ1wYXJzZUludFZhbHVlAQUEbmV4dAULYWNjdW11bGF0b3IEBWxpc3RGCgACJGwFBGxpc3QKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBCGZpbHRlckZuAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAyMAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQECG1heEluZGV4AwkAZgIJAJADAQUFbGlzdEYAAAkAlgMBBQVsaXN0RgkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEJAJEDAgUEbGlzdAAACQCsAgICH2dldFR3YXBTcG90UHJpY2U6IGludmFsaWQgaW50OiAFB2xpc3RTdHIEDGxhc3RNaW51dGVJZAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQ5rX2xhc3RNaW51dGVJZAAABBZlbmRMYXN0Q3VtdWxhdGl2ZVByaWNlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAKwCAgkArAICBR1rX3R3YXBEYXRhTGFzdEN1bXVsYXRpdmVQcmljZQIBXwkApAMBBQxsYXN0TWludXRlSWQAAAQMZW5kTGFzdFByaWNlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAKwCAgkArAICBRNrX3R3YXBEYXRhTGFzdFByaWNlAgFfCQCkAwEFDGxhc3RNaW51dGVJZAAABBJub3dDdW11bGF0aXZlUHJpY2UJAGQCBRZlbmRMYXN0Q3VtdWxhdGl2ZVByaWNlCQBoAgkAZQIFCG1pbnV0ZUlkBQxsYXN0TWludXRlSWQFDGVuZExhc3RQcmljZQQYc3RhcnRMYXN0Q3VtdWxhdGl2ZVByaWNlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAKwCAgkArAICBR1rX3R3YXBEYXRhTGFzdEN1bXVsYXRpdmVQcmljZQIBXwkApAMBBQhtYXhJbmRleAAABA5zdGFydExhc3RQcmljZQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQCsAgIJAKwCAgUTa190d2FwRGF0YUxhc3RQcmljZQIBXwkApAMBBQhtYXhJbmRleAAABBRzdGFydEN1bXVsYXRpdmVQcmljZQkAZAIFGHN0YXJ0TGFzdEN1bXVsYXRpdmVQcmljZQkAaAIJAGUCBQ1zdGFydE1pbnV0ZUlkBQhtYXhJbmRleAUOc3RhcnRMYXN0UHJpY2UJAGkCCQBlAgUSbm93Q3VtdWxhdGl2ZVByaWNlBRRzdGFydEN1bXVsYXRpdmVQcmljZQUNVFdBUF9JTlRFUlZBTAETZ2V0VGVybWluYWxBbW1TdGF0ZQAEDV9wb3NpdGlvblNpemUJARF0b3RhbFBvc2l0aW9uU2l6ZQADCQAAAgUNX3Bvc2l0aW9uU2l6ZQAACQCUCgIJAQZxdEFzdFIACQEGYnNBc3RSAAQJZGlyZWN0aW9uCQBmAgUNX3Bvc2l0aW9uU2l6ZQAABA0kdDAzOTAyNDM5MjAzCQEKc3dhcE91dHB1dAMFCWRpcmVjdGlvbgkBA2FicwEFDV9wb3NpdGlvblNpemUHBBVjdXJyZW50TmV0TWFya2V0VmFsdWUIBQ0kdDAzOTAyNDM5MjAzAl8xBBl0ZXJtaW5hbFF1b3RlQXNzZXRSZXNlcnZlCAUNJHQwMzkwMjQzOTIwMwJfMgQYdGVybWluYWxCYXNlQXNzZXRSZXNlcnZlCAUNJHQwMzkwMjQzOTIwMwJfMwkAlAoCBRl0ZXJtaW5hbFF1b3RlQXNzZXRSZXNlcnZlBRh0ZXJtaW5hbEJhc2VBc3NldFJlc2VydmUBE2dldFF1b3RlQXNzZXRXZWlnaHQEEGJhc2VBc3NldFJlc2VydmURdG90YWxQb3NpdGlvblNpemURcXVvdGVBc3NldFJlc2VydmULdGFyZ2V0UHJpY2UEAWIJALYCAQUQYmFzZUFzc2V0UmVzZXJ2ZQQCc3oJALYCAQURdG90YWxQb3NpdGlvblNpemUEAXEJALYCAQURcXVvdGVBc3NldFJlc2VydmUEAXAJALYCAQULdGFyZ2V0UHJpY2UEAWsJAQVibXVsZAIFAXEFAWIEBG5ld0IJALcCAgUBYgUCc3oEBG5ld1EJAQViZGl2ZAIFAWsFBG5ld0IEAXoJAQViZGl2ZAIFBG5ld1EFBG5ld0IEBnJlc3VsdAkBBWJkaXZkAgUBcAUBegkAoAMBBQZyZXN1bHQBFGdldFN5bmNUZXJtaW5hbFByaWNlAw5fdGVybWluYWxQcmljZQdfcXRBc3RSB19ic0FzdFIEDV9wb3NpdGlvblNpemUJARF0b3RhbFBvc2l0aW9uU2l6ZQADCQAAAgUNX3Bvc2l0aW9uU2l6ZQAABAluZXdRdEFzdFcJAQRkaXZkAgkBBG11bGQCBQ5fdGVybWluYWxQcmljZQUHX2JzQXN0UgUHX3F0QXN0UgkAlQoDBQluZXdRdEFzdFcFDERFQ0lNQUxfVU5JVAAABAlkaXJlY3Rpb24JAGYCBQ1fcG9zaXRpb25TaXplAAAEFWN1cnJlbnROZXRNYXJrZXRWYWx1ZQgJAQpzd2FwT3V0cHV0AwUJZGlyZWN0aW9uCQEDYWJzAQUNX3Bvc2l0aW9uU2l6ZQcCXzEECW5ld1F0QXN0VwkBE2dldFF1b3RlQXNzZXRXZWlnaHQEBQdfYnNBc3RSBQ1fcG9zaXRpb25TaXplBQdfcXRBc3RSBQ5fdGVybWluYWxQcmljZQQJbmV3QnNBc3RXBQxERUNJTUFMX1VOSVQEDW1hcmdpblRvVmF1bHQICQErZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmxCeVZhbHVlcwcFDV9wb3NpdGlvblNpemUFFWN1cnJlbnROZXRNYXJrZXRWYWx1ZQUHX3F0QXN0UgUJbmV3UXRBc3RXBQdfYnNBc3RSBQluZXdCc0FzdFcFD1BOTF9PUFRJT05fU1BPVAJfMgkAlQoDBQluZXdRdEFzdFcFCW5ld0JzQXN0VwUNbWFyZ2luVG9WYXVsdAEKZ2V0RnVuZGluZwAED3VuZGVybHlpbmdQcmljZQkBDmdldE9yYWNsZVByaWNlAAQNc3BvdFR3YXBQcmljZQkBEGdldFR3YXBTcG90UHJpY2UABAdwcmVtaXVtCQBlAgUNc3BvdFR3YXBQcmljZQUPdW5kZXJseWluZ1ByaWNlAwMDCQAAAgkBFnRvdGFsU2hvcnRQb3NpdGlvblNpemUAAAAGCQAAAgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQAAAAYJAQ5pc01hcmtldENsb3NlZAAJAJQKAgAAAAADCQBmAgAABQdwcmVtaXVtBBRzaG9ydFByZW1pdW1GcmFjdGlvbgkBBGRpdmQCCQEEbXVsZAIFB3ByZW1pdW0JARRmdW5kaW5nUGVyaW9kRGVjaW1hbAAFB09ORV9EQVkEE2xvbmdQcmVtaXVtRnJhY3Rpb24JAQRkaXZkAgkBBG11bGQCBRRzaG9ydFByZW1pdW1GcmFjdGlvbgkBFnRvdGFsU2hvcnRQb3NpdGlvblNpemUACQEVdG90YWxMb25nUG9zaXRpb25TaXplAAkAlAoCBRRzaG9ydFByZW1pdW1GcmFjdGlvbgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgQTbG9uZ1ByZW1pdW1GcmFjdGlvbgkBBGRpdmQCCQEEbXVsZAIFB3ByZW1pdW0JARRmdW5kaW5nUGVyaW9kRGVjaW1hbAAFB09ORV9EQVkEFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEEZGl2ZAIJAQRtdWxkAgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQAJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAkAlAoCBRRzaG9ydFByZW1pdW1GcmFjdGlvbgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgEOZ2V0QWRqdXN0ZWRGZWUCC19hcnRpZmFjdElkEF9iYXNlRmVlRGlzY291bnQECmJhc2VGZWVSYXcJAQNmZWUABAdiYXNlRmVlCQEEbXVsZAIFCmJhc2VGZWVSYXcFEF9iYXNlRmVlRGlzY291bnQEDSR0MDQyMDY0NDI1NTkDCQECIT0CBQtfYXJ0aWZhY3RJZAIABAxhcnRpZmFjdEtpbmQJAQRzdHJBAgkBEW5mdE1hbmFnZXJBZGRyZXNzAAkBDnRvQ29tcG9zaXRlS2V5AgUMa190b2tlbl90eXBlBQtfYXJ0aWZhY3RJZAMJAAACBQxhcnRpZmFjdEtpbmQFGEZFRV9SRURVQ1RJT05fVE9LRU5fVFlQRQQJcmVkdWN0aW9uCQEEaW50QQIJARFuZnRNYW5hZ2VyQWRkcmVzcwAJAQ50b0NvbXBvc2l0ZUtleQIFDWtfdG9rZW5fcGFyYW0FC19hcnRpZmFjdElkBAthZGp1c3RlZEZlZQkBBG11bGQCBQdiYXNlRmVlBQlyZWR1Y3Rpb24JAJQKAgULYWRqdXN0ZWRGZWUGCQACAQIZSW52YWxpZCBhdHRhY2hlZCBhcnRpZmFjdAkAlAoCBQdiYXNlRmVlBwQLYWRqdXN0ZWRGZWUIBQ0kdDA0MjA2NDQyNTU5Al8xBAxidXJuQXJ0aWZhY3QIBQ0kdDA0MjA2NDQyNTU5Al8yCQCUCgIFC2FkanVzdGVkRmVlBQxidXJuQXJ0aWZhY3QBF2lzU2FtZUFzc2V0T3JOb1Bvc2l0aW9uAgdfdHJhZGVyCF9hc3NldElkBA9vbGRQb3NpdGlvblNpemUICQELZ2V0UG9zaXRpb24BBQdfdHJhZGVyAl8xAwkAAAIFD29sZFBvc2l0aW9uU2l6ZQAABgkAAAIJARBnZXRQb3NpdGlvbkFzc2V0AQUHX3RyYWRlcgUIX2Fzc2V0SWQBC2lzU2FtZUFzc2V0AgdfdHJhZGVyCF9hc3NldElkCQAAAgkBEGdldFBvc2l0aW9uQXNzZXQBBQdfdHJhZGVyBQhfYXNzZXRJZAEYZ2V0Rm9yVHJhZGVyV2l0aEFydGlmYWN0AgdfdHJhZGVyC19hcnRpZmFjdElkBBBkb0dldEZlZURpc2NvdW50CQD8BwQJAQxtaW5lckFkZHJlc3MAAhJjb21wdXRlRmVlRGlzY291bnQJAMwIAgUHX3RyYWRlcgUDbmlsBQNuaWwDCQAAAgUQZG9HZXRGZWVEaXNjb3VudAUQZG9HZXRGZWVEaXNjb3VudAQLZmVlRGlzY291bnQEByRtYXRjaDAFEGRvR2V0RmVlRGlzY291bnQDCQABAgUHJG1hdGNoMAIDSW50BAF4BQckbWF0Y2gwBQF4CQACAQIhSW52YWxpZCBjb21wdXRlRmVlRGlzY291bnQgcmVzdWx0BA0kdDA0MzIzOTQzMzEzCQEOZ2V0QWRqdXN0ZWRGZWUCBQtfYXJ0aWZhY3RJZAULZmVlRGlzY291bnQEC2FkanVzdGVkRmVlCAUNJHQwNDMyMzk0MzMxMwJfMQQMYnVybkFydGlmYWN0CAUNJHQwNDMyMzk0MzMxMwJfMgkAlAoCBQthZGp1c3RlZEZlZQUMYnVybkFydGlmYWN0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAQ1nZXRBcnRpZmFjdElkAQFpBAphcnRpZmFjdElkAwkAZgIJAJADAQgFAWkIcGF5bWVudHMAAQkA2AQBCQETdmFsdWVPckVycm9yTWVzc2FnZQIICQCRAwIIBQFpCHBheW1lbnRzAAEHYXNzZXRJZAISSW52YWxpZCBhcnRpZmFjdElkAgAFCmFydGlmYWN0SWQBDWRpc3RyaWJ1dGVGZWUBCl9mZWVBbW91bnQEDGZlZVRvU3Rha2VycwkBBG11bGQCBQpfZmVlQW1vdW50CQETZmVlVG9TdGFrZXJzUGVyY2VudAAECmZlZVRvVmF1bHQJAGUCBQpfZmVlQW1vdW50BQxmZWVUb1N0YWtlcnMJAJQKAgUMZmVlVG9TdGFrZXJzBQpmZWVUb1ZhdWx0AQ51cGRhdGVTZXR0aW5ncw0QX2luaXRNYXJnaW5SYXRpbwRfbW1yFF9saXF1aWRhdGlvbkZlZVJhdGlvDl9mdW5kaW5nUGVyaW9kBF9mZWUMX3NwcmVhZExpbWl0D19tYXhQcmljZUltcGFjdBhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8PX21heFByaWNlU3ByZWFkEF9tYXhPcGVuTm90aW9uYWwUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQPX21heE9yYWNsZURlbGF5DF9yb2xsb3ZlckZlZQkAzAgCCQEMSW50ZWdlckVudHJ5AgURa19pbml0TWFyZ2luUmF0aW8FEF9pbml0TWFyZ2luUmF0aW8JAMwIAgkBDEludGVnZXJFbnRyeQIFGGtfbWFpbnRlbmFuY2VNYXJnaW5SYXRpbwUEX21tcgkAzAgCCQEMSW50ZWdlckVudHJ5AgUVa19saXF1aWRhdGlvbkZlZVJhdGlvBRRfbGlxdWlkYXRpb25GZWVSYXRpbwkAzAgCCQEMSW50ZWdlckVudHJ5AgUPa19mdW5kaW5nUGVyaW9kBQ5fZnVuZGluZ1BlcmlvZAkAzAgCCQEMSW50ZWdlckVudHJ5AgUFa19mZWUFBF9mZWUJAMwIAgkBDEludGVnZXJFbnRyeQIFDWtfc3ByZWFkTGltaXQFDF9zcHJlYWRMaW1pdAkAzAgCCQEMSW50ZWdlckVudHJ5AgUQa19tYXhQcmljZUltcGFjdAUPX21heFByaWNlSW1wYWN0CQDMCAIJAQxJbnRlZ2VyRW50cnkCBRlrX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvBRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8JAMwIAgkBDEludGVnZXJFbnRyeQIFEGtfbWF4UHJpY2VTcHJlYWQFD19tYXhQcmljZVNwcmVhZAkAzAgCCQEMSW50ZWdlckVudHJ5AgURa19tYXhPcGVuTm90aW9uYWwFEF9tYXhPcGVuTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFFWtfZmVlVG9TdGFrZXJzUGVyY2VudAUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQJAMwIAgkBDEludGVnZXJFbnRyeQIFEGtfbWF4T3JhY2xlRGVsYXkFFF9mZWVUb1N0YWtlcnNQZXJjZW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ1rX3JvbGxvdmVyRmVlBQxfcm9sbG92ZXJGZWUFA25pbAENdXBkYXRlRnVuZGluZwURX25leHRGdW5kaW5nQmxvY2skX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uJV9sYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24QX2xvbmdGdW5kaW5nUmF0ZRFfc2hvcnRGdW5kaW5nUmF0ZQkAzAgCCQEMSW50ZWdlckVudHJ5AgUSa19uZXh0RnVuZGluZ0Jsb2NrBRFfbmV4dEZ1bmRpbmdCbG9jawkAzAgCCQEMSW50ZWdlckVudHJ5AgUla19sYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUkX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uCQDMCAIJAQxJbnRlZ2VyRW50cnkCBSZrX2xhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUlX2xhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkAzAgCCQEMSW50ZWdlckVudHJ5AgURa19sb25nRnVuZGluZ1JhdGUFEF9sb25nRnVuZGluZ1JhdGUJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfc2hvcnRGdW5kaW5nUmF0ZQURX3Nob3J0RnVuZGluZ1JhdGUFA25pbAEfaW5jcmVtZW50UG9zaXRpb25TZXF1ZW5jZU51bWJlcgIOX2lzTmV3UG9zaXRpb24IX2FkZHJlc3MDBQ5faXNOZXdQb3NpdGlvbgQPY3VycmVudFNlcXVlbmNlCQEMbGFzdFNlcXVlbmNlAAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUSa19wb3NpdGlvblNlcXVlbmNlBQhfYWRkcmVzcwkAZAIFD2N1cnJlbnRTZXF1ZW5jZQABCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQprX3NlcXVlbmNlCQBkAgUPY3VycmVudFNlcXVlbmNlAAEFA25pbAUDbmlsARF1cGRhdGVQb3NpdGlvbkZlZQMOX2lzTmV3UG9zaXRpb24IX2FkZHJlc3MEX2ZlZQMFDl9pc05ld1Bvc2l0aW9uCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBQ1rX3Bvc2l0aW9uRmVlBQhfYWRkcmVzcwUEX2ZlZQUDbmlsBQNuaWwBDnVwZGF0ZVBvc2l0aW9uBghfYWRkcmVzcwVfc2l6ZQdfbWFyZ2luDV9vcGVuTm90aW9uYWwgX2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24QX2xhdGVzdFRpbWVzdGFtcAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUOa19wb3NpdGlvblNpemUFCF9hZGRyZXNzBQVfc2l6ZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUQa19wb3NpdGlvbk1hcmdpbgUIX2FkZHJlc3MFB19tYXJnaW4JAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFFmtfcG9zaXRpb25PcGVuTm90aW9uYWwFCF9hZGRyZXNzBQ1fb3Blbk5vdGlvbmFsCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQhfYWRkcmVzcwUgX2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24JAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAUIX2FkZHJlc3MFEF9sYXRlc3RUaW1lc3RhbXAFA25pbAEKYXBwZW5kVHdhcAEGX3ByaWNlBAhtaW51dGVJZAkAaQIJAGkCCQENbGFzdFRpbWVzdGFtcAAA6AcAPAQQcHJldmlvdXNNaW51dGVJZAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQ5rX2xhc3RNaW51dGVJZAAAAwkAZgIFEHByZXZpb3VzTWludXRlSWQFCG1pbnV0ZUlkCQACAQIRVFdBUCBvdXQtb2Ytb3JkZXIEDGxhc3RNaW51dGVJZAMJAAACBRBwcmV2aW91c01pbnV0ZUlkAAAFCG1pbnV0ZUlkBRBwcmV2aW91c01pbnV0ZUlkAwkAZgIFCG1pbnV0ZUlkBRBwcmV2aW91c01pbnV0ZUlkBBNwcmV2Q3VtdWxhdGl2ZVByaWNlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAKwCAgkArAICBR1rX3R3YXBEYXRhTGFzdEN1bXVsYXRpdmVQcmljZQIBXwkApAMBBRBwcmV2aW91c01pbnV0ZUlkAAAECXByZXZQcmljZQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQCsAgIJAKwCAgUTa190d2FwRGF0YUxhc3RQcmljZQIBXwkApAMBBRBwcmV2aW91c01pbnV0ZUlkBQZfcHJpY2UEE2xhc3RDdW11bGF0aXZlUHJpY2UJAGQCBRNwcmV2Q3VtdWxhdGl2ZVByaWNlCQBoAgkAZQIFCG1pbnV0ZUlkBQxsYXN0TWludXRlSWQFCXByZXZQcmljZQQEbGlzdAkBC3B1c2hUb1F1ZXVlAwkBCXN0clRvTGlzdAEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwUNa19sYXN0RGF0YVN0cgIABQ1UV0FQX0lOVEVSVkFMCQCkAwEFCG1pbnV0ZUlkCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBR1rX3R3YXBEYXRhTGFzdEN1bXVsYXRpdmVQcmljZQkApAMBBQhtaW51dGVJZAUTbGFzdEN1bXVsYXRpdmVQcmljZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUTa190d2FwRGF0YUxhc3RQcmljZQkApAMBBQhtaW51dGVJZAUGX3ByaWNlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBRprX3R3YXBEYXRhUHJldmlvdXNNaW51dGVJZAkApAMBBQhtaW51dGVJZAUQcHJldmlvdXNNaW51dGVJZAkAzAgCCQEMSW50ZWdlckVudHJ5AgUOa19sYXN0TWludXRlSWQFCG1pbnV0ZUlkCQDMCAIJAQtTdHJpbmdFbnRyeQIFDWtfbGFzdERhdGFTdHIJAQlsaXN0VG9TdHIBBQRsaXN0BQNuaWwEGHR3YXBEYXRhUHJldmlvdXNNaW51dGVJZAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBRprX3R3YXBEYXRhUHJldmlvdXNNaW51dGVJZAkApAMBBQhtaW51dGVJZAAABBNwcmV2Q3VtdWxhdGl2ZVByaWNlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFHWtfdHdhcERhdGFMYXN0Q3VtdWxhdGl2ZVByaWNlCQCkAwEFGHR3YXBEYXRhUHJldmlvdXNNaW51dGVJZAAABAlwcmV2UHJpY2UJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUTa190d2FwRGF0YUxhc3RQcmljZQkApAMBBRh0d2FwRGF0YVByZXZpb3VzTWludXRlSWQFBl9wcmljZQQTbGFzdEN1bXVsYXRpdmVQcmljZQkAZAIFE3ByZXZDdW11bGF0aXZlUHJpY2UJAGgCCQBlAgUIbWludXRlSWQFGHR3YXBEYXRhUHJldmlvdXNNaW51dGVJZAUJcHJldlByaWNlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBR1rX3R3YXBEYXRhTGFzdEN1bXVsYXRpdmVQcmljZQkApAMBBQhtaW51dGVJZAUTbGFzdEN1bXVsYXRpdmVQcmljZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUTa190d2FwRGF0YUxhc3RQcmljZQkApAMBBQhtaW51dGVJZAUGX3ByaWNlBQNuaWwBEXVwZGF0ZUFtbVJlc2VydmVzAgdfcXRBc3RSB19ic0FzdFIJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tfcXVvdGVBc3NldFJlc2VydmUFB19xdEFzdFIJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfYmFzZUFzc2V0UmVzZXJ2ZQUHX2JzQXN0UgUDbmlsARB1cGRhdGVBbW1XZWlnaHRzAgdfcXRBc3RXB19ic0FzdFcJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfcXVvdGVBc3NldFdlaWdodAUHX3F0QXN0VwkAzAgCCQEMSW50ZWdlckVudHJ5AgURa19iYXNlQXNzZXRXZWlnaHQFB19ic0FzdFcFA25pbAEJdXBkYXRlQW1tCAdfcXRBc3RSB19ic0FzdFIXX3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIVX29wZW5JbnRlcmVzdE5vdGlvbmFsFl90b3RhbExvbmdQb3NpdGlvblNpemUXX3RvdGFsU2hvcnRQb3NpdGlvblNpemUWX3RvdGFsTG9uZ09wZW5Ob3Rpb25hbBdfdG90YWxTaG9ydE9wZW5Ob3Rpb25hbAQHX3F0QXN0VwkBBnF0QXN0VwAEB19ic0FzdFcJAQZic0FzdFcAAwkBAiE9AgkAZQIFFl90b3RhbExvbmdQb3NpdGlvblNpemUFF190b3RhbFNob3J0UG9zaXRpb25TaXplBRdfdG90YWxQb3NpdGlvblNpemVBZnRlcgkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICAhhJbnZhbGlkIEFNTSBzdGF0ZSBkYXRhOiAJAKQDAQUWX3RvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQIEICsgIAkApAMBBRdfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQIEICE9IAkApAMBBRdfdG90YWxQb3NpdGlvblNpemVBZnRlcgkAzggCCQDOCAIJARF1cGRhdGVBbW1SZXNlcnZlcwIFB19xdEFzdFIFB19ic0FzdFIJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tfdG90YWxQb3NpdGlvblNpemUFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRZrX29wZW5JbnRlcmVzdE5vdGlvbmFsBRVfb3BlbkludGVyZXN0Tm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFF2tfdG90YWxMb25nUG9zaXRpb25TaXplBRZfdG90YWxMb25nUG9zaXRpb25TaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRhrX3RvdGFsU2hvcnRQb3NpdGlvblNpemUFF190b3RhbFNob3J0UG9zaXRpb25TaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRJrX29wZW5JbnRlcmVzdExvbmcFFl90b3RhbExvbmdPcGVuTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tfb3BlbkludGVyZXN0U2hvcnQFF190b3RhbFNob3J0T3Blbk5vdGlvbmFsBQNuaWwJAQphcHBlbmRUd2FwAQkBBGRpdmQCCQEEbXVsZAIFB19xdEFzdFIFB19xdEFzdFcJAQRtdWxkAgUHX2JzQXN0UgUHX2JzQXN0VwEOZGVsZXRlUG9zaXRpb24BCF9hZGRyZXNzCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFDmtfcG9zaXRpb25TaXplBQhfYWRkcmVzcwkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBRBrX3Bvc2l0aW9uTWFyZ2luBQhfYWRkcmVzcwkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBRZrX3Bvc2l0aW9uT3Blbk5vdGlvbmFsBQhfYWRkcmVzcwkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQhfYWRkcmVzcwkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBQ9rX3Bvc2l0aW9uQXNzZXQFCF9hZGRyZXNzCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFDWtfcG9zaXRpb25GZWUFCF9hZGRyZXNzCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAUIX2FkZHJlc3MFA25pbAEId2l0aGRyYXcCCF9hZGRyZXNzB19hbW91bnQEB2JhbGFuY2UJAPAHAgUEdGhpcwkBCnF1b3RlQXNzZXQAAwkAZgIFB19hbW91bnQFB2JhbGFuY2UJAAIBCQCsAgIJAKwCAgkArAICAhNVbmFibGUgdG8gd2l0aGRyYXcgCQCkAwEFB19hbW91bnQCFyBmcm9tIGNvbnRyYWN0IGJhbGFuY2UgCQCkAwEFB2JhbGFuY2UJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwUIX2FkZHJlc3MFB19hbW91bnQJAQpxdW90ZUFzc2V0AAUDbmlsAQ11cGRhdGVCYWxhbmNlAQFpAwkAZgIAAAUBaQkAAgECB0JhbGFuY2UJAMwIAgkBDEludGVnZXJFbnRyeQIFCWtfYmFsYW5jZQUBaQUDbmlsAQt0cmFuc2ZlckZlZQEBaQkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCQEOc3Rha2luZ0FkZHJlc3MABQFpCQEKcXVvdGVBc3NldAAFA25pbAEOZG9CdXJuQXJ0aWZhY3QCDV9idXJuQXJ0aWZhY3QBaQMFDV9idXJuQXJ0aWZhY3QJAMwIAgkBBEJ1cm4CCQETdmFsdWVPckVycm9yTWVzc2FnZQIICQCRAwIIBQFpCHBheW1lbnRzAAEHYXNzZXRJZAIQSW52YWxpZCBhcnRpZmFjdAABBQNuaWwFA25pbBUBaQEFcGF1c2UAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECFEludmFsaWQgcGF1c2UgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQhrX3BhdXNlZAYFA25pbAFpAQd1bnBhdXNlAAMJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAJAAIBAhZJbnZhbGlkIHVucGF1c2UgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQhrX3BhdXNlZAcFA25pbAFpAQxzZXRDbG9zZU9ubHkAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECG0ludmFsaWQgc2V0Q2xvc2VPbmx5IHBhcmFtcwkAzAgCCQEMQm9vbGVhbkVudHJ5AgULa19jbG9zZU9ubHkGBQNuaWwBaQEOdW5zZXRDbG9zZU9ubHkAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECHUludmFsaWQgdW5zZXRDbG9zZU9ubHkgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQtrX2Nsb3NlT25seQcFA25pbAFpAQxhZGRMaXF1aWRpdHkBEV9xdW90ZUFzc2V0QW1vdW50AwMJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAGCQBnAgAABRFfcXVvdGVBc3NldEFtb3VudAkAAgECG0ludmFsaWQgYWRkTGlxdWlkaXR5IHBhcmFtcwQHX3F0QXN0UgkBBnF0QXN0UgAEB19ic0FzdFIJAQZic0FzdFIABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAEBXByaWNlCQEEZGl2ZAIJAQRtdWxkAgUHX3F0QXN0UgUHX3F0QXN0VwkBBG11bGQCBQdfYnNBc3RSBQdfYnNBc3RXBAtxdEFzdFJBZnRlcgkAZAIFB19xdEFzdFIFEV9xdW90ZUFzc2V0QW1vdW50BBRiYXNlQXNzZXRBbW91bnRUb0FkZAkAZQIJAQRkaXZkAgkBBG11bGQCBQtxdEFzdFJBZnRlcgUHX3F0QXN0VwUFcHJpY2UFB19ic0FzdFIEC2JzQXN0UkFmdGVyCQBkAgUHX2JzQXN0UgUUYmFzZUFzc2V0QW1vdW50VG9BZGQEDSR0MDUyNzIwNTI4NzEJARRnZXRTeW5jVGVybWluYWxQcmljZQMJAQ5nZXRPcmFjbGVQcmljZQAFC3F0QXN0UkFmdGVyBQtic0FzdFJBZnRlcgQTbmV3UXVvdGVBc3NldFdlaWdodAgFDSR0MDUyNzIwNTI4NzECXzEEEm5ld0Jhc2VBc3NldFdlaWdodAgFDSR0MDUyNzIwNTI4NzECXzIEDW1hcmdpblRvVmF1bHQIBQ0kdDA1MjcyMDUyODcxAl8zBA1kb0V4Y2hhbmdlUG5MAwkBAiE9AgUNbWFyZ2luVG9WYXVsdAAABA1kb0V4Y2hhbmdlUG5MCQD8BwQJAQx2YXVsdEFkZHJlc3MAAhVleGNoYW5nZUZyZWVBbmRMb2NrZWQJAMwIAgUNbWFyZ2luVG9WYXVsdAUDbmlsBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAkAzggCCQERdXBkYXRlQW1tUmVzZXJ2ZXMCBQtxdEFzdFJBZnRlcgULYnNBc3RSQWZ0ZXIJARB1cGRhdGVBbW1XZWlnaHRzAgUTbmV3UXVvdGVBc3NldFdlaWdodAUSbmV3QmFzZUFzc2V0V2VpZ2h0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBD3JlbW92ZUxpcXVpZGl0eQERX3F1b3RlQXNzZXRBbW91bnQDAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAYJAGcCBRFfcXVvdGVBc3NldEFtb3VudAAACQACAQIeSW52YWxpZCByZW1vdmVMaXF1aWRpdHkgcGFyYW1zBAdfcXRBc3RSCQEGcXRBc3RSAAQHX2JzQXN0UgkBBmJzQXN0UgAEB19xdEFzdFcJAQZxdEFzdFcABAdfYnNBc3RXCQEGYnNBc3RXAAQFcHJpY2UJAQRkaXZkAgkBBG11bGQCBQdfcXRBc3RSBQdfcXRBc3RXCQEEbXVsZAIFB19ic0FzdFIFB19ic0FzdFcEC3F0QXN0UkFmdGVyCQBlAgUHX3F0QXN0UgURX3F1b3RlQXNzZXRBbW91bnQEF2Jhc2VBc3NldEFtb3VudFRvUmVtb3ZlCQEDYWJzAQkAZQIJAQRkaXZkAgkBBG11bGQCBQtxdEFzdFJBZnRlcgUHX3F0QXN0VwUFcHJpY2UFB19ic0FzdFIEC2JzQXN0UkFmdGVyCQBlAgUHX2JzQXN0UgUXYmFzZUFzc2V0QW1vdW50VG9SZW1vdmUEDSR0MDUzODAzNTM5NTQJARRnZXRTeW5jVGVybWluYWxQcmljZQMJAQ5nZXRPcmFjbGVQcmljZQAFC3F0QXN0UkFmdGVyBQtic0FzdFJBZnRlcgQTbmV3UXVvdGVBc3NldFdlaWdodAgFDSR0MDUzODAzNTM5NTQCXzEEEm5ld0Jhc2VBc3NldFdlaWdodAgFDSR0MDUzODAzNTM5NTQCXzIEDW1hcmdpblRvVmF1bHQIBQ0kdDA1MzgwMzUzOTU0Al8zBA1kb0V4Y2hhbmdlUG5MAwkBAiE9AgUNbWFyZ2luVG9WYXVsdAAABA1kb0V4Y2hhbmdlUG5MCQD8BwQJAQx2YXVsdEFkZHJlc3MAAhVleGNoYW5nZUZyZWVBbmRMb2NrZWQJAMwIAgUNbWFyZ2luVG9WYXVsdAUDbmlsBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAkAzggCCQERdXBkYXRlQW1tUmVzZXJ2ZXMCBQtxdEFzdFJBZnRlcgULYnNBc3RSQWZ0ZXIJARB1cGRhdGVBbW1XZWlnaHRzAgUTbmV3UXVvdGVBc3NldFdlaWdodAUSbmV3QmFzZUFzc2V0V2VpZ2h0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDmNoYW5nZVNldHRpbmdzDRBfaW5pdE1hcmdpblJhdGlvBF9tbXIUX2xpcXVpZGF0aW9uRmVlUmF0aW8OX2Z1bmRpbmdQZXJpb2QEX2ZlZQxfc3ByZWFkTGltaXQPX21heFByaWNlSW1wYWN0GF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbw9fbWF4UHJpY2VTcHJlYWQQX21heE9wZW5Ob3Rpb25hbBRfZmVlVG9TdGFrZXJzUGVyY2VudA9fbWF4T3JhY2xlRGVsYXkMX3JvbGxvdmVyRmVlAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECHUludmFsaWQgY2hhbmdlU2V0dGluZ3MgcGFyYW1zCQEOdXBkYXRlU2V0dGluZ3MNBRBfaW5pdE1hcmdpblJhdGlvBQRfbW1yBRRfbGlxdWlkYXRpb25GZWVSYXRpbwUOX2Z1bmRpbmdQZXJpb2QFBF9mZWUFDF9zcHJlYWRMaW1pdAUPX21heFByaWNlSW1wYWN0BRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8FD19tYXhQcmljZVNwcmVhZAUQX21heE9wZW5Ob3Rpb25hbAUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQFD19tYXhPcmFjbGVEZWxheQUMX3JvbGxvdmVyRmVlAWkBCmluaXRpYWxpemUTB19xdEFzdFIHX2JzQXN0Ug5fZnVuZGluZ1BlcmlvZBBfaW5pdE1hcmdpblJhdGlvBF9tbXIUX2xpcXVpZGF0aW9uRmVlUmF0aW8EX2ZlZQdfb3JhY2xlCl9vcmFjbGVLZXkPX29yYWNsZUJsb2NrS2V5DF9jb29yZGluYXRvcgxfc3ByZWFkTGltaXQPX21heFByaWNlSW1wYWN0GF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbw9fbWF4UHJpY2VTcHJlYWQQX21heE9wZW5Ob3Rpb25hbBRfZmVlVG9TdGFrZXJzUGVyY2VudA9fbWF4T3JhY2xlRGVsYXkMX3JvbGxvdmVyRmVlAwMDAwMDAwMDAwMDAwMDAwMJAGcCAAAFB19xdEFzdFIGCQBnAgAABQdfYnNBc3RSBgkAZwIAAAUOX2Z1bmRpbmdQZXJpb2QGCQBnAgAABRBfaW5pdE1hcmdpblJhdGlvBgkAZwIAAAUEX21tcgYJAGcCAAAFFF9saXF1aWRhdGlvbkZlZVJhdGlvBgkAZwIAAAUEX2ZlZQYJAGcCAAAFDF9zcHJlYWRMaW1pdAYJAGcCAAAFD19tYXhQcmljZUltcGFjdAYJAGcCAAAFGF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwYJAGcCAAAFD19tYXhQcmljZVNwcmVhZAYJAGcCAAAFEF9tYXhPcGVuTm90aW9uYWwGCQBnAgAABRRfZmVlVG9TdGFrZXJzUGVyY2VudAYJAGYCBRRfZmVlVG9TdGFrZXJzUGVyY2VudAUMREVDSU1BTF9VTklUBgkAZwIAAAUPX21heE9yYWNsZURlbGF5BgkAZwIAAAUMX3JvbGxvdmVyRmVlBgkBC2luaXRpYWxpemVkAAkAAgECHUludmFsaWQgaW5pdGlhbGl6ZSBwYXJhbWV0ZXJzCQDOCAIJAM4IAgkAzggCCQDOCAIJAQl1cGRhdGVBbW0IBQdfcXRBc3RSBQdfYnNBc3RSAAAAAAAAAAAAAAAACQEOdXBkYXRlU2V0dGluZ3MNBRBfaW5pdE1hcmdpblJhdGlvBQRfbW1yBRRfbGlxdWlkYXRpb25GZWVSYXRpbwUOX2Z1bmRpbmdQZXJpb2QFBF9mZWUFDF9zcHJlYWRMaW1pdAUPX21heFByaWNlSW1wYWN0BRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8FD19tYXhQcmljZVNwcmVhZAUQX21heE9wZW5Ob3Rpb25hbAUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQFD19tYXhPcmFjbGVEZWxheQUMX3JvbGxvdmVyRmVlCQENdXBkYXRlRnVuZGluZwUJAGQCCQENbGFzdFRpbWVzdGFtcAAFDl9mdW5kaW5nUGVyaW9kAAAAAAAAAAAJAQ11cGRhdGVCYWxhbmNlAQAACQDMCAIJAQxCb29sZWFuRW50cnkCBQ1rX2luaXRpYWxpemVkBgkAzAgCCQELU3RyaW5nRW50cnkCBQVrX29yYQUHX29yYWNsZQkAzAgCCQELU3RyaW5nRW50cnkCBQlrX29yYV9rZXkFCl9vcmFjbGVLZXkJAMwIAgkBC1N0cmluZ0VudHJ5AgUPa19vcmFfYmxvY2tfa2V5BQ9fb3JhY2xlQmxvY2tLZXkJAMwIAgkBC1N0cmluZ0VudHJ5AgUUa19jb29yZGluYXRvckFkZHJlc3MFDF9jb29yZGluYXRvcgUDbmlsAWkBEGluY3JlYXNlUG9zaXRpb24ECl9kaXJlY3Rpb24JX2xldmVyYWdlE19taW5CYXNlQXNzZXRBbW91bnQIX3JlZkxpbmsEBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQHX3RyYWRlcgkBD2dldEFjdHVhbENhbGxlcgEFAWkECl9yYXdBbW91bnQICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50BAhfYXNzZXRJZAgJAJEDAggFAWkIcGF5bWVudHMAAAdhc3NldElkBAtfYXNzZXRJZFN0cgkA2AQBCQEFdmFsdWUBBQhfYXNzZXRJZAQMaXNRdW90ZUFzc2V0CQAAAgUIX2Fzc2V0SWQJAQpxdW90ZUFzc2V0AAMDAwMDAwMDAwMJAQIhPQIFCl9kaXJlY3Rpb24FCERJUl9MT05HCQECIT0CBQpfZGlyZWN0aW9uBQlESVJfU0hPUlQHBgkAZwIAAAUKX3Jhd0Ftb3VudAYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQEhAQUMaXNRdW90ZUFzc2V0BgkBASEBCQEXaXNTYW1lQXNzZXRPck5vUG9zaXRpb24CBQdfdHJhZGVyBQtfYXNzZXRJZFN0cgYJAQEhAQkBFnJlcXVpcmVNb3JlTWFyZ2luUmF0aW8DCQEEZGl2ZAIFDERFQ0lNQUxfVU5JVAUJX2xldmVyYWdlCQEPaW5pdE1hcmdpblJhdGlvAAYGCQEGcGF1c2VkAAYJAQljbG9zZU9ubHkABgkBDmlzTWFya2V0Q2xvc2VkAAkAAgECI0ludmFsaWQgaW5jcmVhc2VQb3NpdGlvbiBwYXJhbWV0ZXJzBA0kdDA1NzY0NTU3Nzk0CQEYZ2V0Rm9yVHJhZGVyV2l0aEFydGlmYWN0AgUHX3RyYWRlcgkBDWdldEFydGlmYWN0SWQBBQFpBAthZGp1c3RlZEZlZQgFDSR0MDU3NjQ1NTc3OTQCXzEEDGJ1cm5BcnRpZmFjdAgFDSR0MDU3NjQ1NTc3OTQCXzIEB19hbW91bnQJAQRkaXZkAgUKX3Jhd0Ftb3VudAkAZAIJAQRtdWxkAgULYWRqdXN0ZWRGZWUFCV9sZXZlcmFnZQUMREVDSU1BTF9VTklUBBNkaXN0cmlidXRlRmVlQW1vdW50CQBlAgUKX3Jhd0Ftb3VudAUHX2Ftb3VudAQOcmVmZXJyZXJGZWVBbnkJAPwHBAkBD3JlZmVycmFsQWRkcmVzcwACFWFjY2VwdFBheW1lbnRXaXRoTGluawkAzAgCBQdfdHJhZGVyCQDMCAIFCF9yZWZMaW5rBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUTZGlzdHJpYnV0ZUZlZUFtb3VudAUDbmlsAwkAAAIFDnJlZmVycmVyRmVlQW55BQ5yZWZlcnJlckZlZUFueQQLcmVmZXJyZXJGZWUEByRtYXRjaDAFDnJlZmVycmVyRmVlQW55AwkAAQIFByRtYXRjaDACA0ludAQBeAUHJG1hdGNoMAUBeAkAAgECE0ludmFsaWQgcmVmZXJyZXJGZWUECWZlZUFtb3VudAkAZQIFE2Rpc3RyaWJ1dGVGZWVBbW91bnQFC3JlZmVycmVyRmVlBA0kdDA1ODI5MDU4NDU4CQELZ2V0UG9zaXRpb24BBQdfdHJhZGVyBA9vbGRQb3NpdGlvblNpemUIBQ0kdDA1ODI5MDU4NDU4Al8xBBFvbGRQb3NpdGlvbk1hcmdpbggFDSR0MDU4MjkwNTg0NTgCXzIEF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNTgyOTA1ODQ1OAJfMwQUb2xkUG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA1ODI5MDU4NDU4Al80BBRvbGRQb3NpdGlvblRpbWVzdGFtcAgFDSR0MDU4MjkwNTg0NTgCXzUEDWlzTmV3UG9zaXRpb24JAAACBQ9vbGRQb3NpdGlvblNpemUAAAQPaXNTYW1lRGlyZWN0aW9uAwkAZgIFD29sZFBvc2l0aW9uU2l6ZQAACQAAAgUKX2RpcmVjdGlvbgUIRElSX0xPTkcJAAACBQpfZGlyZWN0aW9uBQlESVJfU0hPUlQEDmV4cGFuZEV4aXN0aW5nAwkBASEBBQ1pc05ld1Bvc2l0aW9uBQ9pc1NhbWVEaXJlY3Rpb24HBAVpc0FkZAkAAAIFCl9kaXJlY3Rpb24FCERJUl9MT05HBA0kdDA1ODc0NzYxODY4AwMFDWlzTmV3UG9zaXRpb24GBQ5leHBhbmRFeGlzdGluZwQMb3Blbk5vdGlvbmFsCQEEbXVsZAIFB19hbW91bnQFCV9sZXZlcmFnZQQNJHQwNTkyNTY1OTQyOQkBCXN3YXBJbnB1dAIFBWlzQWRkBQxvcGVuTm90aW9uYWwEFWFtb3VudEJhc2VBc3NldEJvdWdodAgFDSR0MDU5MjU2NTk0MjkCXzEEFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA1OTI1NjU5NDI5Al8yBBViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA1OTI1NjU5NDI5Al8zBBZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCAUNJHQwNTkyNTY1OTQyOQJfNAMDCQECIT0CBRNfbWluQmFzZUFzc2V0QW1vdW50AAAJAGYCBRNfbWluQmFzZUFzc2V0QW1vdW50CQEDYWJzAQUVYW1vdW50QmFzZUFzc2V0Qm91Z2h0BwkAAgEJAKwCAgkArAICCQCsAgICDUxpbWl0IGVycm9yOiAJAKQDAQkBA2FicwEFFWFtb3VudEJhc2VBc3NldEJvdWdodAIDIDwgCQCkAwEFE19taW5CYXNlQXNzZXRBbW91bnQED25ld1Bvc2l0aW9uU2l6ZQkAZAIFD29sZFBvc2l0aW9uU2l6ZQUVYW1vdW50QmFzZUFzc2V0Qm91Z2h0BBp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcgkAZAIJARBvcGVuSW50ZXJlc3RMb25nAAMJAGYCBQ9uZXdQb3NpdGlvblNpemUAAAUMb3Blbk5vdGlvbmFsAAAEG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcgkAZAIJARFvcGVuSW50ZXJlc3RTaG9ydAADCQBmAgAABQ9uZXdQb3NpdGlvblNpemUFDG9wZW5Ob3Rpb25hbAAABA0kdDA1OTk3NTYwMjUwCQEwY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudEFuZFJvbGxvdmVyRmVlBQUPb2xkUG9zaXRpb25TaXplBRFvbGRQb3NpdGlvbk1hcmdpbgUUb2xkUG9zaXRpb25Mc3RVcGRDUEYFFG9sZFBvc2l0aW9uVGltZXN0YW1wBQdfYW1vdW50BAxyZW1haW5NYXJnaW4IBQ0kdDA1OTk3NTYwMjUwAl8xBAJ4MQgFDSR0MDU5OTc1NjAyNTACXzIEAngyCAUNJHQwNTk5NzU2MDI1MAJfMwQLcm9sbG92ZXJGZWUIBQ0kdDA1OTk3NTYwMjUwAl80AwkBASEBCQEZcmVxdWlyZU5vdE92ZXJTcHJlYWRMaW1pdAIFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgkAAgECFU92ZXIgbWF4IHNwcmVhZCBsaW1pdAMJAQEhAQkBHXJlcXVpcmVOb3RPdmVyTWF4T3Blbk5vdGlvbmFsAgUadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIFG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcgkAAgECFk92ZXIgbWF4IG9wZW4gbm90aW9uYWwJAKAKDgUPbmV3UG9zaXRpb25TaXplBQxyZW1haW5NYXJnaW4JAGQCBRdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAUMb3Blbk5vdGlvbmFsCQEfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEFD25ld1Bvc2l0aW9uU2l6ZQkBDWxhc3RUaW1lc3RhbXAABRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIJAGQCCQEUb3BlbkludGVyZXN0Tm90aW9uYWwABQxvcGVuTm90aW9uYWwJAGQCCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAMJAGYCBQ9uZXdQb3NpdGlvblNpemUAAAkBA2FicwEFFWFtb3VudEJhc2VBc3NldEJvdWdodAAACQBkAgkBFnRvdGFsU2hvcnRQb3NpdGlvblNpemUAAwkAZgIAAAUPbmV3UG9zaXRpb25TaXplCQEDYWJzAQUVYW1vdW50QmFzZUFzc2V0Qm91Z2h0AAAFGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyBRt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIFC3JvbGxvdmVyRmVlBAxvcGVuTm90aW9uYWwJAQRtdWxkAgUHX2Ftb3VudAUJX2xldmVyYWdlBA0kdDA2MTU2ODYxNjg0CQEjZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmwCCQClCAEIBQFpBmNhbGxlcgUPUE5MX09QVElPTl9TUE9UBBNvbGRQb3NpdGlvbk5vdGlvbmFsCAUNJHQwNjE1Njg2MTY4NAJfMQQNdW5yZWFsaXplZFBubAgFDSR0MDYxNTY4NjE2ODQCXzIDCQBmAgUTb2xkUG9zaXRpb25Ob3Rpb25hbAUMb3Blbk5vdGlvbmFsCQACAQIuVXNlIGRlY3JlYXNlUG9zaXRpb24gdG8gZGVjcmVhc2UgcG9zaXRpb24gc2l6ZQkAAgECFENsb3NlIHBvc2l0aW9uIGZpcnN0BA9uZXdQb3NpdGlvblNpemUIBQ0kdDA1ODc0NzYxODY4Al8xBBduZXdQb3NpdGlvblJlbWFpbk1hcmdpbggFDSR0MDU4NzQ3NjE4NjgCXzIEF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNTg3NDc2MTg2OAJfMwQUbmV3UG9zaXRpb25MYXRlc3RDUEYIBQ0kdDA1ODc0NzYxODY4Al80BBRuZXdQb3NpdGlvblRpbWVzdGFtcAgFDSR0MDU4NzQ3NjE4NjgCXzUEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDU4NzQ3NjE4NjgCXzYEFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA1ODc0NzYxODY4Al83BBZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCAUNJHQwNTg3NDc2MTg2OAJfOAQZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcggFDSR0MDU4NzQ3NjE4NjgCXzkEDnRvdGFsTG9uZ0FmdGVyCAUNJHQwNTg3NDc2MTg2OANfMTAED3RvdGFsU2hvcnRBZnRlcggFDSR0MDU4NzQ3NjE4NjgDXzExBBp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcggFDSR0MDU4NzQ3NjE4NjgDXzEyBBt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA1ODc0NzYxODY4A18xMwQLcm9sbG92ZXJGZWUIBQ0kdDA1ODc0NzYxODY4A18xNAQNJHQwNjE4NzQ2MTk0NQkBDWRpc3RyaWJ1dGVGZWUBCQBkAgUJZmVlQW1vdW50BQtyb2xsb3ZlckZlZQQMZmVlVG9TdGFrZXJzCAUNJHQwNjE4NzQ2MTk0NQJfMQQKZmVlVG9WYXVsdAgFDSR0MDYxODc0NjE5NDUCXzIEBXN0YWtlAwUMaXNRdW90ZUFzc2V0BAVzdGFrZQkA/AcECQEMdmF1bHRBZGRyZXNzAAIJYWRkTG9ja2VkCQDMCAIHBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUHX2Ftb3VudAUDbmlsAwkAAAIFBXN0YWtlBQVzdGFrZQUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUFc3Rha2UFBXN0YWtlBAxkZXBvc2l0VmF1bHQJAPwHBAkBDHZhdWx0QWRkcmVzcwACB2FkZEZyZWUFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQpmZWVUb1ZhdWx0BQNuaWwDCQAAAgUMZGVwb3NpdFZhdWx0BQxkZXBvc2l0VmF1bHQECW5vdGlmeUZlZQkA/AcECQEMbWluZXJBZGRyZXNzAAIKbm90aWZ5RmVlcwkAzAgCBQdfdHJhZGVyCQDMCAIFCWZlZUFtb3VudAUDbmlsBQNuaWwDCQAAAgUJbm90aWZ5RmVlBQlub3RpZnlGZWUEDm5vdGlmeU5vdGlvbmFsCQD8BwQJAQxtaW5lckFkZHJlc3MAAg5ub3RpZnlOb3Rpb25hbAkAzAgCBQdfdHJhZGVyCQDMCAIFF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBQNuaWwFA25pbAMJAAACBQ5ub3RpZnlOb3Rpb25hbAUObm90aWZ5Tm90aW9uYWwJAM4IAgkAzggCCQDOCAIJAM4IAgkAzggCCQDOCAIJAQ51cGRhdGVQb3NpdGlvbgYFB190cmFkZXIFD25ld1Bvc2l0aW9uU2l6ZQUXbmV3UG9zaXRpb25SZW1haW5NYXJnaW4FF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBRRuZXdQb3NpdGlvbkxhdGVzdENQRgUUbmV3UG9zaXRpb25UaW1lc3RhbXAJAR9pbmNyZW1lbnRQb3NpdGlvblNlcXVlbmNlTnVtYmVyAgUNaXNOZXdQb3NpdGlvbgUHX3RyYWRlcgkBEXVwZGF0ZVBvc2l0aW9uRmVlAwUNaXNOZXdQb3NpdGlvbgUHX3RyYWRlcgULYWRqdXN0ZWRGZWUJAQl1cGRhdGVBbW0IBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIFGW9wZW5JbnRlcmVzdE5vdGlvbmFsQWZ0ZXIFDnRvdGFsTG9uZ0FmdGVyBQ90b3RhbFNob3J0QWZ0ZXIFGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyBRt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIJAQt0cmFuc2ZlckZlZQEFDGZlZVRvU3Rha2VycwkBDXVwZGF0ZUJhbGFuY2UBCQBkAgkBCGNiYWxhbmNlAAUHX2Ftb3VudAkBDmRvQnVybkFydGlmYWN0AgUMYnVybkFydGlmYWN0BQFpCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCWFkZE1hcmdpbgAEBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQHX3RyYWRlcgkApQgBCAUBaQZjYWxsZXIEB19hbW91bnQICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50BAhfYXNzZXRJZAgJAJEDAggFAWkIcGF5bWVudHMAAAdhc3NldElkBAtfYXNzZXRJZFN0cgkA2AQBCQEFdmFsdWUBBQhfYXNzZXRJZAQMaXNRdW90ZUFzc2V0CQAAAgUIX2Fzc2V0SWQJAQpxdW90ZUFzc2V0AAMDAwMDAwMJAQEhAQUMaXNRdW90ZUFzc2V0BgkBASEBCQETcmVxdWlyZU9wZW5Qb3NpdGlvbgEJAKUIAQgFAWkGY2FsbGVyBgkBASEBCQELaXNTYW1lQXNzZXQCBQdfdHJhZGVyBQtfYXNzZXRJZFN0cgYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQZwYXVzZWQABgkBCWNsb3NlT25seQAGCQEOaXNNYXJrZXRDbG9zZWQACQACAQIcSW52YWxpZCBhZGRNYXJnaW4gcGFyYW1ldGVycwQNJHQwNjM4NzE2NDAzOQkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgQPb2xkUG9zaXRpb25TaXplCAUNJHQwNjM4NzE2NDAzOQJfMQQRb2xkUG9zaXRpb25NYXJnaW4IBQ0kdDA2Mzg3MTY0MDM5Al8yBBdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDYzODcxNjQwMzkCXzMEFG9sZFBvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwNjM4NzE2NDAzOQJfNAQUb2xkUG9zaXRpb25UaW1lc3RhbXAIBQ0kdDA2Mzg3MTY0MDM5Al81BAVzdGFrZQkA/AcECQEMdmF1bHRBZGRyZXNzAAIJYWRkTG9ja2VkCQDMCAIHBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUHX2Ftb3VudAUDbmlsAwkAAAIFBXN0YWtlBQVzdGFrZQQLcm9sbG92ZXJGZWUJAQ9jYWxjUm9sbG92ZXJGZWUCBRFvbGRQb3NpdGlvbk1hcmdpbgUUb2xkUG9zaXRpb25UaW1lc3RhbXAEFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMDCQBmAgULcm9sbG92ZXJGZWUAAAQNJHQwNjQzMjk2NDM4OAkBDWRpc3RyaWJ1dGVGZWUBBQtyb2xsb3ZlckZlZQQMZmVlVG9TdGFrZXJzCAUNJHQwNjQzMjk2NDM4OAJfMQQKZmVlVG9WYXVsdAgFDSR0MDY0MzI5NjQzODgCXzIEB3Vuc3Rha2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACDndpdGhkcmF3TG9ja2VkCQDMCAIFDGZlZVRvU3Rha2VycwUDbmlsBQNuaWwDCQAAAgUHdW5zdGFrZQUHdW5zdGFrZQQLbG9ja0JhZERlYnQJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCCQEBLQEFCmZlZVRvVmF1bHQFA25pbAUDbmlsAwkAAAIFC2xvY2tCYWREZWJ0BQtsb2NrQmFkRGVidAkBC3RyYW5zZmVyRmVlAQUMZmVlVG9TdGFrZXJzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwkAzggCCQDOCAIJAQ51cGRhdGVQb3NpdGlvbgYFB190cmFkZXIFD29sZFBvc2l0aW9uU2l6ZQkAZAIJAGUCBRFvbGRQb3NpdGlvbk1hcmdpbgULcm9sbG92ZXJGZWUFB19hbW91bnQFF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsBRRvbGRQb3NpdGlvbkxzdFVwZENQRgkBDWxhc3RUaW1lc3RhbXAACQENdXBkYXRlQmFsYW5jZQEJAGUCCQBkAgkBCGNiYWxhbmNlAAUHX2Ftb3VudAULcm9sbG92ZXJGZWUFFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEMcmVtb3ZlTWFyZ2luAQdfYW1vdW50BARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEB190cmFkZXIJAKUIAQgFAWkGY2FsbGVyAwMDAwMJAGcCAAAFB19hbW91bnQGCQEBIQEJARNyZXF1aXJlT3BlblBvc2l0aW9uAQUHX3RyYWRlcgYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQZwYXVzZWQABgkBDmlzTWFya2V0Q2xvc2VkAAkAAgECH0ludmFsaWQgcmVtb3ZlTWFyZ2luIHBhcmFtZXRlcnMEDSR0MDY1NDMxNjU1OTkJAQtnZXRQb3NpdGlvbgEFB190cmFkZXIED29sZFBvc2l0aW9uU2l6ZQgFDSR0MDY1NDMxNjU1OTkCXzEEEW9sZFBvc2l0aW9uTWFyZ2luCAUNJHQwNjU0MzE2NTU5OQJfMgQXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDA2NTQzMTY1NTk5Al8zBBRvbGRQb3NpdGlvbkxzdFVwZENQRggFDSR0MDY1NDMxNjU1OTkCXzQEFG9sZFBvc2l0aW9uVGltZXN0YW1wCAUNJHQwNjU0MzE2NTU5OQJfNQQNJHQwNjU2MDU2NTg1NAkBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQUFD29sZFBvc2l0aW9uU2l6ZQURb2xkUG9zaXRpb25NYXJnaW4FFG9sZFBvc2l0aW9uTHN0VXBkQ1BGBRRvbGRQb3NpdGlvblRpbWVzdGFtcAkBAS0BBQdfYW1vdW50BAxyZW1haW5NYXJnaW4IBQ0kdDA2NTYwNTY1ODU0Al8xBAdiYWREZWJ0CAUNJHQwNjU2MDU2NTg1NAJfMgQOZnVuZGluZ1BheW1lbnQIBQ0kdDA2NTYwNTY1ODU0Al8zBAtyb2xsb3ZlckZlZQgFDSR0MDY1NjA1NjU4NTQCXzQDCQECIT0CBQdiYWREZWJ0AAAJAAIBAh1JbnZhbGlkIHJlbW92ZWQgbWFyZ2luIGFtb3VudAQLbWFyZ2luUmF0aW8JAQ9jYWxjTWFyZ2luUmF0aW8DBQxyZW1haW5NYXJnaW4FB2JhZERlYnQFF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsAwkBASEBCQEWcmVxdWlyZU1vcmVNYXJnaW5SYXRpbwMFC21hcmdpblJhdGlvCQEPaW5pdE1hcmdpblJhdGlvAAYJAAIBCQCsAgIJAKwCAgkArAICAhlUb28gbXVjaCBtYXJnaW4gcmVtb3ZlZDogCQCkAwEFC21hcmdpblJhdGlvAgMgPCAJAKQDAQkBD2luaXRNYXJnaW5SYXRpbwAEDSR0MDY2MjQwNjYyOTkJAQ1kaXN0cmlidXRlRmVlAQULcm9sbG92ZXJGZWUEDGZlZVRvU3Rha2VycwgFDSR0MDY2MjQwNjYyOTkCXzEECmZlZVRvVmF1bHQIBQ0kdDA2NjI0MDY2Mjk5Al8yBBZkb1RyYW5zZmVyRmVlVG9TdGFrZXJzAwkAZgIFC3JvbGxvdmVyRmVlAAAEC2xvY2tCYWREZWJ0CQD8BwQJAQx2YXVsdEFkZHJlc3MAAhVleGNoYW5nZUZyZWVBbmRMb2NrZWQJAMwIAgkBAS0BBQpmZWVUb1ZhdWx0BQNuaWwFA25pbAMJAAACBQtsb2NrQmFkRGVidAULbG9ja0JhZERlYnQJAQt0cmFuc2ZlckZlZQEFDGZlZVRvU3Rha2VycwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMFFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMEB3Vuc3Rha2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACDndpdGhkcmF3TG9ja2VkCQDMCAIJAGQCBQdfYW1vdW50BQxmZWVUb1N0YWtlcnMFA25pbAUDbmlsAwkAAAIFB3Vuc3Rha2UFB3Vuc3Rha2UJAM4IAgkAzggCCQDOCAIJAQ51cGRhdGVQb3NpdGlvbgYFB190cmFkZXIFD29sZFBvc2l0aW9uU2l6ZQUMcmVtYWluTWFyZ2luBRdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAkBH2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24BBQ9vbGRQb3NpdGlvblNpemUJAQ1sYXN0VGltZXN0YW1wAAkBCHdpdGhkcmF3AggFAWkGY2FsbGVyBQdfYW1vdW50CQENdXBkYXRlQmFsYW5jZQEJAGUCCQBlAgkBCGNiYWxhbmNlAAUHX2Ftb3VudAULcm9sbG92ZXJGZWUFFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQENY2xvc2VQb3NpdGlvbgMFX3NpemUUX21pblF1b3RlQXNzZXRBbW91bnQMX2FkZFRvTWFyZ2luBARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEB190cmFkZXIJAQ9nZXRBY3R1YWxDYWxsZXIBBQFpBA5fdHJhZGVyQWRkcmVzcwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEFB190cmFkZXICDkludmFsaWQgY2FsbGVyBAtwb3NpdGlvbkZlZQkBDmdldFBvc2l0aW9uRmVlAQUHX3RyYWRlcgMDAwMDAwkBASEBCQETcmVxdWlyZU9wZW5Qb3NpdGlvbgEFB190cmFkZXIGCQEBIQEJAQtpbml0aWFsaXplZAAGCQEGcGF1c2VkAAYJAGcCAAAFBV9zaXplBgkAZgIAAAUUX21pblF1b3RlQXNzZXRBbW91bnQGCQEOaXNNYXJrZXRDbG9zZWQACQACAQIgSW52YWxpZCBjbG9zZVBvc2l0aW9uIHBhcmFtZXRlcnMEDSR0MDY3ODMxNjc5NzEJAQtnZXRQb3NpdGlvbgEFB190cmFkZXIED29sZFBvc2l0aW9uU2l6ZQgFDSR0MDY3ODMxNjc5NzECXzEEEW9sZFBvc2l0aW9uTWFyZ2luCAUNJHQwNjc4MzE2Nzk3MQJfMgQXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDA2NzgzMTY3OTcxAl8zBBRvbGRQb3NpdGlvbkxzdFVwZENQRggFDSR0MDY3ODMxNjc5NzECXzQEDSR0MDY3OTc3Njg1NTAJARVpbnRlcm5hbENsb3NlUG9zaXRpb24GBQdfdHJhZGVyBQVfc2l6ZQULcG9zaXRpb25GZWUFFF9taW5RdW90ZUFzc2V0QW1vdW50BQxfYWRkVG9NYXJnaW4GBA9uZXdQb3NpdGlvblNpemUIBQ0kdDA2Nzk3NzY4NTUwAl8xBBFuZXdQb3NpdGlvbk1hcmdpbggFDSR0MDY3OTc3Njg1NTACXzIEF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNjc5Nzc2ODU1MAJfMwQUbmV3UG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA2Nzk3NzY4NTUwAl80BA9wb3NpdGlvbkJhZERlYnQIBQ0kdDA2Nzk3NzY4NTUwAl81BAtyZWFsaXplZFBubAgFDSR0MDY3OTc3Njg1NTACXzYEDm1hcmdpblRvVHJhZGVyCAUNJHQwNjc5Nzc2ODU1MAJfNwQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDY3OTc3Njg1NTACXzgEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDY3OTc3Njg1NTACXzkEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDA2Nzk3NzY4NTUwA18xMAQZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcggFDSR0MDY3OTc3Njg1NTADXzExBA50b3RhbExvbmdBZnRlcggFDSR0MDY3OTc3Njg1NTADXzEyBA90b3RhbFNob3J0QWZ0ZXIIBQ0kdDA2Nzk3NzY4NTUwA18xMwQadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA2Nzk3NzY4NTUwA18xNAQbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCAUNJHQwNjc5Nzc2ODU1MANfMTUEC3JlYWxpemVkRmVlCAUNJHQwNjc5Nzc2ODU1MANfMTYDCQBmAgUPcG9zaXRpb25CYWREZWJ0AAAJAAIBAipJbnZhbGlkIGNsb3NlUG9zaXRpb24gcGFyYW1ldGVyczogYmFkIGRlYnQEDmlzUGFydGlhbENsb3NlCQECIT0CBQ9uZXdQb3NpdGlvblNpemUAAAQOd2l0aGRyYXdBbW91bnQJAGQCBQ5tYXJnaW5Ub1RyYWRlcgULcmVhbGl6ZWRGZWUECmFtbUJhbGFuY2UJAGUCCQEIY2JhbGFuY2UABQ53aXRoZHJhd0Ftb3VudAQNYW1tTmV3QmFsYW5jZQMJAGYCAAAFCmFtbUJhbGFuY2UAAAUKYW1tQmFsYW5jZQQHdW5zdGFrZQkA/AcECQEMdmF1bHRBZGRyZXNzAAIOd2l0aGRyYXdMb2NrZWQJAMwIAgUOd2l0aGRyYXdBbW91bnQFA25pbAUDbmlsAwkAAAIFB3Vuc3Rha2UFB3Vuc3Rha2UEDSR0MDY5MDYwNjkxMTkJAQ1kaXN0cmlidXRlRmVlAQULcmVhbGl6ZWRGZWUEDGZlZVRvU3Rha2VycwgFDSR0MDY5MDYwNjkxMTkCXzEECmZlZVRvVmF1bHQIBQ0kdDA2OTA2MDY5MTE5Al8yBAxkZXBvc2l0VmF1bHQJAPwHBAkBDHZhdWx0QWRkcmVzcwACB2FkZEZyZWUFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQpmZWVUb1ZhdWx0BQNuaWwDCQAAAgUMZGVwb3NpdFZhdWx0BQxkZXBvc2l0VmF1bHQECW5vdGlmeUZlZQkA/AcECQEMbWluZXJBZGRyZXNzAAIKbm90aWZ5RmVlcwkAzAgCBQdfdHJhZGVyCQDMCAIFC3JlYWxpemVkRmVlBQNuaWwFA25pbAMJAAACBQlub3RpZnlGZWUFCW5vdGlmeUZlZQQObm90aWZ5Tm90aW9uYWwJAPwHBAkBDG1pbmVyQWRkcmVzcwACDm5vdGlmeU5vdGlvbmFsCQDMCAIFB190cmFkZXIJAMwIAgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFA25pbAUDbmlsAwkAAAIFDm5vdGlmeU5vdGlvbmFsBQ5ub3RpZnlOb3Rpb25hbAkAzggCCQDOCAIJAM4IAgkAzggCAwUOaXNQYXJ0aWFsQ2xvc2UJAQ51cGRhdGVQb3NpdGlvbgYFB190cmFkZXIFD25ld1Bvc2l0aW9uU2l6ZQURbmV3UG9zaXRpb25NYXJnaW4FF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBRRuZXdQb3NpdGlvbkxzdFVwZENQRgkBDWxhc3RUaW1lc3RhbXAACQEOZGVsZXRlUG9zaXRpb24BBQdfdHJhZGVyCQEJdXBkYXRlQW1tCAUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBRZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyBRlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyBQ50b3RhbExvbmdBZnRlcgUPdG90YWxTaG9ydEFmdGVyBRp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcgUbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyAwkAZgIFDm1hcmdpblRvVHJhZGVyAAAJAQh3aXRoZHJhdwIFDl90cmFkZXJBZGRyZXNzBQ5tYXJnaW5Ub1RyYWRlcgUDbmlsCQENdXBkYXRlQmFsYW5jZQEFDWFtbU5ld0JhbGFuY2UJAQt0cmFuc2ZlckZlZQEFDGZlZVRvU3Rha2VycwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQlsaXF1aWRhdGUBB190cmFkZXIEBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQPc3BvdE1hcmdpblJhdGlvCQEWZ2V0TWFyZ2luUmF0aW9CeU9wdGlvbgIFB190cmFkZXIFD1BOTF9PUFRJT05fU1BPVAQWbGlxdWlkYXRpb25NYXJnaW5SYXRpbwMJARZpc092ZXJGbHVjdHVhdGlvbkxpbWl0AAQRb3JhY2xlTWFyZ2luUmF0aW8JARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAgUHX3RyYWRlcgURUE5MX09QVElPTl9PUkFDTEUJAQR2bWF4AgUPc3BvdE1hcmdpblJhdGlvBRFvcmFjbGVNYXJnaW5SYXRpbwUPc3BvdE1hcmdpblJhdGlvAwMDAwMJAQEhAQkBFnJlcXVpcmVNb3JlTWFyZ2luUmF0aW8DBRZsaXF1aWRhdGlvbk1hcmdpblJhdGlvCQEWbWFpbnRlbmFuY2VNYXJnaW5SYXRpbwAHBgkBASEBCQETcmVxdWlyZU9wZW5Qb3NpdGlvbgEFB190cmFkZXIGCQEBIQEJAQtpbml0aWFsaXplZAAGCQEGcGF1c2VkAAYJAQ5pc01hcmtldENsb3NlZAAJAAIBAhNVbmFibGUgdG8gbGlxdWlkYXRlBBRpc1BhcnRpYWxMaXF1aWRhdGlvbgMDCQBmAgUPc3BvdE1hcmdpblJhdGlvCQETbGlxdWlkYXRpb25GZWVSYXRpbwAGCQBmAgkBF3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAAAABgkAZgIFDERFQ0lNQUxfVU5JVAkBF3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAAQPb2xkUG9zaXRpb25TaXplCAkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgJfMQQPcG9zaXRpb25TaXplQWJzCQEDYWJzAQUPb2xkUG9zaXRpb25TaXplBA0kdDA3MTQzMjcxNzU1AwUUaXNQYXJ0aWFsTGlxdWlkYXRpb24ED2xpcXVpZGF0aW9uU2l6ZQkBG2dldFBhcnRpYWxMaXF1aWRhdGlvbkFtb3VudAIFB190cmFkZXIFD29sZFBvc2l0aW9uU2l6ZQQQbGlxdWlkYXRpb25SYXRpbwkBBGRpdmQCCQEDYWJzAQUPbGlxdWlkYXRpb25TaXplBQ9wb3NpdGlvblNpemVBYnMJAJQKAgUQbGlxdWlkYXRpb25SYXRpbwkBA2FicwEFD2xpcXVpZGF0aW9uU2l6ZQkAlAoCAAAFD3Bvc2l0aW9uU2l6ZUFicwQQbGlxdWlkYXRpb25SYXRpbwgFDSR0MDcxNDMyNzE3NTUCXzEED2xpcXVpZGF0aW9uU2l6ZQgFDSR0MDcxNDMyNzE3NTUCXzIEDSR0MDcxNzYxNzIzODcJARVpbnRlcm5hbENsb3NlUG9zaXRpb24GBQdfdHJhZGVyAwUUaXNQYXJ0aWFsTGlxdWlkYXRpb24FD2xpcXVpZGF0aW9uU2l6ZQUPcG9zaXRpb25TaXplQWJzCQETbGlxdWlkYXRpb25GZWVSYXRpbwAAAAYHBA9uZXdQb3NpdGlvblNpemUIBQ0kdDA3MTc2MTcyMzg3Al8xBBFuZXdQb3NpdGlvbk1hcmdpbggFDSR0MDcxNzYxNzIzODcCXzIEF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNzE3NjE3MjM4NwJfMwQUbmV3UG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA3MTc2MTcyMzg3Al80BA9wb3NpdGlvbkJhZERlYnQIBQ0kdDA3MTc2MTcyMzg3Al81BAtyZWFsaXplZFBubAgFDSR0MDcxNzYxNzIzODcCXzYEDm1hcmdpblRvVHJhZGVyCAUNJHQwNzE3NjE3MjM4NwJfNwQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDcxNzYxNzIzODcCXzgEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDcxNzYxNzIzODcCXzkEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDA3MTc2MTcyMzg3A18xMAQZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcggFDSR0MDcxNzYxNzIzODcDXzExBA50b3RhbExvbmdBZnRlcggFDSR0MDcxNzYxNzIzODcDXzEyBA90b3RhbFNob3J0QWZ0ZXIIBQ0kdDA3MTc2MTcyMzg3A18xMwQadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA3MTc2MTcyMzg3A18xNAQbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCAUNJHQwNzE3NjE3MjM4NwNfMTUEEmxpcXVpZGF0aW9uUGVuYWx0eQgFDSR0MDcxNzYxNzIzODcDXzE2BA9mZWVUb0xpcXVpZGF0b3IJAGkCBRJsaXF1aWRhdGlvblBlbmFsdHkAAgQKZmVlVG9WYXVsdAkAZQIFEmxpcXVpZGF0aW9uUGVuYWx0eQUPZmVlVG9MaXF1aWRhdG9yBAphbW1CYWxhbmNlCQBlAgkBCGNiYWxhbmNlAAUSbGlxdWlkYXRpb25QZW5hbHR5BA1uZXdBbW1CYWxhbmNlAwkAZgIAAAUKYW1tQmFsYW5jZQAABQphbW1CYWxhbmNlBAtsb2NrQmFkRGVidAMJAGYCBQ9wb3NpdGlvbkJhZERlYnQAAAQLbG9ja0JhZERlYnQJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCBQ9wb3NpdGlvbkJhZERlYnQFA25pbAUDbmlsAwkAAAIFC2xvY2tCYWREZWJ0BQtsb2NrQmFkRGVidAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgULbG9ja0JhZERlYnQFC2xvY2tCYWREZWJ0BAd1bnN0YWtlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAg53aXRoZHJhd0xvY2tlZAkAzAgCBRJsaXF1aWRhdGlvblBlbmFsdHkFA25pbAUDbmlsAwkAAAIFB3Vuc3Rha2UFB3Vuc3Rha2UEEGRlcG9zaXRJbnN1cmFuY2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACB2FkZEZyZWUFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQpmZWVUb1ZhdWx0BQNuaWwDCQAAAgUQZGVwb3NpdEluc3VyYW5jZQUQZGVwb3NpdEluc3VyYW5jZQQObm90aWZ5Tm90aW9uYWwJAPwHBAkBDG1pbmVyQWRkcmVzcwACDm5vdGlmeU5vdGlvbmFsCQDMCAIFB190cmFkZXIJAMwIAgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFA25pbAUDbmlsAwkAAAIFDm5vdGlmeU5vdGlvbmFsBQ5ub3RpZnlOb3Rpb25hbAkAzggCCQDOCAIJAM4IAgMFFGlzUGFydGlhbExpcXVpZGF0aW9uCQEOdXBkYXRlUG9zaXRpb24GBQdfdHJhZGVyBQ9uZXdQb3NpdGlvblNpemUFEW5ld1Bvc2l0aW9uTWFyZ2luBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUUbmV3UG9zaXRpb25Mc3RVcGRDUEYJAQ1sYXN0VGltZXN0YW1wAAkBDmRlbGV0ZVBvc2l0aW9uAQUHX3RyYWRlcgkBCXVwZGF0ZUFtbQgFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgUWdG90YWxQb3NpdGlvblNpemVBZnRlcgUZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcgUOdG90YWxMb25nQWZ0ZXIFD3RvdGFsU2hvcnRBZnRlcgUadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIFG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcgkBCHdpdGhkcmF3AggFAWkGY2FsbGVyBQ9mZWVUb0xpcXVpZGF0b3IJAQ11cGRhdGVCYWxhbmNlAQUNbmV3QW1tQmFsYW5jZQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQpwYXlGdW5kaW5nAAQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBBVmdW5kaW5nQmxvY2tUaW1lc3RhbXAJARluZXh0RnVuZGluZ0Jsb2NrVGltZXN0YW1wAAMDAwkAZgIFFWZ1bmRpbmdCbG9ja1RpbWVzdGFtcAkBDWxhc3RUaW1lc3RhbXAABgkBASEBCQELaW5pdGlhbGl6ZWQABgkBBnBhdXNlZAAJAAIBCQCsAgIJAKwCAgkArAICAiFJbnZhbGlkIGZ1bmRpbmcgYmxvY2sgdGltZXN0YW1wOiAJAKQDAQkBDWxhc3RUaW1lc3RhbXAAAgMgPCAJAKQDAQUVZnVuZGluZ0Jsb2NrVGltZXN0YW1wBA91bmRlcmx5aW5nUHJpY2UJAQ5nZXRPcmFjbGVQcmljZQAEDSR0MDc0MzUzNzQ0MTUJAQpnZXRGdW5kaW5nAAQUc2hvcnRQcmVtaXVtRnJhY3Rpb24IBQ0kdDA3NDM1Mzc0NDE1Al8xBBNsb25nUHJlbWl1bUZyYWN0aW9uCAUNJHQwNzQzNTM3NDQxNQJfMgkBDXVwZGF0ZUZ1bmRpbmcFCQBkAgUVZnVuZGluZ0Jsb2NrVGltZXN0YW1wCQEUZnVuZGluZ1BlcmlvZFNlY29uZHMACQBkAgkBI2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAAUTbG9uZ1ByZW1pdW1GcmFjdGlvbgkAZAIJASRsYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24ABRRzaG9ydFByZW1pdW1GcmFjdGlvbgkBBGRpdmQCBRNsb25nUHJlbWl1bUZyYWN0aW9uBQ91bmRlcmx5aW5nUHJpY2UJAQRkaXZkAgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24FD3VuZGVybHlpbmdQcmljZQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlAAQHX3F0QXN0UgkBBnF0QXN0UgAEB19ic0FzdFIJAQZic0FzdFIABA0kdDA3NDg0Nzc0OTgyCQEUZ2V0U3luY1Rlcm1pbmFsUHJpY2UDCQEOZ2V0T3JhY2xlUHJpY2UABQdfcXRBc3RSBQdfYnNBc3RSBBNuZXdRdW90ZUFzc2V0V2VpZ2h0CAUNJHQwNzQ4NDc3NDk4MgJfMQQSbmV3QmFzZUFzc2V0V2VpZ2h0CAUNJHQwNzQ4NDc3NDk4MgJfMgQNbWFyZ2luVG9WYXVsdAgFDSR0MDc0ODQ3NzQ5ODICXzMEDWRvRXhjaGFuZ2VQbkwDCQECIT0CBQ1tYXJnaW5Ub1ZhdWx0AAAEDWRvRXhjaGFuZ2VQbkwJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCBQ1tYXJnaW5Ub1ZhdWx0BQNuaWwFA25pbAMJAAACBQ1kb0V4Y2hhbmdlUG5MBQ1kb0V4Y2hhbmdlUG5MBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBQ1kb0V4Y2hhbmdlUG5MBQ1kb0V4Y2hhbmdlUG5MCQDOCAIJARB1cGRhdGVBbW1XZWlnaHRzAgUTbmV3UXVvdGVBc3NldFdlaWdodAUSbmV3QmFzZUFzc2V0V2VpZ2h0CQEKYXBwZW5kVHdhcAEJAQRkaXZkAgkBBG11bGQCBQdfcXRBc3RSBRNuZXdRdW90ZUFzc2V0V2VpZ2h0CQEEbXVsZAIFB19ic0FzdFIFEm5ld0Jhc2VBc3NldFdlaWdodAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpASd2aWV3X2NhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnQBB190cmFkZXIEBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQNJHQwNzU1NTE3NTY3NQkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgQMcG9zaXRpb25TaXplCAUNJHQwNzU1NTE3NTY3NQJfMQQOcG9zaXRpb25NYXJnaW4IBQ0kdDA3NTU1MTc1Njc1Al8yBANwb24IBQ0kdDA3NTU1MTc1Njc1Al8zBBFwb3NpdGlvbkxzdFVwZENQRggFDSR0MDc1NTUxNzU2NzUCXzQEEXBvc2l0aW9uVGltZXN0YW1wCAUNJHQwNzU1NTE3NTY3NQJfNQQNJHQwNzU2Nzg3NTc3OQkBI2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sAgUHX3RyYWRlcgUPUE5MX09QVElPTl9TUE9UBBBwb3NpdGlvbk5vdGlvbmFsCAUNJHQwNzU2Nzg3NTc3OQJfMQQNdW5yZWFsaXplZFBubAgFDSR0MDc1Njc4NzU3NzkCXzIEDSR0MDc1NzgyNzYwMDYJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQxwb3NpdGlvblNpemUFDnBvc2l0aW9uTWFyZ2luBRFwb3NpdGlvbkxzdFVwZENQRgURcG9zaXRpb25UaW1lc3RhbXAFDXVucmVhbGl6ZWRQbmwEDHJlbWFpbk1hcmdpbggFDSR0MDc1NzgyNzYwMDYCXzEEB2JhZERlYnQIBQ0kdDA3NTc4Mjc2MDA2Al8yBA5mdW5kaW5nUGF5bWVudAgFDSR0MDc1NzgyNzYwMDYCXzMEC3JvbGxvdmVyRmVlCAUNJHQwNzU3ODI3NjAwNgJfNAkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAQFzAQUMcmVtYWluTWFyZ2luCQEBcwEFDmZ1bmRpbmdQYXltZW50CQEBcwEJAQ5nZXRNYXJnaW5SYXRpbwEFB190cmFkZXIJAQFzAQUNdW5yZWFsaXplZFBubAkBAXMBBQdiYWREZWJ0CQEBcwEFEHBvc2l0aW9uTm90aW9uYWwJAQFzAQULcm9sbG92ZXJGZWUJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEVdmlld19nZXRQZWdBZGp1c3RDb3N0AQZfcHJpY2UEB19xdEFzdFIJAQZxdEFzdFIABAdfYnNBc3RSCQEGYnNBc3RSAAQGcmVzdWx0CQEUZ2V0U3luY1Rlcm1pbmFsUHJpY2UDBQZfcHJpY2UFB19xdEFzdFIFB19ic0FzdFIJAAIBCQCkAwEIBQZyZXN1bHQCXzMBaQEYdmlld19nZXRUZXJtaW5hbEFtbVByaWNlAAQNJHQwNzY0NDI3NjUyMwkBE2dldFRlcm1pbmFsQW1tU3RhdGUABBl0ZXJtaW5hbFF1b3RlQXNzZXRSZXNlcnZlCAUNJHQwNzY0NDI3NjUyMwJfMQQYdGVybWluYWxCYXNlQXNzZXRSZXNlcnZlCAUNJHQwNzY0NDI3NjUyMwJfMgQFcHJpY2UJAQRkaXZkAgkBBG11bGQCBRl0ZXJtaW5hbFF1b3RlQXNzZXRSZXNlcnZlCQEGcXRBc3RXAAkBBG11bGQCBRh0ZXJtaW5hbEJhc2VBc3NldFJlc2VydmUJAQZic0FzdFcACQACAQkApAMBBQVwcmljZQFpAQ92aWV3X2dldEZ1bmRpbmcABA91bmRlcmx5aW5nUHJpY2UJAQ5nZXRPcmFjbGVQcmljZQAEDSR0MDc2NzM4NzY4MDAJAQpnZXRGdW5kaW5nAAQUc2hvcnRQcmVtaXVtRnJhY3Rpb24IBQ0kdDA3NjczODc2ODAwAl8xBBNsb25nUHJlbWl1bUZyYWN0aW9uCAUNJHQwNzY3Mzg3NjgwMAJfMgQLbG9uZ0Z1bmRpbmcJAQRkaXZkAgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgUPdW5kZXJseWluZ1ByaWNlBAxzaG9ydEZ1bmRpbmcJAQRkaXZkAgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24FD3VuZGVybHlpbmdQcmljZQkAAgEJAKwCAgkArAICCQCsAgIJAQFzAQULbG9uZ0Z1bmRpbmcJAQFzAQUMc2hvcnRGdW5kaW5nCQEBcwEJARBnZXRUd2FwU3BvdFByaWNlAAkBAXMBCQEOZ2V0T3JhY2xlUHJpY2UAAWkBEGNvbXB1dGVTcG90UHJpY2UABAZyZXN1bHQJAQxnZXRTcG90UHJpY2UACQCUCgIFA25pbAUGcmVzdWx0AWkBH2NvbXB1dGVGZWVGb3JUcmFkZXJXaXRoQXJ0aWZhY3QCB190cmFkZXILX2FydGlmYWN0SWQEBnJlc3VsdAkBGGdldEZvclRyYWRlcldpdGhBcnRpZmFjdAIFB190cmFkZXIFC19hcnRpZmFjdElkCQCUCgIFA25pbAUGcmVzdWx0AQJ0eAEGdmVyaWZ5AAkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAAkBDmFkbWluUHVibGljS2V5AP5v8SI=", "height": 2415004, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: ALbafyQFaGSpkuqRPvWjNcaDSSZYHYvpY916UR55TQVv Next: EKwSsGao7Q9g5SQjyAqESnKtazdjozYyzr53WRrYrBWp Diff:
OldNewDifferences
2727
2828 let k_positionFee = "k_positionFee"
2929
30+let k_positionLastUpdatedTimestamp = "k_positionTimestamp"
31+
3032 let k_initialized = "k_initialized"
3133
3234 let k_paused = "k_paused"
3436 let k_closeOnly = "k_closeOnly"
3537
3638 let k_fee = "k_fee"
39+
40+let k_rolloverFee = "k_rollover_fee"
3741
3842 let k_fundingPeriod = "k_fundingPeriod"
3943
117121
118122 let k_referral_address = "k_referral_address"
119123
120-let k_collateral_address = "k_collateral_address"
121-
122124 let k_exchange_address = "k_exchange_address"
123125
124126 let k_nft_manager_address = "k_nft_manager_address"
125-
126-let k_trader_market_asset_collateral = "k_trader_market_asset_collateral"
127127
128128 func toCompositeKey (_key,_address) = ((_key + "_") + _address)
129129
161161 func nftManagerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_nft_manager_address)), "NFT Manager not set")
162162
163163
164-func collateralAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_collateral_address)), "Collateral Manager not set")
165-
166-
167164 func swapAddress () = valueOrErrorMessage(addressFromString(valueOrErrorMessage(getString(coordinator(), k_exchange_address), "No swap address")), "Invalid swap address")
168-
169-
170-let k_whitelist_asset = "k_whitelist_asset"
171-
172-func isWhitelistAsset (_assetId) = valueOrElse(getBoolean(collateralAddress(), toCompositeKey(k_whitelist_asset, _assetId)), false)
173165
174166
175167 let k_token_param = "k_token_param"
191183 let DECIMAL_NUMBERS = 6
192184
193185 let DECIMAL_UNIT = (1 * (((((10 * 10) * 10) * 10) * 10) * 10))
186+
187+let MINUTES_IN_YEAR = (525600 * DECIMAL_UNIT)
194188
195189 let ONE_DAY = (86400 * DECIMAL_UNIT)
196190
237231 else _y
238232
239233
240-func listToStr (_list) = {
241- func _join (accumulator,val) = ((accumulator + val) + ",")
242-
243- let newListStr = {
244- let $l = _list
245- let $s = size($l)
246- let $acc0 = ""
247- func $f0_1 ($a,$i) = if (($i >= $s))
248- then $a
249- else _join($a, $l[$i])
250-
251- func $f0_2 ($a,$i) = if (($i >= $s))
252- then $a
253- else throw("List size exceeds 20")
254-
255- $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)
256- }
257- let newListStrU = dropRight(newListStr, 1)
258- let newListStrR = if ((take(newListStrU, 1) == ","))
259- then drop(newListStrU, 1)
260- else newListStrU
261- newListStrR
262- }
234+func listToStr (_list) = if ((size(_list) == 0))
235+ then ""
236+ else makeString(_list, ",")
263237
264238
265-func strToList (_str) = split(_str, ",")
239+func strToList (_str) = if ((_str == ""))
240+ then nil
241+ else split(_str, ",")
266242
267243
268244 func pushToQueue (_list,_maxSize,_value) = if ((size(_list) > _maxSize))
292268
293269
294270 func fee () = int(k_fee)
271+
272+
273+func rolloverFeeRate () = int(k_rolloverFee)
295274
296275
297276 func initMarginRatio () = int(k_initMarginRatio)
375354 func maxOracleDelay () = int(k_maxOracleDelay)
376355
377356
357+func lastTimestamp () = lastBlock.timestamp
358+
359+
378360 func getActualCaller (i) = valueOrElse(getString(ordersAddress(), "k_sender"), toString(i.caller))
379361
380362
403385 let positionSizeOpt = getInteger(this, toCompositeKey(k_positionSize, _trader))
404386 match positionSizeOpt {
405387 case positionSize: Int =>
406- $Tuple4(positionSize, getIntegerValue(this, toCompositeKey(k_positionMargin, _trader)), getIntegerValue(this, toCompositeKey(k_positionOpenNotional, _trader)), getIntegerValue(this, toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _trader)))
388+ $Tuple5(positionSize, getIntegerValue(this, toCompositeKey(k_positionMargin, _trader)), getIntegerValue(this, toCompositeKey(k_positionOpenNotional, _trader)), getIntegerValue(this, toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _trader)), getIntegerValue(this, toCompositeKey(k_positionLastUpdatedTimestamp, _trader)))
407389 case _ =>
408- $Tuple4(0, 0, 0, 0)
390+ $Tuple5(0, 0, 0, 0, 0)
409391 }
410392 }
411393
483465 let amountBaseAssetBought = if (_isAdd)
484466 then amountBaseAssetBoughtAbs
485467 else -(amountBaseAssetBoughtAbs)
486- let $t01713817308 = updateReserve(_isAdd, quoteAssetAmountAdjusted, amountBaseAssetBoughtAbs)
487- let quoteAssetReserveAfter1 = $t01713817308._1
488- let baseAssetReserveAfter1 = $t01713817308._2
489- let totalPositionSizeAfter1 = $t01713817308._3
468+ let $t01703617206 = updateReserve(_isAdd, quoteAssetAmountAdjusted, amountBaseAssetBoughtAbs)
469+ let quoteAssetReserveAfter1 = $t01703617206._1
470+ let baseAssetReserveAfter1 = $t01703617206._2
471+ let totalPositionSizeAfter1 = $t01703617206._3
490472 let priceBefore = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
491473 let marketPrice = divd(_quoteAssetAmount, amountBaseAssetBoughtAbs)
492474 let priceDiff = abs((priceBefore - marketPrice))
498480 }
499481
500482
501-func calcRemainMarginWithFundingPayment (_oldPositionSize,_oldPositionMargin,_oldPositionCumulativePremiumFraction,_marginDelta) = {
483+func calcRolloverFee (_oldPositionMargin,_oldPositionLastUpdatedTimestamp) = {
484+ let positionMinutes = ((((lastTimestamp() - _oldPositionLastUpdatedTimestamp) / 1000) / 60) * DECIMAL_UNIT)
485+ let rolloverFee = divd(muld(muld(_oldPositionMargin, positionMinutes), rolloverFeeRate()), MINUTES_IN_YEAR)
486+ rolloverFee
487+ }
488+
489+
490+func calcRemainMarginWithFundingPaymentAndRolloverFee (_oldPositionSize,_oldPositionMargin,_oldPositionCumulativePremiumFraction,_oldPositionLastUpdatedTimestamp,_marginDelta) = {
502491 let fundingPayment = if ((_oldPositionSize != 0))
503492 then {
504493 let _latestCumulativePremiumFraction = latestCumulativePremiumFraction(_oldPositionSize)
505494 muld((_latestCumulativePremiumFraction - _oldPositionCumulativePremiumFraction), _oldPositionSize)
506495 }
507496 else 0
508- let signedMargin = ((_marginDelta - fundingPayment) + _oldPositionMargin)
509- let $t01879518922 = if ((0 > signedMargin))
497+ let rolloverFee = calcRolloverFee(_oldPositionMargin, _oldPositionLastUpdatedTimestamp)
498+ let signedMargin = (((_marginDelta - rolloverFee) - fundingPayment) + _oldPositionMargin)
499+ let $t01946119588 = if ((0 > signedMargin))
510500 then $Tuple2(0, abs(signedMargin))
511501 else $Tuple2(abs(signedMargin), 0)
512- let remainMargin = $t01879518922._1
513- let badDebt = $t01879518922._2
514- $Tuple3(remainMargin, badDebt, fundingPayment)
502+ let remainMargin = $t01946119588._1
503+ let badDebt = $t01946119588._2
504+ $Tuple4(remainMargin, badDebt, fundingPayment, rolloverFee)
515505 }
516506
517507
528518 let quoteAssetDelta = abs((quoteAssetAfter - _quoteAssetReserve))
529519 let quoteAssetSold = muld(quoteAssetDelta, _quoteAssetWeight)
530520 let maxPriceImpactValue = maxPriceImpact()
531- let $t02009220254 = updateReserve(!(_isAdd), quoteAssetDelta, _baseAssetAmount)
532- let quoteAssetReserveAfter1 = $t02009220254._1
533- let baseAssetReserveAfter1 = $t02009220254._2
534- let totalPositionSizeAfter1 = $t02009220254._3
521+ let $t02085021012 = updateReserve(!(_isAdd), quoteAssetDelta, _baseAssetAmount)
522+ let quoteAssetReserveAfter1 = $t02085021012._1
523+ let baseAssetReserveAfter1 = $t02085021012._2
524+ let totalPositionSizeAfter1 = $t02085021012._3
535525 let marketPrice = divd(quoteAssetSold, _baseAssetAmount)
536526 let priceDiff = abs((priceBefore - marketPrice))
537527 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
552542
553543
554544 func getOraclePrice () = {
555- let oracle = valueOrErrorMessage(addressFromString(getStringValue(this, k_ora)), "")
556- let priceKey = getStringValue(this, k_ora_key)
545+ let oracle = valueOrErrorMessage(addressFromString(valueOrErrorMessage(getString(this, k_ora), ("No value: " + k_ora))), "")
546+ let priceKey = valueOrElse(getString(this, k_ora_key), ("No value: " + k_ora_key))
557547 let lastValue = valueOrErrorMessage(getInteger(oracle, priceKey), ((("Can not get oracle price. Oracle: " + toString(oracle)) + " key: ") + priceKey))
558548 let blockKey = valueOrElse(getString(this, k_ora_block_key), "")
559549 if ((blockKey != ""))
633623 let isShort = (0 > _positionSize)
634624 let positionNotional = if ((_option == PNL_OPTION_SPOT))
635625 then {
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
626+ let outPositionNotional = swapOutputWithReserves(!(isShort), positionSizeAbs, false, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)._1
641627 outPositionNotional
642628 }
643629 else muld(positionSizeAbs, getOraclePrice())
658644
659645
660646 func getPositionNotionalAndUnrealizedPnl (_trader,_option) = {
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
647+ let $t02857728705 = getPosition(_trader)
648+ let positionSize = $t02857728705._1
649+ let positionMargin = $t02857728705._2
650+ let positionOpenNotional = $t02857728705._3
651+ let positionLstUpdCPF = $t02857728705._4
666652 getPositionNotionalAndUnrealizedPnlByValues(positionSize, positionOpenNotional, qtAstR(), qtAstW(), bsAstR(), bsAstW(), _option)
667653 }
668654
671657
672658
673659 func getMarginRatioByOption (_trader,_option) = {
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
660+ let $t02922029361 = getPosition(_trader)
661+ let positionSize = $t02922029361._1
662+ let positionMargin = $t02922029361._2
663+ let pon = $t02922029361._3
664+ let positionLastUpdatedCPF = $t02922029361._4
665+ let positionTimestamp = $t02922029361._5
666+ let $t02936729460 = getPositionNotionalAndUnrealizedPnl(_trader, _option)
667+ let positionNotional = $t02936729460._1
668+ let unrealizedPnl = $t02936729460._2
669+ let $t02946529677 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLastUpdatedCPF, positionTimestamp, unrealizedPnl)
670+ let remainMargin = $t02946529677._1
671+ let badDebt = $t02946529677._2
685672 calcMarginRatio(remainMargin, badDebt, positionNotional)
686673 }
687674
696683 let maxExchangedQuoteAssetAmount = swapResult._1
697684 let priceImpact = swapResult._7
698685 if ((maxPriceImpact() > priceImpact))
699- then maxExchangedQuoteAssetAmount
700- else {
701- let exchangedPositionSize = muld(abs(_positionSize), partialLiquidationRatio())
702- let exchangedQuoteAssetAmount = swapOutput((_positionSize > 0), exchangedPositionSize, false)._1
703- exchangedQuoteAssetAmount
704- }
686+ then maxExchangedPositionSize
687+ else muld(abs(_positionSize), partialLiquidationRatio())
705688 }
706689
707690
708-func internalClosePosition (_trader,_checkMaxPriceImpact) = {
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
714- let unrealizedPnl = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)._2
715- let $t02933129499 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
716- let remainMargin = $t02933129499._1
717- let badDebt = $t02933129499._2
718- let exchangedPositionSize = -(positionSize)
719- let realizedPnl = unrealizedPnl
720- let marginToVault = -(remainMargin)
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
728- let openInterestNotionalAfter = (openInterestNotional() - positionOpenNotional)
729- $Tuple13(exchangedPositionSize, badDebt, realizedPnl, marginToVault, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, exchangedQuoteAssetAmount, totalLongAfter, totalShortAfter, (openInterestLong() - (if ((positionSize > 0))
730- then positionOpenNotional
731- else 0)), (openInterestShort() - (if ((0 > positionSize))
732- then positionOpenNotional
733- else 0)))
691+func internalClosePosition (_trader,_size,_fee,_minQuoteAssetAmount,_addToMargin,_checkMaxPriceImpact) = {
692+ let $t03072130877 = getPosition(_trader)
693+ let oldPositionSize = $t03072130877._1
694+ let oldPositionMargin = $t03072130877._2
695+ let oldPositionOpenNotional = $t03072130877._3
696+ let oldPositionLstUpdCPF = $t03072130877._4
697+ let oldPositionTimestamp = $t03072130877._5
698+ let isLongPosition = (oldPositionSize > 0)
699+ let absOldPositionSize = abs(oldPositionSize)
700+ if (if ((absOldPositionSize >= _size))
701+ then (_size > 0)
702+ else false)
703+ then {
704+ let isPartialClose = (absOldPositionSize > _size)
705+ let $t03116931620 = swapOutput((oldPositionSize > 0), _size, _checkMaxPriceImpact)
706+ let exchangedQuoteAssetAmount = $t03116931620._1
707+ let quoteAssetReserveAfter = $t03116931620._2
708+ let baseAssetReserveAfter = $t03116931620._3
709+ let totalPositionSizeAfter = $t03116931620._4
710+ let exchangedPositionSize = if ((oldPositionSize > 0))
711+ then -(_size)
712+ else _size
713+ let $t03183532042 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
714+ let oldPositionNotional = $t03183532042._1
715+ let unrealizedPnl = $t03183532042._2
716+ let realizedRatio = divd(abs(exchangedPositionSize), absOldPositionSize)
717+ let realizedPnl = muld(unrealizedPnl, realizedRatio)
718+ let $t03238332629 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, unrealizedPnl)
719+ let remainMarginBefore = $t03238332629._1
720+ let x1 = $t03238332629._2
721+ let x2 = $t03238332629._3
722+ let rolloverFee = $t03238332629._4
723+ let positionBadDebt = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, realizedPnl)._2
724+ let realizedCloseFee = muld(muld(oldPositionNotional, realizedRatio), _fee)
725+ let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
726+ let remainOpenNotional = if ((oldPositionSize > 0))
727+ then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
728+ else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
729+ let newPositionSize = (oldPositionSize + exchangedPositionSize)
730+ let $t03403534421 = if ((newPositionSize == 0))
731+ then $Tuple2(0, 0)
732+ else $Tuple2(abs(remainOpenNotional), latestCumulativePremiumFraction(newPositionSize))
733+ let newPositionOpenNotional = $t03403534421._1
734+ let newPositionLstUpdCPF = $t03403534421._2
735+ let openNotionalDelta = (oldPositionOpenNotional - newPositionOpenNotional)
736+ let marginRatio = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
737+ let newPositionMarginWithSameRatio = if ((oldPositionSize > 0))
738+ then (muld((newPositionOpenNotional + unrealizedPnlAfter), marginRatio) - unrealizedPnlAfter)
739+ else (muld((newPositionOpenNotional - unrealizedPnlAfter), marginRatio) - unrealizedPnlAfter)
740+ let marginToTraderRaw = ((remainMarginBefore - (newPositionMarginWithSameRatio + unrealizedPnlAfter)) - realizedCloseFee)
741+ let marginToTrader = if ((0 > marginToTraderRaw))
742+ then throw("Invalid internalClosePosition params: unable to pay fee")
743+ else marginToTraderRaw
744+ let newPositionMargin = if (_addToMargin)
745+ then (newPositionMarginWithSameRatio + marginToTrader)
746+ else newPositionMarginWithSameRatio
747+ if (if ((_minQuoteAssetAmount != 0))
748+ then (_minQuoteAssetAmount > exchangedQuoteAssetAmount)
749+ else false)
750+ then throw(((("Limit error: " + toString(exchangedQuoteAssetAmount)) + " < ") + toString(_minQuoteAssetAmount)))
751+ else $Tuple17(newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, positionBadDebt, realizedPnl, if (if (_addToMargin)
752+ then isPartialClose
753+ else false)
754+ then 0
755+ else marginToTrader, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() - openNotionalDelta), (totalLongPositionSize() - (if (isLongPosition)
756+ then abs(exchangedPositionSize)
757+ else 0)), (totalShortPositionSize() - (if (!(isLongPosition))
758+ then abs(exchangedPositionSize)
759+ else 0)), (openInterestLong() - (if (isLongPosition)
760+ then openNotionalDelta
761+ else 0)), (openInterestShort() - (if (!(isLongPosition))
762+ then openNotionalDelta
763+ else 0)), (realizedCloseFee + rolloverFee), exchangedQuoteAssetAmount)
764+ }
765+ else throw("Invalid internalClosePosition params: invalid position size")
734766 }
735767
736768
737769 func getTwapSpotPrice () = {
738- let minuteId = ((lastBlock.timestamp / 1000) / 60)
770+ let minuteId = ((lastTimestamp() / 1000) / 60)
739771 let startMinuteId = (minuteId - TWAP_INTERVAL)
740772 let listStr = valueOrElse(getString(this, k_lastDataStr), "")
741773 let list = split(listStr, ",")
742- func filterFn (accumulator,next) = if ((startMinuteId >= parseIntValue(next)))
774+ func filterFn (accumulator,next) = if ((startMinuteId >= valueOrErrorMessage(parseInt(next), ("getTwapSpotPrice: invalid int: " + listStr))))
743775 then (accumulator :+ parseIntValue(next))
744776 else accumulator
745777
759791 }
760792 let maxIndex = if ((size(listF) > 0))
761793 then max(listF)
762- else parseIntValue(list[0])
794+ else valueOrErrorMessage(parseInt(list[0]), ("getTwapSpotPrice: invalid int: " + listStr))
763795 let lastMinuteId = valueOrElse(getInteger(this, k_lastMinuteId), 0)
764796 let endLastCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(lastMinuteId))), 0)
765797 let endLastPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(lastMinuteId))), 0)
777809 then $Tuple2(qtAstR(), bsAstR())
778810 else {
779811 let direction = (_positionSize > 0)
780- let $t03202332202 = swapOutput(direction, abs(_positionSize), false)
781- let currentNetMarketValue = $t03202332202._1
782- let terminalQuoteAssetReserve = $t03202332202._2
783- let terminalBaseAssetReserve = $t03202332202._3
812+ let $t03902439203 = swapOutput(direction, abs(_positionSize), false)
813+ let currentNetMarketValue = $t03902439203._1
814+ let terminalQuoteAssetReserve = $t03902439203._2
815+ let terminalBaseAssetReserve = $t03902439203._3
784816 $Tuple2(terminalQuoteAssetReserve, terminalBaseAssetReserve)
785817 }
786818 }
845877 func getAdjustedFee (_artifactId,_baseFeeDiscount) = {
846878 let baseFeeRaw = fee()
847879 let baseFee = muld(baseFeeRaw, _baseFeeDiscount)
848- let $t03506335558 = if ((_artifactId != ""))
880+ let $t04206442559 = if ((_artifactId != ""))
849881 then {
850882 let artifactKind = strA(nftManagerAddress(), toCompositeKey(k_token_type, _artifactId))
851883 if ((artifactKind == FEE_REDUCTION_TOKEN_TYPE))
857889 else throw("Invalid attached artifact")
858890 }
859891 else $Tuple2(baseFee, false)
860- let adjustedFee = $t03506335558._1
861- let burnArtifact = $t03506335558._2
892+ let adjustedFee = $t04206442559._1
893+ let burnArtifact = $t04206442559._2
862894 $Tuple2(adjustedFee, burnArtifact)
863895 }
864896
874906 func isSameAsset (_trader,_assetId) = (getPositionAsset(_trader) == _assetId)
875907
876908
877-func getBorrowedByTraderInMarketKey (_amm,_assetId,_trader) = ((((((k_trader_market_asset_collateral + "_") + _amm) + "_") + _assetId) + "_") + _trader)
878-
879-
880-func getBorrowedByTrader (_trader) = {
881- let positionAsset = getPositionAsset(_trader)
882- if ((positionAsset == toBase58String(quoteAsset())))
883- then $Tuple2(0, positionAsset)
884- else {
885- let key = getBorrowedByTraderInMarketKey(toString(this), positionAsset, _trader)
886- let borrow = valueOrElse(getInteger(collateralAddress(), key), 0)
887- $Tuple2(borrow, positionAsset)
888- }
889- }
890-
891-
892909 func getForTraderWithArtifact (_trader,_artifactId) = {
893910 let doGetFeeDiscount = invoke(minerAddress(), "computeFeeDiscount", [_trader], nil)
894911 if ((doGetFeeDiscount == doGetFeeDiscount))
899916 case _ =>
900917 throw("Invalid computeFeeDiscount result")
901918 }
902- let $t03678936863 = getAdjustedFee(_artifactId, feeDiscount)
903- let adjustedFee = $t03678936863._1
904- let burnArtifact = $t03678936863._2
919+ let $t04323943313 = getAdjustedFee(_artifactId, feeDiscount)
920+ let adjustedFee = $t04323943313._1
921+ let burnArtifact = $t04323943313._2
905922 $Tuple2(adjustedFee, burnArtifact)
906923 }
907924 else throw("Strict value is not equal to itself.")
923940 }
924941
925942
926-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)]
943+func updateSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee) = [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), IntegerEntry(k_rolloverFee, _rolloverFee)]
927944
928945
929946 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)]
930-
931-
932-func updatePositionAsset (_address,_assetId) = [StringEntry(toCompositeKey(k_positionAsset, _address), _assetId)]
933947
934948
935949 func incrementPositionSequenceNumber (_isNewPosition,_address) = if (_isNewPosition)
945959 else nil
946960
947961
948-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)]
962+func updatePosition (_address,_size,_margin,_openNotional,_latestCumulativePremiumFraction,_latestTimestamp) = [IntegerEntry(toCompositeKey(k_positionSize, _address), _size), IntegerEntry(toCompositeKey(k_positionMargin, _address), _margin), IntegerEntry(toCompositeKey(k_positionOpenNotional, _address), _openNotional), IntegerEntry(toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _address), _latestCumulativePremiumFraction), IntegerEntry(toCompositeKey(k_positionLastUpdatedTimestamp, _address), _latestTimestamp)]
949963
950964
951965 func appendTwap (_price) = {
952- let minuteId = ((lastBlock.timestamp / 1000) / 60)
966+ let minuteId = ((lastTimestamp() / 1000) / 60)
953967 let previousMinuteId = valueOrElse(getInteger(this, k_lastMinuteId), 0)
954968 if ((previousMinuteId > minuteId))
955969 then throw("TWAP out-of-order")
9911005 }
9921006
9931007
994-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))]
1008+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)), DeleteEntry(toCompositeKey(k_positionFee, _address)), DeleteEntry(toCompositeKey(k_positionLastUpdatedTimestamp, _address))]
9951009
9961010
9971011 func withdraw (_address,_amount) = {
10571071 let qtAstRAfter = (_qtAstR + _quoteAssetAmount)
10581072 let baseAssetAmountToAdd = (divd(muld(qtAstRAfter, _qtAstW), price) - _bsAstR)
10591073 let bsAstRAfter = (_bsAstR + baseAssetAmountToAdd)
1060- let $t04610746258 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1061- let newQuoteAssetWeight = $t04610746258._1
1062- let newBaseAssetWeight = $t04610746258._2
1063- let marginToVault = $t04610746258._3
1074+ let $t05272052871 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1075+ let newQuoteAssetWeight = $t05272052871._1
1076+ let newBaseAssetWeight = $t05272052871._2
1077+ let marginToVault = $t05272052871._3
10641078 let doExchangePnL = if ((marginToVault != 0))
10651079 then {
10661080 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
10901104 let qtAstRAfter = (_qtAstR - _quoteAssetAmount)
10911105 let baseAssetAmountToRemove = abs((divd(muld(qtAstRAfter, _qtAstW), price) - _bsAstR))
10921106 let bsAstRAfter = (_bsAstR - baseAssetAmountToRemove)
1093- let $t04719047341 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1094- let newQuoteAssetWeight = $t04719047341._1
1095- let newBaseAssetWeight = $t04719047341._2
1096- let marginToVault = $t04719047341._3
1107+ let $t05380353954 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1108+ let newQuoteAssetWeight = $t05380353954._1
1109+ let newBaseAssetWeight = $t05380353954._2
1110+ let marginToVault = $t05380353954._3
10971111 let doExchangePnL = if ((marginToVault != 0))
10981112 then {
10991113 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
11101124
11111125
11121126 @Callable(i)
1113-func changeSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay) = if ((i.caller != adminAddress()))
1127+func changeSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee) = if ((i.caller != adminAddress()))
11141128 then throw("Invalid changeSettings params")
1115- else updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread, _maxOpenNotional, _feeToStakersPercent, _maxOracleDelay)
1129+ else updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread, _maxOpenNotional, _feeToStakersPercent, _maxOracleDelay, _rolloverFee)
11161130
11171131
11181132
11191133 @Callable(i)
1120-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))
1134+func initialize (_qtAstR,_bsAstR,_fundingPeriod,_initMarginRatio,_mmr,_liquidationFeeRatio,_fee,_oracle,_oracleKey,_oracleBlockKey,_coordinator,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee) = if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if ((0 >= _qtAstR))
11211135 then true
11221136 else (0 >= _bsAstR))
11231137 then true
11471161 then true
11481162 else (0 >= _maxOracleDelay))
11491163 then true
1164+ else (0 >= _rolloverFee))
1165+ then true
11501166 else initialized())
11511167 then throw("Invalid initialize parameters")
1152- 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)])
1168+ else ((((updateAmm(_qtAstR, _bsAstR, 0, 0, 0, 0, 0, 0) ++ updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread, _maxOpenNotional, _feeToStakersPercent, _maxOracleDelay, _rolloverFee)) ++ updateFunding((lastTimestamp() + _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)])
11531169
11541170
11551171
11631179 let _assetId = i.payments[0].assetId
11641180 let _assetIdStr = toBase58String(value(_assetId))
11651181 let isQuoteAsset = (_assetId == quoteAsset())
1166- let isCollateralAsset = isWhitelistAsset(_assetIdStr)
11671182 if (if (if (if (if (if (if (if (if (if ((_direction != DIR_LONG))
11681183 then (_direction != DIR_SHORT)
11691184 else false)
11721187 then true
11731188 else !(initialized()))
11741189 then true
1175- else if (!(isQuoteAsset))
1176- then !(isCollateralAsset)
1177- else false)
1190+ else !(isQuoteAsset))
11781191 then true
11791192 else !(isSameAssetOrNoPosition(_trader, _assetIdStr)))
11801193 then true
11871200 else isMarketClosed())
11881201 then throw("Invalid increasePosition parameters")
11891202 else {
1190- let $t05100951158 = getForTraderWithArtifact(_trader, getArtifactId(i))
1191- let adjustedFee = $t05100951158._1
1192- let burnArtifact = $t05100951158._2
1203+ let $t05764557794 = getForTraderWithArtifact(_trader, getArtifactId(i))
1204+ let adjustedFee = $t05764557794._1
1205+ let burnArtifact = $t05764557794._2
11931206 let _amount = divd(_rawAmount, (muld(adjustedFee, _leverage) + DECIMAL_UNIT))
1194- let rawFeeAmount = (_rawAmount - _amount)
1195- let distributeFeeAmount = if (isCollateralAsset)
1207+ let distributeFeeAmount = (_rawAmount - _amount)
1208+ let referrerFeeAny = invoke(referralAddress(), "acceptPaymentWithLink", [_trader, _refLink], [AttachedPayment(quoteAsset(), distributeFeeAmount)])
1209+ if ((referrerFeeAny == referrerFeeAny))
11961210 then {
1197- let doBorrow = invoke(collateralAddress(), "borrow", [_trader], [AttachedPayment(_assetId, _amount)])
1198- if ((doBorrow == doBorrow))
1211+ let referrerFee = match referrerFeeAny {
1212+ case x: Int =>
1213+ x
1214+ case _ =>
1215+ throw("Invalid referrerFee")
1216+ }
1217+ let feeAmount = (distributeFeeAmount - referrerFee)
1218+ let $t05829058458 = getPosition(_trader)
1219+ let oldPositionSize = $t05829058458._1
1220+ let oldPositionMargin = $t05829058458._2
1221+ let oldPositionOpenNotional = $t05829058458._3
1222+ let oldPositionLstUpdCPF = $t05829058458._4
1223+ let oldPositionTimestamp = $t05829058458._5
1224+ let isNewPosition = (oldPositionSize == 0)
1225+ let isSameDirection = if ((oldPositionSize > 0))
1226+ then (_direction == DIR_LONG)
1227+ else (_direction == DIR_SHORT)
1228+ let expandExisting = if (!(isNewPosition))
1229+ then isSameDirection
1230+ else false
1231+ let isAdd = (_direction == DIR_LONG)
1232+ let $t05874761868 = if (if (isNewPosition)
1233+ then true
1234+ else expandExisting)
11991235 then {
1200- let balanceBefore = assetBalance(this, quoteAsset())
1201- if ((balanceBefore == balanceBefore))
1202- then {
1203- let doSwap = invoke(swapAddress(), "swap", [toBase58String(quoteAsset()), 0], [AttachedPayment(_assetId, rawFeeAmount)])
1204- if ((doSwap == doSwap))
1205- then {
1206- let balanceAfter = assetBalance(this, quoteAsset())
1207- if ((balanceAfter == balanceAfter))
1208- then {
1209- let exchangedAmount = (balanceAfter - balanceBefore)
1210- if ((exchangedAmount == exchangedAmount))
1211- then exchangedAmount
1212- else throw("Strict value is not equal to itself.")
1213- }
1214- else throw("Strict value is not equal to itself.")
1215- }
1216- else throw("Strict value is not equal to itself.")
1236+ let openNotional = muld(_amount, _leverage)
1237+ let $t05925659429 = swapInput(isAdd, openNotional)
1238+ let amountBaseAssetBought = $t05925659429._1
1239+ let quoteAssetReserveAfter = $t05925659429._2
1240+ let baseAssetReserveAfter = $t05925659429._3
1241+ let totalPositionSizeAfter = $t05925659429._4
1242+ if (if ((_minBaseAssetAmount != 0))
1243+ then (_minBaseAssetAmount > abs(amountBaseAssetBought))
1244+ else false)
1245+ then throw(((("Limit error: " + toString(abs(amountBaseAssetBought))) + " < ") + toString(_minBaseAssetAmount)))
1246+ else {
1247+ let newPositionSize = (oldPositionSize + amountBaseAssetBought)
1248+ let totalLongOpenInterestAfter = (openInterestLong() + (if ((newPositionSize > 0))
1249+ then openNotional
1250+ else 0))
1251+ let totalShortOpenInterestAfter = (openInterestShort() + (if ((0 > newPositionSize))
1252+ then openNotional
1253+ else 0))
1254+ let $t05997560250 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
1255+ let remainMargin = $t05997560250._1
1256+ let x1 = $t05997560250._2
1257+ let x2 = $t05997560250._3
1258+ let rolloverFee = $t05997560250._4
1259+ if (!(requireNotOverSpreadLimit(quoteAssetReserveAfter, baseAssetReserveAfter)))
1260+ then throw("Over max spread limit")
1261+ else if (!(requireNotOverMaxOpenNotional(totalLongOpenInterestAfter, totalShortOpenInterestAfter)))
1262+ then throw("Over max open notional")
1263+ else $Tuple14(newPositionSize, remainMargin, (oldPositionOpenNotional + openNotional), latestCumulativePremiumFraction(newPositionSize), lastTimestamp(), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() + openNotional), (totalLongPositionSize() + (if ((newPositionSize > 0))
1264+ then abs(amountBaseAssetBought)
1265+ else 0)), (totalShortPositionSize() + (if ((0 > newPositionSize))
1266+ then abs(amountBaseAssetBought)
1267+ else 0)), totalLongOpenInterestAfter, totalShortOpenInterestAfter, rolloverFee)
12171268 }
1269+ }
1270+ else {
1271+ let openNotional = muld(_amount, _leverage)
1272+ let $t06156861684 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
1273+ let oldPositionNotional = $t06156861684._1
1274+ let unrealizedPnl = $t06156861684._2
1275+ if ((oldPositionNotional > openNotional))
1276+ then throw("Use decreasePosition to decrease position size")
1277+ else throw("Close position first")
1278+ }
1279+ let newPositionSize = $t05874761868._1
1280+ let newPositionRemainMargin = $t05874761868._2
1281+ let newPositionOpenNotional = $t05874761868._3
1282+ let newPositionLatestCPF = $t05874761868._4
1283+ let newPositionTimestamp = $t05874761868._5
1284+ let baseAssetReserveAfter = $t05874761868._6
1285+ let quoteAssetReserveAfter = $t05874761868._7
1286+ let totalPositionSizeAfter = $t05874761868._8
1287+ let openInterestNotionalAfter = $t05874761868._9
1288+ let totalLongAfter = $t05874761868._10
1289+ let totalShortAfter = $t05874761868._11
1290+ let totalLongOpenInterestAfter = $t05874761868._12
1291+ let totalShortOpenInterestAfter = $t05874761868._13
1292+ let rolloverFee = $t05874761868._14
1293+ let $t06187461945 = distributeFee((feeAmount + rolloverFee))
1294+ let feeToStakers = $t06187461945._1
1295+ let feeToVault = $t06187461945._2
1296+ let stake = if (isQuoteAsset)
1297+ then {
1298+ let stake = invoke(vaultAddress(), "addLocked", [false], [AttachedPayment(quoteAsset(), _amount)])
1299+ if ((stake == stake))
1300+ then nil
12181301 else throw("Strict value is not equal to itself.")
12191302 }
1220- else throw("Strict value is not equal to itself.")
1221- }
1222- else rawFeeAmount
1223- if ((distributeFeeAmount == distributeFeeAmount))
1224- then {
1225- let referrerFeeAny = invoke(referralAddress(), "acceptPaymentWithLink", [_trader, _refLink], [AttachedPayment(quoteAsset(), distributeFeeAmount)])
1226- if ((referrerFeeAny == referrerFeeAny))
1303+ else nil
1304+ if ((stake == stake))
12271305 then {
1228- let referrerFee = match referrerFeeAny {
1229- case x: Int =>
1230- x
1231- case _ =>
1232- throw("Invalid referrerFee")
1233- }
1234- let feeAmount = (distributeFeeAmount - referrerFee)
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
1240- let isNewPosition = (oldPositionSize == 0)
1241- let isSameDirection = if ((oldPositionSize > 0))
1242- then (_direction == DIR_LONG)
1243- else (_direction == DIR_SHORT)
1244- let expandExisting = if (!(isNewPosition))
1245- then isSameDirection
1246- else false
1247- let isAdd = (_direction == DIR_LONG)
1248- let $t05292955891 = if (if (isNewPosition)
1249- then true
1250- else expandExisting)
1306+ let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1307+ if ((depositVault == depositVault))
12511308 then {
1252- let openNotional = muld(_amount, _leverage)
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
1258- if (if ((_minBaseAssetAmount != 0))
1259- then (_minBaseAssetAmount > abs(amountBaseAssetBought))
1260- else false)
1261- then throw(((("Limit error: " + toString(abs(amountBaseAssetBought))) + " < ") + toString(_minBaseAssetAmount)))
1262- else {
1263- let newPositionSize = (oldPositionSize + amountBaseAssetBought)
1264- let totalLongOpenInterestAfter = (openInterestLong() + (if ((newPositionSize > 0))
1265- then openNotional
1266- else 0))
1267- let totalShortOpenInterestAfter = (openInterestShort() + (if ((0 > newPositionSize))
1268- then openNotional
1269- else 0))
1270- let $t05411054331 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, _amount)
1271- let remainMargin = $t05411054331._1
1272- let x1 = $t05411054331._2
1273- let x2 = $t05411054331._3
1274- if (!(requireNotOverSpreadLimit(quoteAssetReserveAfter, baseAssetReserveAfter)))
1275- then throw("Over max spread limit")
1276- else if (!(requireNotOverMaxOpenNotional(totalLongOpenInterestAfter, totalShortOpenInterestAfter)))
1277- then throw("Over max open notional")
1278- else $Tuple12(newPositionSize, remainMargin, (oldPositionOpenNotional + openNotional), latestCumulativePremiumFraction(newPositionSize), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() + openNotional), (totalLongPositionSize() + (if ((newPositionSize > 0))
1279- then abs(amountBaseAssetBought)
1280- else 0)), (totalShortPositionSize() + (if ((0 > newPositionSize))
1281- then abs(amountBaseAssetBought)
1282- else 0)), totalLongOpenInterestAfter, totalShortOpenInterestAfter)
1283- }
1284- }
1285- else {
1286- let openNotional = muld(_amount, _leverage)
1287- let $t05559155707 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
1288- let oldPositionNotional = $t05559155707._1
1289- let unrealizedPnl = $t05559155707._2
1290- if ((oldPositionNotional > openNotional))
1291- then throw("Use decreasePosition to decrease position size")
1292- else throw("Close position first")
1293- }
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
1309- let stake = if (isQuoteAsset)
1310- then {
1311- let stake = invoke(vaultAddress(), "addLocked", [false], [AttachedPayment(quoteAsset(), _amount)])
1312- if ((stake == stake))
1313- then nil
1314- else throw("Strict value is not equal to itself.")
1315- }
1316- else nil
1317- if ((stake == stake))
1318- then {
1319- let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1320- if ((depositVault == depositVault))
1309+ let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, feeAmount], nil)
1310+ if ((notifyFee == notifyFee))
13211311 then {
1322- let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, feeAmount], nil)
1323- if ((notifyFee == notifyFee))
1324- then {
1325- let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
1326- if ((notifyNotional == notifyNotional))
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))
1328- else throw("Strict value is not equal to itself.")
1329- }
1312+ let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
1313+ if ((notifyNotional == notifyNotional))
1314+ then ((((((updatePosition(_trader, newPositionSize, newPositionRemainMargin, newPositionOpenNotional, newPositionLatestCPF, newPositionTimestamp) ++ incrementPositionSequenceNumber(isNewPosition, _trader)) ++ updatePositionFee(isNewPosition, _trader, adjustedFee)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ transferFee(feeToStakers)) ++ updateBalance((cbalance() + _amount))) ++ doBurnArtifact(burnArtifact, i))
13301315 else throw("Strict value is not equal to itself.")
13311316 }
13321317 else throw("Strict value is not equal to itself.")
13531338 let _assetId = i.payments[0].assetId
13541339 let _assetIdStr = toBase58String(value(_assetId))
13551340 let isQuoteAsset = (_assetId == quoteAsset())
1356- let isCollateralAsset = isWhitelistAsset(_assetIdStr)
1357- if (if (if (if (if (if (if (if (!(isQuoteAsset))
1358- then !(isCollateralAsset)
1359- else false)
1341+ if (if (if (if (if (if (if (!(isQuoteAsset))
13601342 then true
13611343 else !(requireOpenPosition(toString(i.caller))))
13621344 then true
13711353 else isMarketClosed())
13721354 then throw("Invalid addMargin parameters")
13731355 else {
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)
1356+ let $t06387164039 = getPosition(_trader)
1357+ let oldPositionSize = $t06387164039._1
1358+ let oldPositionMargin = $t06387164039._2
1359+ let oldPositionOpenNotional = $t06387164039._3
1360+ let oldPositionLstUpdCPF = $t06387164039._4
1361+ let oldPositionTimestamp = $t06387164039._5
1362+ let stake = invoke(vaultAddress(), "addLocked", [false], [AttachedPayment(quoteAsset(), _amount)])
1363+ if ((stake == stake))
13801364 then {
1381- let stake = invoke(vaultAddress(), "addLocked", [false], [AttachedPayment(quoteAsset(), _amount)])
1382- if ((stake == stake))
1383- then nil
1365+ let rolloverFee = calcRolloverFee(oldPositionMargin, oldPositionTimestamp)
1366+ let doTransferFeeToStakers = if ((rolloverFee > 0))
1367+ then {
1368+ let $t06432964388 = distributeFee(rolloverFee)
1369+ let feeToStakers = $t06432964388._1
1370+ let feeToVault = $t06432964388._2
1371+ let unstake = invoke(vaultAddress(), "withdrawLocked", [feeToStakers], nil)
1372+ if ((unstake == unstake))
1373+ then {
1374+ let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
1375+ if ((lockBadDebt == lockBadDebt))
1376+ then transferFee(feeToStakers)
1377+ else throw("Strict value is not equal to itself.")
1378+ }
1379+ else throw("Strict value is not equal to itself.")
1380+ }
1381+ else nil
1382+ if ((doTransferFeeToStakers == doTransferFeeToStakers))
1383+ then ((updatePosition(_trader, oldPositionSize, ((oldPositionMargin - rolloverFee) + _amount), oldPositionOpenNotional, oldPositionLstUpdCPF, lastTimestamp()) ++ updateBalance(((cbalance() + _amount) - rolloverFee))) ++ doTransferFeeToStakers)
13841384 else throw("Strict value is not equal to itself.")
13851385 }
1386- else nil
1387- if ((stake == stake))
1388- then (updatePosition(_trader, oldPositionSize, (oldPositionMargin + _amount), oldPositionOpenNotional, oldPositionLstUpdCPF) ++ updateBalance((cbalance() + _amount)))
13891386 else throw("Strict value is not equal to itself.")
13901387 }
13911388 }
14111408 else isMarketClosed())
14121409 then throw("Invalid removeMargin parameters")
14131410 else {
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
1419- let marginDelta = -(_amount)
1420- let $t05909759276 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, marginDelta)
1421- let remainMargin = $t05909759276._1
1422- let badDebt = $t05909759276._2
1411+ let $t06543165599 = getPosition(_trader)
1412+ let oldPositionSize = $t06543165599._1
1413+ let oldPositionMargin = $t06543165599._2
1414+ let oldPositionOpenNotional = $t06543165599._3
1415+ let oldPositionLstUpdCPF = $t06543165599._4
1416+ let oldPositionTimestamp = $t06543165599._5
1417+ let $t06560565854 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, -(_amount))
1418+ let remainMargin = $t06560565854._1
1419+ let badDebt = $t06560565854._2
1420+ let fundingPayment = $t06560565854._3
1421+ let rolloverFee = $t06560565854._4
14231422 if ((badDebt != 0))
14241423 then throw("Invalid removed margin amount")
14251424 else {
14271426 if (!(requireMoreMarginRatio(marginRatio, initMarginRatio(), true)))
14281427 then throw(((("Too much margin removed: " + toString(marginRatio)) + " < ") + toString(initMarginRatio())))
14291428 else {
1430- let quoteAssetStr = toBase58String(quoteAsset())
1431- let $t05972059774 = getBorrowedByTrader(_trader)
1432- let borrowed = $t05972059774._1
1433- let assetId = $t05972059774._2
1434- let toRepay = if ((_amount > borrowed))
1435- then borrowed
1436- else _amount
1437- let toWithdraw = if ((borrowed > _amount))
1438- then 0
1439- else (_amount - borrowed)
1440- let finalBorrow = (borrowed - toRepay)
1441- let switchPositionToQuote = if ((finalBorrow > 0))
1442- then nil
1443- else updatePositionAsset(_trader, quoteAssetStr)
1444- let doSanityCheck = if (((toRepay + toWithdraw) != _amount))
1445- then throw(((((("toRepay=" + toString(toRepay)) + " + toWithdraw=") + toString(toWithdraw)) + " != ") + toString(_amount)))
1429+ let $t06624066299 = distributeFee(rolloverFee)
1430+ let feeToStakers = $t06624066299._1
1431+ let feeToVault = $t06624066299._2
1432+ let doTransferFeeToStakers = if ((rolloverFee > 0))
1433+ then {
1434+ let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
1435+ if ((lockBadDebt == lockBadDebt))
1436+ then transferFee(feeToStakers)
1437+ else throw("Strict value is not equal to itself.")
1438+ }
14461439 else nil
1447- if ((doSanityCheck == doSanityCheck))
1440+ if ((doTransferFeeToStakers == doTransferFeeToStakers))
14481441 then {
1449- let doUnstake = if ((toWithdraw > 0))
1450- then {
1451- let doUnstake = invoke(vaultAddress(), "withdrawLocked", [toWithdraw], nil)
1452- if ((doUnstake == doUnstake))
1453- then nil
1454- else throw("Strict value is not equal to itself.")
1455- }
1456- else nil
1457- if ((doUnstake == doUnstake))
1458- then {
1459- let returnCollateralAction = if ((toRepay > 0))
1460- then {
1461- let doRepay = invoke(collateralAddress(), "repay", [_trader, toRepay, assetId], nil)
1462- if ((doRepay == doRepay))
1463- then [ScriptTransfer(i.caller, toRepay, fromBase58String(assetId))]
1464- else throw("Strict value is not equal to itself.")
1465- }
1466- else nil
1467- if ((returnCollateralAction == returnCollateralAction))
1468- then ((((updatePosition(_trader, oldPositionSize, remainMargin, oldPositionOpenNotional, latestCumulativePremiumFraction(oldPositionSize)) ++ (if ((toWithdraw > 0))
1469- then withdraw(i.caller, toWithdraw)
1470- else nil)) ++ updateBalance((cbalance() - _amount))) ++ switchPositionToQuote) ++ returnCollateralAction)
1471- else throw("Strict value is not equal to itself.")
1472- }
1442+ let unstake = invoke(vaultAddress(), "withdrawLocked", [(_amount + feeToStakers)], nil)
1443+ if ((unstake == unstake))
1444+ then (((updatePosition(_trader, oldPositionSize, remainMargin, oldPositionOpenNotional, latestCumulativePremiumFraction(oldPositionSize), lastTimestamp()) ++ withdraw(i.caller, _amount)) ++ updateBalance(((cbalance() - _amount) - rolloverFee))) ++ doTransferFeeToStakers)
14731445 else throw("Strict value is not equal to itself.")
14741446 }
14751447 else throw("Strict value is not equal to itself.")
15031475 else isMarketClosed())
15041476 then throw("Invalid closePosition parameters")
15051477 else {
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))
1512- then {
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
1518- let exchangedPositionSize = if ((oldPositionSize > 0))
1519- then -(_size)
1520- else _size
1521- let $t06296263116 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1522- let oldPositionNotional = $t06296263116._1
1523- let unrealizedPnl = $t06296263116._2
1524- let mr = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
1525- let realizedRatio = divd(abs(exchangedPositionSize), abs(oldPositionSize))
1526- let realizedPnl = muld(unrealizedPnl, realizedRatio)
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
1530- let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
1531- let remainOpenNotional = if ((oldPositionSize > 0))
1532- then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
1533- else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
1534- let newPositionOpenNotional = abs(remainOpenNotional)
1535- let newPositionSize = (oldPositionSize + exchangedPositionSize)
1536- let newPositionLstUpdCPF = latestCumulativePremiumFraction(newPositionSize)
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
1546- if (if ((_minQuoteAssetAmount != 0))
1547- then (_minQuoteAssetAmount > exchangedQuoteAssetAmount)
1548- else false)
1549- then throw(((("Limit error: " + toString(exchangedQuoteAssetAmount)) + " < ") + toString(_minQuoteAssetAmount)))
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))
1555- then abs(exchangedPositionSize)
1556- else 0)), (totalShortPositionSize() - (if ((0 > newPositionSize))
1557- then abs(exchangedPositionSize)
1558- else 0)), (openInterestLong() - (if ((newPositionSize > 0))
1559- then openNotionalDelta
1560- else 0)), (openInterestShort() - (if ((0 > newPositionSize))
1561- then openNotionalDelta
1562- else 0)), realizedFee)
1563- }
1564- else if ((_size > abs(oldPositionSize)))
1565- then throw("Invalid closePosition parameters")
1566- else {
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
1586- if (if ((_minQuoteAssetAmount != 0))
1587- then (_minQuoteAssetAmount > exchangedQuoteAssetAmount)
1588- else false)
1589- then throw(((("Limit error: " + toString(exchangedQuoteAssetAmount)) + " < ") + toString(_minQuoteAssetAmount)))
1590- else $Tuple16(0, 0, 0, 0, positionBadDebt, realizedPnl, marginToTrader, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter, realizedFee)
1591- }
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
1478+ let $t06783167971 = getPosition(_trader)
1479+ let oldPositionSize = $t06783167971._1
1480+ let oldPositionMargin = $t06783167971._2
1481+ let oldPositionOpenNotional = $t06783167971._3
1482+ let oldPositionLstUpdCPF = $t06783167971._4
1483+ let $t06797768550 = internalClosePosition(_trader, _size, positionFee, _minQuoteAssetAmount, _addToMargin, true)
1484+ let newPositionSize = $t06797768550._1
1485+ let newPositionMargin = $t06797768550._2
1486+ let newPositionOpenNotional = $t06797768550._3
1487+ let newPositionLstUpdCPF = $t06797768550._4
1488+ let positionBadDebt = $t06797768550._5
1489+ let realizedPnl = $t06797768550._6
1490+ let marginToTrader = $t06797768550._7
1491+ let quoteAssetReserveAfter = $t06797768550._8
1492+ let baseAssetReserveAfter = $t06797768550._9
1493+ let totalPositionSizeAfter = $t06797768550._10
1494+ let openInterestNotionalAfter = $t06797768550._11
1495+ let totalLongAfter = $t06797768550._12
1496+ let totalShortAfter = $t06797768550._13
1497+ let totalLongOpenInterestAfter = $t06797768550._14
1498+ let totalShortOpenInterestAfter = $t06797768550._15
1499+ let realizedFee = $t06797768550._16
16081500 if ((positionBadDebt > 0))
1609- then throw("Unable to close position with bad debt")
1501+ then throw("Invalid closePosition parameters: bad debt")
16101502 else {
16111503 let isPartialClose = (newPositionSize != 0)
16121504 let withdrawAmount = (marginToTrader + realizedFee)
16131505 let ammBalance = (cbalance() - withdrawAmount)
1614- let $t06818368390 = if ((0 > ammBalance))
1615- then $Tuple2(0, abs(ammBalance))
1616- else $Tuple2(ammBalance, 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))
1623- then if ((withdrawAmount >= borrowed))
1624- then {
1625- let doRepay = invoke(collateralAddress(), "repay", [_trader, borrowed, assetId], nil)
1626- if ((doRepay == doRepay))
1627- then $Tuple3(borrowed, (withdrawAmount - borrowed), isPartialClose)
1628- else throw("Strict value is not equal to itself.")
1629- }
1630- else {
1631- let realizeAndClose = invoke(collateralAddress(), if (isPartialClose)
1632- then "repay"
1633- else "realizePartiallyAndClose", [_trader, withdrawAmount, assetId], nil)
1634- if ((realizeAndClose == realizeAndClose))
1635- then $Tuple3(withdrawAmount, 0, false)
1636- else throw("Strict value is not equal to itself.")
1637- }
1638- else $Tuple3(0, withdrawAmount, false)
1639- if (($t06845969319 == $t06845969319))
1506+ let ammNewBalance = if ((0 > ammBalance))
1507+ then 0
1508+ else ammBalance
1509+ let unstake = invoke(vaultAddress(), "withdrawLocked", [withdrawAmount], nil)
1510+ if ((unstake == unstake))
16401511 then {
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))
1512+ let $t06906069119 = distributeFee(realizedFee)
1513+ let feeToStakers = $t06906069119._1
1514+ let feeToVault = $t06906069119._2
1515+ let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1516+ if ((depositVault == depositVault))
1517+ then {
1518+ let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, realizedFee], nil)
1519+ if ((notifyFee == notifyFee))
16511520 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- }
1667- else throw("Strict value is not equal to itself.")
1668- }
1669- if (($t06932770394 == $t06932770394))
1670- then {
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- }
1521+ let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
1522+ if ((notifyNotional == notifyNotional))
1523+ then (((((if (isPartialClose)
1524+ then updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, lastTimestamp())
1525+ else deletePosition(_trader)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ (if ((marginToTrader > 0))
1526+ then withdraw(_traderAddress, marginToTrader)
1527+ else nil)) ++ updateBalance(ammNewBalance)) ++ transferFee(feeToStakers))
17111528 else throw("Strict value is not equal to itself.")
17121529 }
17131530 else throw("Strict value is not equal to itself.")
17291546 if ((sync == sync))
17301547 then {
17311548 let spotMarginRatio = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
1732- let marginRatio = if (isOverFluctuationLimit())
1549+ let liquidationMarginRatio = if (isOverFluctuationLimit())
17331550 then {
17341551 let oracleMarginRatio = getMarginRatioByOption(_trader, PNL_OPTION_ORACLE)
17351552 vmax(spotMarginRatio, oracleMarginRatio)
17361553 }
17371554 else spotMarginRatio
1738- if (if (if (if (if (!(requireMoreMarginRatio(marginRatio, maintenanceMarginRatio(), false)))
1555+ if (if (if (if (if (!(requireMoreMarginRatio(liquidationMarginRatio, maintenanceMarginRatio(), false)))
17391556 then true
17401557 else !(requireOpenPosition(_trader)))
17411558 then true
17451562 then true
17461563 else isMarketClosed())
17471564 then throw("Unable to liquidate")
1748- else if (if (if ((spotMarginRatio > liquidationFeeRatio()))
1749- then (partialLiquidationRatio() > 0)
1750- else false)
1751- then (DECIMAL_UNIT > partialLiquidationRatio())
1752- else false)
1753- then {
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
1759- let _direction = if ((oldPositionSize > 0))
1760- then DIR_SHORT
1761- else DIR_LONG
1762- let isAdd = (_direction == DIR_LONG)
1763- let exchangedQuoteAssetAmount = getPartialLiquidationAmount(_trader, oldPositionSize)
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
1772- let liquidationRatio = divd(abs(exchangedPositionSize), abs(oldPositionSize))
1773- let realizedPnl = muld(unrealizedPnl, liquidationRatio)
1774- let $t07445374686 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl)
1775- let remainMargin = $t07445374686._1
1776- let badDebt = $t07445374686._2
1777- let fundingPayment = $t07445374686._3
1778- let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
1779- let remainOpenNotional = if ((oldPositionSize > 0))
1780- then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
1781- else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
1782- let liquidationPenalty = muld(exchangedQuoteAssetAmount, liquidationFeeRatio())
1783- let feeToLiquidator = (liquidationPenalty / 2)
1784- let feeToVault = (liquidationPenalty - feeToLiquidator)
1785- let newPositionMargin = (remainMargin - liquidationPenalty)
1786- let newPositionSize = (oldPositionSize + exchangedPositionSize)
1787- let newPositionOpenNotional = abs(remainOpenNotional)
1788- let openNotionalDelta = (oldPositionOpenNotional - newPositionOpenNotional)
1789- let newPositionLstUpdCPF = latestCumulativePremiumFraction(newPositionSize)
1790- let openInterestNotionalAfter = (openInterestNotional() - openNotionalDelta)
1791- let ammBalance = (cbalance() - liquidationPenalty)
1792- let $t07592776056 = if ((0 > ammBalance))
1793- then $Tuple2(0, abs(ammBalance))
1794- else $Tuple2(ammBalance, 0)
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
1800- let doLiquidateCollateral = if ((borrowed > 0))
1801- then {
1802- let collateralToSell = muld(borrowed, liquidationRatio)
1803- let realizeAndClose = invoke(collateralAddress(), "realizePartially", [_trader, assetId, collateralToSell], nil)
1804- if ((realizeAndClose == realizeAndClose))
1805- then nil
1806- else throw("Strict value is not equal to itself.")
1807- }
1808- else nil
1809- if ((doLiquidateCollateral == doLiquidateCollateral))
1810- then {
1811- let unstake = invoke(vaultAddress(), "withdrawLocked", [liquidationPenalty], nil)
1812- if ((unstake == unstake))
1813- then {
1814- let depositInsurance = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1815- if ((depositInsurance == depositInsurance))
1816- then {
1817- let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
1818- if ((notifyNotional == notifyNotional))
1819- then (((updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, (totalLongPositionSize() - (if ((newPositionSize > 0))
1820- then abs(exchangedPositionSize)
1821- else 0)), (totalShortPositionSize() - (if ((0 > newPositionSize))
1822- then abs(exchangedPositionSize)
1823- else 0)), (openInterestLong() - (if ((newPositionSize > 0))
1824- then openNotionalDelta
1825- else 0)), (openInterestShort() - (if ((0 > newPositionSize))
1826- then openNotionalDelta
1827- else 0)))) ++ withdraw(i.caller, feeToLiquidator)) ++ updateBalance(newAmmBalance))
1828- else throw("Strict value is not equal to itself.")
1829- }
1830- else throw("Strict value is not equal to itself.")
1831- }
1832- else throw("Strict value is not equal to itself.")
1833- }
1834- else throw("Strict value is not equal to itself.")
1835- }
1836- else {
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
1851- let liquidationPenalty = muld(exchangedQuoteAssetAmount, liquidationFeeRatio())
1852- let feeToLiquidator = (liquidationPenalty / 2)
1853- let feeToVault = (liquidationPenalty - feeToLiquidator)
1854- let ammBalance = (cbalance() - liquidationPenalty)
1855- let $t07870078829 = if ((0 > ammBalance))
1856- then $Tuple2(0, abs(ammBalance))
1857- else $Tuple2(ammBalance, 0)
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
1863- let doLiquidateCollateral = if ((borrowed > 0))
1864- then {
1865- let realizeAndClose = invoke(collateralAddress(), "realizePartiallyAndClose", [_trader, 0, assetId], nil)
1866- if ((realizeAndClose == realizeAndClose))
1867- then nil
1868- else throw("Strict value is not equal to itself.")
1869- }
1870- else nil
1871- if ((doLiquidateCollateral == doLiquidateCollateral))
1872- then {
1873- let x = if ((badDebt > 0))
1874- then {
1875- let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [badDebt], nil)
1876- if ((lockBadDebt == lockBadDebt))
1877- then nil
1878- else throw("Strict value is not equal to itself.")
1879- }
1880- else nil
1881- if ((x == x))
1882- then {
1883- let unstake = invoke(vaultAddress(), "withdrawLocked", [liquidationPenalty], nil)
1884- if ((unstake == unstake))
1885- then {
1886- let depositInsurance = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1887- if ((depositInsurance == depositInsurance))
1888- then {
1889- let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, 0], nil)
1890- if ((notifyNotional == notifyNotional))
1891- then (((deletePosition(_trader) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ withdraw(i.caller, feeToLiquidator)) ++ updateBalance(newAmmBalance))
1892- else throw("Strict value is not equal to itself.")
1893- }
1894- else throw("Strict value is not equal to itself.")
1895- }
1896- else throw("Strict value is not equal to itself.")
1897- }
1898- else throw("Strict value is not equal to itself.")
1899- }
1900- else throw("Strict value is not equal to itself.")
1901- }
1565+ else {
1566+ let isPartialLiquidation = if (if ((spotMarginRatio > liquidationFeeRatio()))
1567+ then true
1568+ else (partialLiquidationRatio() > 0))
1569+ then true
1570+ else (DECIMAL_UNIT > partialLiquidationRatio())
1571+ let oldPositionSize = getPosition(_trader)._1
1572+ let positionSizeAbs = abs(oldPositionSize)
1573+ let $t07143271755 = if (isPartialLiquidation)
1574+ then {
1575+ let liquidationSize = getPartialLiquidationAmount(_trader, oldPositionSize)
1576+ let liquidationRatio = divd(abs(liquidationSize), positionSizeAbs)
1577+ $Tuple2(liquidationRatio, abs(liquidationSize))
1578+ }
1579+ else $Tuple2(0, positionSizeAbs)
1580+ let liquidationRatio = $t07143271755._1
1581+ let liquidationSize = $t07143271755._2
1582+ let $t07176172387 = internalClosePosition(_trader, if (isPartialLiquidation)
1583+ then liquidationSize
1584+ else positionSizeAbs, liquidationFeeRatio(), 0, true, false)
1585+ let newPositionSize = $t07176172387._1
1586+ let newPositionMargin = $t07176172387._2
1587+ let newPositionOpenNotional = $t07176172387._3
1588+ let newPositionLstUpdCPF = $t07176172387._4
1589+ let positionBadDebt = $t07176172387._5
1590+ let realizedPnl = $t07176172387._6
1591+ let marginToTrader = $t07176172387._7
1592+ let quoteAssetReserveAfter = $t07176172387._8
1593+ let baseAssetReserveAfter = $t07176172387._9
1594+ let totalPositionSizeAfter = $t07176172387._10
1595+ let openInterestNotionalAfter = $t07176172387._11
1596+ let totalLongAfter = $t07176172387._12
1597+ let totalShortAfter = $t07176172387._13
1598+ let totalLongOpenInterestAfter = $t07176172387._14
1599+ let totalShortOpenInterestAfter = $t07176172387._15
1600+ let liquidationPenalty = $t07176172387._16
1601+ let feeToLiquidator = (liquidationPenalty / 2)
1602+ let feeToVault = (liquidationPenalty - feeToLiquidator)
1603+ let ammBalance = (cbalance() - liquidationPenalty)
1604+ let newAmmBalance = if ((0 > ammBalance))
1605+ then 0
1606+ else ammBalance
1607+ let lockBadDebt = if ((positionBadDebt > 0))
1608+ then {
1609+ let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [positionBadDebt], nil)
1610+ if ((lockBadDebt == lockBadDebt))
1611+ then nil
1612+ else throw("Strict value is not equal to itself.")
1613+ }
1614+ else nil
1615+ if ((lockBadDebt == lockBadDebt))
1616+ then {
1617+ let unstake = invoke(vaultAddress(), "withdrawLocked", [liquidationPenalty], nil)
1618+ if ((unstake == unstake))
1619+ then {
1620+ let depositInsurance = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1621+ if ((depositInsurance == depositInsurance))
1622+ then {
1623+ let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
1624+ if ((notifyNotional == notifyNotional))
1625+ then ((((if (isPartialLiquidation)
1626+ then updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, lastTimestamp())
1627+ else deletePosition(_trader)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ withdraw(i.caller, feeToLiquidator)) ++ updateBalance(newAmmBalance))
1628+ else throw("Strict value is not equal to itself.")
1629+ }
1630+ else throw("Strict value is not equal to itself.")
1631+ }
1632+ else throw("Strict value is not equal to itself.")
1633+ }
1634+ else throw("Strict value is not equal to itself.")
1635+ }
19021636 }
19031637 else throw("Strict value is not equal to itself.")
19041638 }
19111645 if ((sync == sync))
19121646 then {
19131647 let fundingBlockTimestamp = nextFundingBlockTimestamp()
1914- if (if (if ((fundingBlockTimestamp > lastBlock.timestamp))
1648+ if (if (if ((fundingBlockTimestamp > lastTimestamp()))
19151649 then true
19161650 else !(initialized()))
19171651 then true
19181652 else paused())
1919- then throw(((("Invalid funding block timestamp: " + toString(lastBlock.timestamp)) + " < ") + toString(fundingBlockTimestamp)))
1653+ then throw(((("Invalid funding block timestamp: " + toString(lastTimestamp())) + " < ") + toString(fundingBlockTimestamp)))
19201654 else {
19211655 let underlyingPrice = getOraclePrice()
1922- let $t08076380825 = getFunding()
1923- let shortPremiumFraction = $t08076380825._1
1924- let longPremiumFraction = $t08076380825._2
1656+ let $t07435374415 = getFunding()
1657+ let shortPremiumFraction = $t07435374415._1
1658+ let longPremiumFraction = $t07435374415._2
19251659 updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice))
19261660 }
19271661 }
19341668 func syncTerminalPriceToOracle () = {
19351669 let _qtAstR = qtAstR()
19361670 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
1671+ let $t07484774982 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1672+ let newQuoteAssetWeight = $t07484774982._1
1673+ let newBaseAssetWeight = $t07484774982._2
1674+ let marginToVault = $t07484774982._3
19411675 let doExchangePnL = if ((marginToVault != 0))
19421676 then {
19431677 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
19581692 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
19591693 if ((sync == sync))
19601694 then {
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
1973- throw((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)))
1695+ let $t07555175675 = getPosition(_trader)
1696+ let positionSize = $t07555175675._1
1697+ let positionMargin = $t07555175675._2
1698+ let pon = $t07555175675._3
1699+ let positionLstUpdCPF = $t07555175675._4
1700+ let positionTimestamp = $t07555175675._5
1701+ let $t07567875779 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1702+ let positionNotional = $t07567875779._1
1703+ let unrealizedPnl = $t07567875779._2
1704+ let $t07578276006 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
1705+ let remainMargin = $t07578276006._1
1706+ let badDebt = $t07578276006._2
1707+ let fundingPayment = $t07578276006._3
1708+ let rolloverFee = $t07578276006._4
1709+ throw(((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)) + s(rolloverFee)))
19741710 }
19751711 else throw("Strict value is not equal to itself.")
19761712 }
19891725
19901726 @Callable(i)
19911727 func view_getTerminalAmmPrice () = {
1992- let $t08275782838 = getTerminalAmmState()
1993- let terminalQuoteAssetReserve = $t08275782838._1
1994- let terminalBaseAssetReserve = $t08275782838._2
1728+ let $t07644276523 = getTerminalAmmState()
1729+ let terminalQuoteAssetReserve = $t07644276523._1
1730+ let terminalBaseAssetReserve = $t07644276523._2
19951731 let price = divd(muld(terminalQuoteAssetReserve, qtAstW()), muld(terminalBaseAssetReserve, bsAstW()))
19961732 throw(toString(price))
19971733 }
20011737 @Callable(i)
20021738 func view_getFunding () = {
20031739 let underlyingPrice = getOraclePrice()
2004- let $t08305383115 = getFunding()
2005- let shortPremiumFraction = $t08305383115._1
2006- let longPremiumFraction = $t08305383115._2
1740+ let $t07673876800 = getFunding()
1741+ let shortPremiumFraction = $t07673876800._1
1742+ let longPremiumFraction = $t07673876800._2
20071743 let longFunding = divd(longPremiumFraction, underlyingPrice)
20081744 let shortFunding = divd(shortPremiumFraction, underlyingPrice)
20091745 throw((((s(longFunding) + s(shortFunding)) + s(getTwapSpotPrice())) + s(getOraclePrice())))
2010- }
2011-
2012-
2013-
2014-@Callable(i)
2015-func view_getBorrowedByTrader (_trader) = {
2016- let $t08340183455 = getBorrowedByTrader(_trader)
2017- let borrowed = $t08340183455._1
2018- let assetId = $t08340183455._2
2019- throw((s(borrowed) + assetId))
20201746 }
20211747
20221748
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
88 let k_ora_open_key = "k_ora_open_key"
99
1010 let k_ora = "k_ora"
1111
1212 let k_balance = "k_balance"
1313
1414 let k_sequence = "k_sequence"
1515
1616 let k_positionSize = "k_positionSize"
1717
1818 let k_positionMargin = "k_positionMargin"
1919
2020 let k_positionOpenNotional = "k_positionOpenNotional"
2121
2222 let k_positionLastUpdatedCumulativePremiumFraction = "k_positionFraction"
2323
2424 let k_positionSequence = "k_positionSequence"
2525
2626 let k_positionAsset = "k_positionAsset"
2727
2828 let k_positionFee = "k_positionFee"
2929
30+let k_positionLastUpdatedTimestamp = "k_positionTimestamp"
31+
3032 let k_initialized = "k_initialized"
3133
3234 let k_paused = "k_paused"
3335
3436 let k_closeOnly = "k_closeOnly"
3537
3638 let k_fee = "k_fee"
39+
40+let k_rolloverFee = "k_rollover_fee"
3741
3842 let k_fundingPeriod = "k_fundingPeriod"
3943
4044 let k_initMarginRatio = "k_initMarginRatio"
4145
4246 let k_maintenanceMarginRatio = "k_mmr"
4347
4448 let k_liquidationFeeRatio = "k_liquidationFeeRatio"
4549
4650 let k_partialLiquidationRatio = "k_partLiquidationRatio"
4751
4852 let k_spreadLimit = "k_spreadLimit"
4953
5054 let k_maxPriceImpact = "k_maxPriceImpact"
5155
5256 let k_maxPriceSpread = "k_maxPriceSpread"
5357
5458 let k_maxOpenNotional = "k_maxOpenNotional"
5559
5660 let k_feeToStakersPercent = "k_feeToStakersPercent"
5761
5862 let k_maxOracleDelay = "k_maxOracleDelay"
5963
6064 let k_lastDataStr = "k_lastDataStr"
6165
6266 let k_lastMinuteId = "k_lastMinuteId"
6367
6468 let k_twapDataLastCumulativePrice = "k_twapDataLastCumulativePrice"
6569
6670 let k_twapDataLastPrice = "k_twapDataLastPrice"
6771
6872 let k_twapDataPreviousMinuteId = "k_twapDataPreviousMinuteId"
6973
7074 let k_latestLongCumulativePremiumFraction = "k_latestLongPremiumFraction"
7175
7276 let k_latestShortCumulativePremiumFraction = "k_latestShortPremiumFraction"
7377
7478 let k_nextFundingBlock = "k_nextFundingBlockMinTimestamp"
7579
7680 let k_longFundingRate = "k_longFundingRate"
7781
7882 let k_shortFundingRate = "k_shortFundingRate"
7983
8084 let k_quoteAssetReserve = "k_qtAstR"
8185
8286 let k_baseAssetReserve = "k_bsAstR"
8387
8488 let k_quoteAssetWeight = "k_qtAstW"
8589
8690 let k_baseAssetWeight = "k_bsAstW"
8791
8892 let k_totalPositionSize = "k_totalPositionSize"
8993
9094 let k_totalLongPositionSize = "k_totalLongPositionSize"
9195
9296 let k_totalShortPositionSize = "k_totalShortPositionSize"
9397
9498 let k_openInterestNotional = "k_openInterestNotional"
9599
96100 let k_openInterestShort = "k_openInterestShort"
97101
98102 let k_openInterestLong = "k_openInterestLong"
99103
100104 let k_coordinatorAddress = "k_coordinatorAddress"
101105
102106 let k_vault_address = "k_vault_address"
103107
104108 let k_admin_address = "k_admin_address"
105109
106110 let k_admin_public_key = "k_admin_public_key"
107111
108112 let k_quote_asset = "k_quote_asset"
109113
110114 let k_quote_staking = "k_quote_staking"
111115
112116 let k_staking_address = "k_staking_address"
113117
114118 let k_miner_address = "k_miner_address"
115119
116120 let k_orders_address = "k_orders_address"
117121
118122 let k_referral_address = "k_referral_address"
119123
120-let k_collateral_address = "k_collateral_address"
121-
122124 let k_exchange_address = "k_exchange_address"
123125
124126 let k_nft_manager_address = "k_nft_manager_address"
125-
126-let k_trader_market_asset_collateral = "k_trader_market_asset_collateral"
127127
128128 func toCompositeKey (_key,_address) = ((_key + "_") + _address)
129129
130130
131131 func coordinator () = valueOrErrorMessage(addressFromString(getStringValue(this, k_coordinatorAddress)), "Coordinator not set")
132132
133133
134134 func adminAddress () = addressFromString(getStringValue(coordinator(), k_admin_address))
135135
136136
137137 func adminPublicKey () = fromBase58String(getStringValue(coordinator(), k_admin_public_key))
138138
139139
140140 func quoteAsset () = fromBase58String(getStringValue(coordinator(), k_quote_asset))
141141
142142
143143 func quoteAssetStaking () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_quote_staking)), "Quote asset staking not set")
144144
145145
146146 func stakingAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_staking_address)), "Staking not set")
147147
148148
149149 func vaultAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_vault_address)), "Vault not set")
150150
151151
152152 func minerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_miner_address)), "Miner not set")
153153
154154
155155 func ordersAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_orders_address)), "Orders not set")
156156
157157
158158 func referralAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_referral_address)), "Referral not set")
159159
160160
161161 func nftManagerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_nft_manager_address)), "NFT Manager not set")
162162
163163
164-func collateralAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_collateral_address)), "Collateral Manager not set")
165-
166-
167164 func swapAddress () = valueOrErrorMessage(addressFromString(valueOrErrorMessage(getString(coordinator(), k_exchange_address), "No swap address")), "Invalid swap address")
168-
169-
170-let k_whitelist_asset = "k_whitelist_asset"
171-
172-func isWhitelistAsset (_assetId) = valueOrElse(getBoolean(collateralAddress(), toCompositeKey(k_whitelist_asset, _assetId)), false)
173165
174166
175167 let k_token_param = "k_token_param"
176168
177169 let k_token_type = "k_token_type"
178170
179171 let FEE_REDUCTION_TOKEN_TYPE = "fee_reduction"
180172
181173 let DIR_LONG = 1
182174
183175 let DIR_SHORT = 2
184176
185177 let TWAP_INTERVAL = 15
186178
187179 let ORACLE_INTERVAL = 15
188180
189181 let SECONDS = 1000
190182
191183 let DECIMAL_NUMBERS = 6
192184
193185 let DECIMAL_UNIT = (1 * (((((10 * 10) * 10) * 10) * 10) * 10))
186+
187+let MINUTES_IN_YEAR = (525600 * DECIMAL_UNIT)
194188
195189 let ONE_DAY = (86400 * DECIMAL_UNIT)
196190
197191 let ALL_FEES = 100
198192
199193 let PNL_OPTION_SPOT = 1
200194
201195 let PNL_OPTION_ORACLE = 2
202196
203197 func s (_x) = (toString(_x) + ",")
204198
205199
206200 func divd (_x,_y) = fraction(_x, DECIMAL_UNIT, _y, HALFEVEN)
207201
208202
209203 func muld (_x,_y) = fraction(_x, _y, DECIMAL_UNIT, HALFEVEN)
210204
211205
212206 func sqrtd (_x) = sqrt(_x, DECIMAL_NUMBERS, DECIMAL_NUMBERS, HALFEVEN)
213207
214208
215209 func powd (_x,_y) = pow(_x, DECIMAL_NUMBERS, _y, DECIMAL_NUMBERS, DECIMAL_NUMBERS, HALFEVEN)
216210
217211
218212 func bdivd (_x,_y) = fraction(_x, toBigInt(DECIMAL_UNIT), _y, HALFEVEN)
219213
220214
221215 func bmuld (_x,_y) = fraction(_x, _y, toBigInt(DECIMAL_UNIT), HALFEVEN)
222216
223217
224218 func bsqrtd (_x) = sqrtBigInt(_x, DECIMAL_NUMBERS, DECIMAL_NUMBERS, HALFEVEN)
225219
226220
227221 func bpowd (_x,_y) = pow(_x, DECIMAL_NUMBERS, _y, DECIMAL_NUMBERS, DECIMAL_NUMBERS, HALFEVEN)
228222
229223
230224 func abs (_x) = if ((_x > 0))
231225 then _x
232226 else -(_x)
233227
234228
235229 func vmax (_x,_y) = if ((_x >= _y))
236230 then _x
237231 else _y
238232
239233
240-func listToStr (_list) = {
241- func _join (accumulator,val) = ((accumulator + val) + ",")
242-
243- let newListStr = {
244- let $l = _list
245- let $s = size($l)
246- let $acc0 = ""
247- func $f0_1 ($a,$i) = if (($i >= $s))
248- then $a
249- else _join($a, $l[$i])
250-
251- func $f0_2 ($a,$i) = if (($i >= $s))
252- then $a
253- else throw("List size exceeds 20")
254-
255- $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)
256- }
257- let newListStrU = dropRight(newListStr, 1)
258- let newListStrR = if ((take(newListStrU, 1) == ","))
259- then drop(newListStrU, 1)
260- else newListStrU
261- newListStrR
262- }
234+func listToStr (_list) = if ((size(_list) == 0))
235+ then ""
236+ else makeString(_list, ",")
263237
264238
265-func strToList (_str) = split(_str, ",")
239+func strToList (_str) = if ((_str == ""))
240+ then nil
241+ else split(_str, ",")
266242
267243
268244 func pushToQueue (_list,_maxSize,_value) = if ((size(_list) > _maxSize))
269245 then (removeByIndex(_list, 0) :+ _value)
270246 else (_list :+ _value)
271247
272248
273249 func int (k) = valueOrErrorMessage(getInteger(this, k), ("no value for " + k))
274250
275251
276252 func intOr (k,def) = valueOrElse(getInteger(this, k), def)
277253
278254
279255 func strA (_address,_key) = {
280256 let val = valueOrErrorMessage(getString(_address, _key), ("No value for key " + _key))
281257 val
282258 }
283259
284260
285261 func intA (_address,_key) = {
286262 let val = valueOrErrorMessage(getInteger(_address, _key), ("No value for key " + _key))
287263 val
288264 }
289265
290266
291267 func cbalance () = int(k_balance)
292268
293269
294270 func fee () = int(k_fee)
271+
272+
273+func rolloverFeeRate () = int(k_rolloverFee)
295274
296275
297276 func initMarginRatio () = int(k_initMarginRatio)
298277
299278
300279 func qtAstR () = int(k_quoteAssetReserve)
301280
302281
303282 func bsAstR () = int(k_baseAssetReserve)
304283
305284
306285 func qtAstW () = intOr(k_quoteAssetWeight, DECIMAL_UNIT)
307286
308287
309288 func bsAstW () = intOr(k_baseAssetWeight, DECIMAL_UNIT)
310289
311290
312291 func totalPositionSize () = int(k_totalPositionSize)
313292
314293
315294 func openInterestNotional () = int(k_openInterestNotional)
316295
317296
318297 func openInterestShort () = int(k_openInterestShort)
319298
320299
321300 func openInterestLong () = int(k_openInterestLong)
322301
323302
324303 func nextFundingBlockTimestamp () = int(k_nextFundingBlock)
325304
326305
327306 func fundingPeriodRaw () = int(k_fundingPeriod)
328307
329308
330309 func fundingPeriodDecimal () = (fundingPeriodRaw() * DECIMAL_UNIT)
331310
332311
333312 func fundingPeriodSeconds () = (fundingPeriodRaw() * SECONDS)
334313
335314
336315 func maintenanceMarginRatio () = int(k_maintenanceMarginRatio)
337316
338317
339318 func liquidationFeeRatio () = int(k_liquidationFeeRatio)
340319
341320
342321 func partialLiquidationRatio () = int(k_partialLiquidationRatio)
343322
344323
345324 func spreadLimit () = int(k_spreadLimit)
346325
347326
348327 func maxPriceImpact () = int(k_maxPriceImpact)
349328
350329
351330 func maxPriceSpread () = int(k_maxPriceSpread)
352331
353332
354333 func maxOpenNotional () = int(k_maxOpenNotional)
355334
356335
357336 func latestLongCumulativePremiumFraction () = int(k_latestLongCumulativePremiumFraction)
358337
359338
360339 func latestShortCumulativePremiumFraction () = int(k_latestShortCumulativePremiumFraction)
361340
362341
363342 func totalShortPositionSize () = int(k_totalShortPositionSize)
364343
365344
366345 func totalLongPositionSize () = int(k_totalLongPositionSize)
367346
368347
369348 func lastSequence () = intOr(k_sequence, 0)
370349
371350
372351 func feeToStakersPercent () = int(k_feeToStakersPercent)
373352
374353
375354 func maxOracleDelay () = int(k_maxOracleDelay)
376355
377356
357+func lastTimestamp () = lastBlock.timestamp
358+
359+
378360 func getActualCaller (i) = valueOrElse(getString(ordersAddress(), "k_sender"), toString(i.caller))
379361
380362
381363 func requireMoreMarginRatio (_marginRatio,_baseMarginRatio,_largerThanOrEqualTo) = {
382364 let remainingMarginRatio = (_marginRatio - _baseMarginRatio)
383365 if (if (_largerThanOrEqualTo)
384366 then (0 > remainingMarginRatio)
385367 else false)
386368 then throw(((("Invalid margin: " + toString(_marginRatio)) + " < ") + toString(_baseMarginRatio)))
387369 else if (if (!(_largerThanOrEqualTo))
388370 then (remainingMarginRatio >= 0)
389371 else false)
390372 then throw(((("Invalid margin: " + toString(_marginRatio)) + " > ") + toString(_baseMarginRatio)))
391373 else true
392374 }
393375
394376
395377 func latestCumulativePremiumFraction (_positionSize) = if ((_positionSize == 0))
396378 then throw("Should not be called with _positionSize == 0")
397379 else if ((_positionSize > 0))
398380 then latestLongCumulativePremiumFraction()
399381 else latestShortCumulativePremiumFraction()
400382
401383
402384 func getPosition (_trader) = {
403385 let positionSizeOpt = getInteger(this, toCompositeKey(k_positionSize, _trader))
404386 match positionSizeOpt {
405387 case positionSize: Int =>
406- $Tuple4(positionSize, getIntegerValue(this, toCompositeKey(k_positionMargin, _trader)), getIntegerValue(this, toCompositeKey(k_positionOpenNotional, _trader)), getIntegerValue(this, toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _trader)))
388+ $Tuple5(positionSize, getIntegerValue(this, toCompositeKey(k_positionMargin, _trader)), getIntegerValue(this, toCompositeKey(k_positionOpenNotional, _trader)), getIntegerValue(this, toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _trader)), getIntegerValue(this, toCompositeKey(k_positionLastUpdatedTimestamp, _trader)))
407389 case _ =>
408- $Tuple4(0, 0, 0, 0)
390+ $Tuple5(0, 0, 0, 0, 0)
409391 }
410392 }
411393
412394
413395 func getPositionAsset (_trader) = {
414396 let positionAssetOpt = getString(this, toCompositeKey(k_positionAsset, _trader))
415397 match positionAssetOpt {
416398 case positionAsset: String =>
417399 positionAsset
418400 case _ =>
419401 toBase58String(quoteAsset())
420402 }
421403 }
422404
423405
424406 func getPositionFee (_trader) = {
425407 let positionFeeOpt = getInteger(this, toCompositeKey(k_positionFee, _trader))
426408 match positionFeeOpt {
427409 case positionFee: Int =>
428410 positionFee
429411 case _ =>
430412 fee()
431413 }
432414 }
433415
434416
435417 func requireOpenPosition (_trader) = if ((getPosition(_trader)._1 == 0))
436418 then throw("No open position")
437419 else true
438420
439421
440422 func initialized () = valueOrElse(getBoolean(this, k_initialized), false)
441423
442424
443425 func paused () = valueOrElse(getBoolean(this, k_paused), false)
444426
445427
446428 func closeOnly () = valueOrElse(getBoolean(this, k_closeOnly), false)
447429
448430
449431 func updateReserve (_isAdd,_quoteAssetAmount,_baseAssetAmount) = if (_isAdd)
450432 then {
451433 let newBase = (bsAstR() - _baseAssetAmount)
452434 if ((0 >= newBase))
453435 then throw("Tx lead to base asset reserve <= 0, revert")
454436 else $Tuple3((qtAstR() + _quoteAssetAmount), newBase, (totalPositionSize() + _baseAssetAmount))
455437 }
456438 else {
457439 let newQuote = (qtAstR() - _quoteAssetAmount)
458440 if ((0 >= newQuote))
459441 then throw("Tx lead to base quote reserve <= 0, revert")
460442 else $Tuple3(newQuote, (bsAstR() + _baseAssetAmount), (totalPositionSize() - _baseAssetAmount))
461443 }
462444
463445
464446 func calcInvariant (_qtAstR,_bsAstR) = {
465447 let bqtAstR = toBigInt(_qtAstR)
466448 let bbsAstR = toBigInt(_bsAstR)
467449 bmuld(bqtAstR, bbsAstR)
468450 }
469451
470452
471453 func swapInput (_isAdd,_quoteAssetAmount) = {
472454 let _qtAstR = qtAstR()
473455 let _bsAstR = bsAstR()
474456 let _qtAstW = qtAstW()
475457 let _bsAstW = bsAstW()
476458 let quoteAssetAmountAdjusted = divd(_quoteAssetAmount, _qtAstW)
477459 let k = calcInvariant(_qtAstR, _bsAstR)
478460 let quoteAssetReserveAfter = if (_isAdd)
479461 then (_qtAstR + quoteAssetAmountAdjusted)
480462 else (_qtAstR - quoteAssetAmountAdjusted)
481463 let baseAssetReserveAfter = toInt(bdivd(k, toBigInt(quoteAssetReserveAfter)))
482464 let amountBaseAssetBoughtAbs = abs((baseAssetReserveAfter - _bsAstR))
483465 let amountBaseAssetBought = if (_isAdd)
484466 then amountBaseAssetBoughtAbs
485467 else -(amountBaseAssetBoughtAbs)
486- let $t01713817308 = updateReserve(_isAdd, quoteAssetAmountAdjusted, amountBaseAssetBoughtAbs)
487- let quoteAssetReserveAfter1 = $t01713817308._1
488- let baseAssetReserveAfter1 = $t01713817308._2
489- let totalPositionSizeAfter1 = $t01713817308._3
468+ let $t01703617206 = updateReserve(_isAdd, quoteAssetAmountAdjusted, amountBaseAssetBoughtAbs)
469+ let quoteAssetReserveAfter1 = $t01703617206._1
470+ let baseAssetReserveAfter1 = $t01703617206._2
471+ let totalPositionSizeAfter1 = $t01703617206._3
490472 let priceBefore = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
491473 let marketPrice = divd(_quoteAssetAmount, amountBaseAssetBoughtAbs)
492474 let priceDiff = abs((priceBefore - marketPrice))
493475 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
494476 let maxPriceImpactValue = maxPriceImpact()
495477 if ((priceImpact > maxPriceImpactValue))
496478 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)))
497479 else $Tuple4(amountBaseAssetBought, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1)
498480 }
499481
500482
501-func calcRemainMarginWithFundingPayment (_oldPositionSize,_oldPositionMargin,_oldPositionCumulativePremiumFraction,_marginDelta) = {
483+func calcRolloverFee (_oldPositionMargin,_oldPositionLastUpdatedTimestamp) = {
484+ let positionMinutes = ((((lastTimestamp() - _oldPositionLastUpdatedTimestamp) / 1000) / 60) * DECIMAL_UNIT)
485+ let rolloverFee = divd(muld(muld(_oldPositionMargin, positionMinutes), rolloverFeeRate()), MINUTES_IN_YEAR)
486+ rolloverFee
487+ }
488+
489+
490+func calcRemainMarginWithFundingPaymentAndRolloverFee (_oldPositionSize,_oldPositionMargin,_oldPositionCumulativePremiumFraction,_oldPositionLastUpdatedTimestamp,_marginDelta) = {
502491 let fundingPayment = if ((_oldPositionSize != 0))
503492 then {
504493 let _latestCumulativePremiumFraction = latestCumulativePremiumFraction(_oldPositionSize)
505494 muld((_latestCumulativePremiumFraction - _oldPositionCumulativePremiumFraction), _oldPositionSize)
506495 }
507496 else 0
508- let signedMargin = ((_marginDelta - fundingPayment) + _oldPositionMargin)
509- let $t01879518922 = if ((0 > signedMargin))
497+ let rolloverFee = calcRolloverFee(_oldPositionMargin, _oldPositionLastUpdatedTimestamp)
498+ let signedMargin = (((_marginDelta - rolloverFee) - fundingPayment) + _oldPositionMargin)
499+ let $t01946119588 = if ((0 > signedMargin))
510500 then $Tuple2(0, abs(signedMargin))
511501 else $Tuple2(abs(signedMargin), 0)
512- let remainMargin = $t01879518922._1
513- let badDebt = $t01879518922._2
514- $Tuple3(remainMargin, badDebt, fundingPayment)
502+ let remainMargin = $t01946119588._1
503+ let badDebt = $t01946119588._2
504+ $Tuple4(remainMargin, badDebt, fundingPayment, rolloverFee)
515505 }
516506
517507
518508 func swapOutputWithReserves (_isAdd,_baseAssetAmount,_checkMaxPriceImpact,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight) = {
519509 let priceBefore = divd(muld(_quoteAssetReserve, _quoteAssetWeight), muld(_baseAssetReserve, _baseAssetWeight))
520510 if ((_baseAssetAmount == 0))
521511 then throw("Invalid base asset amount")
522512 else {
523513 let k = calcInvariant(_quoteAssetReserve, _baseAssetReserve)
524514 let baseAssetPoolAmountAfter = if (_isAdd)
525515 then (_baseAssetReserve + _baseAssetAmount)
526516 else (_baseAssetReserve - _baseAssetAmount)
527517 let quoteAssetAfter = toInt(bdivd(k, toBigInt(baseAssetPoolAmountAfter)))
528518 let quoteAssetDelta = abs((quoteAssetAfter - _quoteAssetReserve))
529519 let quoteAssetSold = muld(quoteAssetDelta, _quoteAssetWeight)
530520 let maxPriceImpactValue = maxPriceImpact()
531- let $t02009220254 = updateReserve(!(_isAdd), quoteAssetDelta, _baseAssetAmount)
532- let quoteAssetReserveAfter1 = $t02009220254._1
533- let baseAssetReserveAfter1 = $t02009220254._2
534- let totalPositionSizeAfter1 = $t02009220254._3
521+ let $t02085021012 = updateReserve(!(_isAdd), quoteAssetDelta, _baseAssetAmount)
522+ let quoteAssetReserveAfter1 = $t02085021012._1
523+ let baseAssetReserveAfter1 = $t02085021012._2
524+ let totalPositionSizeAfter1 = $t02085021012._3
535525 let marketPrice = divd(quoteAssetSold, _baseAssetAmount)
536526 let priceDiff = abs((priceBefore - marketPrice))
537527 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
538528 if (if ((priceImpact > maxPriceImpactValue))
539529 then _checkMaxPriceImpact
540530 else false)
541531 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)))
542532 else $Tuple7(quoteAssetSold, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1, (totalLongPositionSize() - (if (_isAdd)
543533 then abs(_baseAssetAmount)
544534 else 0)), (totalShortPositionSize() - (if (!(_isAdd))
545535 then abs(_baseAssetAmount)
546536 else 0)), priceImpact)
547537 }
548538 }
549539
550540
551541 func swapOutput (_isAdd,_baseAssetAmount,_checkMaxPriceImpact) = swapOutputWithReserves(_isAdd, _baseAssetAmount, _checkMaxPriceImpact, qtAstR(), qtAstW(), bsAstR(), bsAstW())
552542
553543
554544 func getOraclePrice () = {
555- let oracle = valueOrErrorMessage(addressFromString(getStringValue(this, k_ora)), "")
556- let priceKey = getStringValue(this, k_ora_key)
545+ let oracle = valueOrErrorMessage(addressFromString(valueOrErrorMessage(getString(this, k_ora), ("No value: " + k_ora))), "")
546+ let priceKey = valueOrElse(getString(this, k_ora_key), ("No value: " + k_ora_key))
557547 let lastValue = valueOrErrorMessage(getInteger(oracle, priceKey), ((("Can not get oracle price. Oracle: " + toString(oracle)) + " key: ") + priceKey))
558548 let blockKey = valueOrElse(getString(this, k_ora_block_key), "")
559549 if ((blockKey != ""))
560550 then {
561551 let currentBlock = lastBlock.height
562552 let lastOracleBlock = valueOrErrorMessage(getInteger(oracle, blockKey), ((("Can not get oracle block. Oracle: " + toString(oracle)) + " key: ") + blockKey))
563553 if (((currentBlock - lastOracleBlock) > maxOracleDelay()))
564554 then throw(((("Oracle stale data. Last oracle block: " + toString(lastOracleBlock)) + " current block: ") + toString(currentBlock)))
565555 else lastValue
566556 }
567557 else lastValue
568558 }
569559
570560
571561 func isMarketClosed () = {
572562 let oracle = valueOrErrorMessage(addressFromString(getStringValue(this, k_ora)), "")
573563 let openKey = valueOrElse(getString(this, k_ora_open_key), "")
574564 if ((openKey != ""))
575565 then {
576566 let isOpen = valueOrErrorMessage(getBoolean(oracle, openKey), ((("Can not get oracle is open/closed. Oracle: " + toString(oracle)) + " key: ") + openKey))
577567 !(isOpen)
578568 }
579569 else false
580570 }
581571
582572
583573 func absPriceDiff (_oraclePrice,_quoteAssetReserve,_baseAssetReserve,_qtAstW,_bsAstW) = {
584574 let priceAfter = divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW))
585575 let averagePrice = divd((_oraclePrice + priceAfter), (2 * DECIMAL_UNIT))
586576 let absPriceDiff = divd(abs((_oraclePrice - priceAfter)), averagePrice)
587577 absPriceDiff
588578 }
589579
590580
591581 func requireNotOverSpreadLimit (_quoteAssetReserve,_baseAssetReserve) = {
592582 let oraclePrice = getOraclePrice()
593583 let _qtAstW = qtAstW()
594584 let _bsAstW = bsAstW()
595585 let absPriceDiffBefore = absPriceDiff(oraclePrice, qtAstR(), bsAstR(), _qtAstW, _bsAstW)
596586 let absPriceDiffAfter = absPriceDiff(oraclePrice, _quoteAssetReserve, _baseAssetReserve, _qtAstW, _bsAstW)
597587 if (if ((absPriceDiffAfter > maxPriceSpread()))
598588 then (absPriceDiffAfter > absPriceDiffBefore)
599589 else false)
600590 then throw(((("Price spread " + toString(absPriceDiffAfter)) + " > max price spread ") + toString(maxPriceSpread())))
601591 else true
602592 }
603593
604594
605595 func requireNotOverMaxOpenNotional (_longOpenNotional,_shortOpenNotional) = {
606596 let _maxOpenNotional = maxOpenNotional()
607597 if ((_longOpenNotional > _maxOpenNotional))
608598 then throw(((("Long open notional " + toString(_longOpenNotional)) + " > max open notional ") + toString(_maxOpenNotional)))
609599 else if ((_shortOpenNotional > _maxOpenNotional))
610600 then throw(((("Short open notional " + toString(_shortOpenNotional)) + " > max open notional ") + toString(_maxOpenNotional)))
611601 else true
612602 }
613603
614604
615605 func getSpotPrice () = {
616606 let _quoteAssetReserve = qtAstR()
617607 let _baseAssetReserve = bsAstR()
618608 let _qtAstW = qtAstW()
619609 let _bsAstW = bsAstW()
620610 divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW))
621611 }
622612
623613
624614 func isOverFluctuationLimit () = {
625615 let oraclePrice = getOraclePrice()
626616 let currentPrice = getSpotPrice()
627617 (divd(abs((oraclePrice - currentPrice)), oraclePrice) > spreadLimit())
628618 }
629619
630620
631621 func getPositionAdjustedOpenNotional (_positionSize,_option,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight) = {
632622 let positionSizeAbs = abs(_positionSize)
633623 let isShort = (0 > _positionSize)
634624 let positionNotional = if ((_option == PNL_OPTION_SPOT))
635625 then {
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
626+ let outPositionNotional = swapOutputWithReserves(!(isShort), positionSizeAbs, false, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)._1
641627 outPositionNotional
642628 }
643629 else muld(positionSizeAbs, getOraclePrice())
644630 positionNotional
645631 }
646632
647633
648634 func getPositionNotionalAndUnrealizedPnlByValues (_positionSize,_positionOpenNotional,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight,_option) = if ((_positionSize == 0))
649635 then throw("Invalid position size")
650636 else {
651637 let isShort = (0 > _positionSize)
652638 let positionNotional = getPositionAdjustedOpenNotional(_positionSize, _option, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)
653639 let unrealizedPnl = if (isShort)
654640 then (_positionOpenNotional - positionNotional)
655641 else (positionNotional - _positionOpenNotional)
656642 $Tuple2(positionNotional, unrealizedPnl)
657643 }
658644
659645
660646 func getPositionNotionalAndUnrealizedPnl (_trader,_option) = {
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
647+ let $t02857728705 = getPosition(_trader)
648+ let positionSize = $t02857728705._1
649+ let positionMargin = $t02857728705._2
650+ let positionOpenNotional = $t02857728705._3
651+ let positionLstUpdCPF = $t02857728705._4
666652 getPositionNotionalAndUnrealizedPnlByValues(positionSize, positionOpenNotional, qtAstR(), qtAstW(), bsAstR(), bsAstW(), _option)
667653 }
668654
669655
670656 func calcMarginRatio (_remainMargin,_badDebt,_positionNotional) = divd((_remainMargin - _badDebt), _positionNotional)
671657
672658
673659 func getMarginRatioByOption (_trader,_option) = {
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
660+ let $t02922029361 = getPosition(_trader)
661+ let positionSize = $t02922029361._1
662+ let positionMargin = $t02922029361._2
663+ let pon = $t02922029361._3
664+ let positionLastUpdatedCPF = $t02922029361._4
665+ let positionTimestamp = $t02922029361._5
666+ let $t02936729460 = getPositionNotionalAndUnrealizedPnl(_trader, _option)
667+ let positionNotional = $t02936729460._1
668+ let unrealizedPnl = $t02936729460._2
669+ let $t02946529677 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLastUpdatedCPF, positionTimestamp, unrealizedPnl)
670+ let remainMargin = $t02946529677._1
671+ let badDebt = $t02946529677._2
685672 calcMarginRatio(remainMargin, badDebt, positionNotional)
686673 }
687674
688675
689676 func getMarginRatio (_trader) = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
690677
691678
692679 func getPartialLiquidationAmount (_trader,_positionSize) = {
693680 let maximumRatio = vmax(partialLiquidationRatio(), (DECIMAL_UNIT - divd(getMarginRatio(_trader), maintenanceMarginRatio())))
694681 let maxExchangedPositionSize = muld(abs(_positionSize), maximumRatio)
695682 let swapResult = swapOutput((_positionSize > 0), maxExchangedPositionSize, false)
696683 let maxExchangedQuoteAssetAmount = swapResult._1
697684 let priceImpact = swapResult._7
698685 if ((maxPriceImpact() > priceImpact))
699- then maxExchangedQuoteAssetAmount
700- else {
701- let exchangedPositionSize = muld(abs(_positionSize), partialLiquidationRatio())
702- let exchangedQuoteAssetAmount = swapOutput((_positionSize > 0), exchangedPositionSize, false)._1
703- exchangedQuoteAssetAmount
704- }
686+ then maxExchangedPositionSize
687+ else muld(abs(_positionSize), partialLiquidationRatio())
705688 }
706689
707690
708-func internalClosePosition (_trader,_checkMaxPriceImpact) = {
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
714- let unrealizedPnl = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)._2
715- let $t02933129499 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
716- let remainMargin = $t02933129499._1
717- let badDebt = $t02933129499._2
718- let exchangedPositionSize = -(positionSize)
719- let realizedPnl = unrealizedPnl
720- let marginToVault = -(remainMargin)
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
728- let openInterestNotionalAfter = (openInterestNotional() - positionOpenNotional)
729- $Tuple13(exchangedPositionSize, badDebt, realizedPnl, marginToVault, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, exchangedQuoteAssetAmount, totalLongAfter, totalShortAfter, (openInterestLong() - (if ((positionSize > 0))
730- then positionOpenNotional
731- else 0)), (openInterestShort() - (if ((0 > positionSize))
732- then positionOpenNotional
733- else 0)))
691+func internalClosePosition (_trader,_size,_fee,_minQuoteAssetAmount,_addToMargin,_checkMaxPriceImpact) = {
692+ let $t03072130877 = getPosition(_trader)
693+ let oldPositionSize = $t03072130877._1
694+ let oldPositionMargin = $t03072130877._2
695+ let oldPositionOpenNotional = $t03072130877._3
696+ let oldPositionLstUpdCPF = $t03072130877._4
697+ let oldPositionTimestamp = $t03072130877._5
698+ let isLongPosition = (oldPositionSize > 0)
699+ let absOldPositionSize = abs(oldPositionSize)
700+ if (if ((absOldPositionSize >= _size))
701+ then (_size > 0)
702+ else false)
703+ then {
704+ let isPartialClose = (absOldPositionSize > _size)
705+ let $t03116931620 = swapOutput((oldPositionSize > 0), _size, _checkMaxPriceImpact)
706+ let exchangedQuoteAssetAmount = $t03116931620._1
707+ let quoteAssetReserveAfter = $t03116931620._2
708+ let baseAssetReserveAfter = $t03116931620._3
709+ let totalPositionSizeAfter = $t03116931620._4
710+ let exchangedPositionSize = if ((oldPositionSize > 0))
711+ then -(_size)
712+ else _size
713+ let $t03183532042 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
714+ let oldPositionNotional = $t03183532042._1
715+ let unrealizedPnl = $t03183532042._2
716+ let realizedRatio = divd(abs(exchangedPositionSize), absOldPositionSize)
717+ let realizedPnl = muld(unrealizedPnl, realizedRatio)
718+ let $t03238332629 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, unrealizedPnl)
719+ let remainMarginBefore = $t03238332629._1
720+ let x1 = $t03238332629._2
721+ let x2 = $t03238332629._3
722+ let rolloverFee = $t03238332629._4
723+ let positionBadDebt = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, realizedPnl)._2
724+ let realizedCloseFee = muld(muld(oldPositionNotional, realizedRatio), _fee)
725+ let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
726+ let remainOpenNotional = if ((oldPositionSize > 0))
727+ then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
728+ else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
729+ let newPositionSize = (oldPositionSize + exchangedPositionSize)
730+ let $t03403534421 = if ((newPositionSize == 0))
731+ then $Tuple2(0, 0)
732+ else $Tuple2(abs(remainOpenNotional), latestCumulativePremiumFraction(newPositionSize))
733+ let newPositionOpenNotional = $t03403534421._1
734+ let newPositionLstUpdCPF = $t03403534421._2
735+ let openNotionalDelta = (oldPositionOpenNotional - newPositionOpenNotional)
736+ let marginRatio = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
737+ let newPositionMarginWithSameRatio = if ((oldPositionSize > 0))
738+ then (muld((newPositionOpenNotional + unrealizedPnlAfter), marginRatio) - unrealizedPnlAfter)
739+ else (muld((newPositionOpenNotional - unrealizedPnlAfter), marginRatio) - unrealizedPnlAfter)
740+ let marginToTraderRaw = ((remainMarginBefore - (newPositionMarginWithSameRatio + unrealizedPnlAfter)) - realizedCloseFee)
741+ let marginToTrader = if ((0 > marginToTraderRaw))
742+ then throw("Invalid internalClosePosition params: unable to pay fee")
743+ else marginToTraderRaw
744+ let newPositionMargin = if (_addToMargin)
745+ then (newPositionMarginWithSameRatio + marginToTrader)
746+ else newPositionMarginWithSameRatio
747+ if (if ((_minQuoteAssetAmount != 0))
748+ then (_minQuoteAssetAmount > exchangedQuoteAssetAmount)
749+ else false)
750+ then throw(((("Limit error: " + toString(exchangedQuoteAssetAmount)) + " < ") + toString(_minQuoteAssetAmount)))
751+ else $Tuple17(newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, positionBadDebt, realizedPnl, if (if (_addToMargin)
752+ then isPartialClose
753+ else false)
754+ then 0
755+ else marginToTrader, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() - openNotionalDelta), (totalLongPositionSize() - (if (isLongPosition)
756+ then abs(exchangedPositionSize)
757+ else 0)), (totalShortPositionSize() - (if (!(isLongPosition))
758+ then abs(exchangedPositionSize)
759+ else 0)), (openInterestLong() - (if (isLongPosition)
760+ then openNotionalDelta
761+ else 0)), (openInterestShort() - (if (!(isLongPosition))
762+ then openNotionalDelta
763+ else 0)), (realizedCloseFee + rolloverFee), exchangedQuoteAssetAmount)
764+ }
765+ else throw("Invalid internalClosePosition params: invalid position size")
734766 }
735767
736768
737769 func getTwapSpotPrice () = {
738- let minuteId = ((lastBlock.timestamp / 1000) / 60)
770+ let minuteId = ((lastTimestamp() / 1000) / 60)
739771 let startMinuteId = (minuteId - TWAP_INTERVAL)
740772 let listStr = valueOrElse(getString(this, k_lastDataStr), "")
741773 let list = split(listStr, ",")
742- func filterFn (accumulator,next) = if ((startMinuteId >= parseIntValue(next)))
774+ func filterFn (accumulator,next) = if ((startMinuteId >= valueOrErrorMessage(parseInt(next), ("getTwapSpotPrice: invalid int: " + listStr))))
743775 then (accumulator :+ parseIntValue(next))
744776 else accumulator
745777
746778 let listF = {
747779 let $l = list
748780 let $s = size($l)
749781 let $acc0 = nil
750782 func $f0_1 ($a,$i) = if (($i >= $s))
751783 then $a
752784 else filterFn($a, $l[$i])
753785
754786 func $f0_2 ($a,$i) = if (($i >= $s))
755787 then $a
756788 else throw("List size exceeds 20")
757789
758790 $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)
759791 }
760792 let maxIndex = if ((size(listF) > 0))
761793 then max(listF)
762- else parseIntValue(list[0])
794+ else valueOrErrorMessage(parseInt(list[0]), ("getTwapSpotPrice: invalid int: " + listStr))
763795 let lastMinuteId = valueOrElse(getInteger(this, k_lastMinuteId), 0)
764796 let endLastCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(lastMinuteId))), 0)
765797 let endLastPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(lastMinuteId))), 0)
766798 let nowCumulativePrice = (endLastCumulativePrice + ((minuteId - lastMinuteId) * endLastPrice))
767799 let startLastCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(maxIndex))), 0)
768800 let startLastPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(maxIndex))), 0)
769801 let startCumulativePrice = (startLastCumulativePrice + ((startMinuteId - maxIndex) * startLastPrice))
770802 ((nowCumulativePrice - startCumulativePrice) / TWAP_INTERVAL)
771803 }
772804
773805
774806 func getTerminalAmmState () = {
775807 let _positionSize = totalPositionSize()
776808 if ((_positionSize == 0))
777809 then $Tuple2(qtAstR(), bsAstR())
778810 else {
779811 let direction = (_positionSize > 0)
780- let $t03202332202 = swapOutput(direction, abs(_positionSize), false)
781- let currentNetMarketValue = $t03202332202._1
782- let terminalQuoteAssetReserve = $t03202332202._2
783- let terminalBaseAssetReserve = $t03202332202._3
812+ let $t03902439203 = swapOutput(direction, abs(_positionSize), false)
813+ let currentNetMarketValue = $t03902439203._1
814+ let terminalQuoteAssetReserve = $t03902439203._2
815+ let terminalBaseAssetReserve = $t03902439203._3
784816 $Tuple2(terminalQuoteAssetReserve, terminalBaseAssetReserve)
785817 }
786818 }
787819
788820
789821 func getQuoteAssetWeight (baseAssetReserve,totalPositionSize,quoteAssetReserve,targetPrice) = {
790822 let b = toBigInt(baseAssetReserve)
791823 let sz = toBigInt(totalPositionSize)
792824 let q = toBigInt(quoteAssetReserve)
793825 let p = toBigInt(targetPrice)
794826 let k = bmuld(q, b)
795827 let newB = (b + sz)
796828 let newQ = bdivd(k, newB)
797829 let z = bdivd(newQ, newB)
798830 let result = bdivd(p, z)
799831 toInt(result)
800832 }
801833
802834
803835 func getSyncTerminalPrice (_terminalPrice,_qtAstR,_bsAstR) = {
804836 let _positionSize = totalPositionSize()
805837 if ((_positionSize == 0))
806838 then {
807839 let newQtAstW = divd(muld(_terminalPrice, _bsAstR), _qtAstR)
808840 $Tuple3(newQtAstW, DECIMAL_UNIT, 0)
809841 }
810842 else {
811843 let direction = (_positionSize > 0)
812844 let currentNetMarketValue = swapOutput(direction, abs(_positionSize), false)._1
813845 let newQtAstW = getQuoteAssetWeight(_bsAstR, _positionSize, _qtAstR, _terminalPrice)
814846 let newBsAstW = DECIMAL_UNIT
815847 let marginToVault = getPositionNotionalAndUnrealizedPnlByValues(_positionSize, currentNetMarketValue, _qtAstR, newQtAstW, _bsAstR, newBsAstW, PNL_OPTION_SPOT)._2
816848 $Tuple3(newQtAstW, newBsAstW, marginToVault)
817849 }
818850 }
819851
820852
821853 func getFunding () = {
822854 let underlyingPrice = getOraclePrice()
823855 let spotTwapPrice = getTwapSpotPrice()
824856 let premium = (spotTwapPrice - underlyingPrice)
825857 if (if (if ((totalShortPositionSize() == 0))
826858 then true
827859 else (totalLongPositionSize() == 0))
828860 then true
829861 else isMarketClosed())
830862 then $Tuple2(0, 0)
831863 else if ((0 > premium))
832864 then {
833865 let shortPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY)
834866 let longPremiumFraction = divd(muld(shortPremiumFraction, totalShortPositionSize()), totalLongPositionSize())
835867 $Tuple2(shortPremiumFraction, longPremiumFraction)
836868 }
837869 else {
838870 let longPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY)
839871 let shortPremiumFraction = divd(muld(longPremiumFraction, totalLongPositionSize()), totalShortPositionSize())
840872 $Tuple2(shortPremiumFraction, longPremiumFraction)
841873 }
842874 }
843875
844876
845877 func getAdjustedFee (_artifactId,_baseFeeDiscount) = {
846878 let baseFeeRaw = fee()
847879 let baseFee = muld(baseFeeRaw, _baseFeeDiscount)
848- let $t03506335558 = if ((_artifactId != ""))
880+ let $t04206442559 = if ((_artifactId != ""))
849881 then {
850882 let artifactKind = strA(nftManagerAddress(), toCompositeKey(k_token_type, _artifactId))
851883 if ((artifactKind == FEE_REDUCTION_TOKEN_TYPE))
852884 then {
853885 let reduction = intA(nftManagerAddress(), toCompositeKey(k_token_param, _artifactId))
854886 let adjustedFee = muld(baseFee, reduction)
855887 $Tuple2(adjustedFee, true)
856888 }
857889 else throw("Invalid attached artifact")
858890 }
859891 else $Tuple2(baseFee, false)
860- let adjustedFee = $t03506335558._1
861- let burnArtifact = $t03506335558._2
892+ let adjustedFee = $t04206442559._1
893+ let burnArtifact = $t04206442559._2
862894 $Tuple2(adjustedFee, burnArtifact)
863895 }
864896
865897
866898 func isSameAssetOrNoPosition (_trader,_assetId) = {
867899 let oldPositionSize = getPosition(_trader)._1
868900 if ((oldPositionSize == 0))
869901 then true
870902 else (getPositionAsset(_trader) == _assetId)
871903 }
872904
873905
874906 func isSameAsset (_trader,_assetId) = (getPositionAsset(_trader) == _assetId)
875907
876908
877-func getBorrowedByTraderInMarketKey (_amm,_assetId,_trader) = ((((((k_trader_market_asset_collateral + "_") + _amm) + "_") + _assetId) + "_") + _trader)
878-
879-
880-func getBorrowedByTrader (_trader) = {
881- let positionAsset = getPositionAsset(_trader)
882- if ((positionAsset == toBase58String(quoteAsset())))
883- then $Tuple2(0, positionAsset)
884- else {
885- let key = getBorrowedByTraderInMarketKey(toString(this), positionAsset, _trader)
886- let borrow = valueOrElse(getInteger(collateralAddress(), key), 0)
887- $Tuple2(borrow, positionAsset)
888- }
889- }
890-
891-
892909 func getForTraderWithArtifact (_trader,_artifactId) = {
893910 let doGetFeeDiscount = invoke(minerAddress(), "computeFeeDiscount", [_trader], nil)
894911 if ((doGetFeeDiscount == doGetFeeDiscount))
895912 then {
896913 let feeDiscount = match doGetFeeDiscount {
897914 case x: Int =>
898915 x
899916 case _ =>
900917 throw("Invalid computeFeeDiscount result")
901918 }
902- let $t03678936863 = getAdjustedFee(_artifactId, feeDiscount)
903- let adjustedFee = $t03678936863._1
904- let burnArtifact = $t03678936863._2
919+ let $t04323943313 = getAdjustedFee(_artifactId, feeDiscount)
920+ let adjustedFee = $t04323943313._1
921+ let burnArtifact = $t04323943313._2
905922 $Tuple2(adjustedFee, burnArtifact)
906923 }
907924 else throw("Strict value is not equal to itself.")
908925 }
909926
910927
911928 func getArtifactId (i) = {
912929 let artifactId = if ((size(i.payments) > 1))
913930 then toBase58String(valueOrErrorMessage(i.payments[1].assetId, "Invalid artifactId"))
914931 else ""
915932 artifactId
916933 }
917934
918935
919936 func distributeFee (_feeAmount) = {
920937 let feeToStakers = muld(_feeAmount, feeToStakersPercent())
921938 let feeToVault = (_feeAmount - feeToStakers)
922939 $Tuple2(feeToStakers, feeToVault)
923940 }
924941
925942
926-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)]
943+func updateSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee) = [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), IntegerEntry(k_rolloverFee, _rolloverFee)]
927944
928945
929946 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)]
930-
931-
932-func updatePositionAsset (_address,_assetId) = [StringEntry(toCompositeKey(k_positionAsset, _address), _assetId)]
933947
934948
935949 func incrementPositionSequenceNumber (_isNewPosition,_address) = if (_isNewPosition)
936950 then {
937951 let currentSequence = lastSequence()
938952 [IntegerEntry(toCompositeKey(k_positionSequence, _address), (currentSequence + 1)), IntegerEntry(k_sequence, (currentSequence + 1))]
939953 }
940954 else nil
941955
942956
943957 func updatePositionFee (_isNewPosition,_address,_fee) = if (_isNewPosition)
944958 then [IntegerEntry(toCompositeKey(k_positionFee, _address), _fee)]
945959 else nil
946960
947961
948-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)]
962+func updatePosition (_address,_size,_margin,_openNotional,_latestCumulativePremiumFraction,_latestTimestamp) = [IntegerEntry(toCompositeKey(k_positionSize, _address), _size), IntegerEntry(toCompositeKey(k_positionMargin, _address), _margin), IntegerEntry(toCompositeKey(k_positionOpenNotional, _address), _openNotional), IntegerEntry(toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _address), _latestCumulativePremiumFraction), IntegerEntry(toCompositeKey(k_positionLastUpdatedTimestamp, _address), _latestTimestamp)]
949963
950964
951965 func appendTwap (_price) = {
952- let minuteId = ((lastBlock.timestamp / 1000) / 60)
966+ let minuteId = ((lastTimestamp() / 1000) / 60)
953967 let previousMinuteId = valueOrElse(getInteger(this, k_lastMinuteId), 0)
954968 if ((previousMinuteId > minuteId))
955969 then throw("TWAP out-of-order")
956970 else {
957971 let lastMinuteId = if ((previousMinuteId == 0))
958972 then minuteId
959973 else previousMinuteId
960974 if ((minuteId > previousMinuteId))
961975 then {
962976 let prevCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(previousMinuteId))), 0)
963977 let prevPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(previousMinuteId))), _price)
964978 let lastCumulativePrice = (prevCumulativePrice + ((minuteId - lastMinuteId) * prevPrice))
965979 let list = pushToQueue(strToList(valueOrElse(getString(this, k_lastDataStr), "")), TWAP_INTERVAL, toString(minuteId))
966980 [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))]
967981 }
968982 else {
969983 let twapDataPreviousMinuteId = valueOrElse(getInteger(this, toCompositeKey(k_twapDataPreviousMinuteId, toString(minuteId))), 0)
970984 let prevCumulativePrice = valueOrElse(getInteger(this, toCompositeKey(k_twapDataLastCumulativePrice, toString(twapDataPreviousMinuteId))), 0)
971985 let prevPrice = valueOrElse(getInteger(this, toCompositeKey(k_twapDataLastPrice, toString(twapDataPreviousMinuteId))), _price)
972986 let lastCumulativePrice = (prevCumulativePrice + ((minuteId - twapDataPreviousMinuteId) * prevPrice))
973987 [IntegerEntry(toCompositeKey(k_twapDataLastCumulativePrice, toString(minuteId)), lastCumulativePrice), IntegerEntry(toCompositeKey(k_twapDataLastPrice, toString(minuteId)), _price)]
974988 }
975989 }
976990 }
977991
978992
979993 func updateAmmReserves (_qtAstR,_bsAstR) = [IntegerEntry(k_quoteAssetReserve, _qtAstR), IntegerEntry(k_baseAssetReserve, _bsAstR)]
980994
981995
982996 func updateAmmWeights (_qtAstW,_bsAstW) = [IntegerEntry(k_quoteAssetWeight, _qtAstW), IntegerEntry(k_baseAssetWeight, _bsAstW)]
983997
984998
985999 func updateAmm (_qtAstR,_bsAstR,_totalPositionSizeAfter,_openInterestNotional,_totalLongPositionSize,_totalShortPositionSize,_totalLongOpenNotional,_totalShortOpenNotional) = {
9861000 let _qtAstW = qtAstW()
9871001 let _bsAstW = bsAstW()
9881002 if (((_totalLongPositionSize - _totalShortPositionSize) != _totalPositionSizeAfter))
9891003 then throw(((((("Invalid AMM state data: " + toString(_totalLongPositionSize)) + " + ") + toString(_totalShortPositionSize)) + " != ") + toString(_totalPositionSizeAfter)))
9901004 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))))
9911005 }
9921006
9931007
994-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))]
1008+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)), DeleteEntry(toCompositeKey(k_positionFee, _address)), DeleteEntry(toCompositeKey(k_positionLastUpdatedTimestamp, _address))]
9951009
9961010
9971011 func withdraw (_address,_amount) = {
9981012 let balance = assetBalance(this, quoteAsset())
9991013 if ((_amount > balance))
10001014 then throw(((("Unable to withdraw " + toString(_amount)) + " from contract balance ") + toString(balance)))
10011015 else [ScriptTransfer(_address, _amount, quoteAsset())]
10021016 }
10031017
10041018
10051019 func updateBalance (i) = if ((0 > i))
10061020 then throw("Balance")
10071021 else [IntegerEntry(k_balance, i)]
10081022
10091023
10101024 func transferFee (i) = [ScriptTransfer(stakingAddress(), i, quoteAsset())]
10111025
10121026
10131027 func doBurnArtifact (_burnArtifact,i) = if (_burnArtifact)
10141028 then [Burn(valueOrErrorMessage(i.payments[1].assetId, "Invalid artifact"), 1)]
10151029 else nil
10161030
10171031
10181032 @Callable(i)
10191033 func pause () = if ((i.caller != adminAddress()))
10201034 then throw("Invalid pause params")
10211035 else [BooleanEntry(k_paused, true)]
10221036
10231037
10241038
10251039 @Callable(i)
10261040 func unpause () = if ((i.caller != adminAddress()))
10271041 then throw("Invalid unpause params")
10281042 else [BooleanEntry(k_paused, false)]
10291043
10301044
10311045
10321046 @Callable(i)
10331047 func setCloseOnly () = if ((i.caller != adminAddress()))
10341048 then throw("Invalid setCloseOnly params")
10351049 else [BooleanEntry(k_closeOnly, true)]
10361050
10371051
10381052
10391053 @Callable(i)
10401054 func unsetCloseOnly () = if ((i.caller != adminAddress()))
10411055 then throw("Invalid unsetCloseOnly params")
10421056 else [BooleanEntry(k_closeOnly, false)]
10431057
10441058
10451059
10461060 @Callable(i)
10471061 func addLiquidity (_quoteAssetAmount) = if (if ((i.caller != adminAddress()))
10481062 then true
10491063 else (0 >= _quoteAssetAmount))
10501064 then throw("Invalid addLiquidity params")
10511065 else {
10521066 let _qtAstR = qtAstR()
10531067 let _bsAstR = bsAstR()
10541068 let _qtAstW = qtAstW()
10551069 let _bsAstW = bsAstW()
10561070 let price = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
10571071 let qtAstRAfter = (_qtAstR + _quoteAssetAmount)
10581072 let baseAssetAmountToAdd = (divd(muld(qtAstRAfter, _qtAstW), price) - _bsAstR)
10591073 let bsAstRAfter = (_bsAstR + baseAssetAmountToAdd)
1060- let $t04610746258 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1061- let newQuoteAssetWeight = $t04610746258._1
1062- let newBaseAssetWeight = $t04610746258._2
1063- let marginToVault = $t04610746258._3
1074+ let $t05272052871 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1075+ let newQuoteAssetWeight = $t05272052871._1
1076+ let newBaseAssetWeight = $t05272052871._2
1077+ let marginToVault = $t05272052871._3
10641078 let doExchangePnL = if ((marginToVault != 0))
10651079 then {
10661080 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
10671081 if ((doExchangePnL == doExchangePnL))
10681082 then nil
10691083 else throw("Strict value is not equal to itself.")
10701084 }
10711085 else nil
10721086 if ((doExchangePnL == doExchangePnL))
10731087 then (updateAmmReserves(qtAstRAfter, bsAstRAfter) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
10741088 else throw("Strict value is not equal to itself.")
10751089 }
10761090
10771091
10781092
10791093 @Callable(i)
10801094 func removeLiquidity (_quoteAssetAmount) = if (if ((i.caller != adminAddress()))
10811095 then true
10821096 else (_quoteAssetAmount >= 0))
10831097 then throw("Invalid removeLiquidity params")
10841098 else {
10851099 let _qtAstR = qtAstR()
10861100 let _bsAstR = bsAstR()
10871101 let _qtAstW = qtAstW()
10881102 let _bsAstW = bsAstW()
10891103 let price = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
10901104 let qtAstRAfter = (_qtAstR - _quoteAssetAmount)
10911105 let baseAssetAmountToRemove = abs((divd(muld(qtAstRAfter, _qtAstW), price) - _bsAstR))
10921106 let bsAstRAfter = (_bsAstR - baseAssetAmountToRemove)
1093- let $t04719047341 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1094- let newQuoteAssetWeight = $t04719047341._1
1095- let newBaseAssetWeight = $t04719047341._2
1096- let marginToVault = $t04719047341._3
1107+ let $t05380353954 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1108+ let newQuoteAssetWeight = $t05380353954._1
1109+ let newBaseAssetWeight = $t05380353954._2
1110+ let marginToVault = $t05380353954._3
10971111 let doExchangePnL = if ((marginToVault != 0))
10981112 then {
10991113 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
11001114 if ((doExchangePnL == doExchangePnL))
11011115 then nil
11021116 else throw("Strict value is not equal to itself.")
11031117 }
11041118 else nil
11051119 if ((doExchangePnL == doExchangePnL))
11061120 then (updateAmmReserves(qtAstRAfter, bsAstRAfter) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
11071121 else throw("Strict value is not equal to itself.")
11081122 }
11091123
11101124
11111125
11121126 @Callable(i)
1113-func changeSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay) = if ((i.caller != adminAddress()))
1127+func changeSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee) = if ((i.caller != adminAddress()))
11141128 then throw("Invalid changeSettings params")
1115- else updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread, _maxOpenNotional, _feeToStakersPercent, _maxOracleDelay)
1129+ else updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread, _maxOpenNotional, _feeToStakersPercent, _maxOracleDelay, _rolloverFee)
11161130
11171131
11181132
11191133 @Callable(i)
1120-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))
1134+func initialize (_qtAstR,_bsAstR,_fundingPeriod,_initMarginRatio,_mmr,_liquidationFeeRatio,_fee,_oracle,_oracleKey,_oracleBlockKey,_coordinator,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee) = if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if ((0 >= _qtAstR))
11211135 then true
11221136 else (0 >= _bsAstR))
11231137 then true
11241138 else (0 >= _fundingPeriod))
11251139 then true
11261140 else (0 >= _initMarginRatio))
11271141 then true
11281142 else (0 >= _mmr))
11291143 then true
11301144 else (0 >= _liquidationFeeRatio))
11311145 then true
11321146 else (0 >= _fee))
11331147 then true
11341148 else (0 >= _spreadLimit))
11351149 then true
11361150 else (0 >= _maxPriceImpact))
11371151 then true
11381152 else (0 >= _partialLiquidationRatio))
11391153 then true
11401154 else (0 >= _maxPriceSpread))
11411155 then true
11421156 else (0 >= _maxOpenNotional))
11431157 then true
11441158 else (0 >= _feeToStakersPercent))
11451159 then true
11461160 else (_feeToStakersPercent > DECIMAL_UNIT))
11471161 then true
11481162 else (0 >= _maxOracleDelay))
11491163 then true
1164+ else (0 >= _rolloverFee))
1165+ then true
11501166 else initialized())
11511167 then throw("Invalid initialize parameters")
1152- 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)])
1168+ else ((((updateAmm(_qtAstR, _bsAstR, 0, 0, 0, 0, 0, 0) ++ updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread, _maxOpenNotional, _feeToStakersPercent, _maxOracleDelay, _rolloverFee)) ++ updateFunding((lastTimestamp() + _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)])
11531169
11541170
11551171
11561172 @Callable(i)
11571173 func increasePosition (_direction,_leverage,_minBaseAssetAmount,_refLink) = {
11581174 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
11591175 if ((sync == sync))
11601176 then {
11611177 let _trader = getActualCaller(i)
11621178 let _rawAmount = i.payments[0].amount
11631179 let _assetId = i.payments[0].assetId
11641180 let _assetIdStr = toBase58String(value(_assetId))
11651181 let isQuoteAsset = (_assetId == quoteAsset())
1166- let isCollateralAsset = isWhitelistAsset(_assetIdStr)
11671182 if (if (if (if (if (if (if (if (if (if ((_direction != DIR_LONG))
11681183 then (_direction != DIR_SHORT)
11691184 else false)
11701185 then true
11711186 else (0 >= _rawAmount))
11721187 then true
11731188 else !(initialized()))
11741189 then true
1175- else if (!(isQuoteAsset))
1176- then !(isCollateralAsset)
1177- else false)
1190+ else !(isQuoteAsset))
11781191 then true
11791192 else !(isSameAssetOrNoPosition(_trader, _assetIdStr)))
11801193 then true
11811194 else !(requireMoreMarginRatio(divd(DECIMAL_UNIT, _leverage), initMarginRatio(), true)))
11821195 then true
11831196 else paused())
11841197 then true
11851198 else closeOnly())
11861199 then true
11871200 else isMarketClosed())
11881201 then throw("Invalid increasePosition parameters")
11891202 else {
1190- let $t05100951158 = getForTraderWithArtifact(_trader, getArtifactId(i))
1191- let adjustedFee = $t05100951158._1
1192- let burnArtifact = $t05100951158._2
1203+ let $t05764557794 = getForTraderWithArtifact(_trader, getArtifactId(i))
1204+ let adjustedFee = $t05764557794._1
1205+ let burnArtifact = $t05764557794._2
11931206 let _amount = divd(_rawAmount, (muld(adjustedFee, _leverage) + DECIMAL_UNIT))
1194- let rawFeeAmount = (_rawAmount - _amount)
1195- let distributeFeeAmount = if (isCollateralAsset)
1207+ let distributeFeeAmount = (_rawAmount - _amount)
1208+ let referrerFeeAny = invoke(referralAddress(), "acceptPaymentWithLink", [_trader, _refLink], [AttachedPayment(quoteAsset(), distributeFeeAmount)])
1209+ if ((referrerFeeAny == referrerFeeAny))
11961210 then {
1197- let doBorrow = invoke(collateralAddress(), "borrow", [_trader], [AttachedPayment(_assetId, _amount)])
1198- if ((doBorrow == doBorrow))
1211+ let referrerFee = match referrerFeeAny {
1212+ case x: Int =>
1213+ x
1214+ case _ =>
1215+ throw("Invalid referrerFee")
1216+ }
1217+ let feeAmount = (distributeFeeAmount - referrerFee)
1218+ let $t05829058458 = getPosition(_trader)
1219+ let oldPositionSize = $t05829058458._1
1220+ let oldPositionMargin = $t05829058458._2
1221+ let oldPositionOpenNotional = $t05829058458._3
1222+ let oldPositionLstUpdCPF = $t05829058458._4
1223+ let oldPositionTimestamp = $t05829058458._5
1224+ let isNewPosition = (oldPositionSize == 0)
1225+ let isSameDirection = if ((oldPositionSize > 0))
1226+ then (_direction == DIR_LONG)
1227+ else (_direction == DIR_SHORT)
1228+ let expandExisting = if (!(isNewPosition))
1229+ then isSameDirection
1230+ else false
1231+ let isAdd = (_direction == DIR_LONG)
1232+ let $t05874761868 = if (if (isNewPosition)
1233+ then true
1234+ else expandExisting)
11991235 then {
1200- let balanceBefore = assetBalance(this, quoteAsset())
1201- if ((balanceBefore == balanceBefore))
1202- then {
1203- let doSwap = invoke(swapAddress(), "swap", [toBase58String(quoteAsset()), 0], [AttachedPayment(_assetId, rawFeeAmount)])
1204- if ((doSwap == doSwap))
1205- then {
1206- let balanceAfter = assetBalance(this, quoteAsset())
1207- if ((balanceAfter == balanceAfter))
1208- then {
1209- let exchangedAmount = (balanceAfter - balanceBefore)
1210- if ((exchangedAmount == exchangedAmount))
1211- then exchangedAmount
1212- else throw("Strict value is not equal to itself.")
1213- }
1214- else throw("Strict value is not equal to itself.")
1215- }
1216- else throw("Strict value is not equal to itself.")
1236+ let openNotional = muld(_amount, _leverage)
1237+ let $t05925659429 = swapInput(isAdd, openNotional)
1238+ let amountBaseAssetBought = $t05925659429._1
1239+ let quoteAssetReserveAfter = $t05925659429._2
1240+ let baseAssetReserveAfter = $t05925659429._3
1241+ let totalPositionSizeAfter = $t05925659429._4
1242+ if (if ((_minBaseAssetAmount != 0))
1243+ then (_minBaseAssetAmount > abs(amountBaseAssetBought))
1244+ else false)
1245+ then throw(((("Limit error: " + toString(abs(amountBaseAssetBought))) + " < ") + toString(_minBaseAssetAmount)))
1246+ else {
1247+ let newPositionSize = (oldPositionSize + amountBaseAssetBought)
1248+ let totalLongOpenInterestAfter = (openInterestLong() + (if ((newPositionSize > 0))
1249+ then openNotional
1250+ else 0))
1251+ let totalShortOpenInterestAfter = (openInterestShort() + (if ((0 > newPositionSize))
1252+ then openNotional
1253+ else 0))
1254+ let $t05997560250 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
1255+ let remainMargin = $t05997560250._1
1256+ let x1 = $t05997560250._2
1257+ let x2 = $t05997560250._3
1258+ let rolloverFee = $t05997560250._4
1259+ if (!(requireNotOverSpreadLimit(quoteAssetReserveAfter, baseAssetReserveAfter)))
1260+ then throw("Over max spread limit")
1261+ else if (!(requireNotOverMaxOpenNotional(totalLongOpenInterestAfter, totalShortOpenInterestAfter)))
1262+ then throw("Over max open notional")
1263+ else $Tuple14(newPositionSize, remainMargin, (oldPositionOpenNotional + openNotional), latestCumulativePremiumFraction(newPositionSize), lastTimestamp(), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() + openNotional), (totalLongPositionSize() + (if ((newPositionSize > 0))
1264+ then abs(amountBaseAssetBought)
1265+ else 0)), (totalShortPositionSize() + (if ((0 > newPositionSize))
1266+ then abs(amountBaseAssetBought)
1267+ else 0)), totalLongOpenInterestAfter, totalShortOpenInterestAfter, rolloverFee)
12171268 }
1269+ }
1270+ else {
1271+ let openNotional = muld(_amount, _leverage)
1272+ let $t06156861684 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
1273+ let oldPositionNotional = $t06156861684._1
1274+ let unrealizedPnl = $t06156861684._2
1275+ if ((oldPositionNotional > openNotional))
1276+ then throw("Use decreasePosition to decrease position size")
1277+ else throw("Close position first")
1278+ }
1279+ let newPositionSize = $t05874761868._1
1280+ let newPositionRemainMargin = $t05874761868._2
1281+ let newPositionOpenNotional = $t05874761868._3
1282+ let newPositionLatestCPF = $t05874761868._4
1283+ let newPositionTimestamp = $t05874761868._5
1284+ let baseAssetReserveAfter = $t05874761868._6
1285+ let quoteAssetReserveAfter = $t05874761868._7
1286+ let totalPositionSizeAfter = $t05874761868._8
1287+ let openInterestNotionalAfter = $t05874761868._9
1288+ let totalLongAfter = $t05874761868._10
1289+ let totalShortAfter = $t05874761868._11
1290+ let totalLongOpenInterestAfter = $t05874761868._12
1291+ let totalShortOpenInterestAfter = $t05874761868._13
1292+ let rolloverFee = $t05874761868._14
1293+ let $t06187461945 = distributeFee((feeAmount + rolloverFee))
1294+ let feeToStakers = $t06187461945._1
1295+ let feeToVault = $t06187461945._2
1296+ let stake = if (isQuoteAsset)
1297+ then {
1298+ let stake = invoke(vaultAddress(), "addLocked", [false], [AttachedPayment(quoteAsset(), _amount)])
1299+ if ((stake == stake))
1300+ then nil
12181301 else throw("Strict value is not equal to itself.")
12191302 }
1220- else throw("Strict value is not equal to itself.")
1221- }
1222- else rawFeeAmount
1223- if ((distributeFeeAmount == distributeFeeAmount))
1224- then {
1225- let referrerFeeAny = invoke(referralAddress(), "acceptPaymentWithLink", [_trader, _refLink], [AttachedPayment(quoteAsset(), distributeFeeAmount)])
1226- if ((referrerFeeAny == referrerFeeAny))
1303+ else nil
1304+ if ((stake == stake))
12271305 then {
1228- let referrerFee = match referrerFeeAny {
1229- case x: Int =>
1230- x
1231- case _ =>
1232- throw("Invalid referrerFee")
1233- }
1234- let feeAmount = (distributeFeeAmount - referrerFee)
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
1240- let isNewPosition = (oldPositionSize == 0)
1241- let isSameDirection = if ((oldPositionSize > 0))
1242- then (_direction == DIR_LONG)
1243- else (_direction == DIR_SHORT)
1244- let expandExisting = if (!(isNewPosition))
1245- then isSameDirection
1246- else false
1247- let isAdd = (_direction == DIR_LONG)
1248- let $t05292955891 = if (if (isNewPosition)
1249- then true
1250- else expandExisting)
1306+ let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1307+ if ((depositVault == depositVault))
12511308 then {
1252- let openNotional = muld(_amount, _leverage)
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
1258- if (if ((_minBaseAssetAmount != 0))
1259- then (_minBaseAssetAmount > abs(amountBaseAssetBought))
1260- else false)
1261- then throw(((("Limit error: " + toString(abs(amountBaseAssetBought))) + " < ") + toString(_minBaseAssetAmount)))
1262- else {
1263- let newPositionSize = (oldPositionSize + amountBaseAssetBought)
1264- let totalLongOpenInterestAfter = (openInterestLong() + (if ((newPositionSize > 0))
1265- then openNotional
1266- else 0))
1267- let totalShortOpenInterestAfter = (openInterestShort() + (if ((0 > newPositionSize))
1268- then openNotional
1269- else 0))
1270- let $t05411054331 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, _amount)
1271- let remainMargin = $t05411054331._1
1272- let x1 = $t05411054331._2
1273- let x2 = $t05411054331._3
1274- if (!(requireNotOverSpreadLimit(quoteAssetReserveAfter, baseAssetReserveAfter)))
1275- then throw("Over max spread limit")
1276- else if (!(requireNotOverMaxOpenNotional(totalLongOpenInterestAfter, totalShortOpenInterestAfter)))
1277- then throw("Over max open notional")
1278- else $Tuple12(newPositionSize, remainMargin, (oldPositionOpenNotional + openNotional), latestCumulativePremiumFraction(newPositionSize), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() + openNotional), (totalLongPositionSize() + (if ((newPositionSize > 0))
1279- then abs(amountBaseAssetBought)
1280- else 0)), (totalShortPositionSize() + (if ((0 > newPositionSize))
1281- then abs(amountBaseAssetBought)
1282- else 0)), totalLongOpenInterestAfter, totalShortOpenInterestAfter)
1283- }
1284- }
1285- else {
1286- let openNotional = muld(_amount, _leverage)
1287- let $t05559155707 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
1288- let oldPositionNotional = $t05559155707._1
1289- let unrealizedPnl = $t05559155707._2
1290- if ((oldPositionNotional > openNotional))
1291- then throw("Use decreasePosition to decrease position size")
1292- else throw("Close position first")
1293- }
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
1309- let stake = if (isQuoteAsset)
1310- then {
1311- let stake = invoke(vaultAddress(), "addLocked", [false], [AttachedPayment(quoteAsset(), _amount)])
1312- if ((stake == stake))
1313- then nil
1314- else throw("Strict value is not equal to itself.")
1315- }
1316- else nil
1317- if ((stake == stake))
1318- then {
1319- let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1320- if ((depositVault == depositVault))
1309+ let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, feeAmount], nil)
1310+ if ((notifyFee == notifyFee))
13211311 then {
1322- let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, feeAmount], nil)
1323- if ((notifyFee == notifyFee))
1324- then {
1325- let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
1326- if ((notifyNotional == notifyNotional))
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))
1328- else throw("Strict value is not equal to itself.")
1329- }
1312+ let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
1313+ if ((notifyNotional == notifyNotional))
1314+ then ((((((updatePosition(_trader, newPositionSize, newPositionRemainMargin, newPositionOpenNotional, newPositionLatestCPF, newPositionTimestamp) ++ incrementPositionSequenceNumber(isNewPosition, _trader)) ++ updatePositionFee(isNewPosition, _trader, adjustedFee)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ transferFee(feeToStakers)) ++ updateBalance((cbalance() + _amount))) ++ doBurnArtifact(burnArtifact, i))
13301315 else throw("Strict value is not equal to itself.")
13311316 }
13321317 else throw("Strict value is not equal to itself.")
13331318 }
13341319 else throw("Strict value is not equal to itself.")
13351320 }
13361321 else throw("Strict value is not equal to itself.")
13371322 }
13381323 else throw("Strict value is not equal to itself.")
13391324 }
13401325 }
13411326 else throw("Strict value is not equal to itself.")
13421327 }
13431328
13441329
13451330
13461331 @Callable(i)
13471332 func addMargin () = {
13481333 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
13491334 if ((sync == sync))
13501335 then {
13511336 let _trader = toString(i.caller)
13521337 let _amount = i.payments[0].amount
13531338 let _assetId = i.payments[0].assetId
13541339 let _assetIdStr = toBase58String(value(_assetId))
13551340 let isQuoteAsset = (_assetId == quoteAsset())
1356- let isCollateralAsset = isWhitelistAsset(_assetIdStr)
1357- if (if (if (if (if (if (if (if (!(isQuoteAsset))
1358- then !(isCollateralAsset)
1359- else false)
1341+ if (if (if (if (if (if (if (!(isQuoteAsset))
13601342 then true
13611343 else !(requireOpenPosition(toString(i.caller))))
13621344 then true
13631345 else !(isSameAsset(_trader, _assetIdStr)))
13641346 then true
13651347 else !(initialized()))
13661348 then true
13671349 else paused())
13681350 then true
13691351 else closeOnly())
13701352 then true
13711353 else isMarketClosed())
13721354 then throw("Invalid addMargin parameters")
13731355 else {
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)
1356+ let $t06387164039 = getPosition(_trader)
1357+ let oldPositionSize = $t06387164039._1
1358+ let oldPositionMargin = $t06387164039._2
1359+ let oldPositionOpenNotional = $t06387164039._3
1360+ let oldPositionLstUpdCPF = $t06387164039._4
1361+ let oldPositionTimestamp = $t06387164039._5
1362+ let stake = invoke(vaultAddress(), "addLocked", [false], [AttachedPayment(quoteAsset(), _amount)])
1363+ if ((stake == stake))
13801364 then {
1381- let stake = invoke(vaultAddress(), "addLocked", [false], [AttachedPayment(quoteAsset(), _amount)])
1382- if ((stake == stake))
1383- then nil
1365+ let rolloverFee = calcRolloverFee(oldPositionMargin, oldPositionTimestamp)
1366+ let doTransferFeeToStakers = if ((rolloverFee > 0))
1367+ then {
1368+ let $t06432964388 = distributeFee(rolloverFee)
1369+ let feeToStakers = $t06432964388._1
1370+ let feeToVault = $t06432964388._2
1371+ let unstake = invoke(vaultAddress(), "withdrawLocked", [feeToStakers], nil)
1372+ if ((unstake == unstake))
1373+ then {
1374+ let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
1375+ if ((lockBadDebt == lockBadDebt))
1376+ then transferFee(feeToStakers)
1377+ else throw("Strict value is not equal to itself.")
1378+ }
1379+ else throw("Strict value is not equal to itself.")
1380+ }
1381+ else nil
1382+ if ((doTransferFeeToStakers == doTransferFeeToStakers))
1383+ then ((updatePosition(_trader, oldPositionSize, ((oldPositionMargin - rolloverFee) + _amount), oldPositionOpenNotional, oldPositionLstUpdCPF, lastTimestamp()) ++ updateBalance(((cbalance() + _amount) - rolloverFee))) ++ doTransferFeeToStakers)
13841384 else throw("Strict value is not equal to itself.")
13851385 }
1386- else nil
1387- if ((stake == stake))
1388- then (updatePosition(_trader, oldPositionSize, (oldPositionMargin + _amount), oldPositionOpenNotional, oldPositionLstUpdCPF) ++ updateBalance((cbalance() + _amount)))
13891386 else throw("Strict value is not equal to itself.")
13901387 }
13911388 }
13921389 else throw("Strict value is not equal to itself.")
13931390 }
13941391
13951392
13961393
13971394 @Callable(i)
13981395 func removeMargin (_amount) = {
13991396 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
14001397 if ((sync == sync))
14011398 then {
14021399 let _trader = toString(i.caller)
14031400 if (if (if (if (if ((0 >= _amount))
14041401 then true
14051402 else !(requireOpenPosition(_trader)))
14061403 then true
14071404 else !(initialized()))
14081405 then true
14091406 else paused())
14101407 then true
14111408 else isMarketClosed())
14121409 then throw("Invalid removeMargin parameters")
14131410 else {
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
1419- let marginDelta = -(_amount)
1420- let $t05909759276 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, marginDelta)
1421- let remainMargin = $t05909759276._1
1422- let badDebt = $t05909759276._2
1411+ let $t06543165599 = getPosition(_trader)
1412+ let oldPositionSize = $t06543165599._1
1413+ let oldPositionMargin = $t06543165599._2
1414+ let oldPositionOpenNotional = $t06543165599._3
1415+ let oldPositionLstUpdCPF = $t06543165599._4
1416+ let oldPositionTimestamp = $t06543165599._5
1417+ let $t06560565854 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, -(_amount))
1418+ let remainMargin = $t06560565854._1
1419+ let badDebt = $t06560565854._2
1420+ let fundingPayment = $t06560565854._3
1421+ let rolloverFee = $t06560565854._4
14231422 if ((badDebt != 0))
14241423 then throw("Invalid removed margin amount")
14251424 else {
14261425 let marginRatio = calcMarginRatio(remainMargin, badDebt, oldPositionOpenNotional)
14271426 if (!(requireMoreMarginRatio(marginRatio, initMarginRatio(), true)))
14281427 then throw(((("Too much margin removed: " + toString(marginRatio)) + " < ") + toString(initMarginRatio())))
14291428 else {
1430- let quoteAssetStr = toBase58String(quoteAsset())
1431- let $t05972059774 = getBorrowedByTrader(_trader)
1432- let borrowed = $t05972059774._1
1433- let assetId = $t05972059774._2
1434- let toRepay = if ((_amount > borrowed))
1435- then borrowed
1436- else _amount
1437- let toWithdraw = if ((borrowed > _amount))
1438- then 0
1439- else (_amount - borrowed)
1440- let finalBorrow = (borrowed - toRepay)
1441- let switchPositionToQuote = if ((finalBorrow > 0))
1442- then nil
1443- else updatePositionAsset(_trader, quoteAssetStr)
1444- let doSanityCheck = if (((toRepay + toWithdraw) != _amount))
1445- then throw(((((("toRepay=" + toString(toRepay)) + " + toWithdraw=") + toString(toWithdraw)) + " != ") + toString(_amount)))
1429+ let $t06624066299 = distributeFee(rolloverFee)
1430+ let feeToStakers = $t06624066299._1
1431+ let feeToVault = $t06624066299._2
1432+ let doTransferFeeToStakers = if ((rolloverFee > 0))
1433+ then {
1434+ let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
1435+ if ((lockBadDebt == lockBadDebt))
1436+ then transferFee(feeToStakers)
1437+ else throw("Strict value is not equal to itself.")
1438+ }
14461439 else nil
1447- if ((doSanityCheck == doSanityCheck))
1440+ if ((doTransferFeeToStakers == doTransferFeeToStakers))
14481441 then {
1449- let doUnstake = if ((toWithdraw > 0))
1450- then {
1451- let doUnstake = invoke(vaultAddress(), "withdrawLocked", [toWithdraw], nil)
1452- if ((doUnstake == doUnstake))
1453- then nil
1454- else throw("Strict value is not equal to itself.")
1455- }
1456- else nil
1457- if ((doUnstake == doUnstake))
1458- then {
1459- let returnCollateralAction = if ((toRepay > 0))
1460- then {
1461- let doRepay = invoke(collateralAddress(), "repay", [_trader, toRepay, assetId], nil)
1462- if ((doRepay == doRepay))
1463- then [ScriptTransfer(i.caller, toRepay, fromBase58String(assetId))]
1464- else throw("Strict value is not equal to itself.")
1465- }
1466- else nil
1467- if ((returnCollateralAction == returnCollateralAction))
1468- then ((((updatePosition(_trader, oldPositionSize, remainMargin, oldPositionOpenNotional, latestCumulativePremiumFraction(oldPositionSize)) ++ (if ((toWithdraw > 0))
1469- then withdraw(i.caller, toWithdraw)
1470- else nil)) ++ updateBalance((cbalance() - _amount))) ++ switchPositionToQuote) ++ returnCollateralAction)
1471- else throw("Strict value is not equal to itself.")
1472- }
1442+ let unstake = invoke(vaultAddress(), "withdrawLocked", [(_amount + feeToStakers)], nil)
1443+ if ((unstake == unstake))
1444+ then (((updatePosition(_trader, oldPositionSize, remainMargin, oldPositionOpenNotional, latestCumulativePremiumFraction(oldPositionSize), lastTimestamp()) ++ withdraw(i.caller, _amount)) ++ updateBalance(((cbalance() - _amount) - rolloverFee))) ++ doTransferFeeToStakers)
14731445 else throw("Strict value is not equal to itself.")
14741446 }
14751447 else throw("Strict value is not equal to itself.")
14761448 }
14771449 }
14781450 }
14791451 }
14801452 else throw("Strict value is not equal to itself.")
14811453 }
14821454
14831455
14841456
14851457 @Callable(i)
14861458 func closePosition (_size,_minQuoteAssetAmount,_addToMargin) = {
14871459 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
14881460 if ((sync == sync))
14891461 then {
14901462 let _trader = getActualCaller(i)
14911463 let _traderAddress = valueOrErrorMessage(addressFromString(_trader), "Invalid caller")
14921464 let positionFee = getPositionFee(_trader)
14931465 if (if (if (if (if (if (!(requireOpenPosition(_trader)))
14941466 then true
14951467 else !(initialized()))
14961468 then true
14971469 else paused())
14981470 then true
14991471 else (0 >= _size))
15001472 then true
15011473 else (0 > _minQuoteAssetAmount))
15021474 then true
15031475 else isMarketClosed())
15041476 then throw("Invalid closePosition parameters")
15051477 else {
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))
1512- then {
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
1518- let exchangedPositionSize = if ((oldPositionSize > 0))
1519- then -(_size)
1520- else _size
1521- let $t06296263116 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1522- let oldPositionNotional = $t06296263116._1
1523- let unrealizedPnl = $t06296263116._2
1524- let mr = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
1525- let realizedRatio = divd(abs(exchangedPositionSize), abs(oldPositionSize))
1526- let realizedPnl = muld(unrealizedPnl, realizedRatio)
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
1530- let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
1531- let remainOpenNotional = if ((oldPositionSize > 0))
1532- then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
1533- else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
1534- let newPositionOpenNotional = abs(remainOpenNotional)
1535- let newPositionSize = (oldPositionSize + exchangedPositionSize)
1536- let newPositionLstUpdCPF = latestCumulativePremiumFraction(newPositionSize)
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
1546- if (if ((_minQuoteAssetAmount != 0))
1547- then (_minQuoteAssetAmount > exchangedQuoteAssetAmount)
1548- else false)
1549- then throw(((("Limit error: " + toString(exchangedQuoteAssetAmount)) + " < ") + toString(_minQuoteAssetAmount)))
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))
1555- then abs(exchangedPositionSize)
1556- else 0)), (totalShortPositionSize() - (if ((0 > newPositionSize))
1557- then abs(exchangedPositionSize)
1558- else 0)), (openInterestLong() - (if ((newPositionSize > 0))
1559- then openNotionalDelta
1560- else 0)), (openInterestShort() - (if ((0 > newPositionSize))
1561- then openNotionalDelta
1562- else 0)), realizedFee)
1563- }
1564- else if ((_size > abs(oldPositionSize)))
1565- then throw("Invalid closePosition parameters")
1566- else {
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
1586- if (if ((_minQuoteAssetAmount != 0))
1587- then (_minQuoteAssetAmount > exchangedQuoteAssetAmount)
1588- else false)
1589- then throw(((("Limit error: " + toString(exchangedQuoteAssetAmount)) + " < ") + toString(_minQuoteAssetAmount)))
1590- else $Tuple16(0, 0, 0, 0, positionBadDebt, realizedPnl, marginToTrader, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter, realizedFee)
1591- }
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
1478+ let $t06783167971 = getPosition(_trader)
1479+ let oldPositionSize = $t06783167971._1
1480+ let oldPositionMargin = $t06783167971._2
1481+ let oldPositionOpenNotional = $t06783167971._3
1482+ let oldPositionLstUpdCPF = $t06783167971._4
1483+ let $t06797768550 = internalClosePosition(_trader, _size, positionFee, _minQuoteAssetAmount, _addToMargin, true)
1484+ let newPositionSize = $t06797768550._1
1485+ let newPositionMargin = $t06797768550._2
1486+ let newPositionOpenNotional = $t06797768550._3
1487+ let newPositionLstUpdCPF = $t06797768550._4
1488+ let positionBadDebt = $t06797768550._5
1489+ let realizedPnl = $t06797768550._6
1490+ let marginToTrader = $t06797768550._7
1491+ let quoteAssetReserveAfter = $t06797768550._8
1492+ let baseAssetReserveAfter = $t06797768550._9
1493+ let totalPositionSizeAfter = $t06797768550._10
1494+ let openInterestNotionalAfter = $t06797768550._11
1495+ let totalLongAfter = $t06797768550._12
1496+ let totalShortAfter = $t06797768550._13
1497+ let totalLongOpenInterestAfter = $t06797768550._14
1498+ let totalShortOpenInterestAfter = $t06797768550._15
1499+ let realizedFee = $t06797768550._16
16081500 if ((positionBadDebt > 0))
1609- then throw("Unable to close position with bad debt")
1501+ then throw("Invalid closePosition parameters: bad debt")
16101502 else {
16111503 let isPartialClose = (newPositionSize != 0)
16121504 let withdrawAmount = (marginToTrader + realizedFee)
16131505 let ammBalance = (cbalance() - withdrawAmount)
1614- let $t06818368390 = if ((0 > ammBalance))
1615- then $Tuple2(0, abs(ammBalance))
1616- else $Tuple2(ammBalance, 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))
1623- then if ((withdrawAmount >= borrowed))
1624- then {
1625- let doRepay = invoke(collateralAddress(), "repay", [_trader, borrowed, assetId], nil)
1626- if ((doRepay == doRepay))
1627- then $Tuple3(borrowed, (withdrawAmount - borrowed), isPartialClose)
1628- else throw("Strict value is not equal to itself.")
1629- }
1630- else {
1631- let realizeAndClose = invoke(collateralAddress(), if (isPartialClose)
1632- then "repay"
1633- else "realizePartiallyAndClose", [_trader, withdrawAmount, assetId], nil)
1634- if ((realizeAndClose == realizeAndClose))
1635- then $Tuple3(withdrawAmount, 0, false)
1636- else throw("Strict value is not equal to itself.")
1637- }
1638- else $Tuple3(0, withdrawAmount, false)
1639- if (($t06845969319 == $t06845969319))
1506+ let ammNewBalance = if ((0 > ammBalance))
1507+ then 0
1508+ else ammBalance
1509+ let unstake = invoke(vaultAddress(), "withdrawLocked", [withdrawAmount], nil)
1510+ if ((unstake == unstake))
16401511 then {
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))
1512+ let $t06906069119 = distributeFee(realizedFee)
1513+ let feeToStakers = $t06906069119._1
1514+ let feeToVault = $t06906069119._2
1515+ let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1516+ if ((depositVault == depositVault))
1517+ then {
1518+ let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, realizedFee], nil)
1519+ if ((notifyFee == notifyFee))
16511520 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- }
1667- else throw("Strict value is not equal to itself.")
1668- }
1669- if (($t06932770394 == $t06932770394))
1670- then {
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- }
1521+ let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
1522+ if ((notifyNotional == notifyNotional))
1523+ then (((((if (isPartialClose)
1524+ then updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, lastTimestamp())
1525+ else deletePosition(_trader)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ (if ((marginToTrader > 0))
1526+ then withdraw(_traderAddress, marginToTrader)
1527+ else nil)) ++ updateBalance(ammNewBalance)) ++ transferFee(feeToStakers))
17111528 else throw("Strict value is not equal to itself.")
17121529 }
17131530 else throw("Strict value is not equal to itself.")
17141531 }
17151532 else throw("Strict value is not equal to itself.")
17161533 }
17171534 else throw("Strict value is not equal to itself.")
17181535 }
17191536 }
17201537 }
17211538 else throw("Strict value is not equal to itself.")
17221539 }
17231540
17241541
17251542
17261543 @Callable(i)
17271544 func liquidate (_trader) = {
17281545 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
17291546 if ((sync == sync))
17301547 then {
17311548 let spotMarginRatio = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
1732- let marginRatio = if (isOverFluctuationLimit())
1549+ let liquidationMarginRatio = if (isOverFluctuationLimit())
17331550 then {
17341551 let oracleMarginRatio = getMarginRatioByOption(_trader, PNL_OPTION_ORACLE)
17351552 vmax(spotMarginRatio, oracleMarginRatio)
17361553 }
17371554 else spotMarginRatio
1738- if (if (if (if (if (!(requireMoreMarginRatio(marginRatio, maintenanceMarginRatio(), false)))
1555+ if (if (if (if (if (!(requireMoreMarginRatio(liquidationMarginRatio, maintenanceMarginRatio(), false)))
17391556 then true
17401557 else !(requireOpenPosition(_trader)))
17411558 then true
17421559 else !(initialized()))
17431560 then true
17441561 else paused())
17451562 then true
17461563 else isMarketClosed())
17471564 then throw("Unable to liquidate")
1748- else if (if (if ((spotMarginRatio > liquidationFeeRatio()))
1749- then (partialLiquidationRatio() > 0)
1750- else false)
1751- then (DECIMAL_UNIT > partialLiquidationRatio())
1752- else false)
1753- then {
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
1759- let _direction = if ((oldPositionSize > 0))
1760- then DIR_SHORT
1761- else DIR_LONG
1762- let isAdd = (_direction == DIR_LONG)
1763- let exchangedQuoteAssetAmount = getPartialLiquidationAmount(_trader, oldPositionSize)
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
1772- let liquidationRatio = divd(abs(exchangedPositionSize), abs(oldPositionSize))
1773- let realizedPnl = muld(unrealizedPnl, liquidationRatio)
1774- let $t07445374686 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl)
1775- let remainMargin = $t07445374686._1
1776- let badDebt = $t07445374686._2
1777- let fundingPayment = $t07445374686._3
1778- let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
1779- let remainOpenNotional = if ((oldPositionSize > 0))
1780- then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
1781- else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
1782- let liquidationPenalty = muld(exchangedQuoteAssetAmount, liquidationFeeRatio())
1783- let feeToLiquidator = (liquidationPenalty / 2)
1784- let feeToVault = (liquidationPenalty - feeToLiquidator)
1785- let newPositionMargin = (remainMargin - liquidationPenalty)
1786- let newPositionSize = (oldPositionSize + exchangedPositionSize)
1787- let newPositionOpenNotional = abs(remainOpenNotional)
1788- let openNotionalDelta = (oldPositionOpenNotional - newPositionOpenNotional)
1789- let newPositionLstUpdCPF = latestCumulativePremiumFraction(newPositionSize)
1790- let openInterestNotionalAfter = (openInterestNotional() - openNotionalDelta)
1791- let ammBalance = (cbalance() - liquidationPenalty)
1792- let $t07592776056 = if ((0 > ammBalance))
1793- then $Tuple2(0, abs(ammBalance))
1794- else $Tuple2(ammBalance, 0)
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
1800- let doLiquidateCollateral = if ((borrowed > 0))
1801- then {
1802- let collateralToSell = muld(borrowed, liquidationRatio)
1803- let realizeAndClose = invoke(collateralAddress(), "realizePartially", [_trader, assetId, collateralToSell], nil)
1804- if ((realizeAndClose == realizeAndClose))
1805- then nil
1806- else throw("Strict value is not equal to itself.")
1807- }
1808- else nil
1809- if ((doLiquidateCollateral == doLiquidateCollateral))
1810- then {
1811- let unstake = invoke(vaultAddress(), "withdrawLocked", [liquidationPenalty], nil)
1812- if ((unstake == unstake))
1813- then {
1814- let depositInsurance = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1815- if ((depositInsurance == depositInsurance))
1816- then {
1817- let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
1818- if ((notifyNotional == notifyNotional))
1819- then (((updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, (totalLongPositionSize() - (if ((newPositionSize > 0))
1820- then abs(exchangedPositionSize)
1821- else 0)), (totalShortPositionSize() - (if ((0 > newPositionSize))
1822- then abs(exchangedPositionSize)
1823- else 0)), (openInterestLong() - (if ((newPositionSize > 0))
1824- then openNotionalDelta
1825- else 0)), (openInterestShort() - (if ((0 > newPositionSize))
1826- then openNotionalDelta
1827- else 0)))) ++ withdraw(i.caller, feeToLiquidator)) ++ updateBalance(newAmmBalance))
1828- else throw("Strict value is not equal to itself.")
1829- }
1830- else throw("Strict value is not equal to itself.")
1831- }
1832- else throw("Strict value is not equal to itself.")
1833- }
1834- else throw("Strict value is not equal to itself.")
1835- }
1836- else {
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
1851- let liquidationPenalty = muld(exchangedQuoteAssetAmount, liquidationFeeRatio())
1852- let feeToLiquidator = (liquidationPenalty / 2)
1853- let feeToVault = (liquidationPenalty - feeToLiquidator)
1854- let ammBalance = (cbalance() - liquidationPenalty)
1855- let $t07870078829 = if ((0 > ammBalance))
1856- then $Tuple2(0, abs(ammBalance))
1857- else $Tuple2(ammBalance, 0)
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
1863- let doLiquidateCollateral = if ((borrowed > 0))
1864- then {
1865- let realizeAndClose = invoke(collateralAddress(), "realizePartiallyAndClose", [_trader, 0, assetId], nil)
1866- if ((realizeAndClose == realizeAndClose))
1867- then nil
1868- else throw("Strict value is not equal to itself.")
1869- }
1870- else nil
1871- if ((doLiquidateCollateral == doLiquidateCollateral))
1872- then {
1873- let x = if ((badDebt > 0))
1874- then {
1875- let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [badDebt], nil)
1876- if ((lockBadDebt == lockBadDebt))
1877- then nil
1878- else throw("Strict value is not equal to itself.")
1879- }
1880- else nil
1881- if ((x == x))
1882- then {
1883- let unstake = invoke(vaultAddress(), "withdrawLocked", [liquidationPenalty], nil)
1884- if ((unstake == unstake))
1885- then {
1886- let depositInsurance = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1887- if ((depositInsurance == depositInsurance))
1888- then {
1889- let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, 0], nil)
1890- if ((notifyNotional == notifyNotional))
1891- then (((deletePosition(_trader) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ withdraw(i.caller, feeToLiquidator)) ++ updateBalance(newAmmBalance))
1892- else throw("Strict value is not equal to itself.")
1893- }
1894- else throw("Strict value is not equal to itself.")
1895- }
1896- else throw("Strict value is not equal to itself.")
1897- }
1898- else throw("Strict value is not equal to itself.")
1899- }
1900- else throw("Strict value is not equal to itself.")
1901- }
1565+ else {
1566+ let isPartialLiquidation = if (if ((spotMarginRatio > liquidationFeeRatio()))
1567+ then true
1568+ else (partialLiquidationRatio() > 0))
1569+ then true
1570+ else (DECIMAL_UNIT > partialLiquidationRatio())
1571+ let oldPositionSize = getPosition(_trader)._1
1572+ let positionSizeAbs = abs(oldPositionSize)
1573+ let $t07143271755 = if (isPartialLiquidation)
1574+ then {
1575+ let liquidationSize = getPartialLiquidationAmount(_trader, oldPositionSize)
1576+ let liquidationRatio = divd(abs(liquidationSize), positionSizeAbs)
1577+ $Tuple2(liquidationRatio, abs(liquidationSize))
1578+ }
1579+ else $Tuple2(0, positionSizeAbs)
1580+ let liquidationRatio = $t07143271755._1
1581+ let liquidationSize = $t07143271755._2
1582+ let $t07176172387 = internalClosePosition(_trader, if (isPartialLiquidation)
1583+ then liquidationSize
1584+ else positionSizeAbs, liquidationFeeRatio(), 0, true, false)
1585+ let newPositionSize = $t07176172387._1
1586+ let newPositionMargin = $t07176172387._2
1587+ let newPositionOpenNotional = $t07176172387._3
1588+ let newPositionLstUpdCPF = $t07176172387._4
1589+ let positionBadDebt = $t07176172387._5
1590+ let realizedPnl = $t07176172387._6
1591+ let marginToTrader = $t07176172387._7
1592+ let quoteAssetReserveAfter = $t07176172387._8
1593+ let baseAssetReserveAfter = $t07176172387._9
1594+ let totalPositionSizeAfter = $t07176172387._10
1595+ let openInterestNotionalAfter = $t07176172387._11
1596+ let totalLongAfter = $t07176172387._12
1597+ let totalShortAfter = $t07176172387._13
1598+ let totalLongOpenInterestAfter = $t07176172387._14
1599+ let totalShortOpenInterestAfter = $t07176172387._15
1600+ let liquidationPenalty = $t07176172387._16
1601+ let feeToLiquidator = (liquidationPenalty / 2)
1602+ let feeToVault = (liquidationPenalty - feeToLiquidator)
1603+ let ammBalance = (cbalance() - liquidationPenalty)
1604+ let newAmmBalance = if ((0 > ammBalance))
1605+ then 0
1606+ else ammBalance
1607+ let lockBadDebt = if ((positionBadDebt > 0))
1608+ then {
1609+ let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [positionBadDebt], nil)
1610+ if ((lockBadDebt == lockBadDebt))
1611+ then nil
1612+ else throw("Strict value is not equal to itself.")
1613+ }
1614+ else nil
1615+ if ((lockBadDebt == lockBadDebt))
1616+ then {
1617+ let unstake = invoke(vaultAddress(), "withdrawLocked", [liquidationPenalty], nil)
1618+ if ((unstake == unstake))
1619+ then {
1620+ let depositInsurance = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1621+ if ((depositInsurance == depositInsurance))
1622+ then {
1623+ let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
1624+ if ((notifyNotional == notifyNotional))
1625+ then ((((if (isPartialLiquidation)
1626+ then updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, lastTimestamp())
1627+ else deletePosition(_trader)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ withdraw(i.caller, feeToLiquidator)) ++ updateBalance(newAmmBalance))
1628+ else throw("Strict value is not equal to itself.")
1629+ }
1630+ else throw("Strict value is not equal to itself.")
1631+ }
1632+ else throw("Strict value is not equal to itself.")
1633+ }
1634+ else throw("Strict value is not equal to itself.")
1635+ }
19021636 }
19031637 else throw("Strict value is not equal to itself.")
19041638 }
19051639
19061640
19071641
19081642 @Callable(i)
19091643 func payFunding () = {
19101644 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
19111645 if ((sync == sync))
19121646 then {
19131647 let fundingBlockTimestamp = nextFundingBlockTimestamp()
1914- if (if (if ((fundingBlockTimestamp > lastBlock.timestamp))
1648+ if (if (if ((fundingBlockTimestamp > lastTimestamp()))
19151649 then true
19161650 else !(initialized()))
19171651 then true
19181652 else paused())
1919- then throw(((("Invalid funding block timestamp: " + toString(lastBlock.timestamp)) + " < ") + toString(fundingBlockTimestamp)))
1653+ then throw(((("Invalid funding block timestamp: " + toString(lastTimestamp())) + " < ") + toString(fundingBlockTimestamp)))
19201654 else {
19211655 let underlyingPrice = getOraclePrice()
1922- let $t08076380825 = getFunding()
1923- let shortPremiumFraction = $t08076380825._1
1924- let longPremiumFraction = $t08076380825._2
1656+ let $t07435374415 = getFunding()
1657+ let shortPremiumFraction = $t07435374415._1
1658+ let longPremiumFraction = $t07435374415._2
19251659 updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice))
19261660 }
19271661 }
19281662 else throw("Strict value is not equal to itself.")
19291663 }
19301664
19311665
19321666
19331667 @Callable(i)
19341668 func syncTerminalPriceToOracle () = {
19351669 let _qtAstR = qtAstR()
19361670 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
1671+ let $t07484774982 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1672+ let newQuoteAssetWeight = $t07484774982._1
1673+ let newBaseAssetWeight = $t07484774982._2
1674+ let marginToVault = $t07484774982._3
19411675 let doExchangePnL = if ((marginToVault != 0))
19421676 then {
19431677 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
19441678 if ((doExchangePnL == doExchangePnL))
19451679 then nil
19461680 else throw("Strict value is not equal to itself.")
19471681 }
19481682 else nil
19491683 if ((doExchangePnL == doExchangePnL))
19501684 then (updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight) ++ appendTwap(divd(muld(_qtAstR, newQuoteAssetWeight), muld(_bsAstR, newBaseAssetWeight))))
19511685 else throw("Strict value is not equal to itself.")
19521686 }
19531687
19541688
19551689
19561690 @Callable(i)
19571691 func view_calcRemainMarginWithFundingPayment (_trader) = {
19581692 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
19591693 if ((sync == sync))
19601694 then {
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
1973- throw((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)))
1695+ let $t07555175675 = getPosition(_trader)
1696+ let positionSize = $t07555175675._1
1697+ let positionMargin = $t07555175675._2
1698+ let pon = $t07555175675._3
1699+ let positionLstUpdCPF = $t07555175675._4
1700+ let positionTimestamp = $t07555175675._5
1701+ let $t07567875779 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1702+ let positionNotional = $t07567875779._1
1703+ let unrealizedPnl = $t07567875779._2
1704+ let $t07578276006 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
1705+ let remainMargin = $t07578276006._1
1706+ let badDebt = $t07578276006._2
1707+ let fundingPayment = $t07578276006._3
1708+ let rolloverFee = $t07578276006._4
1709+ throw(((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)) + s(rolloverFee)))
19741710 }
19751711 else throw("Strict value is not equal to itself.")
19761712 }
19771713
19781714
19791715
19801716 @Callable(i)
19811717 func view_getPegAdjustCost (_price) = {
19821718 let _qtAstR = qtAstR()
19831719 let _bsAstR = bsAstR()
19841720 let result = getSyncTerminalPrice(_price, _qtAstR, _bsAstR)
19851721 throw(toString(result._3))
19861722 }
19871723
19881724
19891725
19901726 @Callable(i)
19911727 func view_getTerminalAmmPrice () = {
1992- let $t08275782838 = getTerminalAmmState()
1993- let terminalQuoteAssetReserve = $t08275782838._1
1994- let terminalBaseAssetReserve = $t08275782838._2
1728+ let $t07644276523 = getTerminalAmmState()
1729+ let terminalQuoteAssetReserve = $t07644276523._1
1730+ let terminalBaseAssetReserve = $t07644276523._2
19951731 let price = divd(muld(terminalQuoteAssetReserve, qtAstW()), muld(terminalBaseAssetReserve, bsAstW()))
19961732 throw(toString(price))
19971733 }
19981734
19991735
20001736
20011737 @Callable(i)
20021738 func view_getFunding () = {
20031739 let underlyingPrice = getOraclePrice()
2004- let $t08305383115 = getFunding()
2005- let shortPremiumFraction = $t08305383115._1
2006- let longPremiumFraction = $t08305383115._2
1740+ let $t07673876800 = getFunding()
1741+ let shortPremiumFraction = $t07673876800._1
1742+ let longPremiumFraction = $t07673876800._2
20071743 let longFunding = divd(longPremiumFraction, underlyingPrice)
20081744 let shortFunding = divd(shortPremiumFraction, underlyingPrice)
20091745 throw((((s(longFunding) + s(shortFunding)) + s(getTwapSpotPrice())) + s(getOraclePrice())))
2010- }
2011-
2012-
2013-
2014-@Callable(i)
2015-func view_getBorrowedByTrader (_trader) = {
2016- let $t08340183455 = getBorrowedByTrader(_trader)
2017- let borrowed = $t08340183455._1
2018- let assetId = $t08340183455._2
2019- throw((s(borrowed) + assetId))
20201746 }
20211747
20221748
20231749
20241750 @Callable(i)
20251751 func computeSpotPrice () = {
20261752 let result = getSpotPrice()
20271753 $Tuple2(nil, result)
20281754 }
20291755
20301756
20311757
20321758 @Callable(i)
20331759 func computeFeeForTraderWithArtifact (_trader,_artifactId) = {
20341760 let result = getForTraderWithArtifact(_trader, _artifactId)
20351761 $Tuple2(nil, result)
20361762 }
20371763
20381764
20391765 @Verifier(tx)
20401766 func verify () = sigVerify(tx.bodyBytes, tx.proofs[0], adminPublicKey())
20411767

github/deemru/w8io/c3f4982 
270.25 ms