tx · 7LMTmZ4KvMvcpnWZQMn3XsLHAxbUmr76FNtoyS4FGCmq

3PQNn3RcXkRCHHrBYxhVvbeQLa8R8KMjoFa:  -0.09000000 Waves

2023.03.17 12:41 [3559413] smart account 3PQNn3RcXkRCHHrBYxhVvbeQLa8R8KMjoFa > SELF 0.00000000 Waves

{ "type": 13, "id": "7LMTmZ4KvMvcpnWZQMn3XsLHAxbUmr76FNtoyS4FGCmq", "fee": 9000000, "feeAssetId": null, "timestamp": 1679046125436, "version": 2, "chainId": 87, "sender": "3PQNn3RcXkRCHHrBYxhVvbeQLa8R8KMjoFa", "senderPublicKey": "FMUD7Eo8pPt3UMp5vBW7GazCX7CeVEkf7xGZ3y5cJdaw", "proofs": [ "496yZ4dUCnZuuWXPT4r8erushax3dVSYzxGGTVuqLWEhMzXpHsrVgtwZp6T55KUyfbxBiFwYskAiYW2xQ2ZRztWe" ], "script": "base64:BgJ0CAISABIAEgASABIDCgEBEgMKAQESEAoOAQEBAQEBAQEBAQEBAQESFQoTAQEBAQEBAQgICAEBAQEBAQEBARIGCgQBAQEIEgASAwoBARIFCgMBAQQSAwoBCBIAEgASABIDCgEIEgMKAQESABIAEgASBAoCCAixAQAMa19iYXNlT3JhY2xlAgxrX2Jhc2VPcmFjbGUADWtfcXVvdGVPcmFjbGUCDWtfcXVvdGVPcmFjbGUACWtfYmFsYW5jZQIJa19iYWxhbmNlAAprX3NlcXVlbmNlAgprX3NlcXVlbmNlAA5rX3Bvc2l0aW9uU2l6ZQIOa19wb3NpdGlvblNpemUAEGtfcG9zaXRpb25NYXJnaW4CEGtfcG9zaXRpb25NYXJnaW4AFmtfcG9zaXRpb25PcGVuTm90aW9uYWwCFmtfcG9zaXRpb25PcGVuTm90aW9uYWwALmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24CEmtfcG9zaXRpb25GcmFjdGlvbgASa19wb3NpdGlvblNlcXVlbmNlAhJrX3Bvc2l0aW9uU2VxdWVuY2UADWtfcG9zaXRpb25GZWUCDWtfcG9zaXRpb25GZWUAHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAITa19wb3NpdGlvblRpbWVzdGFtcAANa19pbml0aWFsaXplZAINa19pbml0aWFsaXplZAAIa19wYXVzZWQCCGtfcGF1c2VkAAtrX2Nsb3NlT25seQILa19jbG9zZU9ubHkABWtfZmVlAgVrX2ZlZQANa19yb2xsb3ZlckZlZQIOa19yb2xsb3Zlcl9mZWUAD2tfZnVuZGluZ1BlcmlvZAIPa19mdW5kaW5nUGVyaW9kABFrX2luaXRNYXJnaW5SYXRpbwIRa19pbml0TWFyZ2luUmF0aW8AGGtfbWFpbnRlbmFuY2VNYXJnaW5SYXRpbwIFa19tbXIAFWtfbGlxdWlkYXRpb25GZWVSYXRpbwIVa19saXF1aWRhdGlvbkZlZVJhdGlvABlrX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAhZrX3BhcnRMaXF1aWRhdGlvblJhdGlvAA1rX3NwcmVhZExpbWl0Ag1rX3NwcmVhZExpbWl0ABBrX21heFByaWNlSW1wYWN0AhBrX21heFByaWNlSW1wYWN0ABBrX21heFByaWNlU3ByZWFkAhBrX21heFByaWNlU3ByZWFkABFrX21heE9wZW5Ob3Rpb25hbAIRa19tYXhPcGVuTm90aW9uYWwAFWtfZmVlVG9TdGFrZXJzUGVyY2VudAIVa19mZWVUb1N0YWtlcnNQZXJjZW50ABBrX21heE9yYWNsZURlbGF5AhBrX21heE9yYWNsZURlbGF5AA1rX2Z1bmRpbmdNb2RlAg1rX2Z1bmRpbmdNb2RlACVrX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAhtrX2xhdGVzdExvbmdQcmVtaXVtRnJhY3Rpb24AJmtfbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAhxrX2xhdGVzdFNob3J0UHJlbWl1bUZyYWN0aW9uABJrX25leHRGdW5kaW5nQmxvY2sCHmtfbmV4dEZ1bmRpbmdCbG9ja01pblRpbWVzdGFtcAARa19sb25nRnVuZGluZ1JhdGUCEWtfbG9uZ0Z1bmRpbmdSYXRlABJrX3Nob3J0RnVuZGluZ1JhdGUCEmtfc2hvcnRGdW5kaW5nUmF0ZQATa19xdW90ZUFzc2V0UmVzZXJ2ZQIIa19xdEFzdFIAEmtfYmFzZUFzc2V0UmVzZXJ2ZQIIa19ic0FzdFIAEmtfcXVvdGVBc3NldFdlaWdodAIIa19xdEFzdFcAEWtfYmFzZUFzc2V0V2VpZ2h0AghrX2JzQXN0VwATa190b3RhbFBvc2l0aW9uU2l6ZQITa190b3RhbFBvc2l0aW9uU2l6ZQAXa190b3RhbExvbmdQb3NpdGlvblNpemUCF2tfdG90YWxMb25nUG9zaXRpb25TaXplABhrX3RvdGFsU2hvcnRQb3NpdGlvblNpemUCGGtfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAWa19vcGVuSW50ZXJlc3ROb3Rpb25hbAIWa19vcGVuSW50ZXJlc3ROb3Rpb25hbAATa19vcGVuSW50ZXJlc3RTaG9ydAITa19vcGVuSW50ZXJlc3RTaG9ydAASa19vcGVuSW50ZXJlc3RMb25nAhJrX29wZW5JbnRlcmVzdExvbmcACGtfbGFzdFR4AghrX2xhc3RUeAAUa19jb29yZGluYXRvckFkZHJlc3MCFGtfY29vcmRpbmF0b3JBZGRyZXNzAA9rX3ZhdWx0X2FkZHJlc3MCD2tfdmF1bHRfYWRkcmVzcwAPa19hZG1pbl9hZGRyZXNzAg9rX2FkbWluX2FkZHJlc3MADWtfcXVvdGVfYXNzZXQCDWtfcXVvdGVfYXNzZXQAD2tfcXVvdGVfc3Rha2luZwIPa19xdW90ZV9zdGFraW5nABFrX3N0YWtpbmdfYWRkcmVzcwIRa19zdGFraW5nX2FkZHJlc3MAD2tfbWluZXJfYWRkcmVzcwIPa19taW5lcl9hZGRyZXNzABBrX29yZGVyc19hZGRyZXNzAhBrX29yZGVyc19hZGRyZXNzABJrX3JlZmVycmFsX2FkZHJlc3MCEmtfcmVmZXJyYWxfYWRkcmVzcwASa19leGNoYW5nZV9hZGRyZXNzAhJrX2V4Y2hhbmdlX2FkZHJlc3MAFWtfbmZ0X21hbmFnZXJfYWRkcmVzcwIVa19uZnRfbWFuYWdlcl9hZGRyZXNzAQ50b0NvbXBvc2l0ZUtleQIEX2tleQhfYWRkcmVzcwkArAICCQCsAgIFBF9rZXkCAV8FCF9hZGRyZXNzAQtjb29yZGluYXRvcgAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCBQR0aGlzBRRrX2Nvb3JkaW5hdG9yQWRkcmVzcwITQ29vcmRpbmF0b3Igbm90IHNldAEMYWRtaW5BZGRyZXNzAAkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABQ9rX2FkbWluX2FkZHJlc3MBCnF1b3RlQXNzZXQACQDZBAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFDWtfcXVvdGVfYXNzZXQBEXF1b3RlQXNzZXRTdGFraW5nAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFD2tfcXVvdGVfc3Rha2luZwIbUXVvdGUgYXNzZXQgc3Rha2luZyBub3Qgc2V0AQ5zdGFraW5nQWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABRFrX3N0YWtpbmdfYWRkcmVzcwIPU3Rha2luZyBub3Qgc2V0AQx2YXVsdEFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUPa192YXVsdF9hZGRyZXNzAg1WYXVsdCBub3Qgc2V0AQxtaW5lckFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUPa19taW5lcl9hZGRyZXNzAg1NaW5lciBub3Qgc2V0AQ1vcmRlcnNBZGRyZXNzAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFEGtfb3JkZXJzX2FkZHJlc3MCDk9yZGVycyBub3Qgc2V0AQ9yZWZlcnJhbEFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUSa19yZWZlcnJhbF9hZGRyZXNzAhBSZWZlcnJhbCBub3Qgc2V0ARFuZnRNYW5hZ2VyQWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABRVrX25mdF9tYW5hZ2VyX2FkZHJlc3MCE05GVCBNYW5hZ2VyIG5vdCBzZXQADWtfdG9rZW5fcGFyYW0CDWtfdG9rZW5fcGFyYW0ADGtfdG9rZW5fdHlwZQIMa190b2tlbl90eXBlABhGRUVfUkVEVUNUSU9OX1RPS0VOX1RZUEUCDWZlZV9yZWR1Y3Rpb24ACERJUl9MT05HAAEACURJUl9TSE9SVAACAAdTRUNPTkRTAOgHAA9ERUNJTUFMX05VTUJFUlMABgAMREVDSU1BTF9VTklUCQBoAgABCQBoAgkAaAIJAGgCCQBoAgkAaAIACgAKAAoACgAKAAoAD01JTlVURVNfSU5fWUVBUgkAaAIAoIogBQxERUNJTUFMX1VOSVQAB09ORV9EQVkJAGgCAICjBQUMREVDSU1BTF9VTklUAA9QTkxfT1BUSU9OX1NQT1QAAQARUE5MX09QVElPTl9PUkFDTEUAAgASRlVORElOR19BU1lNTUVUUklDAAEAEUZVTkRJTkdfU1lNTUVUUklDAAIBAXMBAl94CQCsAgIJAKQDAQUCX3gCASwBBGRpdmQCAl94Al95CQBuBAUCX3gFDERFQ0lNQUxfVU5JVAUCX3kFCEhBTEZFVkVOAQRtdWxkAgJfeAJfeQkAbgQFAl94BQJfeQUMREVDSU1BTF9VTklUBQhIQUxGRVZFTgEFYmRpdmQCAl94Al95CQC9AgQFAl94CQC2AgEFDERFQ0lNQUxfVU5JVAUCX3kFCEhBTEZFVkVOAQVibXVsZAICX3gCX3kJAL0CBAUCX3gFAl95CQC2AgEFDERFQ0lNQUxfVU5JVAUISEFMRkVWRU4BA2FicwECX3gDCQBmAgUCX3gAAAUCX3gJAQEtAQUCX3gBBHZtYXgCAl94Al95AwkAZwIFAl94BQJfeQUCX3gFAl95AQNpbnQBAWsJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBQR0aGlzBQFrCQCsAgICDW5vIHZhbHVlIGZvciAFAWsBBWludE9yAgFrA2RlZgkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQFrBQNkZWYBBHN0ckECCF9hZGRyZXNzBF9rZXkEA3ZhbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFCF9hZGRyZXNzBQRfa2V5CQCsAgICEU5vIHZhbHVlIGZvciBrZXkgBQRfa2V5BQN2YWwBBGludEECCF9hZGRyZXNzBF9rZXkEA3ZhbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFCF9hZGRyZXNzBQRfa2V5CQCsAgICEU5vIHZhbHVlIGZvciBrZXkgBQRfa2V5BQN2YWwBCGNiYWxhbmNlAAkBA2ludAEFCWtfYmFsYW5jZQEDZmVlAAkBA2ludAEFBWtfZmVlAQ9yb2xsb3ZlckZlZVJhdGUACQEDaW50AQUNa19yb2xsb3ZlckZlZQEPaW5pdE1hcmdpblJhdGlvAAkBA2ludAEFEWtfaW5pdE1hcmdpblJhdGlvAQZxdEFzdFIACQEDaW50AQUTa19xdW90ZUFzc2V0UmVzZXJ2ZQEGYnNBc3RSAAkBA2ludAEFEmtfYmFzZUFzc2V0UmVzZXJ2ZQEGcXRBc3RXAAkBBWludE9yAgUSa19xdW90ZUFzc2V0V2VpZ2h0BQxERUNJTUFMX1VOSVQBBmJzQXN0VwAJAQVpbnRPcgIFEWtfYmFzZUFzc2V0V2VpZ2h0BQxERUNJTUFMX1VOSVQBEXRvdGFsUG9zaXRpb25TaXplAAkBA2ludAEFE2tfdG90YWxQb3NpdGlvblNpemUBFG9wZW5JbnRlcmVzdE5vdGlvbmFsAAkBA2ludAEFFmtfb3BlbkludGVyZXN0Tm90aW9uYWwBEW9wZW5JbnRlcmVzdFNob3J0AAkBA2ludAEFE2tfb3BlbkludGVyZXN0U2hvcnQBEG9wZW5JbnRlcmVzdExvbmcACQEDaW50AQUSa19vcGVuSW50ZXJlc3RMb25nARluZXh0RnVuZGluZ0Jsb2NrVGltZXN0YW1wAAkBA2ludAEFEmtfbmV4dEZ1bmRpbmdCbG9jawEQZnVuZGluZ1BlcmlvZFJhdwAJAQNpbnQBBQ9rX2Z1bmRpbmdQZXJpb2QBFGZ1bmRpbmdQZXJpb2REZWNpbWFsAAkAaAIJARBmdW5kaW5nUGVyaW9kUmF3AAUMREVDSU1BTF9VTklUARRmdW5kaW5nUGVyaW9kU2Vjb25kcwAJAGgCCQEQZnVuZGluZ1BlcmlvZFJhdwAFB1NFQ09ORFMBFm1haW50ZW5hbmNlTWFyZ2luUmF0aW8ACQEDaW50AQUYa19tYWludGVuYW5jZU1hcmdpblJhdGlvARNsaXF1aWRhdGlvbkZlZVJhdGlvAAkBA2ludAEFFWtfbGlxdWlkYXRpb25GZWVSYXRpbwEXcGFydGlhbExpcXVpZGF0aW9uUmF0aW8ACQEDaW50AQUZa19wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwELc3ByZWFkTGltaXQACQEDaW50AQUNa19zcHJlYWRMaW1pdAEObWF4UHJpY2VJbXBhY3QACQEDaW50AQUQa19tYXhQcmljZUltcGFjdAEObWF4UHJpY2VTcHJlYWQACQEDaW50AQUQa19tYXhQcmljZVNwcmVhZAEPbWF4T3Blbk5vdGlvbmFsAAkBA2ludAEFEWtfbWF4T3Blbk5vdGlvbmFsASNsYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgAJAQNpbnQBBSVrX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uASRsYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24ACQEDaW50AQUma19sYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24BFnRvdGFsU2hvcnRQb3NpdGlvblNpemUACQEDaW50AQUYa190b3RhbFNob3J0UG9zaXRpb25TaXplARV0b3RhbExvbmdQb3NpdGlvblNpemUACQEDaW50AQUXa190b3RhbExvbmdQb3NpdGlvblNpemUBDGxhc3RTZXF1ZW5jZQAJAQVpbnRPcgIFCmtfc2VxdWVuY2UAAAETZmVlVG9TdGFrZXJzUGVyY2VudAAJAQNpbnQBBRVrX2ZlZVRvU3Rha2Vyc1BlcmNlbnQBDm1heE9yYWNsZURlbGF5AAkBA2ludAEFEGtfbWF4T3JhY2xlRGVsYXkBC2Z1bmRpbmdNb2RlAAkBBWludE9yAgUNa19mdW5kaW5nTW9kZQUSRlVORElOR19BU1lNTUVUUklDAQ1sYXN0VGltZXN0YW1wAAgFCWxhc3RCbG9jawl0aW1lc3RhbXABD2dldEFjdHVhbENhbGxlcgEBaQkBC3ZhbHVlT3JFbHNlAgkAnQgCCQENb3JkZXJzQWRkcmVzcwACCGtfc2VuZGVyCQClCAEIBQFpBmNhbGxlcgEWcmVxdWlyZU1vcmVNYXJnaW5SYXRpbwMMX21hcmdpblJhdGlvEF9iYXNlTWFyZ2luUmF0aW8UX2xhcmdlclRoYW5PckVxdWFsVG8EFHJlbWFpbmluZ01hcmdpblJhdGlvCQBlAgUMX21hcmdpblJhdGlvBRBfYmFzZU1hcmdpblJhdGlvAwMFFF9sYXJnZXJUaGFuT3JFcXVhbFRvCQBmAgAABRRyZW1haW5pbmdNYXJnaW5SYXRpbwcJAAIBCQCsAgIJAKwCAgkArAICAhBJbnZhbGlkIG1hcmdpbjogCQCkAwEFDF9tYXJnaW5SYXRpbwIDIDwgCQCkAwEFEF9iYXNlTWFyZ2luUmF0aW8DAwkBASEBBRRfbGFyZ2VyVGhhbk9yRXF1YWxUbwkAZwIFFHJlbWFpbmluZ01hcmdpblJhdGlvAAAHCQACAQkArAICCQCsAgIJAKwCAgIQSW52YWxpZCBtYXJnaW46IAkApAMBBQxfbWFyZ2luUmF0aW8CAyA+IAkApAMBBRBfYmFzZU1hcmdpblJhdGlvBgEfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgENX3Bvc2l0aW9uU2l6ZQMJAAACBQ1fcG9zaXRpb25TaXplAAAJAAIBAixTaG91bGQgbm90IGJlIGNhbGxlZCB3aXRoIF9wb3NpdGlvblNpemUgPT0gMAMJAGYCBQ1fcG9zaXRpb25TaXplAAAJASNsYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgAJASRsYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24AAQtnZXRQb3NpdGlvbgEHX3RyYWRlcgQPcG9zaXRpb25TaXplT3B0CQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFDmtfcG9zaXRpb25TaXplBQdfdHJhZGVyBAckbWF0Y2gwBQ9wb3NpdGlvblNpemVPcHQDCQABAgUHJG1hdGNoMAIDSW50BAxwb3NpdGlvblNpemUFByRtYXRjaDAJAJcKBQUMcG9zaXRpb25TaXplCQERQGV4dHJOYXRpdmUoMTA1MCkCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBRBrX3Bvc2l0aW9uTWFyZ2luBQdfdHJhZGVyCQERQGV4dHJOYXRpdmUoMTA1MCkCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBRZrX3Bvc2l0aW9uT3Blbk5vdGlvbmFsBQdfdHJhZGVyCQERQGV4dHJOYXRpdmUoMTA1MCkCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQdfdHJhZGVyCQERQGV4dHJOYXRpdmUoMTA1MCkCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBR5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAFB190cmFkZXIJAJcKBQAAAAAAAAAAAAABDmdldFBvc2l0aW9uRmVlAQdfdHJhZGVyBA5wb3NpdGlvbkZlZU9wdAkAmggCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBQ1rX3Bvc2l0aW9uRmVlBQdfdHJhZGVyBAckbWF0Y2gwBQ5wb3NpdGlvbkZlZU9wdAMJAAECBQckbWF0Y2gwAgNJbnQEC3Bvc2l0aW9uRmVlBQckbWF0Y2gwBQtwb3NpdGlvbkZlZQkBA2ZlZQABE3JlcXVpcmVPcGVuUG9zaXRpb24BB190cmFkZXIDCQAAAggJAQtnZXRQb3NpdGlvbgEFB190cmFkZXICXzEAAAkAAgECEE5vIG9wZW4gcG9zaXRpb24GAQ1nZXRPcmFjbGVEYXRhAQNrZXkEDW9yYWNsZURhdGFTdHIJAJ0IAgUEdGhpcwUDa2V5AwMJAQlpc0RlZmluZWQBBQ1vcmFjbGVEYXRhU3RyCQECIT0CCQEFdmFsdWUBBQ1vcmFjbGVEYXRhU3RyAgAHBApvcmFjbGVEYXRhCQC1CQIJAQV2YWx1ZQEFDW9yYWNsZURhdGFTdHICASwEDW9yYWNsZUFkZHJlc3MJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQCRAwIFCm9yYWNsZURhdGEAAAkArAICAhtJbnZhbGlkIG9yYWNsZSBhZGRyZXNzIGluOiAJAQV2YWx1ZQEFDW9yYWNsZURhdGFTdHIECHByaWNlS2V5CQCRAwIFCm9yYWNsZURhdGEAAQQIYmxvY2tLZXkJAJEDAgUKb3JhY2xlRGF0YQACBAdvcGVuS2V5CQCRAwIFCm9yYWNsZURhdGEAAwkAlgoEBQ1vcmFjbGVBZGRyZXNzBQhwcmljZUtleQUIYmxvY2tLZXkFB29wZW5LZXkFBHVuaXQBC2luaXRpYWxpemVkAAkBC3ZhbHVlT3JFbHNlAgkAmwgCBQR0aGlzBQ1rX2luaXRpYWxpemVkBwEGcGF1c2VkAAkBC3ZhbHVlT3JFbHNlAgkAmwgCBQR0aGlzBQhrX3BhdXNlZAcBCWNsb3NlT25seQAJAQt2YWx1ZU9yRWxzZQIJAJsIAgUEdGhpcwULa19jbG9zZU9ubHkHAQ11cGRhdGVSZXNlcnZlAwZfaXNBZGQRX3F1b3RlQXNzZXRBbW91bnQQX2Jhc2VBc3NldEFtb3VudAMFBl9pc0FkZAQHbmV3QmFzZQkAZQIJAQZic0FzdFIABRBfYmFzZUFzc2V0QW1vdW50AwkAZwIAAAUHbmV3QmFzZQkAAgECKlR4IGxlYWQgdG8gYmFzZSBhc3NldCByZXNlcnZlIDw9IDAsIHJldmVydAkAlQoDCQBkAgkBBnF0QXN0UgAFEV9xdW90ZUFzc2V0QW1vdW50BQduZXdCYXNlCQBkAgkBEXRvdGFsUG9zaXRpb25TaXplAAUQX2Jhc2VBc3NldEFtb3VudAQIbmV3UXVvdGUJAGUCCQEGcXRBc3RSAAURX3F1b3RlQXNzZXRBbW91bnQDCQBnAgAABQhuZXdRdW90ZQkAAgECKlR4IGxlYWQgdG8gYmFzZSBxdW90ZSByZXNlcnZlIDw9IDAsIHJldmVydAkAlQoDBQhuZXdRdW90ZQkAZAIJAQZic0FzdFIABRBfYmFzZUFzc2V0QW1vdW50CQBlAgkBEXRvdGFsUG9zaXRpb25TaXplAAUQX2Jhc2VBc3NldEFtb3VudAENY2FsY0ludmFyaWFudAIHX3F0QXN0UgdfYnNBc3RSBAdicXRBc3RSCQC2AgEFB19xdEFzdFIEB2Jic0FzdFIJALYCAQUHX2JzQXN0UgkBBWJtdWxkAgUHYnF0QXN0UgUHYmJzQXN0UgEJc3dhcElucHV0AgZfaXNBZGQRX3F1b3RlQXNzZXRBbW91bnQEB19xdEFzdFIJAQZxdEFzdFIABAdfYnNBc3RSCQEGYnNBc3RSAAQHX3F0QXN0VwkBBnF0QXN0VwAEB19ic0FzdFcJAQZic0FzdFcABBhxdW90ZUFzc2V0QW1vdW50QWRqdXN0ZWQJAQRkaXZkAgURX3F1b3RlQXNzZXRBbW91bnQFB19xdEFzdFcEAWsJAQ1jYWxjSW52YXJpYW50AgUHX3F0QXN0UgUHX2JzQXN0UgQWcXVvdGVBc3NldFJlc2VydmVBZnRlcgMFBl9pc0FkZAkAZAIFB19xdEFzdFIFGHF1b3RlQXNzZXRBbW91bnRBZGp1c3RlZAkAZQIFB19xdEFzdFIFGHF1b3RlQXNzZXRBbW91bnRBZGp1c3RlZAQVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCQCgAwEJAQViZGl2ZAIFAWsJALYCAQUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgQYYW1vdW50QmFzZUFzc2V0Qm91Z2h0QWJzCQEDYWJzAQkAZQIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgUHX2JzQXN0UgQVYW1vdW50QmFzZUFzc2V0Qm91Z2h0AwUGX2lzQWRkBRhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMJAQEtAQUYYW1vdW50QmFzZUFzc2V0Qm91Z2h0QWJzBA0kdDAxNTYwMTE1NzcxCQENdXBkYXRlUmVzZXJ2ZQMFBl9pc0FkZAUYcXVvdGVBc3NldEFtb3VudEFkanVzdGVkBRhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMEF3F1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIxCAUNJHQwMTU2MDExNTc3MQJfMQQWYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyMQgFDSR0MDE1NjAxMTU3NzECXzIEF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxCAUNJHQwMTU2MDExNTc3MQJfMwQLcHJpY2VCZWZvcmUJAQRkaXZkAgkBBG11bGQCBQdfcXRBc3RSBQdfcXRBc3RXCQEEbXVsZAIFB19ic0FzdFIFB19ic0FzdFcEC21hcmtldFByaWNlCQEEZGl2ZAIFEV9xdW90ZUFzc2V0QW1vdW50BRhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMECXByaWNlRGlmZgkBA2FicwEJAGUCBQtwcmljZUJlZm9yZQULbWFya2V0UHJpY2UEC3ByaWNlSW1wYWN0CQBlAgUMREVDSU1BTF9VTklUCQEEZGl2ZAIFC3ByaWNlQmVmb3JlCQBkAgULcHJpY2VCZWZvcmUFCXByaWNlRGlmZgQTbWF4UHJpY2VJbXBhY3RWYWx1ZQkBDm1heFByaWNlSW1wYWN0AAMJAGYCBQtwcmljZUltcGFjdAUTbWF4UHJpY2VJbXBhY3RWYWx1ZQkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgINUHJpY2UgaW1wYWN0IAkApAMBBQtwcmljZUltcGFjdAIUID4gbWF4IHByaWNlIGltcGFjdCAJAKQDAQUTbWF4UHJpY2VJbXBhY3RWYWx1ZQIVIGJlZm9yZSBxdW90ZSBhc3NldDogCQCkAwEFB19xdEFzdFICFCBiZWZvcmUgYmFzZSBhc3NldDogCQCkAwEFB19ic0FzdFICISBxdW90ZSBhc3NldCBhbW91bnQgdG8gZXhjaGFuZ2U6IAkApAMBBRFfcXVvdGVBc3NldEFtb3VudAIPIHByaWNlIGJlZm9yZTogCQCkAwEFC3ByaWNlQmVmb3JlAg4gbWFya2V0UHJpY2U6IAkApAMBBQttYXJrZXRQcmljZQkAlgoEBRVhbW91bnRCYXNlQXNzZXRCb3VnaHQFF3F1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIxBRZiYXNlQXNzZXRSZXNlcnZlQWZ0ZXIxBRd0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyMQEPY2FsY1JvbGxvdmVyRmVlAhJfb2xkUG9zaXRpb25NYXJnaW4gX29sZFBvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAED3Bvc2l0aW9uTWludXRlcwkAaAIJAGkCCQBpAgkAZQIJAQ1sYXN0VGltZXN0YW1wAAUgX29sZFBvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAA6AcAPAUMREVDSU1BTF9VTklUBAtyb2xsb3ZlckZlZQkBBGRpdmQCCQEEbXVsZAIJAQRtdWxkAgUSX29sZFBvc2l0aW9uTWFyZ2luBQ9wb3NpdGlvbk1pbnV0ZXMJAQ9yb2xsb3ZlckZlZVJhdGUABQ9NSU5VVEVTX0lOX1lFQVIFC3JvbGxvdmVyRmVlATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFEF9vbGRQb3NpdGlvblNpemUSX29sZFBvc2l0aW9uTWFyZ2luJV9vbGRQb3NpdGlvbkN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24gX29sZFBvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAMX21hcmdpbkRlbHRhBA5mdW5kaW5nUGF5bWVudAMJAQIhPQIFEF9vbGRQb3NpdGlvblNpemUAAAQgX2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24JAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAQUQX29sZFBvc2l0aW9uU2l6ZQkBBG11bGQCCQBlAgUgX2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FJV9vbGRQb3NpdGlvbkN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FEF9vbGRQb3NpdGlvblNpemUAAAQLcm9sbG92ZXJGZWUJAQ9jYWxjUm9sbG92ZXJGZWUCBRJfb2xkUG9zaXRpb25NYXJnaW4FIF9vbGRQb3NpdGlvbkxhc3RVcGRhdGVkVGltZXN0YW1wBAxzaWduZWRNYXJnaW4JAGQCCQBlAgkAZQIFDF9tYXJnaW5EZWx0YQULcm9sbG92ZXJGZWUFDmZ1bmRpbmdQYXltZW50BRJfb2xkUG9zaXRpb25NYXJnaW4EDSR0MDE4MDI2MTgxNTMDCQBmAgAABQxzaWduZWRNYXJnaW4JAJQKAgAACQEDYWJzAQUMc2lnbmVkTWFyZ2luCQCUCgIJAQNhYnMBBQxzaWduZWRNYXJnaW4AAAQMcmVtYWluTWFyZ2luCAUNJHQwMTgwMjYxODE1MwJfMQQHYmFkRGVidAgFDSR0MDE4MDI2MTgxNTMCXzIJAJYKBAUMcmVtYWluTWFyZ2luBQdiYWREZWJ0BQ5mdW5kaW5nUGF5bWVudAULcm9sbG92ZXJGZWUBFnN3YXBPdXRwdXRXaXRoUmVzZXJ2ZXMHBl9pc0FkZBBfYmFzZUFzc2V0QW1vdW50FF9jaGVja01heFByaWNlSW1wYWN0El9xdW90ZUFzc2V0UmVzZXJ2ZRFfcXVvdGVBc3NldFdlaWdodBFfYmFzZUFzc2V0UmVzZXJ2ZRBfYmFzZUFzc2V0V2VpZ2h0BAtwcmljZUJlZm9yZQkBBGRpdmQCCQEEbXVsZAIFEl9xdW90ZUFzc2V0UmVzZXJ2ZQURX3F1b3RlQXNzZXRXZWlnaHQJAQRtdWxkAgURX2Jhc2VBc3NldFJlc2VydmUFEF9iYXNlQXNzZXRXZWlnaHQDCQAAAgUQX2Jhc2VBc3NldEFtb3VudAAACQACAQIZSW52YWxpZCBiYXNlIGFzc2V0IGFtb3VudAQBawkBDWNhbGNJbnZhcmlhbnQCBRJfcXVvdGVBc3NldFJlc2VydmUFEV9iYXNlQXNzZXRSZXNlcnZlBBhiYXNlQXNzZXRQb29sQW1vdW50QWZ0ZXIDBQZfaXNBZGQJAGQCBRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldEFtb3VudAkAZQIFEV9iYXNlQXNzZXRSZXNlcnZlBRBfYmFzZUFzc2V0QW1vdW50BA9xdW90ZUFzc2V0QWZ0ZXIJAKADAQkBBWJkaXZkAgUBawkAtgIBBRhiYXNlQXNzZXRQb29sQW1vdW50QWZ0ZXIED3F1b3RlQXNzZXREZWx0YQkBA2FicwEJAGUCBQ9xdW90ZUFzc2V0QWZ0ZXIFEl9xdW90ZUFzc2V0UmVzZXJ2ZQQOcXVvdGVBc3NldFNvbGQJAQRtdWxkAgUPcXVvdGVBc3NldERlbHRhBRFfcXVvdGVBc3NldFdlaWdodAQTbWF4UHJpY2VJbXBhY3RWYWx1ZQkBDm1heFByaWNlSW1wYWN0AAQNJHQwMTk0MTUxOTU3NwkBDXVwZGF0ZVJlc2VydmUDCQEBIQEFBl9pc0FkZAUPcXVvdGVBc3NldERlbHRhBRBfYmFzZUFzc2V0QW1vdW50BBdxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyMQgFDSR0MDE5NDE1MTk1NzcCXzEEFmJhc2VBc3NldFJlc2VydmVBZnRlcjEIBQ0kdDAxOTQxNTE5NTc3Al8yBBd0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyMQgFDSR0MDE5NDE1MTk1NzcCXzMEC21hcmtldFByaWNlCQEEZGl2ZAIFDnF1b3RlQXNzZXRTb2xkBRBfYmFzZUFzc2V0QW1vdW50BAlwcmljZURpZmYJAQNhYnMBCQBlAgULcHJpY2VCZWZvcmUFC21hcmtldFByaWNlBAtwcmljZUltcGFjdAkAZQIFDERFQ0lNQUxfVU5JVAkBBGRpdmQCBQtwcmljZUJlZm9yZQkAZAIFC3ByaWNlQmVmb3JlBQlwcmljZURpZmYDAwkAZgIFC3ByaWNlSW1wYWN0BRNtYXhQcmljZUltcGFjdFZhbHVlBRRfY2hlY2tNYXhQcmljZUltcGFjdAcJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgICDVByaWNlIGltcGFjdCAJAKQDAQULcHJpY2VJbXBhY3QCFCA+IG1heCBwcmljZSBpbXBhY3QgCQCkAwEFE21heFByaWNlSW1wYWN0VmFsdWUCFSBiZWZvcmUgcXVvdGUgYXNzZXQ6IAkApAMBBRJfcXVvdGVBc3NldFJlc2VydmUCFCBiZWZvcmUgYmFzZSBhc3NldDogCQCkAwEFEV9iYXNlQXNzZXRSZXNlcnZlAiAgYmFzZSBhc3NldCBhbW91bnQgdG8gZXhjaGFuZ2U6IAkApAMBBRBfYmFzZUFzc2V0QW1vdW50Ag8gcHJpY2UgYmVmb3JlOiAJAKQDAQULcHJpY2VCZWZvcmUCDyBtYXJrZXQgcHJpY2U6IAkApAMBBQttYXJrZXRQcmljZQkAmQoHBQ5xdW90ZUFzc2V0U29sZAUXcXVvdGVBc3NldFJlc2VydmVBZnRlcjEFFmJhc2VBc3NldFJlc2VydmVBZnRlcjEFF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxCQBlAgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQADBQZfaXNBZGQJAQNhYnMBBRBfYmFzZUFzc2V0QW1vdW50AAAJAGUCCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQADCQEBIQEFBl9pc0FkZAkBA2FicwEFEF9iYXNlQXNzZXRBbW91bnQAAAULcHJpY2VJbXBhY3QBCnN3YXBPdXRwdXQDBl9pc0FkZBBfYmFzZUFzc2V0QW1vdW50FF9jaGVja01heFByaWNlSW1wYWN0CQEWc3dhcE91dHB1dFdpdGhSZXNlcnZlcwcFBl9pc0FkZAUQX2Jhc2VBc3NldEFtb3VudAUUX2NoZWNrTWF4UHJpY2VJbXBhY3QJAQZxdEFzdFIACQEGcXRBc3RXAAkBBmJzQXN0UgAJAQZic0FzdFcAARNnZXRPcmFjbGVQcmljZVZhbHVlAwZvcmFjbGUIcHJpY2VLZXkIYmxvY2tLZXkECWxhc3RWYWx1ZQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFBm9yYWNsZQUIcHJpY2VLZXkJAKwCAgkArAICCQCsAgICIkNhbiBub3QgZ2V0IG9yYWNsZSBwcmljZS4gT3JhY2xlOiAJAKUIAQUGb3JhY2xlAgYga2V5OiAFCHByaWNlS2V5AwkBAiE9AgUIYmxvY2tLZXkCAAQMY3VycmVudEJsb2NrCAUJbGFzdEJsb2NrBmhlaWdodAQPbGFzdE9yYWNsZUJsb2NrCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUGb3JhY2xlBQhibG9ja0tleQkArAICCQCsAgIJAKwCAgIiQ2FuIG5vdCBnZXQgb3JhY2xlIGJsb2NrLiBPcmFjbGU6IAkApQgBBQZvcmFjbGUCBiBrZXk6IAUIYmxvY2tLZXkDCQBmAgkAZQIFDGN1cnJlbnRCbG9jawUPbGFzdE9yYWNsZUJsb2NrCQEObWF4T3JhY2xlRGVsYXkACQACAQkArAICCQCsAgIJAKwCAgImT3JhY2xlIHN0YWxlIGRhdGEuIExhc3Qgb3JhY2xlIGJsb2NrOiAJAKQDAQUPbGFzdE9yYWNsZUJsb2NrAhAgY3VycmVudCBibG9jazogCQCkAwEFDGN1cnJlbnRCbG9jawUJbGFzdFZhbHVlBQlsYXN0VmFsdWUBDmdldE9yYWNsZVByaWNlAAQKYmFzZU9yYWNsZQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQENZ2V0T3JhY2xlRGF0YQEFDGtfYmFzZU9yYWNsZQIZTm8gYmFzZSBhc3NldCBvcmFjbGUgZGF0YQQPYmFzZU9yYWNsZVByaWNlCQETZ2V0T3JhY2xlUHJpY2VWYWx1ZQMIBQpiYXNlT3JhY2xlAl8xCAUKYmFzZU9yYWNsZQJfMggFCmJhc2VPcmFjbGUCXzMEC3F1b3RlT3JhY2xlCQENZ2V0T3JhY2xlRGF0YQEFDWtfcXVvdGVPcmFjbGUEEHF1b3RlT3JhY2xlUHJpY2UDCQEJaXNEZWZpbmVkAQULcXVvdGVPcmFjbGUEDHF1b3RlT3JhY2xlVgkBBXZhbHVlAQULcXVvdGVPcmFjbGUJARNnZXRPcmFjbGVQcmljZVZhbHVlAwgFDHF1b3RlT3JhY2xlVgJfMQgFDHF1b3RlT3JhY2xlVgJfMggFDHF1b3RlT3JhY2xlVgJfMwUMREVDSU1BTF9VTklUCQEEZGl2ZAIFD2Jhc2VPcmFjbGVQcmljZQUQcXVvdGVPcmFjbGVQcmljZQEOaXNNYXJrZXRDbG9zZWQABApiYXNlT3JhY2xlCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAQ1nZXRPcmFjbGVEYXRhAQUMa19iYXNlT3JhY2xlAhlObyBiYXNlIGFzc2V0IG9yYWNsZSBkYXRhBAZvcmFjbGUIBQpiYXNlT3JhY2xlAl8xBAdvcGVuS2V5CAUKYmFzZU9yYWNsZQJfNAMJAQIhPQIFB29wZW5LZXkCAAQGaXNPcGVuCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJsIAgUGb3JhY2xlBQdvcGVuS2V5CQCsAgIJAKwCAgkArAICAitDYW4gbm90IGdldCBvcmFjbGUgaXMgb3Blbi9jbG9zZWQuIE9yYWNsZTogCQClCAEFBm9yYWNsZQIGIGtleTogBQdvcGVuS2V5CQEBIQEFBmlzT3BlbgcBDGFic1ByaWNlRGlmZgUMX29yYWNsZVByaWNlEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfYmFzZUFzc2V0UmVzZXJ2ZQdfcXRBc3RXB19ic0FzdFcECnByaWNlQWZ0ZXIJAQRkaXZkAgkBBG11bGQCBRJfcXVvdGVBc3NldFJlc2VydmUFB19xdEFzdFcJAQRtdWxkAgURX2Jhc2VBc3NldFJlc2VydmUFB19ic0FzdFcEDGF2ZXJhZ2VQcmljZQkBBGRpdmQCCQBkAgUMX29yYWNsZVByaWNlBQpwcmljZUFmdGVyCQBoAgACBQxERUNJTUFMX1VOSVQEDGFic1ByaWNlRGlmZgkBBGRpdmQCCQEDYWJzAQkAZQIFDF9vcmFjbGVQcmljZQUKcHJpY2VBZnRlcgUMYXZlcmFnZVByaWNlBQxhYnNQcmljZURpZmYBGXJlcXVpcmVOb3RPdmVyU3ByZWFkTGltaXQCEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfYmFzZUFzc2V0UmVzZXJ2ZQQLb3JhY2xlUHJpY2UJAQ5nZXRPcmFjbGVQcmljZQAEB19xdEFzdFcJAQZxdEFzdFcABAdfYnNBc3RXCQEGYnNBc3RXAAQSYWJzUHJpY2VEaWZmQmVmb3JlCQEMYWJzUHJpY2VEaWZmBQULb3JhY2xlUHJpY2UJAQZxdEFzdFIACQEGYnNBc3RSAAUHX3F0QXN0VwUHX2JzQXN0VwQRYWJzUHJpY2VEaWZmQWZ0ZXIJAQxhYnNQcmljZURpZmYFBQtvcmFjbGVQcmljZQUSX3F1b3RlQXNzZXRSZXNlcnZlBRFfYmFzZUFzc2V0UmVzZXJ2ZQUHX3F0QXN0VwUHX2JzQXN0VwMDCQBmAgURYWJzUHJpY2VEaWZmQWZ0ZXIJAQ5tYXhQcmljZVNwcmVhZAAJAGYCBRFhYnNQcmljZURpZmZBZnRlcgUSYWJzUHJpY2VEaWZmQmVmb3JlBwkAAgEJAKwCAgkArAICCQCsAgICDVByaWNlIHNwcmVhZCAJAKQDAQURYWJzUHJpY2VEaWZmQWZ0ZXICFCA+IG1heCBwcmljZSBzcHJlYWQgCQCkAwEJAQ5tYXhQcmljZVNwcmVhZAAGAR1yZXF1aXJlTm90T3Zlck1heE9wZW5Ob3Rpb25hbAIRX2xvbmdPcGVuTm90aW9uYWwSX3Nob3J0T3Blbk5vdGlvbmFsBBBfbWF4T3Blbk5vdGlvbmFsCQEPbWF4T3Blbk5vdGlvbmFsAAMJAGYCBRFfbG9uZ09wZW5Ob3Rpb25hbAUQX21heE9wZW5Ob3Rpb25hbAkAAgEJAKwCAgkArAICCQCsAgICE0xvbmcgb3BlbiBub3Rpb25hbCAJAKQDAQURX2xvbmdPcGVuTm90aW9uYWwCFSA+IG1heCBvcGVuIG5vdGlvbmFsIAkApAMBBRBfbWF4T3Blbk5vdGlvbmFsAwkAZgIFEl9zaG9ydE9wZW5Ob3Rpb25hbAUQX21heE9wZW5Ob3Rpb25hbAkAAgEJAKwCAgkArAICCQCsAgICFFNob3J0IG9wZW4gbm90aW9uYWwgCQCkAwEFEl9zaG9ydE9wZW5Ob3Rpb25hbAIVID4gbWF4IG9wZW4gbm90aW9uYWwgCQCkAwEFEF9tYXhPcGVuTm90aW9uYWwGAQxnZXRTcG90UHJpY2UABBJfcXVvdGVBc3NldFJlc2VydmUJAQZxdEFzdFIABBFfYmFzZUFzc2V0UmVzZXJ2ZQkBBmJzQXN0UgAEB19xdEFzdFcJAQZxdEFzdFcABAdfYnNBc3RXCQEGYnNBc3RXAAkBBGRpdmQCCQEEbXVsZAIFEl9xdW90ZUFzc2V0UmVzZXJ2ZQUHX3F0QXN0VwkBBG11bGQCBRFfYmFzZUFzc2V0UmVzZXJ2ZQUHX2JzQXN0VwEWaXNPdmVyRmx1Y3R1YXRpb25MaW1pdAAEC29yYWNsZVByaWNlCQEOZ2V0T3JhY2xlUHJpY2UABAxjdXJyZW50UHJpY2UJAQxnZXRTcG90UHJpY2UACQBmAgkBBGRpdmQCCQEDYWJzAQkAZQIFC29yYWNsZVByaWNlBQxjdXJyZW50UHJpY2UFC29yYWNsZVByaWNlCQELc3ByZWFkTGltaXQAAR9nZXRQb3NpdGlvbkFkanVzdGVkT3Blbk5vdGlvbmFsBg1fcG9zaXRpb25TaXplB19vcHRpb24SX3F1b3RlQXNzZXRSZXNlcnZlEV9xdW90ZUFzc2V0V2VpZ2h0EV9iYXNlQXNzZXRSZXNlcnZlEF9iYXNlQXNzZXRXZWlnaHQED3Bvc2l0aW9uU2l6ZUFicwkBA2FicwEFDV9wb3NpdGlvblNpemUEB2lzU2hvcnQJAGYCAAAFDV9wb3NpdGlvblNpemUEEHBvc2l0aW9uTm90aW9uYWwDCQAAAgUHX29wdGlvbgUPUE5MX09QVElPTl9TUE9UBBNvdXRQb3NpdGlvbk5vdGlvbmFsCAkBFnN3YXBPdXRwdXRXaXRoUmVzZXJ2ZXMHCQEBIQEFB2lzU2hvcnQFD3Bvc2l0aW9uU2l6ZUFicwcFEl9xdW90ZUFzc2V0UmVzZXJ2ZQURX3F1b3RlQXNzZXRXZWlnaHQFEV9iYXNlQXNzZXRSZXNlcnZlBRBfYmFzZUFzc2V0V2VpZ2h0Al8xBRNvdXRQb3NpdGlvbk5vdGlvbmFsCQEEbXVsZAIFD3Bvc2l0aW9uU2l6ZUFicwkBDmdldE9yYWNsZVByaWNlAAUQcG9zaXRpb25Ob3Rpb25hbAErZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmxCeVZhbHVlcwcNX3Bvc2l0aW9uU2l6ZRVfcG9zaXRpb25PcGVuTm90aW9uYWwSX3F1b3RlQXNzZXRSZXNlcnZlEV9xdW90ZUFzc2V0V2VpZ2h0EV9iYXNlQXNzZXRSZXNlcnZlEF9iYXNlQXNzZXRXZWlnaHQHX29wdGlvbgMJAAACBQ1fcG9zaXRpb25TaXplAAAJAAIBAhVJbnZhbGlkIHBvc2l0aW9uIHNpemUEB2lzU2hvcnQJAGYCAAAFDV9wb3NpdGlvblNpemUEEHBvc2l0aW9uTm90aW9uYWwJAR9nZXRQb3NpdGlvbkFkanVzdGVkT3Blbk5vdGlvbmFsBgUNX3Bvc2l0aW9uU2l6ZQUHX29wdGlvbgUSX3F1b3RlQXNzZXRSZXNlcnZlBRFfcXVvdGVBc3NldFdlaWdodAURX2Jhc2VBc3NldFJlc2VydmUFEF9iYXNlQXNzZXRXZWlnaHQEDXVucmVhbGl6ZWRQbmwDBQdpc1Nob3J0CQBlAgUVX3Bvc2l0aW9uT3Blbk5vdGlvbmFsBRBwb3NpdGlvbk5vdGlvbmFsCQBlAgUQcG9zaXRpb25Ob3Rpb25hbAUVX3Bvc2l0aW9uT3Blbk5vdGlvbmFsCQCUCgIFEHBvc2l0aW9uTm90aW9uYWwFDXVucmVhbGl6ZWRQbmwBI2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sAgdfdHJhZGVyB19vcHRpb24EDSR0MDI3NDU1Mjc1ODMJAQtnZXRQb3NpdGlvbgEFB190cmFkZXIEDHBvc2l0aW9uU2l6ZQgFDSR0MDI3NDU1Mjc1ODMCXzEEDnBvc2l0aW9uTWFyZ2luCAUNJHQwMjc0NTUyNzU4MwJfMgQUcG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDAyNzQ1NTI3NTgzAl8zBBFwb3NpdGlvbkxzdFVwZENQRggFDSR0MDI3NDU1Mjc1ODMCXzQJAStnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubEJ5VmFsdWVzBwUMcG9zaXRpb25TaXplBRRwb3NpdGlvbk9wZW5Ob3Rpb25hbAkBBnF0QXN0UgAJAQZxdEFzdFcACQEGYnNBc3RSAAkBBmJzQXN0VwAFB19vcHRpb24BD2NhbGNNYXJnaW5SYXRpbwMNX3JlbWFpbk1hcmdpbghfYmFkRGVidBFfcG9zaXRpb25Ob3Rpb25hbAkBBGRpdmQCCQBlAgUNX3JlbWFpbk1hcmdpbgUIX2JhZERlYnQFEV9wb3NpdGlvbk5vdGlvbmFsARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAgdfdHJhZGVyB19vcHRpb24EDSR0MDI4MDk4MjgyMzkJAQtnZXRQb3NpdGlvbgEFB190cmFkZXIEDHBvc2l0aW9uU2l6ZQgFDSR0MDI4MDk4MjgyMzkCXzEEDnBvc2l0aW9uTWFyZ2luCAUNJHQwMjgwOTgyODIzOQJfMgQDcG9uCAUNJHQwMjgwOTgyODIzOQJfMwQWcG9zaXRpb25MYXN0VXBkYXRlZENQRggFDSR0MDI4MDk4MjgyMzkCXzQEEXBvc2l0aW9uVGltZXN0YW1wCAUNJHQwMjgwOTgyODIzOQJfNQQNJHQwMjgyNDUyODMzOAkBI2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sAgUHX3RyYWRlcgUHX29wdGlvbgQQcG9zaXRpb25Ob3Rpb25hbAgFDSR0MDI4MjQ1MjgzMzgCXzEEDXVucmVhbGl6ZWRQbmwIBQ0kdDAyODI0NTI4MzM4Al8yBA0kdDAyODM0MzI4NTU1CQEwY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudEFuZFJvbGxvdmVyRmVlBQUMcG9zaXRpb25TaXplBQ5wb3NpdGlvbk1hcmdpbgUWcG9zaXRpb25MYXN0VXBkYXRlZENQRgURcG9zaXRpb25UaW1lc3RhbXAFDXVucmVhbGl6ZWRQbmwEDHJlbWFpbk1hcmdpbggFDSR0MDI4MzQzMjg1NTUCXzEEB2JhZERlYnQIBQ0kdDAyODM0MzI4NTU1Al8yCQEPY2FsY01hcmdpblJhdGlvAwUMcmVtYWluTWFyZ2luBQdiYWREZWJ0BRBwb3NpdGlvbk5vdGlvbmFsAQ5nZXRNYXJnaW5SYXRpbwEHX3RyYWRlcgkBFmdldE1hcmdpblJhdGlvQnlPcHRpb24CBQdfdHJhZGVyBQ9QTkxfT1BUSU9OX1NQT1QBG2dldFBhcnRpYWxMaXF1aWRhdGlvbkFtb3VudAIHX3RyYWRlcg1fcG9zaXRpb25TaXplBAxtYXhpbXVtUmF0aW8JAQR2bWF4AgkBF3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAAkAZQIFDERFQ0lNQUxfVU5JVAkBBGRpdmQCCQEOZ2V0TWFyZ2luUmF0aW8BBQdfdHJhZGVyCQEWbWFpbnRlbmFuY2VNYXJnaW5SYXRpbwAEGG1heEV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQkBBG11bGQCCQEDYWJzAQUNX3Bvc2l0aW9uU2l6ZQUMbWF4aW11bVJhdGlvBApzd2FwUmVzdWx0CQEKc3dhcE91dHB1dAMJAGYCBQ1fcG9zaXRpb25TaXplAAAFGG1heEV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQcEHG1heEV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQIBQpzd2FwUmVzdWx0Al8xBAtwcmljZUltcGFjdAgFCnN3YXBSZXN1bHQCXzcDCQBmAgkBDm1heFByaWNlSW1wYWN0AAULcHJpY2VJbXBhY3QFGG1heEV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQkBBG11bGQCCQEDYWJzAQUNX3Bvc2l0aW9uU2l6ZQkBF3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAAEVaW50ZXJuYWxDbG9zZVBvc2l0aW9uBwdfdHJhZGVyBV9zaXplBF9mZWUUX21pblF1b3RlQXNzZXRBbW91bnQMX2FkZFRvTWFyZ2luFF9jaGVja01heFByaWNlSW1wYWN0Cl9saXF1aWRhdGUEDSR0MDI5NjIyMjk3NzgJAQtnZXRQb3NpdGlvbgEFB190cmFkZXIED29sZFBvc2l0aW9uU2l6ZQgFDSR0MDI5NjIyMjk3NzgCXzEEEW9sZFBvc2l0aW9uTWFyZ2luCAUNJHQwMjk2MjIyOTc3OAJfMgQXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDAyOTYyMjI5Nzc4Al8zBBRvbGRQb3NpdGlvbkxzdFVwZENQRggFDSR0MDI5NjIyMjk3NzgCXzQEFG9sZFBvc2l0aW9uVGltZXN0YW1wCAUNJHQwMjk2MjIyOTc3OAJfNQQOaXNMb25nUG9zaXRpb24JAGYCBQ9vbGRQb3NpdGlvblNpemUAAAQSYWJzT2xkUG9zaXRpb25TaXplCQEDYWJzAQUPb2xkUG9zaXRpb25TaXplAwMJAGcCBRJhYnNPbGRQb3NpdGlvblNpemUFBV9zaXplCQBmAgUFX3NpemUAAAcEDmlzUGFydGlhbENsb3NlCQBmAgUSYWJzT2xkUG9zaXRpb25TaXplBQVfc2l6ZQQNJHQwMzAwNzAzMDUyMQkBCnN3YXBPdXRwdXQDCQBmAgUPb2xkUG9zaXRpb25TaXplAAAFBV9zaXplBRRfY2hlY2tNYXhQcmljZUltcGFjdAQZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAgFDSR0MDMwMDcwMzA1MjECXzEEFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDAzMDA3MDMwNTIxAl8yBBViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDAzMDA3MDMwNTIxAl8zBBZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCAUNJHQwMzAwNzAzMDUyMQJfNAQVZXhjaGFuZ2VkUG9zaXRpb25TaXplAwkAZgIFD29sZFBvc2l0aW9uU2l6ZQAACQEBLQEFBV9zaXplBQVfc2l6ZQQNJHQwMzA3MzYzMDk0MwkBI2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sAgUHX3RyYWRlcgUPUE5MX09QVElPTl9TUE9UBBNvbGRQb3NpdGlvbk5vdGlvbmFsCAUNJHQwMzA3MzYzMDk0MwJfMQQNdW5yZWFsaXplZFBubAgFDSR0MDMwNzM2MzA5NDMCXzIEDXJlYWxpemVkUmF0aW8JAQRkaXZkAgkBA2FicwEFFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQUSYWJzT2xkUG9zaXRpb25TaXplBAtyZWFsaXplZFBubAkBBG11bGQCBQ11bnJlYWxpemVkUG5sBQ1yZWFsaXplZFJhdGlvBA0kdDAzMTI4NDMxNTMwCQEwY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudEFuZFJvbGxvdmVyRmVlBQUPb2xkUG9zaXRpb25TaXplBRFvbGRQb3NpdGlvbk1hcmdpbgUUb2xkUG9zaXRpb25Mc3RVcGRDUEYFFG9sZFBvc2l0aW9uVGltZXN0YW1wBQ11bnJlYWxpemVkUG5sBBJyZW1haW5NYXJnaW5CZWZvcmUIBQ0kdDAzMTI4NDMxNTMwAl8xBAJ4MQgFDSR0MDMxMjg0MzE1MzACXzIEAngyCAUNJHQwMzEyODQzMTUzMAJfMwQLcm9sbG92ZXJGZWUIBQ0kdDAzMTI4NDMxNTMwAl80BA9wb3NpdGlvbkJhZERlYnQICQEwY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudEFuZFJvbGxvdmVyRmVlBQUPb2xkUG9zaXRpb25TaXplBRFvbGRQb3NpdGlvbk1hcmdpbgUUb2xkUG9zaXRpb25Mc3RVcGRDUEYFFG9sZFBvc2l0aW9uVGltZXN0YW1wBQtyZWFsaXplZFBubAJfMgQQcmVhbGl6ZWRDbG9zZUZlZQkBBG11bGQCCQEEbXVsZAIFE29sZFBvc2l0aW9uTm90aW9uYWwFDXJlYWxpemVkUmF0aW8FBF9mZWUEEnVucmVhbGl6ZWRQbmxBZnRlcgkAZQIFDXVucmVhbGl6ZWRQbmwFC3JlYWxpemVkUG5sBBJyZW1haW5PcGVuTm90aW9uYWwDCQBmAgUPb2xkUG9zaXRpb25TaXplAAAJAGUCCQBlAgUTb2xkUG9zaXRpb25Ob3Rpb25hbAUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAUSdW5yZWFsaXplZFBubEFmdGVyCQBlAgkAZAIFEnVucmVhbGl6ZWRQbmxBZnRlcgUTb2xkUG9zaXRpb25Ob3Rpb25hbAUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAQPbmV3UG9zaXRpb25TaXplCQBkAgUPb2xkUG9zaXRpb25TaXplBRVleGNoYW5nZWRQb3NpdGlvblNpemUEDSR0MDMyOTM2MzMzMjIDCQAAAgUPbmV3UG9zaXRpb25TaXplAAAJAJQKAgAAAAAJAJQKAgkBA2FicwEFEnJlbWFpbk9wZW5Ob3Rpb25hbAkBH2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24BBQ9uZXdQb3NpdGlvblNpemUEF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwMzI5MzYzMzMyMgJfMQQUbmV3UG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDAzMjkzNjMzMzIyAl8yBBFvcGVuTm90aW9uYWxEZWx0YQkAZQIFF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAQLbWFyZ2luUmF0aW8JARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAgUHX3RyYWRlcgUPUE5MX09QVElPTl9TUE9UBB5uZXdQb3NpdGlvbk1hcmdpbldpdGhTYW1lUmF0aW8DCQBmAgUPb2xkUG9zaXRpb25TaXplAAAJAGUCCQEEbXVsZAIJAGQCBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUSdW5yZWFsaXplZFBubEFmdGVyBQttYXJnaW5SYXRpbwUSdW5yZWFsaXplZFBubEFmdGVyCQBlAgkBBG11bGQCCQBlAgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFEnVucmVhbGl6ZWRQbmxBZnRlcgULbWFyZ2luUmF0aW8FEnVucmVhbGl6ZWRQbmxBZnRlcgQRbWFyZ2luVG9UcmFkZXJSYXcJAGUCCQBlAgUScmVtYWluTWFyZ2luQmVmb3JlCQBkAgUebmV3UG9zaXRpb25NYXJnaW5XaXRoU2FtZVJhdGlvBRJ1bnJlYWxpemVkUG5sQWZ0ZXIFEHJlYWxpemVkQ2xvc2VGZWUEDm1hcmdpblRvVHJhZGVyAwkAZgIAAAURbWFyZ2luVG9UcmFkZXJSYXcDBQpfbGlxdWlkYXRlAAAJAAIBAjdJbnZhbGlkIGludGVybmFsQ2xvc2VQb3NpdGlvbiBwYXJhbXM6IHVuYWJsZSB0byBwYXkgZmVlBRFtYXJnaW5Ub1RyYWRlclJhdwQRbmV3UG9zaXRpb25NYXJnaW4DBQxfYWRkVG9NYXJnaW4JAGQCBR5uZXdQb3NpdGlvbk1hcmdpbldpdGhTYW1lUmF0aW8FDm1hcmdpblRvVHJhZGVyBR5uZXdQb3NpdGlvbk1hcmdpbldpdGhTYW1lUmF0aW8DAwkBAiE9AgUUX21pblF1b3RlQXNzZXRBbW91bnQAAAkAZgIFFF9taW5RdW90ZUFzc2V0QW1vdW50BRlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50BwkAAgEJAKwCAgkArAICCQCsAgICDUxpbWl0IGVycm9yOiAJAKQDAQUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAIDIDwgCQCkAwEFFF9taW5RdW90ZUFzc2V0QW1vdW50CQCjChEFD25ld1Bvc2l0aW9uU2l6ZQURbmV3UG9zaXRpb25NYXJnaW4FF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBRRuZXdQb3NpdGlvbkxzdFVwZENQRgUPcG9zaXRpb25CYWREZWJ0BQtyZWFsaXplZFBubAMDBQxfYWRkVG9NYXJnaW4FDmlzUGFydGlhbENsb3NlBwAABQ5tYXJnaW5Ub1RyYWRlcgUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBRZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQBlAgkBFG9wZW5JbnRlcmVzdE5vdGlvbmFsAAURb3Blbk5vdGlvbmFsRGVsdGEJAGUCCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAMFDmlzTG9uZ1Bvc2l0aW9uCQEDYWJzAQUVZXhjaGFuZ2VkUG9zaXRpb25TaXplAAAJAGUCCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQADCQEBIQEFDmlzTG9uZ1Bvc2l0aW9uCQEDYWJzAQUVZXhjaGFuZ2VkUG9zaXRpb25TaXplAAAJAGUCCQEQb3BlbkludGVyZXN0TG9uZwADBQ5pc0xvbmdQb3NpdGlvbgURb3Blbk5vdGlvbmFsRGVsdGEAAAkAZQIJARFvcGVuSW50ZXJlc3RTaG9ydAADCQEBIQEFDmlzTG9uZ1Bvc2l0aW9uBRFvcGVuTm90aW9uYWxEZWx0YQAACQBkAgUQcmVhbGl6ZWRDbG9zZUZlZQULcm9sbG92ZXJGZWUFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQJAAIBCQCsAgIJAKwCAgkArAICAj1JbnZhbGlkIGludGVybmFsQ2xvc2VQb3NpdGlvbiBwYXJhbXM6IGludmFsaWQgcG9zaXRpb24gc2l6ZTogCQCkAwEFBV9zaXplAgYgbWF4OiAJAKQDAQUSYWJzT2xkUG9zaXRpb25TaXplARNnZXRUZXJtaW5hbEFtbVN0YXRlAAQNX3Bvc2l0aW9uU2l6ZQkBEXRvdGFsUG9zaXRpb25TaXplAAMJAAACBQ1fcG9zaXRpb25TaXplAAAJAJQKAgkBBnF0QXN0UgAJAQZic0FzdFIABAlkaXJlY3Rpb24JAGYCBQ1fcG9zaXRpb25TaXplAAAEDSR0MDM2NTU3MzY3MzYJAQpzd2FwT3V0cHV0AwUJZGlyZWN0aW9uCQEDYWJzAQUNX3Bvc2l0aW9uU2l6ZQcEFWN1cnJlbnROZXRNYXJrZXRWYWx1ZQgFDSR0MDM2NTU3MzY3MzYCXzEEGXRlcm1pbmFsUXVvdGVBc3NldFJlc2VydmUIBQ0kdDAzNjU1NzM2NzM2Al8yBBh0ZXJtaW5hbEJhc2VBc3NldFJlc2VydmUIBQ0kdDAzNjU1NzM2NzM2Al8zCQCUCgIFGXRlcm1pbmFsUXVvdGVBc3NldFJlc2VydmUFGHRlcm1pbmFsQmFzZUFzc2V0UmVzZXJ2ZQETZ2V0UXVvdGVBc3NldFdlaWdodAQQYmFzZUFzc2V0UmVzZXJ2ZRF0b3RhbFBvc2l0aW9uU2l6ZRFxdW90ZUFzc2V0UmVzZXJ2ZQt0YXJnZXRQcmljZQQBYgkAtgIBBRBiYXNlQXNzZXRSZXNlcnZlBAJzegkAtgIBBRF0b3RhbFBvc2l0aW9uU2l6ZQQBcQkAtgIBBRFxdW90ZUFzc2V0UmVzZXJ2ZQQBcAkAtgIBBQt0YXJnZXRQcmljZQQBawkBBWJtdWxkAgUBcQUBYgQEbmV3QgkAtwICBQFiBQJzegQEbmV3UQkBBWJkaXZkAgUBawUEbmV3QgQBegkBBWJkaXZkAgUEbmV3UQUEbmV3QgQGcmVzdWx0CQEFYmRpdmQCBQFwBQF6CQCgAwEFBnJlc3VsdAEUZ2V0U3luY1Rlcm1pbmFsUHJpY2UDDl90ZXJtaW5hbFByaWNlB19xdEFzdFIHX2JzQXN0UgQNX3Bvc2l0aW9uU2l6ZQkBEXRvdGFsUG9zaXRpb25TaXplAAMJAAACBQ1fcG9zaXRpb25TaXplAAAECW5ld1F0QXN0VwkBBGRpdmQCCQEEbXVsZAIFDl90ZXJtaW5hbFByaWNlBQdfYnNBc3RSBQdfcXRBc3RSCQCVCgMFCW5ld1F0QXN0VwUMREVDSU1BTF9VTklUAAAECWRpcmVjdGlvbgkAZgIFDV9wb3NpdGlvblNpemUAAAQVY3VycmVudE5ldE1hcmtldFZhbHVlCAkBCnN3YXBPdXRwdXQDBQlkaXJlY3Rpb24JAQNhYnMBBQ1fcG9zaXRpb25TaXplBwJfMQQJbmV3UXRBc3RXCQETZ2V0UXVvdGVBc3NldFdlaWdodAQFB19ic0FzdFIFDV9wb3NpdGlvblNpemUFB19xdEFzdFIFDl90ZXJtaW5hbFByaWNlBAluZXdCc0FzdFcFDERFQ0lNQUxfVU5JVAQNbWFyZ2luVG9WYXVsdAgJAStnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubEJ5VmFsdWVzBwUNX3Bvc2l0aW9uU2l6ZQUVY3VycmVudE5ldE1hcmtldFZhbHVlBQdfcXRBc3RSBQluZXdRdEFzdFcFB19ic0FzdFIFCW5ld0JzQXN0VwUPUE5MX09QVElPTl9TUE9UAl8yCQCVCgMFCW5ld1F0QXN0VwUJbmV3QnNBc3RXBQ1tYXJnaW5Ub1ZhdWx0AQpnZXRGdW5kaW5nAAQPdW5kZXJseWluZ1ByaWNlCQEOZ2V0T3JhY2xlUHJpY2UABAlzcG90UHJpY2UJAQxnZXRTcG90UHJpY2UABAdwcmVtaXVtCQBlAgUJc3BvdFByaWNlBQ91bmRlcmx5aW5nUHJpY2UDAwMJAAACCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAAAAYJAAACCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAAABgkBDmlzTWFya2V0Q2xvc2VkAAkAlQoDAAAAAAAAAwkAZgIAAAUHcHJlbWl1bQQUc2hvcnRQcmVtaXVtRnJhY3Rpb24JAQRkaXZkAgkBBG11bGQCBQdwcmVtaXVtCQEUZnVuZGluZ1BlcmlvZERlY2ltYWwABQdPTkVfREFZAwkAAAIJAQtmdW5kaW5nTW9kZQAFEkZVTkRJTkdfQVNZTU1FVFJJQwQTbG9uZ1ByZW1pdW1GcmFjdGlvbgkBBGRpdmQCCQEEbXVsZAIFFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAJARV0b3RhbExvbmdQb3NpdGlvblNpemUACQCVCgMFFHNob3J0UHJlbWl1bUZyYWN0aW9uBRNsb25nUHJlbWl1bUZyYWN0aW9uAAAEGXNob3J0VG90YWxQcmVtaXVtRnJhY3Rpb24JAQNhYnMBCQEEbXVsZAIFFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAEGGxvbmdUb3RhbFByZW1pdW1GcmFjdGlvbgkBA2FicwEJAQRtdWxkAgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24JARV0b3RhbExvbmdQb3NpdGlvblNpemUABA5wcmVtaXVtVG9WYXVsdAkAZQIFGXNob3J0VG90YWxQcmVtaXVtRnJhY3Rpb24FGGxvbmdUb3RhbFByZW1pdW1GcmFjdGlvbgkAlQoDBRRzaG9ydFByZW1pdW1GcmFjdGlvbgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24FDnByZW1pdW1Ub1ZhdWx0BBNsb25nUHJlbWl1bUZyYWN0aW9uCQEEZGl2ZAIJAQRtdWxkAgUHcHJlbWl1bQkBFGZ1bmRpbmdQZXJpb2REZWNpbWFsAAUHT05FX0RBWQMJAAACCQELZnVuZGluZ01vZGUABRJGVU5ESU5HX0FTWU1NRVRSSUMEFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEEZGl2ZAIJAQRtdWxkAgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQAJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAkAlQoDBRRzaG9ydFByZW1pdW1GcmFjdGlvbgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgAABBhsb25nVG90YWxQcmVtaXVtRnJhY3Rpb24JAQNhYnMBCQEEbXVsZAIFE2xvbmdQcmVtaXVtRnJhY3Rpb24JARV0b3RhbExvbmdQb3NpdGlvblNpemUABBlzaG9ydFRvdGFsUHJlbWl1bUZyYWN0aW9uCQEDYWJzAQkBBG11bGQCBRNsb25nUHJlbWl1bUZyYWN0aW9uCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAEDnByZW1pdW1Ub1ZhdWx0CQBlAgUYbG9uZ1RvdGFsUHJlbWl1bUZyYWN0aW9uBRlzaG9ydFRvdGFsUHJlbWl1bUZyYWN0aW9uCQCVCgMFE2xvbmdQcmVtaXVtRnJhY3Rpb24FE2xvbmdQcmVtaXVtRnJhY3Rpb24FDnByZW1pdW1Ub1ZhdWx0AQ5nZXRBZGp1c3RlZEZlZQILX2FydGlmYWN0SWQQX2Jhc2VGZWVEaXNjb3VudAQKYmFzZUZlZVJhdwkBA2ZlZQAEB2Jhc2VGZWUJAQRtdWxkAgUKYmFzZUZlZVJhdwUQX2Jhc2VGZWVEaXNjb3VudAQNJHQwNDA0NTQ0MDk0OQMJAQIhPQIFC19hcnRpZmFjdElkAgAEDGFydGlmYWN0S2luZAkBBHN0ckECCQERbmZ0TWFuYWdlckFkZHJlc3MACQEOdG9Db21wb3NpdGVLZXkCBQxrX3Rva2VuX3R5cGUFC19hcnRpZmFjdElkAwkAAAIFDGFydGlmYWN0S2luZAUYRkVFX1JFRFVDVElPTl9UT0tFTl9UWVBFBAlyZWR1Y3Rpb24JAQRpbnRBAgkBEW5mdE1hbmFnZXJBZGRyZXNzAAkBDnRvQ29tcG9zaXRlS2V5AgUNa190b2tlbl9wYXJhbQULX2FydGlmYWN0SWQEC2FkanVzdGVkRmVlCQEEbXVsZAIFB2Jhc2VGZWUFCXJlZHVjdGlvbgkAlAoCBQthZGp1c3RlZEZlZQYJAAIBAhlJbnZhbGlkIGF0dGFjaGVkIGFydGlmYWN0CQCUCgIFB2Jhc2VGZWUHBAthZGp1c3RlZEZlZQgFDSR0MDQwNDU0NDA5NDkCXzEEDGJ1cm5BcnRpZmFjdAgFDSR0MDQwNDU0NDA5NDkCXzIJAJQKAgULYWRqdXN0ZWRGZWUFDGJ1cm5BcnRpZmFjdAEYZ2V0Rm9yVHJhZGVyV2l0aEFydGlmYWN0AgdfdHJhZGVyC19hcnRpZmFjdElkBBBkb0dldEZlZURpc2NvdW50CQD8BwQJAQxtaW5lckFkZHJlc3MAAhJjb21wdXRlRmVlRGlzY291bnQJAMwIAgUHX3RyYWRlcgUDbmlsBQNuaWwDCQAAAgUQZG9HZXRGZWVEaXNjb3VudAUQZG9HZXRGZWVEaXNjb3VudAQLZmVlRGlzY291bnQEByRtYXRjaDAFEGRvR2V0RmVlRGlzY291bnQDCQABAgUHJG1hdGNoMAIDSW50BAF4BQckbWF0Y2gwBQF4CQACAQIhSW52YWxpZCBjb21wdXRlRmVlRGlzY291bnQgcmVzdWx0BA0kdDA0MTI5NTQxMzY5CQEOZ2V0QWRqdXN0ZWRGZWUCBQtfYXJ0aWZhY3RJZAULZmVlRGlzY291bnQEC2FkanVzdGVkRmVlCAUNJHQwNDEyOTU0MTM2OQJfMQQMYnVybkFydGlmYWN0CAUNJHQwNDEyOTU0MTM2OQJfMgkAlAoCBQthZGp1c3RlZEZlZQUMYnVybkFydGlmYWN0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAQ1nZXRBcnRpZmFjdElkAQFpBAphcnRpZmFjdElkAwkAZgIJAJADAQgFAWkIcGF5bWVudHMAAQkA2AQBCQETdmFsdWVPckVycm9yTWVzc2FnZQIICQCRAwIIBQFpCHBheW1lbnRzAAEHYXNzZXRJZAISSW52YWxpZCBhcnRpZmFjdElkAgAFCmFydGlmYWN0SWQBDWRpc3RyaWJ1dGVGZWUBCl9mZWVBbW91bnQEDGZlZVRvU3Rha2VycwkBBG11bGQCBQpfZmVlQW1vdW50CQETZmVlVG9TdGFrZXJzUGVyY2VudAAECmZlZVRvVmF1bHQJAGUCBQpfZmVlQW1vdW50BQxmZWVUb1N0YWtlcnMJAJQKAgUMZmVlVG9TdGFrZXJzBQpmZWVUb1ZhdWx0AQ51cGRhdGVTZXR0aW5ncw4QX2luaXRNYXJnaW5SYXRpbwRfbW1yFF9saXF1aWRhdGlvbkZlZVJhdGlvDl9mdW5kaW5nUGVyaW9kBF9mZWUMX3NwcmVhZExpbWl0D19tYXhQcmljZUltcGFjdBhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8PX21heFByaWNlU3ByZWFkEF9tYXhPcGVuTm90aW9uYWwUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQPX21heE9yYWNsZURlbGF5DF9yb2xsb3ZlckZlZQxfZnVuZGluZ01vZGUJAMwIAgkBDEludGVnZXJFbnRyeQIFEWtfaW5pdE1hcmdpblJhdGlvBRBfaW5pdE1hcmdpblJhdGlvCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRhrX21haW50ZW5hbmNlTWFyZ2luUmF0aW8FBF9tbXIJAMwIAgkBDEludGVnZXJFbnRyeQIFFWtfbGlxdWlkYXRpb25GZWVSYXRpbwUUX2xpcXVpZGF0aW9uRmVlUmF0aW8JAMwIAgkBDEludGVnZXJFbnRyeQIFD2tfZnVuZGluZ1BlcmlvZAUOX2Z1bmRpbmdQZXJpb2QJAMwIAgkBDEludGVnZXJFbnRyeQIFBWtfZmVlBQRfZmVlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ1rX3NwcmVhZExpbWl0BQxfc3ByZWFkTGltaXQJAMwIAgkBDEludGVnZXJFbnRyeQIFEGtfbWF4UHJpY2VJbXBhY3QFD19tYXhQcmljZUltcGFjdAkAzAgCCQEMSW50ZWdlckVudHJ5AgUZa19wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwUYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRBrX21heFByaWNlU3ByZWFkBQ9fbWF4UHJpY2VTcHJlYWQJAMwIAgkBDEludGVnZXJFbnRyeQIFEWtfbWF4T3Blbk5vdGlvbmFsBRBfbWF4T3Blbk5vdGlvbmFsCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRVrX2ZlZVRvU3Rha2Vyc1BlcmNlbnQFFF9mZWVUb1N0YWtlcnNQZXJjZW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCBRBrX21heE9yYWNsZURlbGF5BRRfZmVlVG9TdGFrZXJzUGVyY2VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgUNa19yb2xsb3ZlckZlZQUMX3JvbGxvdmVyRmVlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ1rX2Z1bmRpbmdNb2RlBQxfZnVuZGluZ01vZGUFA25pbAENdXBkYXRlRnVuZGluZwURX25leHRGdW5kaW5nQmxvY2skX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uJV9sYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24QX2xvbmdGdW5kaW5nUmF0ZRFfc2hvcnRGdW5kaW5nUmF0ZQkAzAgCCQEMSW50ZWdlckVudHJ5AgUSa19uZXh0RnVuZGluZ0Jsb2NrBRFfbmV4dEZ1bmRpbmdCbG9jawkAzAgCCQEMSW50ZWdlckVudHJ5AgUla19sYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUkX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uCQDMCAIJAQxJbnRlZ2VyRW50cnkCBSZrX2xhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUlX2xhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkAzAgCCQEMSW50ZWdlckVudHJ5AgURa19sb25nRnVuZGluZ1JhdGUFEF9sb25nRnVuZGluZ1JhdGUJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfc2hvcnRGdW5kaW5nUmF0ZQURX3Nob3J0RnVuZGluZ1JhdGUFA25pbAEfaW5jcmVtZW50UG9zaXRpb25TZXF1ZW5jZU51bWJlcgIOX2lzTmV3UG9zaXRpb24IX2FkZHJlc3MDBQ5faXNOZXdQb3NpdGlvbgQPY3VycmVudFNlcXVlbmNlCQEMbGFzdFNlcXVlbmNlAAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUSa19wb3NpdGlvblNlcXVlbmNlBQhfYWRkcmVzcwkAZAIFD2N1cnJlbnRTZXF1ZW5jZQABCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQprX3NlcXVlbmNlCQBkAgUPY3VycmVudFNlcXVlbmNlAAEFA25pbAUDbmlsARF1cGRhdGVQb3NpdGlvbkZlZQMOX2lzTmV3UG9zaXRpb24IX2FkZHJlc3MEX2ZlZQMFDl9pc05ld1Bvc2l0aW9uCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBQ1rX3Bvc2l0aW9uRmVlBQhfYWRkcmVzcwUEX2ZlZQUDbmlsBQNuaWwBDnVwZGF0ZVBvc2l0aW9uBghfYWRkcmVzcwVfc2l6ZQdfbWFyZ2luDV9vcGVuTm90aW9uYWwgX2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24QX2xhdGVzdFRpbWVzdGFtcAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUOa19wb3NpdGlvblNpemUFCF9hZGRyZXNzBQVfc2l6ZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUQa19wb3NpdGlvbk1hcmdpbgUIX2FkZHJlc3MFB19tYXJnaW4JAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFFmtfcG9zaXRpb25PcGVuTm90aW9uYWwFCF9hZGRyZXNzBQ1fb3Blbk5vdGlvbmFsCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQhfYWRkcmVzcwUgX2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24JAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAUIX2FkZHJlc3MFEF9sYXRlc3RUaW1lc3RhbXAFA25pbAERdXBkYXRlQW1tUmVzZXJ2ZXMCB19xdEFzdFIHX2JzQXN0UgkAzAgCCQEMSW50ZWdlckVudHJ5AgUTa19xdW90ZUFzc2V0UmVzZXJ2ZQUHX3F0QXN0UgkAzAgCCQEMSW50ZWdlckVudHJ5AgUSa19iYXNlQXNzZXRSZXNlcnZlBQdfYnNBc3RSBQNuaWwBEHVwZGF0ZUFtbVdlaWdodHMCB19xdEFzdFcHX2JzQXN0VwkAzAgCCQEMSW50ZWdlckVudHJ5AgUSa19xdW90ZUFzc2V0V2VpZ2h0BQdfcXRBc3RXCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRFrX2Jhc2VBc3NldFdlaWdodAUHX2JzQXN0VwUDbmlsAQl1cGRhdGVBbW0IB19xdEFzdFIHX2JzQXN0UhdfdG90YWxQb3NpdGlvblNpemVBZnRlchVfb3BlbkludGVyZXN0Tm90aW9uYWwWX3RvdGFsTG9uZ1Bvc2l0aW9uU2l6ZRdfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZRZfdG90YWxMb25nT3Blbk5vdGlvbmFsF190b3RhbFNob3J0T3Blbk5vdGlvbmFsBAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwADCQECIT0CCQBlAgUWX3RvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQUXX3RvdGFsU2hvcnRQb3NpdGlvblNpemUFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgICGEludmFsaWQgQU1NIHN0YXRlIGRhdGE6IAkApAMBBRZfdG90YWxMb25nUG9zaXRpb25TaXplAgQgKyAgCQCkAwEFF190b3RhbFNob3J0UG9zaXRpb25TaXplAgQgIT0gCQCkAwEFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQDOCAIJARF1cGRhdGVBbW1SZXNlcnZlcwIFB19xdEFzdFIFB19ic0FzdFIJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tfdG90YWxQb3NpdGlvblNpemUFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRZrX29wZW5JbnRlcmVzdE5vdGlvbmFsBRVfb3BlbkludGVyZXN0Tm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFF2tfdG90YWxMb25nUG9zaXRpb25TaXplBRZfdG90YWxMb25nUG9zaXRpb25TaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRhrX3RvdGFsU2hvcnRQb3NpdGlvblNpemUFF190b3RhbFNob3J0UG9zaXRpb25TaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRJrX29wZW5JbnRlcmVzdExvbmcFFl90b3RhbExvbmdPcGVuTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tfb3BlbkludGVyZXN0U2hvcnQFF190b3RhbFNob3J0T3Blbk5vdGlvbmFsBQNuaWwBDmRlbGV0ZVBvc2l0aW9uAQhfYWRkcmVzcwkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBQ5rX3Bvc2l0aW9uU2l6ZQUIX2FkZHJlc3MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBDnRvQ29tcG9zaXRlS2V5AgUQa19wb3NpdGlvbk1hcmdpbgUIX2FkZHJlc3MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBDnRvQ29tcG9zaXRlS2V5AgUWa19wb3NpdGlvbk9wZW5Ob3Rpb25hbAUIX2FkZHJlc3MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBDnRvQ29tcG9zaXRlS2V5AgUua19wb3NpdGlvbkxhc3RVcGRhdGVkQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUIX2FkZHJlc3MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBDnRvQ29tcG9zaXRlS2V5AgUNa19wb3NpdGlvbkZlZQUIX2FkZHJlc3MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBDnRvQ29tcG9zaXRlS2V5AgUea19wb3NpdGlvbkxhc3RVcGRhdGVkVGltZXN0YW1wBQhfYWRkcmVzcwUDbmlsAQh3aXRoZHJhdwIIX2FkZHJlc3MHX2Ftb3VudAQHYmFsYW5jZQkA8AcCBQR0aGlzCQEKcXVvdGVBc3NldAADCQBmAgUHX2Ftb3VudAUHYmFsYW5jZQkAAgEJAKwCAgkArAICCQCsAgICE1VuYWJsZSB0byB3aXRoZHJhdyAJAKQDAQUHX2Ftb3VudAIXIGZyb20gY29udHJhY3QgYmFsYW5jZSAJAKQDAQUHYmFsYW5jZQkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDBQhfYWRkcmVzcwUHX2Ftb3VudAkBCnF1b3RlQXNzZXQABQNuaWwBDXVwZGF0ZUJhbGFuY2UBAWkDCQBmAgAABQFpCQACAQIHQmFsYW5jZQkAzAgCCQEMSW50ZWdlckVudHJ5AgUJa19iYWxhbmNlBQFpBQNuaWwBC3RyYW5zZmVyRmVlAQFpCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMJAQ5zdGFraW5nQWRkcmVzcwAFAWkJAQpxdW90ZUFzc2V0AAUDbmlsAQ5kb0J1cm5BcnRpZmFjdAINX2J1cm5BcnRpZmFjdAFpAwUNX2J1cm5BcnRpZmFjdAkAzAgCCQEEQnVybgIJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAggJAJEDAggFAWkIcGF5bWVudHMAAQdhc3NldElkAhBJbnZhbGlkIGFydGlmYWN0AAEFA25pbAUDbmlsFgFpAQVwYXVzZQADCQECIT0CCAUBaQZjYWxsZXIJAQxhZG1pbkFkZHJlc3MACQACAQIUSW52YWxpZCBwYXVzZSBwYXJhbXMJAMwIAgkBDEJvb2xlYW5FbnRyeQIFCGtfcGF1c2VkBgUDbmlsAWkBB3VucGF1c2UAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECFkludmFsaWQgdW5wYXVzZSBwYXJhbXMJAMwIAgkBDEJvb2xlYW5FbnRyeQIFCGtfcGF1c2VkBwUDbmlsAWkBDHNldENsb3NlT25seQADCQECIT0CCAUBaQZjYWxsZXIJAQxhZG1pbkFkZHJlc3MACQACAQIbSW52YWxpZCBzZXRDbG9zZU9ubHkgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQtrX2Nsb3NlT25seQYFA25pbAFpAQ51bnNldENsb3NlT25seQADCQECIT0CCAUBaQZjYWxsZXIJAQxhZG1pbkFkZHJlc3MACQACAQIdSW52YWxpZCB1bnNldENsb3NlT25seSBwYXJhbXMJAMwIAgkBDEJvb2xlYW5FbnRyeQIFC2tfY2xvc2VPbmx5BwUDbmlsAWkBDGFkZExpcXVpZGl0eQERX3F1b3RlQXNzZXRBbW91bnQDAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAYJAGcCAAAFEV9xdW90ZUFzc2V0QW1vdW50CQACAQIbSW52YWxpZCBhZGRMaXF1aWRpdHkgcGFyYW1zBAdfcXRBc3RSCQEGcXRBc3RSAAQHX2JzQXN0UgkBBmJzQXN0UgAEB19xdEFzdFcJAQZxdEFzdFcABAdfYnNBc3RXCQEGYnNBc3RXAAQFcHJpY2UJAQRkaXZkAgkBBG11bGQCBQdfcXRBc3RSBQdfcXRBc3RXCQEEbXVsZAIFB19ic0FzdFIFB19ic0FzdFcEC3F0QXN0UkFmdGVyCQBkAgUHX3F0QXN0UgURX3F1b3RlQXNzZXRBbW91bnQEFGJhc2VBc3NldEFtb3VudFRvQWRkCQBlAgkBBGRpdmQCCQEEbXVsZAIFC3F0QXN0UkFmdGVyBQdfcXRBc3RXBQVwcmljZQUHX2JzQXN0UgQLYnNBc3RSQWZ0ZXIJAGQCBQdfYnNBc3RSBRRiYXNlQXNzZXRBbW91bnRUb0FkZAQNJHQwNDkyNjM0OTQxNAkBFGdldFN5bmNUZXJtaW5hbFByaWNlAwkBDmdldE9yYWNsZVByaWNlAAULcXRBc3RSQWZ0ZXIFC2JzQXN0UkFmdGVyBBNuZXdRdW90ZUFzc2V0V2VpZ2h0CAUNJHQwNDkyNjM0OTQxNAJfMQQSbmV3QmFzZUFzc2V0V2VpZ2h0CAUNJHQwNDkyNjM0OTQxNAJfMgQNbWFyZ2luVG9WYXVsdAgFDSR0MDQ5MjYzNDk0MTQCXzMEDWRvRXhjaGFuZ2VQbkwDCQECIT0CBQ1tYXJnaW5Ub1ZhdWx0AAAEDWRvRXhjaGFuZ2VQbkwJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCBQ1tYXJnaW5Ub1ZhdWx0BQNuaWwFA25pbAMJAAACBQ1kb0V4Y2hhbmdlUG5MBQ1kb0V4Y2hhbmdlUG5MBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBQ1kb0V4Y2hhbmdlUG5MBQ1kb0V4Y2hhbmdlUG5MCQDOCAIJARF1cGRhdGVBbW1SZXNlcnZlcwIFC3F0QXN0UkFmdGVyBQtic0FzdFJBZnRlcgkBEHVwZGF0ZUFtbVdlaWdodHMCBRNuZXdRdW90ZUFzc2V0V2VpZ2h0BRJuZXdCYXNlQXNzZXRXZWlnaHQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEPcmVtb3ZlTGlxdWlkaXR5ARFfcXVvdGVBc3NldEFtb3VudAMDCQECIT0CCAUBaQZjYWxsZXIJAQxhZG1pbkFkZHJlc3MABgkAZwIFEV9xdW90ZUFzc2V0QW1vdW50AAAJAAIBAh5JbnZhbGlkIHJlbW92ZUxpcXVpZGl0eSBwYXJhbXMEB19xdEFzdFIJAQZxdEFzdFIABAdfYnNBc3RSCQEGYnNBc3RSAAQHX3F0QXN0VwkBBnF0QXN0VwAEB19ic0FzdFcJAQZic0FzdFcABAVwcmljZQkBBGRpdmQCCQEEbXVsZAIFB19xdEFzdFIFB19xdEFzdFcJAQRtdWxkAgUHX2JzQXN0UgUHX2JzQXN0VwQLcXRBc3RSQWZ0ZXIJAGUCBQdfcXRBc3RSBRFfcXVvdGVBc3NldEFtb3VudAQXYmFzZUFzc2V0QW1vdW50VG9SZW1vdmUJAQNhYnMBCQBlAgkBBGRpdmQCCQEEbXVsZAIFC3F0QXN0UkFmdGVyBQdfcXRBc3RXBQVwcmljZQUHX2JzQXN0UgQLYnNBc3RSQWZ0ZXIJAGUCBQdfYnNBc3RSBRdiYXNlQXNzZXRBbW91bnRUb1JlbW92ZQQNJHQwNTA1MTA1MDY2MQkBFGdldFN5bmNUZXJtaW5hbFByaWNlAwkBDmdldE9yYWNsZVByaWNlAAULcXRBc3RSQWZ0ZXIFC2JzQXN0UkFmdGVyBBNuZXdRdW90ZUFzc2V0V2VpZ2h0CAUNJHQwNTA1MTA1MDY2MQJfMQQSbmV3QmFzZUFzc2V0V2VpZ2h0CAUNJHQwNTA1MTA1MDY2MQJfMgQNbWFyZ2luVG9WYXVsdAgFDSR0MDUwNTEwNTA2NjECXzMEDWRvRXhjaGFuZ2VQbkwDCQECIT0CBQ1tYXJnaW5Ub1ZhdWx0AAAEDWRvRXhjaGFuZ2VQbkwJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCBQ1tYXJnaW5Ub1ZhdWx0BQNuaWwFA25pbAMJAAACBQ1kb0V4Y2hhbmdlUG5MBQ1kb0V4Y2hhbmdlUG5MBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBQ1kb0V4Y2hhbmdlUG5MBQ1kb0V4Y2hhbmdlUG5MCQDOCAIJARF1cGRhdGVBbW1SZXNlcnZlcwIFC3F0QXN0UkFmdGVyBQtic0FzdFJBZnRlcgkBEHVwZGF0ZUFtbVdlaWdodHMCBRNuZXdRdW90ZUFzc2V0V2VpZ2h0BRJuZXdCYXNlQXNzZXRXZWlnaHQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEOY2hhbmdlU2V0dGluZ3MOEF9pbml0TWFyZ2luUmF0aW8EX21tchRfbGlxdWlkYXRpb25GZWVSYXRpbw5fZnVuZGluZ1BlcmlvZARfZmVlDF9zcHJlYWRMaW1pdA9fbWF4UHJpY2VJbXBhY3QYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvD19tYXhQcmljZVNwcmVhZBBfbWF4T3Blbk5vdGlvbmFsFF9mZWVUb1N0YWtlcnNQZXJjZW50D19tYXhPcmFjbGVEZWxheQxfcm9sbG92ZXJGZWUMX2Z1bmRpbmdNb2RlAwMDAwMDAwMDAwMDAwMDAwMJAGcCAAAFDl9mdW5kaW5nUGVyaW9kBgkAZwIAAAUQX2luaXRNYXJnaW5SYXRpbwYJAGcCAAAFBF9tbXIGCQBnAgAABRRfbGlxdWlkYXRpb25GZWVSYXRpbwYJAGcCAAAFBF9mZWUGCQBnAgAABQxfc3ByZWFkTGltaXQGCQBnAgAABQ9fbWF4UHJpY2VJbXBhY3QGCQBnAgAABRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8GCQBnAgAABQ9fbWF4UHJpY2VTcHJlYWQGCQBnAgAABRBfbWF4T3Blbk5vdGlvbmFsBgkAZwIAAAUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQGCQBmAgUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQFDERFQ0lNQUxfVU5JVAYJAGcCAAAFD19tYXhPcmFjbGVEZWxheQYJAGcCAAAFDF9yb2xsb3ZlckZlZQYDCQECIT0CBQxfZnVuZGluZ01vZGUFEUZVTkRJTkdfU1lNTUVUUklDCQECIT0CBQxfZnVuZGluZ01vZGUFEkZVTkRJTkdfQVNZTU1FVFJJQwcGCQEBIQEJAQtpbml0aWFsaXplZAAGCQECIT0CCAUBaQZjYWxsZXIJAQxhZG1pbkFkZHJlc3MACQACAQIdSW52YWxpZCBjaGFuZ2VTZXR0aW5ncyBwYXJhbXMJAQ51cGRhdGVTZXR0aW5ncw4FEF9pbml0TWFyZ2luUmF0aW8FBF9tbXIFFF9saXF1aWRhdGlvbkZlZVJhdGlvBQ5fZnVuZGluZ1BlcmlvZAUEX2ZlZQUMX3NwcmVhZExpbWl0BQ9fbWF4UHJpY2VJbXBhY3QFGF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwUPX21heFByaWNlU3ByZWFkBRBfbWF4T3Blbk5vdGlvbmFsBRRfZmVlVG9TdGFrZXJzUGVyY2VudAUPX21heE9yYWNsZURlbGF5BQxfcm9sbG92ZXJGZWUFDF9mdW5kaW5nTW9kZQFpAQppbml0aWFsaXplEwdfcXRBc3RSB19ic0FzdFIOX2Z1bmRpbmdQZXJpb2QQX2luaXRNYXJnaW5SYXRpbwRfbW1yFF9saXF1aWRhdGlvbkZlZVJhdGlvBF9mZWUPX2Jhc2VPcmFjbGVEYXRhEF9xdW90ZU9yYWNsZURhdGEMX2Nvb3JkaW5hdG9yDF9zcHJlYWRMaW1pdA9fbWF4UHJpY2VJbXBhY3QYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvD19tYXhQcmljZVNwcmVhZBBfbWF4T3Blbk5vdGlvbmFsFF9mZWVUb1N0YWtlcnNQZXJjZW50D19tYXhPcmFjbGVEZWxheQxfcm9sbG92ZXJGZWUMX2Z1bmRpbmdNb2RlAwMDAwMDAwMDAwMDAwMDAwMDAwkAZwIAAAUHX3F0QXN0UgYJAGcCAAAFB19ic0FzdFIGCQBnAgAABQ5fZnVuZGluZ1BlcmlvZAYJAGcCAAAFEF9pbml0TWFyZ2luUmF0aW8GCQBnAgAABQRfbW1yBgkAZwIAAAUUX2xpcXVpZGF0aW9uRmVlUmF0aW8GCQBnAgAABQRfZmVlBgkAZwIAAAUMX3NwcmVhZExpbWl0BgkAZwIAAAUPX21heFByaWNlSW1wYWN0BgkAZwIAAAUYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvBgkAZwIAAAUPX21heFByaWNlU3ByZWFkBgkAZwIAAAUQX21heE9wZW5Ob3Rpb25hbAYJAGcCAAAFFF9mZWVUb1N0YWtlcnNQZXJjZW50BgkAZgIFFF9mZWVUb1N0YWtlcnNQZXJjZW50BQxERUNJTUFMX1VOSVQGCQBnAgAABQ9fbWF4T3JhY2xlRGVsYXkGCQBnAgAABQxfcm9sbG92ZXJGZWUGAwkBAiE9AgUMX2Z1bmRpbmdNb2RlBRFGVU5ESU5HX1NZTU1FVFJJQwkBAiE9AgUMX2Z1bmRpbmdNb2RlBRJGVU5ESU5HX0FTWU1NRVRSSUMHBgkBC2luaXRpYWxpemVkAAYJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECHUludmFsaWQgaW5pdGlhbGl6ZSBwYXJhbWV0ZXJzCQDOCAIJAM4IAgkAzggCCQDOCAIJAQl1cGRhdGVBbW0IBQdfcXRBc3RSBQdfYnNBc3RSAAAAAAAAAAAAAAAACQEOdXBkYXRlU2V0dGluZ3MOBRBfaW5pdE1hcmdpblJhdGlvBQRfbW1yBRRfbGlxdWlkYXRpb25GZWVSYXRpbwUOX2Z1bmRpbmdQZXJpb2QFBF9mZWUFDF9zcHJlYWRMaW1pdAUPX21heFByaWNlSW1wYWN0BRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8FD19tYXhQcmljZVNwcmVhZAUQX21heE9wZW5Ob3Rpb25hbAUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQFD19tYXhPcmFjbGVEZWxheQUMX3JvbGxvdmVyRmVlBQxfZnVuZGluZ01vZGUJAQ11cGRhdGVGdW5kaW5nBQkAZAIJAQ1sYXN0VGltZXN0YW1wAAUOX2Z1bmRpbmdQZXJpb2QAAAAAAAAAAAkBDXVwZGF0ZUJhbGFuY2UBAAAJAMwIAgkBDEJvb2xlYW5FbnRyeQIFDWtfaW5pdGlhbGl6ZWQGCQDMCAIJAQtTdHJpbmdFbnRyeQIFDGtfYmFzZU9yYWNsZQUPX2Jhc2VPcmFjbGVEYXRhCQDMCAIJAQtTdHJpbmdFbnRyeQIFDWtfcXVvdGVPcmFjbGUFEF9xdW90ZU9yYWNsZURhdGEJAMwIAgkBC1N0cmluZ0VudHJ5AgUUa19jb29yZGluYXRvckFkZHJlc3MJAKUIAQkBEUBleHRyTmF0aXZlKDEwNjIpAQUMX2Nvb3JkaW5hdG9yBQNuaWwBaQEQaW5jcmVhc2VQb3NpdGlvbgQKX2RpcmVjdGlvbglfbGV2ZXJhZ2UTX21pbkJhc2VBc3NldEFtb3VudAhfcmVmTGluawQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBBBlbnN1cmVDYWxsZWRPbmNlCQD8BwQFBHRoaXMCEGVuc3VyZUNhbGxlZE9uY2UFA25pbAUDbmlsAwkAAAIFEGVuc3VyZUNhbGxlZE9uY2UFEGVuc3VyZUNhbGxlZE9uY2UEB190cmFkZXIJAQ9nZXRBY3R1YWxDYWxsZXIBBQFpBApfcmF3QW1vdW50CAkAkQMCCAUBaQhwYXltZW50cwAABmFtb3VudAQIX2Fzc2V0SWQICQCRAwIIBQFpCHBheW1lbnRzAAAHYXNzZXRJZAQLX2Fzc2V0SWRTdHIJANgEAQkBBXZhbHVlAQUIX2Fzc2V0SWQEDGlzUXVvdGVBc3NldAkAAAIFCF9hc3NldElkCQEKcXVvdGVBc3NldAADAwMDAwMDAwMJAQIhPQIFCl9kaXJlY3Rpb24FCERJUl9MT05HCQECIT0CBQpfZGlyZWN0aW9uBQlESVJfU0hPUlQHBgkAZwIAAAUKX3Jhd0Ftb3VudAYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQEhAQUMaXNRdW90ZUFzc2V0BgkBASEBCQEWcmVxdWlyZU1vcmVNYXJnaW5SYXRpbwMJAQRkaXZkAgUMREVDSU1BTF9VTklUBQlfbGV2ZXJhZ2UJAQ9pbml0TWFyZ2luUmF0aW8ABgYJAQZwYXVzZWQABgkBCWNsb3NlT25seQAGCQEOaXNNYXJrZXRDbG9zZWQACQACAQIjSW52YWxpZCBpbmNyZWFzZVBvc2l0aW9uIHBhcmFtZXRlcnMEDSR0MDU2NzMxNTY4ODAJARhnZXRGb3JUcmFkZXJXaXRoQXJ0aWZhY3QCBQdfdHJhZGVyCQENZ2V0QXJ0aWZhY3RJZAEFAWkEC2FkanVzdGVkRmVlCAUNJHQwNTY3MzE1Njg4MAJfMQQMYnVybkFydGlmYWN0CAUNJHQwNTY3MzE1Njg4MAJfMgQHX2Ftb3VudAkBBGRpdmQCBQpfcmF3QW1vdW50CQBkAgkBBG11bGQCBQthZGp1c3RlZEZlZQUJX2xldmVyYWdlBQxERUNJTUFMX1VOSVQEE2Rpc3RyaWJ1dGVGZWVBbW91bnQJAGUCBQpfcmF3QW1vdW50BQdfYW1vdW50BA5yZWZlcnJlckZlZUFueQkA/AcECQEPcmVmZXJyYWxBZGRyZXNzAAIVYWNjZXB0UGF5bWVudFdpdGhMaW5rCQDMCAIFB190cmFkZXIJAMwIAgUIX3JlZkxpbmsFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABRNkaXN0cmlidXRlRmVlQW1vdW50BQNuaWwDCQAAAgUOcmVmZXJyZXJGZWVBbnkFDnJlZmVycmVyRmVlQW55BAtyZWZlcnJlckZlZQQHJG1hdGNoMAUOcmVmZXJyZXJGZWVBbnkDCQABAgUHJG1hdGNoMAIDSW50BAF4BQckbWF0Y2gwBQF4CQACAQITSW52YWxpZCByZWZlcnJlckZlZQQJZmVlQW1vdW50CQBlAgUTZGlzdHJpYnV0ZUZlZUFtb3VudAULcmVmZXJyZXJGZWUEDSR0MDU3Mzc2NTc1NDQJAQtnZXRQb3NpdGlvbgEFB190cmFkZXIED29sZFBvc2l0aW9uU2l6ZQgFDSR0MDU3Mzc2NTc1NDQCXzEEEW9sZFBvc2l0aW9uTWFyZ2luCAUNJHQwNTczNzY1NzU0NAJfMgQXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDA1NzM3NjU3NTQ0Al8zBBRvbGRQb3NpdGlvbkxzdFVwZENQRggFDSR0MDU3Mzc2NTc1NDQCXzQEFG9sZFBvc2l0aW9uVGltZXN0YW1wCAUNJHQwNTczNzY1NzU0NAJfNQQNaXNOZXdQb3NpdGlvbgkAAAIFD29sZFBvc2l0aW9uU2l6ZQAABA9pc1NhbWVEaXJlY3Rpb24DCQBmAgUPb2xkUG9zaXRpb25TaXplAAAJAAACBQpfZGlyZWN0aW9uBQhESVJfTE9ORwkAAAIFCl9kaXJlY3Rpb24FCURJUl9TSE9SVAQOZXhwYW5kRXhpc3RpbmcDCQEBIQEFDWlzTmV3UG9zaXRpb24FD2lzU2FtZURpcmVjdGlvbgcEBWlzQWRkCQAAAgUKX2RpcmVjdGlvbgUIRElSX0xPTkcEDSR0MDU3ODMzNjA5NTQDAwUNaXNOZXdQb3NpdGlvbgYFDmV4cGFuZEV4aXN0aW5nBAxvcGVuTm90aW9uYWwJAQRtdWxkAgUHX2Ftb3VudAUJX2xldmVyYWdlBA0kdDA1ODM0MjU4NTE1CQEJc3dhcElucHV0AgUFaXNBZGQFDG9wZW5Ob3Rpb25hbAQVYW1vdW50QmFzZUFzc2V0Qm91Z2h0CAUNJHQwNTgzNDI1ODUxNQJfMQQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDU4MzQyNTg1MTUCXzIEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDU4MzQyNTg1MTUCXzMEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDA1ODM0MjU4NTE1Al80AwMJAQIhPQIFE19taW5CYXNlQXNzZXRBbW91bnQAAAkAZgIFE19taW5CYXNlQXNzZXRBbW91bnQJAQNhYnMBBRVhbW91bnRCYXNlQXNzZXRCb3VnaHQHCQACAQkArAICCQCsAgIJAKwCAgINTGltaXQgZXJyb3I6IAkApAMBCQEDYWJzAQUVYW1vdW50QmFzZUFzc2V0Qm91Z2h0AgMgPCAJAKQDAQUTX21pbkJhc2VBc3NldEFtb3VudAQPbmV3UG9zaXRpb25TaXplCQBkAgUPb2xkUG9zaXRpb25TaXplBRVhbW91bnRCYXNlQXNzZXRCb3VnaHQEGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyCQBkAgkBEG9wZW5JbnRlcmVzdExvbmcAAwkAZgIFD25ld1Bvc2l0aW9uU2l6ZQAABQxvcGVuTm90aW9uYWwAAAQbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCQBkAgkBEW9wZW5JbnRlcmVzdFNob3J0AAMJAGYCAAAFD25ld1Bvc2l0aW9uU2l6ZQUMb3Blbk5vdGlvbmFsAAAEDSR0MDU5MDYxNTkzMzYJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQ9vbGRQb3NpdGlvblNpemUFEW9sZFBvc2l0aW9uTWFyZ2luBRRvbGRQb3NpdGlvbkxzdFVwZENQRgUUb2xkUG9zaXRpb25UaW1lc3RhbXAFB19hbW91bnQEDHJlbWFpbk1hcmdpbggFDSR0MDU5MDYxNTkzMzYCXzEEAngxCAUNJHQwNTkwNjE1OTMzNgJfMgQCeDIIBQ0kdDA1OTA2MTU5MzM2Al8zBAtyb2xsb3ZlckZlZQgFDSR0MDU5MDYxNTkzMzYCXzQDCQEBIQEJARlyZXF1aXJlTm90T3ZlclNwcmVhZExpbWl0AgUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCQACAQIVT3ZlciBtYXggc3ByZWFkIGxpbWl0AwkBASEBCQEdcmVxdWlyZU5vdE92ZXJNYXhPcGVuTm90aW9uYWwCBRp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcgUbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCQACAQIWT3ZlciBtYXggb3BlbiBub3Rpb25hbAkAoAoOBQ9uZXdQb3NpdGlvblNpemUFDHJlbWFpbk1hcmdpbgkAZAIFF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsBQxvcGVuTm90aW9uYWwJAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAQUPbmV3UG9zaXRpb25TaXplCQENbGFzdFRpbWVzdGFtcAAFFWJhc2VBc3NldFJlc2VydmVBZnRlcgUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUWdG90YWxQb3NpdGlvblNpemVBZnRlcgkAZAIJARRvcGVuSW50ZXJlc3ROb3Rpb25hbAAFDG9wZW5Ob3Rpb25hbAkAZAIJARV0b3RhbExvbmdQb3NpdGlvblNpemUAAwkAZgIFD25ld1Bvc2l0aW9uU2l6ZQAACQEDYWJzAQUVYW1vdW50QmFzZUFzc2V0Qm91Z2h0AAAJAGQCCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQADCQBmAgAABQ9uZXdQb3NpdGlvblNpemUJAQNhYnMBBRVhbW91bnRCYXNlQXNzZXRCb3VnaHQAAAUadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIFG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcgULcm9sbG92ZXJGZWUEDG9wZW5Ob3Rpb25hbAkBBG11bGQCBQdfYW1vdW50BQlfbGV2ZXJhZ2UEDSR0MDYwNjU0NjA3NzAJASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAIJAKUIAQgFAWkGY2FsbGVyBQ9QTkxfT1BUSU9OX1NQT1QEE29sZFBvc2l0aW9uTm90aW9uYWwIBQ0kdDA2MDY1NDYwNzcwAl8xBA11bnJlYWxpemVkUG5sCAUNJHQwNjA2NTQ2MDc3MAJfMgMJAGYCBRNvbGRQb3NpdGlvbk5vdGlvbmFsBQxvcGVuTm90aW9uYWwJAAIBAi5Vc2UgZGVjcmVhc2VQb3NpdGlvbiB0byBkZWNyZWFzZSBwb3NpdGlvbiBzaXplCQACAQIUQ2xvc2UgcG9zaXRpb24gZmlyc3QED25ld1Bvc2l0aW9uU2l6ZQgFDSR0MDU3ODMzNjA5NTQCXzEEF25ld1Bvc2l0aW9uUmVtYWluTWFyZ2luCAUNJHQwNTc4MzM2MDk1NAJfMgQXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDA1NzgzMzYwOTU0Al8zBBRuZXdQb3NpdGlvbkxhdGVzdENQRggFDSR0MDU3ODMzNjA5NTQCXzQEFG5ld1Bvc2l0aW9uVGltZXN0YW1wCAUNJHQwNTc4MzM2MDk1NAJfNQQVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNTc4MzM2MDk1NAJfNgQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDU3ODMzNjA5NTQCXzcEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDA1NzgzMzYwOTU0Al84BBlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyCAUNJHQwNTc4MzM2MDk1NAJfOQQOdG90YWxMb25nQWZ0ZXIIBQ0kdDA1NzgzMzYwOTU0A18xMAQPdG90YWxTaG9ydEFmdGVyCAUNJHQwNTc4MzM2MDk1NANfMTEEGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyCAUNJHQwNTc4MzM2MDk1NANfMTIEG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcggFDSR0MDU3ODMzNjA5NTQDXzEzBAtyb2xsb3ZlckZlZQgFDSR0MDU3ODMzNjA5NTQDXzE0BA0kdDA2MDk2MDYxMDMxCQENZGlzdHJpYnV0ZUZlZQEJAGQCBQlmZWVBbW91bnQFC3JvbGxvdmVyRmVlBAxmZWVUb1N0YWtlcnMIBQ0kdDA2MDk2MDYxMDMxAl8xBApmZWVUb1ZhdWx0CAUNJHQwNjA5NjA2MTAzMQJfMgQFc3Rha2UDCQBnAgUHX2Ftb3VudAULcm9sbG92ZXJGZWUJAPwHBAkBDHZhdWx0QWRkcmVzcwACCWFkZExvY2tlZAUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQEKcXVvdGVBc3NldAAJAGUCBQdfYW1vdW50BQtyb2xsb3ZlckZlZQUDbmlsCQD8BwQJAQx2YXVsdEFkZHJlc3MAAg53aXRoZHJhd0xvY2tlZAkAzAgCCQBlAgULcm9sbG92ZXJGZWUFB19hbW91bnQFA25pbAUDbmlsAwkAAAIFBXN0YWtlBQVzdGFrZQQMZGVwb3NpdFZhdWx0CQD8BwQJAQx2YXVsdEFkZHJlc3MAAgdhZGRGcmVlBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUKZmVlVG9WYXVsdAUDbmlsAwkAAAIFDGRlcG9zaXRWYXVsdAUMZGVwb3NpdFZhdWx0BAlub3RpZnlGZWUJAPwHBAkBDG1pbmVyQWRkcmVzcwACCm5vdGlmeUZlZXMJAMwIAgUHX3RyYWRlcgkAzAgCBQlmZWVBbW91bnQFA25pbAUDbmlsAwkAAAIFCW5vdGlmeUZlZQUJbm90aWZ5RmVlBA5ub3RpZnlOb3Rpb25hbAkA/AcECQEMbWluZXJBZGRyZXNzAAIObm90aWZ5Tm90aW9uYWwJAMwIAgUHX3RyYWRlcgkAzAgCBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUDbmlsBQNuaWwDCQAAAgUObm90aWZ5Tm90aW9uYWwFDm5vdGlmeU5vdGlvbmFsCQDOCAIJAM4IAgkAzggCCQDOCAIJAM4IAgkAzggCCQEOdXBkYXRlUG9zaXRpb24GBQdfdHJhZGVyBQ9uZXdQb3NpdGlvblNpemUFF25ld1Bvc2l0aW9uUmVtYWluTWFyZ2luBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUUbmV3UG9zaXRpb25MYXRlc3RDUEYFFG5ld1Bvc2l0aW9uVGltZXN0YW1wCQEfaW5jcmVtZW50UG9zaXRpb25TZXF1ZW5jZU51bWJlcgIFDWlzTmV3UG9zaXRpb24FB190cmFkZXIJARF1cGRhdGVQb3NpdGlvbkZlZQMFDWlzTmV3UG9zaXRpb24FB190cmFkZXIFC2FkanVzdGVkRmVlCQEJdXBkYXRlQW1tCAUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBRZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyBRlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyBQ50b3RhbExvbmdBZnRlcgUPdG90YWxTaG9ydEFmdGVyBRp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcgUbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCQELdHJhbnNmZXJGZWUBBQxmZWVUb1N0YWtlcnMJAQ11cGRhdGVCYWxhbmNlAQkAZQIJAGQCCQEIY2JhbGFuY2UABQdfYW1vdW50BQtyb2xsb3ZlckZlZQkBDmRvQnVybkFydGlmYWN0AgUMYnVybkFydGlmYWN0BQFpCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCWFkZE1hcmdpbgAEBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQQZW5zdXJlQ2FsbGVkT25jZQkA/AcEBQR0aGlzAhBlbnN1cmVDYWxsZWRPbmNlBQNuaWwFA25pbAMJAAACBRBlbnN1cmVDYWxsZWRPbmNlBRBlbnN1cmVDYWxsZWRPbmNlBAdfdHJhZGVyCQClCAEIBQFpBmNhbGxlcgQHX2Ftb3VudAgJAJEDAggFAWkIcGF5bWVudHMAAAZhbW91bnQECF9hc3NldElkCAkAkQMCCAUBaQhwYXltZW50cwAAB2Fzc2V0SWQEC19hc3NldElkU3RyCQDYBAEJAQV2YWx1ZQEFCF9hc3NldElkBAxpc1F1b3RlQXNzZXQJAAACBQhfYXNzZXRJZAkBCnF1b3RlQXNzZXQAAwMDAwMDCQEBIQEFDGlzUXVvdGVBc3NldAYJAQEhAQkBE3JlcXVpcmVPcGVuUG9zaXRpb24BCQClCAEIBQFpBmNhbGxlcgYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQZwYXVzZWQABgkBCWNsb3NlT25seQAGCQEOaXNNYXJrZXRDbG9zZWQACQACAQIcSW52YWxpZCBhZGRNYXJnaW4gcGFyYW1ldGVycwQNJHQwNjMyNDY2MzQxNAkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgQPb2xkUG9zaXRpb25TaXplCAUNJHQwNjMyNDY2MzQxNAJfMQQRb2xkUG9zaXRpb25NYXJnaW4IBQ0kdDA2MzI0NjYzNDE0Al8yBBdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDYzMjQ2NjM0MTQCXzMEFG9sZFBvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwNjMyNDY2MzQxNAJfNAQUb2xkUG9zaXRpb25UaW1lc3RhbXAIBQ0kdDA2MzI0NjYzNDE0Al81BAVzdGFrZQkA/AcECQEMdmF1bHRBZGRyZXNzAAIJYWRkTG9ja2VkBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUHX2Ftb3VudAUDbmlsAwkAAAIFBXN0YWtlBQVzdGFrZQQLcm9sbG92ZXJGZWUJAQ9jYWxjUm9sbG92ZXJGZWUCBRFvbGRQb3NpdGlvbk1hcmdpbgUUb2xkUG9zaXRpb25UaW1lc3RhbXAEFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMDCQBmAgULcm9sbG92ZXJGZWUAAAQNJHQwNjM2OTk2Mzc1OAkBDWRpc3RyaWJ1dGVGZWUBBQtyb2xsb3ZlckZlZQQMZmVlVG9TdGFrZXJzCAUNJHQwNjM2OTk2Mzc1OAJfMQQKZmVlVG9WYXVsdAgFDSR0MDYzNjk5NjM3NTgCXzIEB3Vuc3Rha2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACDndpdGhkcmF3TG9ja2VkCQDMCAIFDGZlZVRvU3Rha2VycwUDbmlsBQNuaWwDCQAAAgUHdW5zdGFrZQUHdW5zdGFrZQQLbG9ja0JhZERlYnQJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCCQEBLQEFCmZlZVRvVmF1bHQFA25pbAUDbmlsAwkAAAIFC2xvY2tCYWREZWJ0BQtsb2NrQmFkRGVidAkBC3RyYW5zZmVyRmVlAQUMZmVlVG9TdGFrZXJzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwkAzggCCQDOCAIJAQ51cGRhdGVQb3NpdGlvbgYFB190cmFkZXIFD29sZFBvc2l0aW9uU2l6ZQkAZAIJAGUCBRFvbGRQb3NpdGlvbk1hcmdpbgULcm9sbG92ZXJGZWUFB19hbW91bnQFF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsBRRvbGRQb3NpdGlvbkxzdFVwZENQRgkBDWxhc3RUaW1lc3RhbXAACQENdXBkYXRlQmFsYW5jZQEJAGUCCQBkAgkBCGNiYWxhbmNlAAUHX2Ftb3VudAULcm9sbG92ZXJGZWUFFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEMcmVtb3ZlTWFyZ2luAQdfYW1vdW50BARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEEGVuc3VyZUNhbGxlZE9uY2UJAPwHBAUEdGhpcwIQZW5zdXJlQ2FsbGVkT25jZQUDbmlsBQNuaWwDCQAAAgUQZW5zdXJlQ2FsbGVkT25jZQUQZW5zdXJlQ2FsbGVkT25jZQQHX3RyYWRlcgkApQgBCAUBaQZjYWxsZXIDAwMDAwkAZwIAAAUHX2Ftb3VudAYJAQEhAQkBE3JlcXVpcmVPcGVuUG9zaXRpb24BBQdfdHJhZGVyBgkBASEBCQELaW5pdGlhbGl6ZWQABgkBBnBhdXNlZAAGCQEOaXNNYXJrZXRDbG9zZWQACQACAQIfSW52YWxpZCByZW1vdmVNYXJnaW4gcGFyYW1ldGVycwQNJHQwNjUxMzE2NTI5OQkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgQPb2xkUG9zaXRpb25TaXplCAUNJHQwNjUxMzE2NTI5OQJfMQQRb2xkUG9zaXRpb25NYXJnaW4IBQ0kdDA2NTEzMTY1Mjk5Al8yBBdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDY1MTMxNjUyOTkCXzMEFG9sZFBvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwNjUxMzE2NTI5OQJfNAQUb2xkUG9zaXRpb25UaW1lc3RhbXAIBQ0kdDA2NTEzMTY1Mjk5Al81BA0kdDA2NTMwNTY1NTU0CQEwY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudEFuZFJvbGxvdmVyRmVlBQUPb2xkUG9zaXRpb25TaXplBRFvbGRQb3NpdGlvbk1hcmdpbgUUb2xkUG9zaXRpb25Mc3RVcGRDUEYFFG9sZFBvc2l0aW9uVGltZXN0YW1wCQEBLQEFB19hbW91bnQEDHJlbWFpbk1hcmdpbggFDSR0MDY1MzA1NjU1NTQCXzEEB2JhZERlYnQIBQ0kdDA2NTMwNTY1NTU0Al8yBA5mdW5kaW5nUGF5bWVudAgFDSR0MDY1MzA1NjU1NTQCXzMEC3JvbGxvdmVyRmVlCAUNJHQwNjUzMDU2NTU1NAJfNAMJAQIhPQIFB2JhZERlYnQAAAkAAgECHUludmFsaWQgcmVtb3ZlZCBtYXJnaW4gYW1vdW50BAttYXJnaW5SYXRpbwkBD2NhbGNNYXJnaW5SYXRpbwMFDHJlbWFpbk1hcmdpbgUHYmFkRGVidAUXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwDCQEBIQEJARZyZXF1aXJlTW9yZU1hcmdpblJhdGlvAwULbWFyZ2luUmF0aW8JAQ9pbml0TWFyZ2luUmF0aW8ABgkAAgEJAKwCAgkArAICCQCsAgICGVRvbyBtdWNoIG1hcmdpbiByZW1vdmVkOiAJAKQDAQULbWFyZ2luUmF0aW8CAyA8IAkApAMBCQEPaW5pdE1hcmdpblJhdGlvAAQNJHQwNjU5NDA2NTk5OQkBDWRpc3RyaWJ1dGVGZWUBBQtyb2xsb3ZlckZlZQQMZmVlVG9TdGFrZXJzCAUNJHQwNjU5NDA2NTk5OQJfMQQKZmVlVG9WYXVsdAgFDSR0MDY1OTQwNjU5OTkCXzIEFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMDCQBmAgULcm9sbG92ZXJGZWUAAAQLbG9ja0JhZERlYnQJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCCQEBLQEFCmZlZVRvVmF1bHQFA25pbAUDbmlsAwkAAAIFC2xvY2tCYWREZWJ0BQtsb2NrQmFkRGVidAkBC3RyYW5zZmVyRmVlAQUMZmVlVG9TdGFrZXJzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwQHdW5zdGFrZQkA/AcECQEMdmF1bHRBZGRyZXNzAAIOd2l0aGRyYXdMb2NrZWQJAMwIAgkAZAIFB19hbW91bnQFDGZlZVRvU3Rha2VycwUDbmlsBQNuaWwDCQAAAgUHdW5zdGFrZQUHdW5zdGFrZQkAzggCCQDOCAIJAM4IAgkBDnVwZGF0ZVBvc2l0aW9uBgUHX3RyYWRlcgUPb2xkUG9zaXRpb25TaXplBQxyZW1haW5NYXJnaW4FF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCQEfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEFD29sZFBvc2l0aW9uU2l6ZQkBDWxhc3RUaW1lc3RhbXAACQEId2l0aGRyYXcCCAUBaQZjYWxsZXIFB19hbW91bnQJAQ11cGRhdGVCYWxhbmNlAQkAZQIJAGUCCQEIY2JhbGFuY2UABQdfYW1vdW50BQtyb2xsb3ZlckZlZQUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ1jbG9zZVBvc2l0aW9uAwVfc2l6ZRRfbWluUXVvdGVBc3NldEFtb3VudAxfYWRkVG9NYXJnaW4EBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQQZW5zdXJlQ2FsbGVkT25jZQkA/AcEBQR0aGlzAhBlbnN1cmVDYWxsZWRPbmNlBQNuaWwFA25pbAMJAAACBRBlbnN1cmVDYWxsZWRPbmNlBRBlbnN1cmVDYWxsZWRPbmNlBAdfdHJhZGVyCQEPZ2V0QWN0dWFsQ2FsbGVyAQUBaQQOX3RyYWRlckFkZHJlc3MJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBBQdfdHJhZGVyAg5JbnZhbGlkIGNhbGxlcgQLcG9zaXRpb25GZWUJAQ5nZXRQb3NpdGlvbkZlZQEFB190cmFkZXIDAwMDAwMJAQEhAQkBE3JlcXVpcmVPcGVuUG9zaXRpb24BBQdfdHJhZGVyBgkBASEBCQELaW5pdGlhbGl6ZWQABgkBBnBhdXNlZAAGCQBnAgAABQVfc2l6ZQYJAGYCAAAFFF9taW5RdW90ZUFzc2V0QW1vdW50BgkBDmlzTWFya2V0Q2xvc2VkAAkAAgECIEludmFsaWQgY2xvc2VQb3NpdGlvbiBwYXJhbWV0ZXJzBBRvbGRQb3NpdGlvblRpbWVzdGFtcAgJAQtnZXRQb3NpdGlvbgEFB190cmFkZXICXzUEDSR0MDY4MTc0Njg3NTkJARVpbnRlcm5hbENsb3NlUG9zaXRpb24HBQdfdHJhZGVyBQVfc2l6ZQULcG9zaXRpb25GZWUFFF9taW5RdW90ZUFzc2V0QW1vdW50BQxfYWRkVG9NYXJnaW4GBgQPbmV3UG9zaXRpb25TaXplCAUNJHQwNjgxNzQ2ODc1OQJfMQQRbmV3UG9zaXRpb25NYXJnaW4IBQ0kdDA2ODE3NDY4NzU5Al8yBBduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDY4MTc0Njg3NTkCXzMEFG5ld1Bvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwNjgxNzQ2ODc1OQJfNAQPcG9zaXRpb25CYWREZWJ0CAUNJHQwNjgxNzQ2ODc1OQJfNQQLcmVhbGl6ZWRQbmwIBQ0kdDA2ODE3NDY4NzU5Al82BA5tYXJnaW5Ub1RyYWRlcggFDSR0MDY4MTc0Njg3NTkCXzcEFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA2ODE3NDY4NzU5Al84BBViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA2ODE3NDY4NzU5Al85BBZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCAUNJHQwNjgxNzQ2ODc1OQNfMTAEGW9wZW5JbnRlcmVzdE5vdGlvbmFsQWZ0ZXIIBQ0kdDA2ODE3NDY4NzU5A18xMQQOdG90YWxMb25nQWZ0ZXIIBQ0kdDA2ODE3NDY4NzU5A18xMgQPdG90YWxTaG9ydEFmdGVyCAUNJHQwNjgxNzQ2ODc1OQNfMTMEGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyCAUNJHQwNjgxNzQ2ODc1OQNfMTQEG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcggFDSR0MDY4MTc0Njg3NTkDXzE1BAtyZWFsaXplZEZlZQgFDSR0MDY4MTc0Njg3NTkDXzE2AwkAZgIFD3Bvc2l0aW9uQmFkRGVidAAACQACAQIqSW52YWxpZCBjbG9zZVBvc2l0aW9uIHBhcmFtZXRlcnM6IGJhZCBkZWJ0AwkAZwIFFG9sZFBvc2l0aW9uVGltZXN0YW1wCQENbGFzdFRpbWVzdGFtcAAJAAIBAlNJbnZhbGlkIGNsb3NlUG9zaXRpb24gcGFyYW1ldGVyczogd2FpdCBhdCBsZWFzdCAxIGJsb2NrIGJlZm9yZSBjbG9zaW5nIHRoZSBwb3NpdGlvbgQOaXNQYXJ0aWFsQ2xvc2UJAQIhPQIFD25ld1Bvc2l0aW9uU2l6ZQAABA53aXRoZHJhd0Ftb3VudAkAZAIFDm1hcmdpblRvVHJhZGVyBQtyZWFsaXplZEZlZQQKYW1tQmFsYW5jZQkAZQIJAQhjYmFsYW5jZQAFDndpdGhkcmF3QW1vdW50BA1hbW1OZXdCYWxhbmNlAwkAZgIAAAUKYW1tQmFsYW5jZQAABQphbW1CYWxhbmNlBAd1bnN0YWtlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAg53aXRoZHJhd0xvY2tlZAkAzAgCBQ53aXRoZHJhd0Ftb3VudAUDbmlsBQNuaWwDCQAAAgUHdW5zdGFrZQUHdW5zdGFrZQQNJHQwNjk0MzE2OTQ5MAkBDWRpc3RyaWJ1dGVGZWUBBQtyZWFsaXplZEZlZQQMZmVlVG9TdGFrZXJzCAUNJHQwNjk0MzE2OTQ5MAJfMQQKZmVlVG9WYXVsdAgFDSR0MDY5NDMxNjk0OTACXzIEDGRlcG9zaXRWYXVsdAkA/AcECQEMdmF1bHRBZGRyZXNzAAIHYWRkRnJlZQUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQEKcXVvdGVBc3NldAAFCmZlZVRvVmF1bHQFA25pbAMJAAACBQxkZXBvc2l0VmF1bHQFDGRlcG9zaXRWYXVsdAQJbm90aWZ5RmVlCQD8BwQJAQxtaW5lckFkZHJlc3MAAgpub3RpZnlGZWVzCQDMCAIFB190cmFkZXIJAMwIAgULcmVhbGl6ZWRGZWUFA25pbAUDbmlsAwkAAAIFCW5vdGlmeUZlZQUJbm90aWZ5RmVlBA5ub3RpZnlOb3Rpb25hbAkA/AcECQEMbWluZXJBZGRyZXNzAAIObm90aWZ5Tm90aW9uYWwJAMwIAgUHX3RyYWRlcgkAzAgCBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUDbmlsBQNuaWwDCQAAAgUObm90aWZ5Tm90aW9uYWwFDm5vdGlmeU5vdGlvbmFsCQDOCAIJAM4IAgkAzggCCQDOCAIDBQ5pc1BhcnRpYWxDbG9zZQkBDnVwZGF0ZVBvc2l0aW9uBgUHX3RyYWRlcgUPbmV3UG9zaXRpb25TaXplBRFuZXdQb3NpdGlvbk1hcmdpbgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFFG5ld1Bvc2l0aW9uTHN0VXBkQ1BGCQENbGFzdFRpbWVzdGFtcAAJAQ5kZWxldGVQb3NpdGlvbgEFB190cmFkZXIJAQl1cGRhdGVBbW0IBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIFGW9wZW5JbnRlcmVzdE5vdGlvbmFsQWZ0ZXIFDnRvdGFsTG9uZ0FmdGVyBQ90b3RhbFNob3J0QWZ0ZXIFGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyBRt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIDCQBmAgUObWFyZ2luVG9UcmFkZXIAAAkBCHdpdGhkcmF3AgUOX3RyYWRlckFkZHJlc3MFDm1hcmdpblRvVHJhZGVyBQNuaWwJAQ11cGRhdGVCYWxhbmNlAQUNYW1tTmV3QmFsYW5jZQkBC3RyYW5zZmVyRmVlAQUMZmVlVG9TdGFrZXJzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCWxpcXVpZGF0ZQEHX3RyYWRlcgQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBA9zcG90TWFyZ2luUmF0aW8JARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAgUHX3RyYWRlcgUPUE5MX09QVElPTl9TUE9UBBZsaXF1aWRhdGlvbk1hcmdpblJhdGlvAwkBFmlzT3ZlckZsdWN0dWF0aW9uTGltaXQABBFvcmFjbGVNYXJnaW5SYXRpbwkBFmdldE1hcmdpblJhdGlvQnlPcHRpb24CBQdfdHJhZGVyBRFQTkxfT1BUSU9OX09SQUNMRQkBBHZtYXgCBQ9zcG90TWFyZ2luUmF0aW8FEW9yYWNsZU1hcmdpblJhdGlvBQ9zcG90TWFyZ2luUmF0aW8DAwMDAwkBASEBCQEWcmVxdWlyZU1vcmVNYXJnaW5SYXRpbwMFFmxpcXVpZGF0aW9uTWFyZ2luUmF0aW8JARZtYWludGVuYW5jZU1hcmdpblJhdGlvAAcGCQEBIQEJARNyZXF1aXJlT3BlblBvc2l0aW9uAQUHX3RyYWRlcgYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQZwYXVzZWQABgkBDmlzTWFya2V0Q2xvc2VkAAkAAgECE1VuYWJsZSB0byBsaXF1aWRhdGUEFGlzUGFydGlhbExpcXVpZGF0aW9uAwMJAGYCBQ9zcG90TWFyZ2luUmF0aW8JARNsaXF1aWRhdGlvbkZlZVJhdGlvAAkAZgIJARdwYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwAAAAcJAGYCBQxERUNJTUFMX1VOSVQJARdwYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwAHBA9vbGRQb3NpdGlvblNpemUICQELZ2V0UG9zaXRpb24BBQdfdHJhZGVyAl8xBA9wb3NpdGlvblNpemVBYnMJAQNhYnMBBQ9vbGRQb3NpdGlvblNpemUEDSR0MDcxOTExNzIyMzQDBRRpc1BhcnRpYWxMaXF1aWRhdGlvbgQPbGlxdWlkYXRpb25TaXplCQEbZ2V0UGFydGlhbExpcXVpZGF0aW9uQW1vdW50AgUHX3RyYWRlcgUPb2xkUG9zaXRpb25TaXplBBBsaXF1aWRhdGlvblJhdGlvCQEEZGl2ZAIJAQNhYnMBBQ9saXF1aWRhdGlvblNpemUFD3Bvc2l0aW9uU2l6ZUFicwkAlAoCBRBsaXF1aWRhdGlvblJhdGlvCQEDYWJzAQUPbGlxdWlkYXRpb25TaXplCQCUCgIAAAUPcG9zaXRpb25TaXplQWJzBBBsaXF1aWRhdGlvblJhdGlvCAUNJHQwNzE5MTE3MjIzNAJfMQQPbGlxdWlkYXRpb25TaXplCAUNJHQwNzE5MTE3MjIzNAJfMgQNJHQwNzIyNDA3Mjg3OAkBFWludGVybmFsQ2xvc2VQb3NpdGlvbgcFB190cmFkZXIDBRRpc1BhcnRpYWxMaXF1aWRhdGlvbgUPbGlxdWlkYXRpb25TaXplBQ9wb3NpdGlvblNpemVBYnMJARNsaXF1aWRhdGlvbkZlZVJhdGlvAAAABgcGBA9uZXdQb3NpdGlvblNpemUIBQ0kdDA3MjI0MDcyODc4Al8xBBFuZXdQb3NpdGlvbk1hcmdpbggFDSR0MDcyMjQwNzI4NzgCXzIEF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNzIyNDA3Mjg3OAJfMwQUbmV3UG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA3MjI0MDcyODc4Al80BA9wb3NpdGlvbkJhZERlYnQIBQ0kdDA3MjI0MDcyODc4Al81BAtyZWFsaXplZFBubAgFDSR0MDcyMjQwNzI4NzgCXzYEDm1hcmdpblRvVHJhZGVyCAUNJHQwNzIyNDA3Mjg3OAJfNwQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDcyMjQwNzI4NzgCXzgEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDcyMjQwNzI4NzgCXzkEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDA3MjI0MDcyODc4A18xMAQZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcggFDSR0MDcyMjQwNzI4NzgDXzExBA50b3RhbExvbmdBZnRlcggFDSR0MDcyMjQwNzI4NzgDXzEyBA90b3RhbFNob3J0QWZ0ZXIIBQ0kdDA3MjI0MDcyODc4A18xMwQadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA3MjI0MDcyODc4A18xNAQbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCAUNJHQwNzIyNDA3Mjg3OANfMTUEEmxpcXVpZGF0aW9uUGVuYWx0eQgFDSR0MDcyMjQwNzI4NzgDXzE2BA9mZWVUb0xpcXVpZGF0b3IJAGkCBRJsaXF1aWRhdGlvblBlbmFsdHkAAgQKZmVlVG9WYXVsdAkAZQIFEmxpcXVpZGF0aW9uUGVuYWx0eQUPZmVlVG9MaXF1aWRhdG9yBAphbW1CYWxhbmNlCQBlAgkBCGNiYWxhbmNlAAUSbGlxdWlkYXRpb25QZW5hbHR5BA1uZXdBbW1CYWxhbmNlAwkAZgIAAAUKYW1tQmFsYW5jZQAABQphbW1CYWxhbmNlBAtsb2NrQmFkRGVidAMJAGYCBQ9wb3NpdGlvbkJhZERlYnQAAAQLbG9ja0JhZERlYnQJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCCQBkAgUPcG9zaXRpb25CYWREZWJ0BRJsaXF1aWRhdGlvblBlbmFsdHkFA25pbAUDbmlsAwkAAAIFC2xvY2tCYWREZWJ0BQtsb2NrQmFkRGVidAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgULbG9ja0JhZERlYnQFC2xvY2tCYWREZWJ0BAd1bnN0YWtlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAg53aXRoZHJhd0xvY2tlZAkAzAgCBRJsaXF1aWRhdGlvblBlbmFsdHkFA25pbAUDbmlsAwkAAAIFB3Vuc3Rha2UFB3Vuc3Rha2UEEGRlcG9zaXRJbnN1cmFuY2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACB2FkZEZyZWUFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQpmZWVUb1ZhdWx0BQNuaWwDCQAAAgUQZGVwb3NpdEluc3VyYW5jZQUQZGVwb3NpdEluc3VyYW5jZQQObm90aWZ5Tm90aW9uYWwJAPwHBAkBDG1pbmVyQWRkcmVzcwACDm5vdGlmeU5vdGlvbmFsCQDMCAIFB190cmFkZXIJAMwIAgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFA25pbAUDbmlsAwkAAAIFDm5vdGlmeU5vdGlvbmFsBQ5ub3RpZnlOb3Rpb25hbAkAzggCCQDOCAIJAM4IAgMFFGlzUGFydGlhbExpcXVpZGF0aW9uCQEOdXBkYXRlUG9zaXRpb24GBQdfdHJhZGVyBQ9uZXdQb3NpdGlvblNpemUFEW5ld1Bvc2l0aW9uTWFyZ2luBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUUbmV3UG9zaXRpb25Mc3RVcGRDUEYJAQ1sYXN0VGltZXN0YW1wAAkBDmRlbGV0ZVBvc2l0aW9uAQUHX3RyYWRlcgkBCXVwZGF0ZUFtbQgFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgUWdG90YWxQb3NpdGlvblNpemVBZnRlcgUZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcgUOdG90YWxMb25nQWZ0ZXIFD3RvdGFsU2hvcnRBZnRlcgUadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIFG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcgkBCHdpdGhkcmF3AggFAWkGY2FsbGVyBQ9mZWVUb0xpcXVpZGF0b3IJAQ11cGRhdGVCYWxhbmNlAQUNbmV3QW1tQmFsYW5jZQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQpwYXlGdW5kaW5nAAQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBBVmdW5kaW5nQmxvY2tUaW1lc3RhbXAJARluZXh0RnVuZGluZ0Jsb2NrVGltZXN0YW1wAAMDAwkAZgIFFWZ1bmRpbmdCbG9ja1RpbWVzdGFtcAkBDWxhc3RUaW1lc3RhbXAABgkBASEBCQELaW5pdGlhbGl6ZWQABgkBBnBhdXNlZAAJAAIBCQCsAgIJAKwCAgkArAICAiFJbnZhbGlkIGZ1bmRpbmcgYmxvY2sgdGltZXN0YW1wOiAJAKQDAQkBDWxhc3RUaW1lc3RhbXAAAgMgPCAJAKQDAQUVZnVuZGluZ0Jsb2NrVGltZXN0YW1wBA91bmRlcmx5aW5nUHJpY2UJAQ5nZXRPcmFjbGVQcmljZQAEDSR0MDc0OTkxNzUwNjkJAQpnZXRGdW5kaW5nAAQUc2hvcnRQcmVtaXVtRnJhY3Rpb24IBQ0kdDA3NDk5MTc1MDY5Al8xBBNsb25nUHJlbWl1bUZyYWN0aW9uCAUNJHQwNzQ5OTE3NTA2OQJfMgQOcHJlbWl1bVRvVmF1bHQIBQ0kdDA3NDk5MTc1MDY5Al8zBBNkb1BheUZ1bmRpbmdUb1ZhdWx0AwkAZgIFDnByZW1pdW1Ub1ZhdWx0AAAEE2RvUGF5RnVuZGluZ1RvVmF1bHQJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCCQEBLQEFDnByZW1pdW1Ub1ZhdWx0BQNuaWwFA25pbAMJAAACBRNkb1BheUZ1bmRpbmdUb1ZhdWx0BRNkb1BheUZ1bmRpbmdUb1ZhdWx0BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBRNkb1BheUZ1bmRpbmdUb1ZhdWx0BRNkb1BheUZ1bmRpbmdUb1ZhdWx0CQENdXBkYXRlRnVuZGluZwUJAGQCBRVmdW5kaW5nQmxvY2tUaW1lc3RhbXAJARRmdW5kaW5nUGVyaW9kU2Vjb25kcwAJAGQCCQEjbGF0ZXN0TG9uZ0N1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24ABRNsb25nUHJlbWl1bUZyYWN0aW9uCQBkAgkBJGxhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgAFFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEEZGl2ZAIFE2xvbmdQcmVtaXVtRnJhY3Rpb24FD3VuZGVybHlpbmdQcmljZQkBBGRpdmQCBRRzaG9ydFByZW1pdW1GcmFjdGlvbgUPdW5kZXJseWluZ1ByaWNlCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUABAdfcXRBc3RSCQEGcXRBc3RSAAQHX2JzQXN0UgkBBmJzQXN0UgAEDSR0MDc2MTIwNzY0ODYJARRnZXRTeW5jVGVybWluYWxQcmljZQMJAQ5nZXRPcmFjbGVQcmljZQAFB19xdEFzdFIFB19ic0FzdFIEE25ld1F1b3RlQXNzZXRXZWlnaHQIBQ0kdDA3NjEyMDc2NDg2Al8xBBJuZXdCYXNlQXNzZXRXZWlnaHQIBQ0kdDA3NjEyMDc2NDg2Al8yBA1tYXJnaW5Ub1ZhdWx0CAUNJHQwNzYxMjA3NjQ4NgJfMwQQbWFyZ2luVG9WYXVsdEFkagMDCQBmAgAABQ1tYXJnaW5Ub1ZhdWx0CQBmAgkBA2FicwEFDW1hcmdpblRvVmF1bHQJAQhjYmFsYW5jZQAHCQEBLQEJAQhjYmFsYW5jZQAFDW1hcmdpblRvVmF1bHQEDWRvRXhjaGFuZ2VQbkwDCQECIT0CBRBtYXJnaW5Ub1ZhdWx0QWRqAAAEDWRvRXhjaGFuZ2VQbkwJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCBRBtYXJnaW5Ub1ZhdWx0QWRqBQNuaWwFA25pbAMJAAACBQ1kb0V4Y2hhbmdlUG5MBQ1kb0V4Y2hhbmdlUG5MBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBQ1kb0V4Y2hhbmdlUG5MBQ1kb0V4Y2hhbmdlUG5MCQDOCAIJAQ11cGRhdGVCYWxhbmNlAQkAZAIJAQhjYmFsYW5jZQAFEG1hcmdpblRvVmF1bHRBZGoJARB1cGRhdGVBbW1XZWlnaHRzAgUTbmV3UXVvdGVBc3NldFdlaWdodAUSbmV3QmFzZUFzc2V0V2VpZ2h0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBEGVuc3VyZUNhbGxlZE9uY2UAAwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIiSW52YWxpZCBzYXZlQ3VycmVudFR4SWQgcGFyYW1ldGVycwQGbGFzdFR4CQELdmFsdWVPckVsc2UCCQCdCAIFBHRoaXMFCGtfbGFzdFR4AgADCQECIT0CBQZsYXN0VHgJANgEAQgFAWkNdHJhbnNhY3Rpb25JZAkAzAgCCQELU3RyaW5nRW50cnkCBQhrX2xhc3RUeAUGbGFzdFR4BQNuaWwJAAIBAilDYW4gbm90IGNhbGwgdkFNTSBtZXRob2RzIHR3aWNlIGluIG9uZSB0eAFpASd2aWV3X2NhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnQBB190cmFkZXIEBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQNJHQwNzgwMzU3ODE1OQkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgQMcG9zaXRpb25TaXplCAUNJHQwNzgwMzU3ODE1OQJfMQQOcG9zaXRpb25NYXJnaW4IBQ0kdDA3ODAzNTc4MTU5Al8yBANwb24IBQ0kdDA3ODAzNTc4MTU5Al8zBBFwb3NpdGlvbkxzdFVwZENQRggFDSR0MDc4MDM1NzgxNTkCXzQEEXBvc2l0aW9uVGltZXN0YW1wCAUNJHQwNzgwMzU3ODE1OQJfNQQNJHQwNzgxNjI3ODI2MwkBI2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sAgUHX3RyYWRlcgUPUE5MX09QVElPTl9TUE9UBBBwb3NpdGlvbk5vdGlvbmFsCAUNJHQwNzgxNjI3ODI2MwJfMQQNdW5yZWFsaXplZFBubAgFDSR0MDc4MTYyNzgyNjMCXzIEDSR0MDc4MjY2Nzg0OTAJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQxwb3NpdGlvblNpemUFDnBvc2l0aW9uTWFyZ2luBRFwb3NpdGlvbkxzdFVwZENQRgURcG9zaXRpb25UaW1lc3RhbXAFDXVucmVhbGl6ZWRQbmwEDHJlbWFpbk1hcmdpbggFDSR0MDc4MjY2Nzg0OTACXzEEB2JhZERlYnQIBQ0kdDA3ODI2Njc4NDkwAl8yBA5mdW5kaW5nUGF5bWVudAgFDSR0MDc4MjY2Nzg0OTACXzMEC3JvbGxvdmVyRmVlCAUNJHQwNzgyNjY3ODQ5MAJfNAkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAQFzAQUMcmVtYWluTWFyZ2luCQEBcwEFDmZ1bmRpbmdQYXltZW50CQEBcwEJAQ5nZXRNYXJnaW5SYXRpbwEFB190cmFkZXIJAQFzAQUNdW5yZWFsaXplZFBubAkBAXMBBQdiYWREZWJ0CQEBcwEFEHBvc2l0aW9uTm90aW9uYWwJAQFzAQULcm9sbG92ZXJGZWUJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEVdmlld19nZXRQZWdBZGp1c3RDb3N0AQZfcHJpY2UEB19xdEFzdFIJAQZxdEFzdFIABAdfYnNBc3RSCQEGYnNBc3RSAAQGcmVzdWx0CQEUZ2V0U3luY1Rlcm1pbmFsUHJpY2UDBQZfcHJpY2UFB19xdEFzdFIFB19ic0FzdFIJAAIBCQCkAwEIBQZyZXN1bHQCXzMBaQEYdmlld19nZXRUZXJtaW5hbEFtbVByaWNlAAQNJHQwNzkyMTM3OTI5NAkBE2dldFRlcm1pbmFsQW1tU3RhdGUABBl0ZXJtaW5hbFF1b3RlQXNzZXRSZXNlcnZlCAUNJHQwNzkyMTM3OTI5NAJfMQQYdGVybWluYWxCYXNlQXNzZXRSZXNlcnZlCAUNJHQwNzkyMTM3OTI5NAJfMgQFcHJpY2UJAQRkaXZkAgkBBG11bGQCBRl0ZXJtaW5hbFF1b3RlQXNzZXRSZXNlcnZlCQEGcXRBc3RXAAkBBG11bGQCBRh0ZXJtaW5hbEJhc2VBc3NldFJlc2VydmUJAQZic0FzdFcACQACAQkApAMBBQVwcmljZQFpAQ92aWV3X2dldEZ1bmRpbmcABARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMED3VuZGVybHlpbmdQcmljZQkBDmdldE9yYWNsZVByaWNlAAQNJHQwNzk4NTM3OTkzMQkBCmdldEZ1bmRpbmcABBRzaG9ydFByZW1pdW1GcmFjdGlvbggFDSR0MDc5ODUzNzk5MzECXzEEE2xvbmdQcmVtaXVtRnJhY3Rpb24IBQ0kdDA3OTg1Mzc5OTMxAl8yBA5wcmVtaXVtVG9WYXVsdAgFDSR0MDc5ODUzNzk5MzECXzMEC2xvbmdGdW5kaW5nCQEEZGl2ZAIFE2xvbmdQcmVtaXVtRnJhY3Rpb24FD3VuZGVybHlpbmdQcmljZQQMc2hvcnRGdW5kaW5nCQEEZGl2ZAIFFHNob3J0UHJlbWl1bUZyYWN0aW9uBQ91bmRlcmx5aW5nUHJpY2UJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAQFzAQULbG9uZ0Z1bmRpbmcJAQFzAQUMc2hvcnRGdW5kaW5nCQEBcwEJAQxnZXRTcG90UHJpY2UACQEBcwEJAQ5nZXRPcmFjbGVQcmljZQAJAQFzAQUOcHJlbWl1bVRvVmF1bHQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEQY29tcHV0ZVNwb3RQcmljZQAEBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQGcmVzdWx0CQEMZ2V0U3BvdFByaWNlAAkAlAoCBQNuaWwFBnJlc3VsdAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAR9jb21wdXRlRmVlRm9yVHJhZGVyV2l0aEFydGlmYWN0AgdfdHJhZGVyC19hcnRpZmFjdElkBAZyZXN1bHQJARhnZXRGb3JUcmFkZXJXaXRoQXJ0aWZhY3QCBQdfdHJhZGVyBQtfYXJ0aWZhY3RJZAkAlAoCBQNuaWwFBnJlc3VsdAECdHgBBnZlcmlmeQAEDmNvb3JkaW5hdG9yU3RyCQCdCAIFBHRoaXMFFGtfY29vcmRpbmF0b3JBZGRyZXNzAwkBCWlzRGVmaW5lZAEFDmNvb3JkaW5hdG9yU3RyBAVhZG1pbgkAnQgCCQERQGV4dHJOYXRpdmUoMTA2MikBCQEFdmFsdWUBBQ5jb29yZGluYXRvclN0cgUPa19hZG1pbl9hZGRyZXNzAwkBCWlzRGVmaW5lZAEFBWFkbWluCQELdmFsdWVPckVsc2UCCQCbCAIJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAQV2YWx1ZQEFBWFkbWluCQCsAgIJAKwCAgkArAICAgdzdGF0dXNfCQClCAEFBHRoaXMCAV8JANgEAQgFAnR4AmlkBwkAAgECLnVuYWJsZSB0byB2ZXJpZnk6IGFkbWluIG5vdCBzZXQgaW4gY29vcmRpbmF0b3IJAPQDAwgFAnR4CWJvZHlCeXRlcwkAkQMCCAUCdHgGcHJvb2ZzAAAIBQJ0eA9zZW5kZXJQdWJsaWNLZXnWHV1c", "height": 3559413, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: EVHRKGGppJ4UWM7NfirCTLD6GbTwGXNh4h5GzG9TSqRb Next: 9U7qApWxbiXEPRsZaiLsm5Cuw1DqgRe71JK4GsxBeXh9 Diff:
OldNewDifferences
1818 let k_positionLastUpdatedCumulativePremiumFraction = "k_positionFraction"
1919
2020 let k_positionSequence = "k_positionSequence"
21-
22-let k_positionAsset = "k_positionAsset"
2321
2422 let k_positionFee = "k_positionFee"
2523
5755
5856 let k_maxOracleDelay = "k_maxOracleDelay"
5957
60-let k_lastDataStr = "k_lastDataStr"
61-
62-let k_lastMinuteId = "k_lastMinuteId"
63-
64-let k_twapDataLastCumulativePrice = "k_twapDataLastCumulativePrice"
65-
66-let k_twapDataLastPrice = "k_twapDataLastPrice"
67-
68-let k_twapDataPreviousMinuteId = "k_twapDataPreviousMinuteId"
58+let k_fundingMode = "k_fundingMode"
6959
7060 let k_latestLongCumulativePremiumFraction = "k_latestLongPremiumFraction"
7161
164154
165155 let DIR_SHORT = 2
166156
167-let TWAP_INTERVAL = 15
168-
169157 let SECONDS = 1000
170158
171159 let DECIMAL_NUMBERS = 6
179167 let PNL_OPTION_SPOT = 1
180168
181169 let PNL_OPTION_ORACLE = 2
170+
171+let FUNDING_ASYMMETRIC = 1
172+
173+let FUNDING_SYMMETRIC = 2
182174
183175 func s (_x) = (toString(_x) + ",")
184176
203195 func vmax (_x,_y) = if ((_x >= _y))
204196 then _x
205197 else _y
206-
207-
208-func listToStr (_list) = if ((size(_list) == 0))
209- then ""
210- else makeString(_list, ",")
211-
212-
213-func strToList (_str) = if ((_str == ""))
214- then nil
215- else split(_str, ",")
216-
217-
218-func pushToQueue (_list,_maxSize,_value) = if ((size(_list) > _maxSize))
219- then (removeByIndex(_list, 0) :+ _value)
220- else (_list :+ _value)
221198
222199
223200 func int (k) = valueOrErrorMessage(getInteger(this, k), ("no value for " + k))
328305 func maxOracleDelay () = int(k_maxOracleDelay)
329306
330307
308+func fundingMode () = intOr(k_fundingMode, FUNDING_ASYMMETRIC)
309+
310+
331311 func lastTimestamp () = lastBlock.timestamp
332312
333313
362342 $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)))
363343 case _ =>
364344 $Tuple5(0, 0, 0, 0, 0)
365- }
366- }
367-
368-
369-func getPositionAsset (_trader) = {
370- let positionAssetOpt = getString(this, toCompositeKey(k_positionAsset, _trader))
371- match positionAssetOpt {
372- case positionAsset: String =>
373- positionAsset
374- case _ =>
375- toBase58String(quoteAsset())
376345 }
377346 }
378347
456425 let amountBaseAssetBought = if (_isAdd)
457426 then amountBaseAssetBoughtAbs
458427 else -(amountBaseAssetBoughtAbs)
459- let $t01672216892 = updateReserve(_isAdd, quoteAssetAmountAdjusted, amountBaseAssetBoughtAbs)
460- let quoteAssetReserveAfter1 = $t01672216892._1
461- let baseAssetReserveAfter1 = $t01672216892._2
462- let totalPositionSizeAfter1 = $t01672216892._3
428+ let $t01560115771 = updateReserve(_isAdd, quoteAssetAmountAdjusted, amountBaseAssetBoughtAbs)
429+ let quoteAssetReserveAfter1 = $t01560115771._1
430+ let baseAssetReserveAfter1 = $t01560115771._2
431+ let totalPositionSizeAfter1 = $t01560115771._3
463432 let priceBefore = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
464433 let marketPrice = divd(_quoteAssetAmount, amountBaseAssetBoughtAbs)
465434 let priceDiff = abs((priceBefore - marketPrice))
487456 else 0
488457 let rolloverFee = calcRolloverFee(_oldPositionMargin, _oldPositionLastUpdatedTimestamp)
489458 let signedMargin = (((_marginDelta - rolloverFee) - fundingPayment) + _oldPositionMargin)
490- let $t01914719274 = if ((0 > signedMargin))
459+ let $t01802618153 = if ((0 > signedMargin))
491460 then $Tuple2(0, abs(signedMargin))
492461 else $Tuple2(abs(signedMargin), 0)
493- let remainMargin = $t01914719274._1
494- let badDebt = $t01914719274._2
462+ let remainMargin = $t01802618153._1
463+ let badDebt = $t01802618153._2
495464 $Tuple4(remainMargin, badDebt, fundingPayment, rolloverFee)
496465 }
497466
509478 let quoteAssetDelta = abs((quoteAssetAfter - _quoteAssetReserve))
510479 let quoteAssetSold = muld(quoteAssetDelta, _quoteAssetWeight)
511480 let maxPriceImpactValue = maxPriceImpact()
512- let $t02053620698 = updateReserve(!(_isAdd), quoteAssetDelta, _baseAssetAmount)
513- let quoteAssetReserveAfter1 = $t02053620698._1
514- let baseAssetReserveAfter1 = $t02053620698._2
515- let totalPositionSizeAfter1 = $t02053620698._3
481+ let $t01941519577 = updateReserve(!(_isAdd), quoteAssetDelta, _baseAssetAmount)
482+ let quoteAssetReserveAfter1 = $t01941519577._1
483+ let baseAssetReserveAfter1 = $t01941519577._2
484+ let totalPositionSizeAfter1 = $t01941519577._3
516485 let marketPrice = divd(quoteAssetSold, _baseAssetAmount)
517486 let priceDiff = abs((priceBefore - marketPrice))
518487 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
647616
648617
649618 func getPositionNotionalAndUnrealizedPnl (_trader,_option) = {
650- let $t02857628704 = getPosition(_trader)
651- let positionSize = $t02857628704._1
652- let positionMargin = $t02857628704._2
653- let positionOpenNotional = $t02857628704._3
654- let positionLstUpdCPF = $t02857628704._4
619+ let $t02745527583 = getPosition(_trader)
620+ let positionSize = $t02745527583._1
621+ let positionMargin = $t02745527583._2
622+ let positionOpenNotional = $t02745527583._3
623+ let positionLstUpdCPF = $t02745527583._4
655624 getPositionNotionalAndUnrealizedPnlByValues(positionSize, positionOpenNotional, qtAstR(), qtAstW(), bsAstR(), bsAstW(), _option)
656625 }
657626
660629
661630
662631 func getMarginRatioByOption (_trader,_option) = {
663- let $t02921929360 = getPosition(_trader)
664- let positionSize = $t02921929360._1
665- let positionMargin = $t02921929360._2
666- let pon = $t02921929360._3
667- let positionLastUpdatedCPF = $t02921929360._4
668- let positionTimestamp = $t02921929360._5
669- let $t02936629459 = getPositionNotionalAndUnrealizedPnl(_trader, _option)
670- let positionNotional = $t02936629459._1
671- let unrealizedPnl = $t02936629459._2
672- let $t02946429676 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLastUpdatedCPF, positionTimestamp, unrealizedPnl)
673- let remainMargin = $t02946429676._1
674- let badDebt = $t02946429676._2
632+ let $t02809828239 = getPosition(_trader)
633+ let positionSize = $t02809828239._1
634+ let positionMargin = $t02809828239._2
635+ let pon = $t02809828239._3
636+ let positionLastUpdatedCPF = $t02809828239._4
637+ let positionTimestamp = $t02809828239._5
638+ let $t02824528338 = getPositionNotionalAndUnrealizedPnl(_trader, _option)
639+ let positionNotional = $t02824528338._1
640+ let unrealizedPnl = $t02824528338._2
641+ let $t02834328555 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLastUpdatedCPF, positionTimestamp, unrealizedPnl)
642+ let remainMargin = $t02834328555._1
643+ let badDebt = $t02834328555._2
675644 calcMarginRatio(remainMargin, badDebt, positionNotional)
676645 }
677646
692661
693662
694663 func internalClosePosition (_trader,_size,_fee,_minQuoteAssetAmount,_addToMargin,_checkMaxPriceImpact,_liquidate) = {
695- let $t03074330899 = getPosition(_trader)
696- let oldPositionSize = $t03074330899._1
697- let oldPositionMargin = $t03074330899._2
698- let oldPositionOpenNotional = $t03074330899._3
699- let oldPositionLstUpdCPF = $t03074330899._4
700- let oldPositionTimestamp = $t03074330899._5
664+ let $t02962229778 = getPosition(_trader)
665+ let oldPositionSize = $t02962229778._1
666+ let oldPositionMargin = $t02962229778._2
667+ let oldPositionOpenNotional = $t02962229778._3
668+ let oldPositionLstUpdCPF = $t02962229778._4
669+ let oldPositionTimestamp = $t02962229778._5
701670 let isLongPosition = (oldPositionSize > 0)
702671 let absOldPositionSize = abs(oldPositionSize)
703672 if (if ((absOldPositionSize >= _size))
705674 else false)
706675 then {
707676 let isPartialClose = (absOldPositionSize > _size)
708- let $t03119131642 = swapOutput((oldPositionSize > 0), _size, _checkMaxPriceImpact)
709- let exchangedQuoteAssetAmount = $t03119131642._1
710- let quoteAssetReserveAfter = $t03119131642._2
711- let baseAssetReserveAfter = $t03119131642._3
712- let totalPositionSizeAfter = $t03119131642._4
677+ let $t03007030521 = swapOutput((oldPositionSize > 0), _size, _checkMaxPriceImpact)
678+ let exchangedQuoteAssetAmount = $t03007030521._1
679+ let quoteAssetReserveAfter = $t03007030521._2
680+ let baseAssetReserveAfter = $t03007030521._3
681+ let totalPositionSizeAfter = $t03007030521._4
713682 let exchangedPositionSize = if ((oldPositionSize > 0))
714683 then -(_size)
715684 else _size
716- let $t03185732064 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
717- let oldPositionNotional = $t03185732064._1
718- let unrealizedPnl = $t03185732064._2
685+ let $t03073630943 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
686+ let oldPositionNotional = $t03073630943._1
687+ let unrealizedPnl = $t03073630943._2
719688 let realizedRatio = divd(abs(exchangedPositionSize), absOldPositionSize)
720689 let realizedPnl = muld(unrealizedPnl, realizedRatio)
721- let $t03240532651 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, unrealizedPnl)
722- let remainMarginBefore = $t03240532651._1
723- let x1 = $t03240532651._2
724- let x2 = $t03240532651._3
725- let rolloverFee = $t03240532651._4
690+ let $t03128431530 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, unrealizedPnl)
691+ let remainMarginBefore = $t03128431530._1
692+ let x1 = $t03128431530._2
693+ let x2 = $t03128431530._3
694+ let rolloverFee = $t03128431530._4
726695 let positionBadDebt = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, realizedPnl)._2
727696 let realizedCloseFee = muld(muld(oldPositionNotional, realizedRatio), _fee)
728697 let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
730699 then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
731700 else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
732701 let newPositionSize = (oldPositionSize + exchangedPositionSize)
733- let $t03405734443 = if ((newPositionSize == 0))
702+ let $t03293633322 = if ((newPositionSize == 0))
734703 then $Tuple2(0, 0)
735704 else $Tuple2(abs(remainOpenNotional), latestCumulativePremiumFraction(newPositionSize))
736- let newPositionOpenNotional = $t03405734443._1
737- let newPositionLstUpdCPF = $t03405734443._2
705+ let newPositionOpenNotional = $t03293633322._1
706+ let newPositionLstUpdCPF = $t03293633322._2
738707 let openNotionalDelta = (oldPositionOpenNotional - newPositionOpenNotional)
739708 let marginRatio = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
740709 let newPositionMarginWithSameRatio = if ((oldPositionSize > 0))
771740 }
772741
773742
774-func getTwapSpotPrice () = {
775- let minuteId = ((lastTimestamp() / 1000) / 60)
776- let startMinuteId = (minuteId - TWAP_INTERVAL)
777- let listStr = valueOrElse(getString(this, k_lastDataStr), "")
778- let list = split(listStr, ",")
779- func filterFn (accumulator,next) = if ((startMinuteId >= valueOrErrorMessage(parseInt(next), ("getTwapSpotPrice: invalid int: " + listStr))))
780- then (accumulator :+ parseIntValue(next))
781- else accumulator
782-
783- let listF = {
784- let $l = list
785- let $s = size($l)
786- let $acc0 = nil
787- func $f0_1 ($a,$i) = if (($i >= $s))
788- then $a
789- else filterFn($a, $l[$i])
790-
791- func $f0_2 ($a,$i) = if (($i >= $s))
792- then $a
793- else throw("List size exceeds 20")
794-
795- $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)
796- }
797- let maxIndex = if ((size(listF) > 0))
798- then max(listF)
799- else valueOrErrorMessage(parseInt(list[0]), ("getTwapSpotPrice: invalid int: " + listStr))
800- let lastMinuteId = valueOrElse(getInteger(this, k_lastMinuteId), 0)
801- let endLastCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(lastMinuteId))), 0)
802- let endLastPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(lastMinuteId))), 0)
803- let nowCumulativePrice = (endLastCumulativePrice + ((minuteId - lastMinuteId) * endLastPrice))
804- let startLastCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(maxIndex))), 0)
805- let startLastPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(maxIndex))), 0)
806- let startCumulativePrice = (startLastCumulativePrice + ((startMinuteId - maxIndex) * startLastPrice))
807- ((nowCumulativePrice - startCumulativePrice) / TWAP_INTERVAL)
808- }
809-
810-
811743 func getTerminalAmmState () = {
812744 let _positionSize = totalPositionSize()
813745 if ((_positionSize == 0))
814746 then $Tuple2(qtAstR(), bsAstR())
815747 else {
816748 let direction = (_positionSize > 0)
817- let $t03918039359 = swapOutput(direction, abs(_positionSize), false)
818- let currentNetMarketValue = $t03918039359._1
819- let terminalQuoteAssetReserve = $t03918039359._2
820- let terminalBaseAssetReserve = $t03918039359._3
749+ let $t03655736736 = swapOutput(direction, abs(_positionSize), false)
750+ let currentNetMarketValue = $t03655736736._1
751+ let terminalQuoteAssetReserve = $t03655736736._2
752+ let terminalBaseAssetReserve = $t03655736736._3
821753 $Tuple2(terminalQuoteAssetReserve, terminalBaseAssetReserve)
822754 }
823755 }
857789
858790 func getFunding () = {
859791 let underlyingPrice = getOraclePrice()
860- let spotTwapPrice = getTwapSpotPrice()
861- let premium = (spotTwapPrice - underlyingPrice)
792+ let spotPrice = getSpotPrice()
793+ let premium = (spotPrice - underlyingPrice)
862794 if (if (if ((totalShortPositionSize() == 0))
863795 then true
864796 else (totalLongPositionSize() == 0))
865797 then true
866798 else isMarketClosed())
867- then $Tuple2(0, 0)
799+ then $Tuple3(0, 0, 0)
868800 else if ((0 > premium))
869801 then {
870802 let shortPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY)
871- let longPremiumFraction = divd(muld(shortPremiumFraction, totalShortPositionSize()), totalLongPositionSize())
872- $Tuple2(shortPremiumFraction, longPremiumFraction)
803+ if ((fundingMode() == FUNDING_ASYMMETRIC))
804+ then {
805+ let longPremiumFraction = divd(muld(shortPremiumFraction, totalShortPositionSize()), totalLongPositionSize())
806+ $Tuple3(shortPremiumFraction, longPremiumFraction, 0)
807+ }
808+ else {
809+ let shortTotalPremiumFraction = abs(muld(shortPremiumFraction, totalShortPositionSize()))
810+ let longTotalPremiumFraction = abs(muld(shortPremiumFraction, totalLongPositionSize()))
811+ let premiumToVault = (shortTotalPremiumFraction - longTotalPremiumFraction)
812+ $Tuple3(shortPremiumFraction, shortPremiumFraction, premiumToVault)
813+ }
873814 }
874815 else {
875816 let longPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY)
876- let shortPremiumFraction = divd(muld(longPremiumFraction, totalLongPositionSize()), totalShortPositionSize())
877- $Tuple2(shortPremiumFraction, longPremiumFraction)
817+ if ((fundingMode() == FUNDING_ASYMMETRIC))
818+ then {
819+ let shortPremiumFraction = divd(muld(longPremiumFraction, totalLongPositionSize()), totalShortPositionSize())
820+ $Tuple3(shortPremiumFraction, longPremiumFraction, 0)
821+ }
822+ else {
823+ let longTotalPremiumFraction = abs(muld(longPremiumFraction, totalLongPositionSize()))
824+ let shortTotalPremiumFraction = abs(muld(longPremiumFraction, totalShortPositionSize()))
825+ let premiumToVault = (longTotalPremiumFraction - shortTotalPremiumFraction)
826+ $Tuple3(longPremiumFraction, longPremiumFraction, premiumToVault)
827+ }
878828 }
879829 }
880830
882832 func getAdjustedFee (_artifactId,_baseFeeDiscount) = {
883833 let baseFeeRaw = fee()
884834 let baseFee = muld(baseFeeRaw, _baseFeeDiscount)
885- let $t04222042715 = if ((_artifactId != ""))
835+ let $t04045440949 = if ((_artifactId != ""))
886836 then {
887837 let artifactKind = strA(nftManagerAddress(), toCompositeKey(k_token_type, _artifactId))
888838 if ((artifactKind == FEE_REDUCTION_TOKEN_TYPE))
894844 else throw("Invalid attached artifact")
895845 }
896846 else $Tuple2(baseFee, false)
897- let adjustedFee = $t04222042715._1
898- let burnArtifact = $t04222042715._2
847+ let adjustedFee = $t04045440949._1
848+ let burnArtifact = $t04045440949._2
899849 $Tuple2(adjustedFee, burnArtifact)
900850 }
901-
902-
903-func isSameAssetOrNoPosition (_trader,_assetId) = {
904- let oldPositionSize = getPosition(_trader)._1
905- if ((oldPositionSize == 0))
906- then true
907- else (getPositionAsset(_trader) == _assetId)
908- }
909-
910-
911-func isSameAsset (_trader,_assetId) = (getPositionAsset(_trader) == _assetId)
912851
913852
914853 func getForTraderWithArtifact (_trader,_artifactId) = {
921860 case _ =>
922861 throw("Invalid computeFeeDiscount result")
923862 }
924- let $t04339543469 = getAdjustedFee(_artifactId, feeDiscount)
925- let adjustedFee = $t04339543469._1
926- let burnArtifact = $t04339543469._2
863+ let $t04129541369 = getAdjustedFee(_artifactId, feeDiscount)
864+ let adjustedFee = $t04129541369._1
865+ let burnArtifact = $t04129541369._2
927866 $Tuple2(adjustedFee, burnArtifact)
928867 }
929868 else throw("Strict value is not equal to itself.")
945884 }
946885
947886
948-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)]
887+func updateSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee,_fundingMode) = [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), IntegerEntry(k_fundingMode, _fundingMode)]
949888
950889
951890 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)]
967906 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)]
968907
969908
970-func appendTwap (_price) = {
971- let minuteId = ((lastTimestamp() / 1000) / 60)
972- let previousMinuteId = valueOrElse(getInteger(this, k_lastMinuteId), 0)
973- if ((previousMinuteId > minuteId))
974- then throw("TWAP out-of-order")
975- else {
976- let lastMinuteId = if ((previousMinuteId == 0))
977- then minuteId
978- else previousMinuteId
979- if ((minuteId > previousMinuteId))
980- then {
981- let prevCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(previousMinuteId))), 0)
982- let prevPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(previousMinuteId))), _price)
983- let lastCumulativePrice = (prevCumulativePrice + ((minuteId - lastMinuteId) * prevPrice))
984- let list = pushToQueue(strToList(valueOrElse(getString(this, k_lastDataStr), "")), TWAP_INTERVAL, toString(minuteId))
985-[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))]
986- }
987- else {
988- let twapDataPreviousMinuteId = valueOrElse(getInteger(this, toCompositeKey(k_twapDataPreviousMinuteId, toString(minuteId))), 0)
989- let prevCumulativePrice = valueOrElse(getInteger(this, toCompositeKey(k_twapDataLastCumulativePrice, toString(twapDataPreviousMinuteId))), 0)
990- let prevPrice = valueOrElse(getInteger(this, toCompositeKey(k_twapDataLastPrice, toString(twapDataPreviousMinuteId))), _price)
991- let lastCumulativePrice = (prevCumulativePrice + ((minuteId - twapDataPreviousMinuteId) * prevPrice))
992-[IntegerEntry(toCompositeKey(k_twapDataLastCumulativePrice, toString(minuteId)), lastCumulativePrice), IntegerEntry(toCompositeKey(k_twapDataLastPrice, toString(minuteId)), _price)]
993- }
994- }
995- }
996-
997-
998909 func updateAmmReserves (_qtAstR,_bsAstR) = [IntegerEntry(k_quoteAssetReserve, _qtAstR), IntegerEntry(k_baseAssetReserve, _bsAstR)]
999910
1000911
1006917 let _bsAstW = bsAstW()
1007918 if (((_totalLongPositionSize - _totalShortPositionSize) != _totalPositionSizeAfter))
1008919 then throw(((((("Invalid AMM state data: " + toString(_totalLongPositionSize)) + " + ") + toString(_totalShortPositionSize)) + " != ") + toString(_totalPositionSizeAfter)))
1009- 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))))
920+ 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)])
1010921 }
1011922
1012923
1013-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))]
924+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_positionFee, _address)), DeleteEntry(toCompositeKey(k_positionLastUpdatedTimestamp, _address))]
1014925
1015926
1016927 func withdraw (_address,_amount) = {
1076987 let qtAstRAfter = (_qtAstR + _quoteAssetAmount)
1077988 let baseAssetAmountToAdd = (divd(muld(qtAstRAfter, _qtAstW), price) - _bsAstR)
1078989 let bsAstRAfter = (_bsAstR + baseAssetAmountToAdd)
1079- let $t05287653027 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1080- let newQuoteAssetWeight = $t05287653027._1
1081- let newBaseAssetWeight = $t05287653027._2
1082- let marginToVault = $t05287653027._3
990+ let $t04926349414 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
991+ let newQuoteAssetWeight = $t04926349414._1
992+ let newBaseAssetWeight = $t04926349414._2
993+ let marginToVault = $t04926349414._3
1083994 let doExchangePnL = if ((marginToVault != 0))
1084995 then {
1085996 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
11091020 let qtAstRAfter = (_qtAstR - _quoteAssetAmount)
11101021 let baseAssetAmountToRemove = abs((divd(muld(qtAstRAfter, _qtAstW), price) - _bsAstR))
11111022 let bsAstRAfter = (_bsAstR - baseAssetAmountToRemove)
1112- let $t05395954110 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1113- let newQuoteAssetWeight = $t05395954110._1
1114- let newBaseAssetWeight = $t05395954110._2
1115- let marginToVault = $t05395954110._3
1023+ let $t05051050661 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1024+ let newQuoteAssetWeight = $t05051050661._1
1025+ let newBaseAssetWeight = $t05051050661._2
1026+ let marginToVault = $t05051050661._3
11161027 let doExchangePnL = if ((marginToVault != 0))
11171028 then {
11181029 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
11291040
11301041
11311042 @Callable(i)
1132-func changeSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee) = if ((i.caller != adminAddress()))
1043+func changeSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee,_fundingMode) = if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if ((0 >= _fundingPeriod))
1044+ then true
1045+ else (0 >= _initMarginRatio))
1046+ then true
1047+ else (0 >= _mmr))
1048+ then true
1049+ else (0 >= _liquidationFeeRatio))
1050+ then true
1051+ else (0 >= _fee))
1052+ then true
1053+ else (0 >= _spreadLimit))
1054+ then true
1055+ else (0 >= _maxPriceImpact))
1056+ then true
1057+ else (0 >= _partialLiquidationRatio))
1058+ then true
1059+ else (0 >= _maxPriceSpread))
1060+ then true
1061+ else (0 >= _maxOpenNotional))
1062+ then true
1063+ else (0 >= _feeToStakersPercent))
1064+ then true
1065+ else (_feeToStakersPercent > DECIMAL_UNIT))
1066+ then true
1067+ else (0 >= _maxOracleDelay))
1068+ then true
1069+ else (0 >= _rolloverFee))
1070+ then true
1071+ else if ((_fundingMode != FUNDING_SYMMETRIC))
1072+ then (_fundingMode != FUNDING_ASYMMETRIC)
1073+ else false)
1074+ then true
1075+ else !(initialized()))
1076+ then true
1077+ else (i.caller != adminAddress()))
11331078 then throw("Invalid changeSettings params")
1134- else updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread, _maxOpenNotional, _feeToStakersPercent, _maxOracleDelay, _rolloverFee)
1079+ else updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread, _maxOpenNotional, _feeToStakersPercent, _maxOracleDelay, _rolloverFee, _fundingMode)
11351080
11361081
11371082
11381083 @Callable(i)
1139-func initialize (_qtAstR,_bsAstR,_fundingPeriod,_initMarginRatio,_mmr,_liquidationFeeRatio,_fee,_baseOracleData,_quoteOracleData,_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 (if ((0 >= _qtAstR))
1084+func initialize (_qtAstR,_bsAstR,_fundingPeriod,_initMarginRatio,_mmr,_liquidationFeeRatio,_fee,_baseOracleData,_quoteOracleData,_coordinator,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee,_fundingMode) = if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if ((0 >= _qtAstR))
11401085 then true
11411086 else (0 >= _bsAstR))
11421087 then true
11681113 then true
11691114 else (0 >= _rolloverFee))
11701115 then true
1116+ else if ((_fundingMode != FUNDING_SYMMETRIC))
1117+ then (_fundingMode != FUNDING_ASYMMETRIC)
1118+ else false)
1119+ then true
11711120 else initialized())
11721121 then true
11731122 else (i.caller != this))
11741123 then throw("Invalid initialize parameters")
1175- 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_baseOracle, _baseOracleData), StringEntry(k_quoteOracle, _quoteOracleData), StringEntry(k_coordinatorAddress, toString(addressFromStringValue(_coordinator)))])
1124+ else ((((updateAmm(_qtAstR, _bsAstR, 0, 0, 0, 0, 0, 0) ++ updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread, _maxOpenNotional, _feeToStakersPercent, _maxOracleDelay, _rolloverFee, _fundingMode)) ++ updateFunding((lastTimestamp() + _fundingPeriod), 0, 0, 0, 0)) ++ updateBalance(0)) ++ [BooleanEntry(k_initialized, true), StringEntry(k_baseOracle, _baseOracleData), StringEntry(k_quoteOracle, _quoteOracleData), StringEntry(k_coordinatorAddress, toString(addressFromStringValue(_coordinator)))])
11761125
11771126
11781127
11891138 let _assetId = i.payments[0].assetId
11901139 let _assetIdStr = toBase58String(value(_assetId))
11911140 let isQuoteAsset = (_assetId == quoteAsset())
1192- if (if (if (if (if (if (if (if (if (if ((_direction != DIR_LONG))
1141+ if (if (if (if (if (if (if (if (if ((_direction != DIR_LONG))
11931142 then (_direction != DIR_SHORT)
11941143 else false)
11951144 then true
11981147 else !(initialized()))
11991148 then true
12001149 else !(isQuoteAsset))
1201- then true
1202- else !(isSameAssetOrNoPosition(_trader, _assetIdStr)))
12031150 then true
12041151 else !(requireMoreMarginRatio(divd(DECIMAL_UNIT, _leverage), initMarginRatio(), true)))
12051152 then true
12101157 else isMarketClosed())
12111158 then throw("Invalid increasePosition parameters")
12121159 else {
1213- let $t05788858037 = getForTraderWithArtifact(_trader, getArtifactId(i))
1214- let adjustedFee = $t05788858037._1
1215- let burnArtifact = $t05788858037._2
1160+ let $t05673156880 = getForTraderWithArtifact(_trader, getArtifactId(i))
1161+ let adjustedFee = $t05673156880._1
1162+ let burnArtifact = $t05673156880._2
12161163 let _amount = divd(_rawAmount, (muld(adjustedFee, _leverage) + DECIMAL_UNIT))
12171164 let distributeFeeAmount = (_rawAmount - _amount)
12181165 let referrerFeeAny = invoke(referralAddress(), "acceptPaymentWithLink", [_trader, _refLink], [AttachedPayment(quoteAsset(), distributeFeeAmount)])
12251172 throw("Invalid referrerFee")
12261173 }
12271174 let feeAmount = (distributeFeeAmount - referrerFee)
1228- let $t05853358701 = getPosition(_trader)
1229- let oldPositionSize = $t05853358701._1
1230- let oldPositionMargin = $t05853358701._2
1231- let oldPositionOpenNotional = $t05853358701._3
1232- let oldPositionLstUpdCPF = $t05853358701._4
1233- let oldPositionTimestamp = $t05853358701._5
1175+ let $t05737657544 = getPosition(_trader)
1176+ let oldPositionSize = $t05737657544._1
1177+ let oldPositionMargin = $t05737657544._2
1178+ let oldPositionOpenNotional = $t05737657544._3
1179+ let oldPositionLstUpdCPF = $t05737657544._4
1180+ let oldPositionTimestamp = $t05737657544._5
12341181 let isNewPosition = (oldPositionSize == 0)
12351182 let isSameDirection = if ((oldPositionSize > 0))
12361183 then (_direction == DIR_LONG)
12391186 then isSameDirection
12401187 else false
12411188 let isAdd = (_direction == DIR_LONG)
1242- let $t05899062111 = if (if (isNewPosition)
1189+ let $t05783360954 = if (if (isNewPosition)
12431190 then true
12441191 else expandExisting)
12451192 then {
12461193 let openNotional = muld(_amount, _leverage)
1247- let $t05949959672 = swapInput(isAdd, openNotional)
1248- let amountBaseAssetBought = $t05949959672._1
1249- let quoteAssetReserveAfter = $t05949959672._2
1250- let baseAssetReserveAfter = $t05949959672._3
1251- let totalPositionSizeAfter = $t05949959672._4
1194+ let $t05834258515 = swapInput(isAdd, openNotional)
1195+ let amountBaseAssetBought = $t05834258515._1
1196+ let quoteAssetReserveAfter = $t05834258515._2
1197+ let baseAssetReserveAfter = $t05834258515._3
1198+ let totalPositionSizeAfter = $t05834258515._4
12521199 if (if ((_minBaseAssetAmount != 0))
12531200 then (_minBaseAssetAmount > abs(amountBaseAssetBought))
12541201 else false)
12611208 let totalShortOpenInterestAfter = (openInterestShort() + (if ((0 > newPositionSize))
12621209 then openNotional
12631210 else 0))
1264- let $t06021860493 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
1265- let remainMargin = $t06021860493._1
1266- let x1 = $t06021860493._2
1267- let x2 = $t06021860493._3
1268- let rolloverFee = $t06021860493._4
1211+ let $t05906159336 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
1212+ let remainMargin = $t05906159336._1
1213+ let x1 = $t05906159336._2
1214+ let x2 = $t05906159336._3
1215+ let rolloverFee = $t05906159336._4
12691216 if (!(requireNotOverSpreadLimit(quoteAssetReserveAfter, baseAssetReserveAfter)))
12701217 then throw("Over max spread limit")
12711218 else if (!(requireNotOverMaxOpenNotional(totalLongOpenInterestAfter, totalShortOpenInterestAfter)))
12791226 }
12801227 else {
12811228 let openNotional = muld(_amount, _leverage)
1282- let $t06181161927 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
1283- let oldPositionNotional = $t06181161927._1
1284- let unrealizedPnl = $t06181161927._2
1229+ let $t06065460770 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
1230+ let oldPositionNotional = $t06065460770._1
1231+ let unrealizedPnl = $t06065460770._2
12851232 if ((oldPositionNotional > openNotional))
12861233 then throw("Use decreasePosition to decrease position size")
12871234 else throw("Close position first")
12881235 }
1289- let newPositionSize = $t05899062111._1
1290- let newPositionRemainMargin = $t05899062111._2
1291- let newPositionOpenNotional = $t05899062111._3
1292- let newPositionLatestCPF = $t05899062111._4
1293- let newPositionTimestamp = $t05899062111._5
1294- let baseAssetReserveAfter = $t05899062111._6
1295- let quoteAssetReserveAfter = $t05899062111._7
1296- let totalPositionSizeAfter = $t05899062111._8
1297- let openInterestNotionalAfter = $t05899062111._9
1298- let totalLongAfter = $t05899062111._10
1299- let totalShortAfter = $t05899062111._11
1300- let totalLongOpenInterestAfter = $t05899062111._12
1301- let totalShortOpenInterestAfter = $t05899062111._13
1302- let rolloverFee = $t05899062111._14
1303- let $t06211762188 = distributeFee((feeAmount + rolloverFee))
1304- let feeToStakers = $t06211762188._1
1305- let feeToVault = $t06211762188._2
1236+ let newPositionSize = $t05783360954._1
1237+ let newPositionRemainMargin = $t05783360954._2
1238+ let newPositionOpenNotional = $t05783360954._3
1239+ let newPositionLatestCPF = $t05783360954._4
1240+ let newPositionTimestamp = $t05783360954._5
1241+ let baseAssetReserveAfter = $t05783360954._6
1242+ let quoteAssetReserveAfter = $t05783360954._7
1243+ let totalPositionSizeAfter = $t05783360954._8
1244+ let openInterestNotionalAfter = $t05783360954._9
1245+ let totalLongAfter = $t05783360954._10
1246+ let totalShortAfter = $t05783360954._11
1247+ let totalLongOpenInterestAfter = $t05783360954._12
1248+ let totalShortOpenInterestAfter = $t05783360954._13
1249+ let rolloverFee = $t05783360954._14
1250+ let $t06096061031 = distributeFee((feeAmount + rolloverFee))
1251+ let feeToStakers = $t06096061031._1
1252+ let feeToVault = $t06096061031._2
13061253 let stake = if ((_amount >= rolloverFee))
13071254 then invoke(vaultAddress(), "addLocked", nil, [AttachedPayment(quoteAsset(), (_amount - rolloverFee))])
13081255 else invoke(vaultAddress(), "withdrawLocked", [(rolloverFee - _amount)], nil)
13481295 let _assetId = i.payments[0].assetId
13491296 let _assetIdStr = toBase58String(value(_assetId))
13501297 let isQuoteAsset = (_assetId == quoteAsset())
1351- if (if (if (if (if (if (if (!(isQuoteAsset))
1298+ if (if (if (if (if (if (!(isQuoteAsset))
13521299 then true
13531300 else !(requireOpenPosition(toString(i.caller))))
1354- then true
1355- else !(isSameAsset(_trader, _assetIdStr)))
13561301 then true
13571302 else !(initialized()))
13581303 then true
13631308 else isMarketClosed())
13641309 then throw("Invalid addMargin parameters")
13651310 else {
1366- let $t06429964467 = getPosition(_trader)
1367- let oldPositionSize = $t06429964467._1
1368- let oldPositionMargin = $t06429964467._2
1369- let oldPositionOpenNotional = $t06429964467._3
1370- let oldPositionLstUpdCPF = $t06429964467._4
1371- let oldPositionTimestamp = $t06429964467._5
1311+ let $t06324663414 = getPosition(_trader)
1312+ let oldPositionSize = $t06324663414._1
1313+ let oldPositionMargin = $t06324663414._2
1314+ let oldPositionOpenNotional = $t06324663414._3
1315+ let oldPositionLstUpdCPF = $t06324663414._4
1316+ let oldPositionTimestamp = $t06324663414._5
13721317 let stake = invoke(vaultAddress(), "addLocked", nil, [AttachedPayment(quoteAsset(), _amount)])
13731318 if ((stake == stake))
13741319 then {
13751320 let rolloverFee = calcRolloverFee(oldPositionMargin, oldPositionTimestamp)
13761321 let doTransferFeeToStakers = if ((rolloverFee > 0))
13771322 then {
1378- let $t06475264811 = distributeFee(rolloverFee)
1379- let feeToStakers = $t06475264811._1
1380- let feeToVault = $t06475264811._2
1323+ let $t06369963758 = distributeFee(rolloverFee)
1324+ let feeToStakers = $t06369963758._1
1325+ let feeToVault = $t06369963758._2
13811326 let unstake = invoke(vaultAddress(), "withdrawLocked", [feeToStakers], nil)
13821327 if ((unstake == unstake))
13831328 then {
14231368 else isMarketClosed())
14241369 then throw("Invalid removeMargin parameters")
14251370 else {
1426- let $t06592366091 = getPosition(_trader)
1427- let oldPositionSize = $t06592366091._1
1428- let oldPositionMargin = $t06592366091._2
1429- let oldPositionOpenNotional = $t06592366091._3
1430- let oldPositionLstUpdCPF = $t06592366091._4
1431- let oldPositionTimestamp = $t06592366091._5
1432- let $t06609766346 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, -(_amount))
1433- let remainMargin = $t06609766346._1
1434- let badDebt = $t06609766346._2
1435- let fundingPayment = $t06609766346._3
1436- let rolloverFee = $t06609766346._4
1371+ let $t06513165299 = getPosition(_trader)
1372+ let oldPositionSize = $t06513165299._1
1373+ let oldPositionMargin = $t06513165299._2
1374+ let oldPositionOpenNotional = $t06513165299._3
1375+ let oldPositionLstUpdCPF = $t06513165299._4
1376+ let oldPositionTimestamp = $t06513165299._5
1377+ let $t06530565554 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, -(_amount))
1378+ let remainMargin = $t06530565554._1
1379+ let badDebt = $t06530565554._2
1380+ let fundingPayment = $t06530565554._3
1381+ let rolloverFee = $t06530565554._4
14371382 if ((badDebt != 0))
14381383 then throw("Invalid removed margin amount")
14391384 else {
14411386 if (!(requireMoreMarginRatio(marginRatio, initMarginRatio(), true)))
14421387 then throw(((("Too much margin removed: " + toString(marginRatio)) + " < ") + toString(initMarginRatio())))
14431388 else {
1444- let $t06673266791 = distributeFee(rolloverFee)
1445- let feeToStakers = $t06673266791._1
1446- let feeToVault = $t06673266791._2
1389+ let $t06594065999 = distributeFee(rolloverFee)
1390+ let feeToStakers = $t06594065999._1
1391+ let feeToVault = $t06594065999._2
14471392 let doTransferFeeToStakers = if ((rolloverFee > 0))
14481393 then {
14491394 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
14961441 then throw("Invalid closePosition parameters")
14971442 else {
14981443 let oldPositionTimestamp = getPosition(_trader)._5
1499- let $t06844869033 = internalClosePosition(_trader, _size, positionFee, _minQuoteAssetAmount, _addToMargin, true, true)
1500- let newPositionSize = $t06844869033._1
1501- let newPositionMargin = $t06844869033._2
1502- let newPositionOpenNotional = $t06844869033._3
1503- let newPositionLstUpdCPF = $t06844869033._4
1504- let positionBadDebt = $t06844869033._5
1505- let realizedPnl = $t06844869033._6
1506- let marginToTrader = $t06844869033._7
1507- let quoteAssetReserveAfter = $t06844869033._8
1508- let baseAssetReserveAfter = $t06844869033._9
1509- let totalPositionSizeAfter = $t06844869033._10
1510- let openInterestNotionalAfter = $t06844869033._11
1511- let totalLongAfter = $t06844869033._12
1512- let totalShortAfter = $t06844869033._13
1513- let totalLongOpenInterestAfter = $t06844869033._14
1514- let totalShortOpenInterestAfter = $t06844869033._15
1515- let realizedFee = $t06844869033._16
1444+ let $t06817468759 = internalClosePosition(_trader, _size, positionFee, _minQuoteAssetAmount, _addToMargin, true, true)
1445+ let newPositionSize = $t06817468759._1
1446+ let newPositionMargin = $t06817468759._2
1447+ let newPositionOpenNotional = $t06817468759._3
1448+ let newPositionLstUpdCPF = $t06817468759._4
1449+ let positionBadDebt = $t06817468759._5
1450+ let realizedPnl = $t06817468759._6
1451+ let marginToTrader = $t06817468759._7
1452+ let quoteAssetReserveAfter = $t06817468759._8
1453+ let baseAssetReserveAfter = $t06817468759._9
1454+ let totalPositionSizeAfter = $t06817468759._10
1455+ let openInterestNotionalAfter = $t06817468759._11
1456+ let totalLongAfter = $t06817468759._12
1457+ let totalShortAfter = $t06817468759._13
1458+ let totalLongOpenInterestAfter = $t06817468759._14
1459+ let totalShortOpenInterestAfter = $t06817468759._15
1460+ let realizedFee = $t06817468759._16
15161461 if ((positionBadDebt > 0))
15171462 then throw("Invalid closePosition parameters: bad debt")
15181463 else if ((oldPositionTimestamp >= lastTimestamp()))
15271472 let unstake = invoke(vaultAddress(), "withdrawLocked", [withdrawAmount], nil)
15281473 if ((unstake == unstake))
15291474 then {
1530- let $t06970569764 = distributeFee(realizedFee)
1531- let feeToStakers = $t06970569764._1
1532- let feeToVault = $t06970569764._2
1475+ let $t06943169490 = distributeFee(realizedFee)
1476+ let feeToStakers = $t06943169490._1
1477+ let feeToVault = $t06943169490._2
15331478 let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
15341479 if ((depositVault == depositVault))
15351480 then {
15901535 else false
15911536 let oldPositionSize = getPosition(_trader)._1
15921537 let positionSizeAbs = abs(oldPositionSize)
1593- let $t07207772400 = if (isPartialLiquidation)
1538+ let $t07191172234 = if (isPartialLiquidation)
15941539 then {
15951540 let liquidationSize = getPartialLiquidationAmount(_trader, oldPositionSize)
15961541 let liquidationRatio = divd(abs(liquidationSize), positionSizeAbs)
15971542 $Tuple2(liquidationRatio, abs(liquidationSize))
15981543 }
15991544 else $Tuple2(0, positionSizeAbs)
1600- let liquidationRatio = $t07207772400._1
1601- let liquidationSize = $t07207772400._2
1602- let $t07240673044 = internalClosePosition(_trader, if (isPartialLiquidation)
1545+ let liquidationRatio = $t07191172234._1
1546+ let liquidationSize = $t07191172234._2
1547+ let $t07224072878 = internalClosePosition(_trader, if (isPartialLiquidation)
16031548 then liquidationSize
16041549 else positionSizeAbs, liquidationFeeRatio(), 0, true, false, true)
1605- let newPositionSize = $t07240673044._1
1606- let newPositionMargin = $t07240673044._2
1607- let newPositionOpenNotional = $t07240673044._3
1608- let newPositionLstUpdCPF = $t07240673044._4
1609- let positionBadDebt = $t07240673044._5
1610- let realizedPnl = $t07240673044._6
1611- let marginToTrader = $t07240673044._7
1612- let quoteAssetReserveAfter = $t07240673044._8
1613- let baseAssetReserveAfter = $t07240673044._9
1614- let totalPositionSizeAfter = $t07240673044._10
1615- let openInterestNotionalAfter = $t07240673044._11
1616- let totalLongAfter = $t07240673044._12
1617- let totalShortAfter = $t07240673044._13
1618- let totalLongOpenInterestAfter = $t07240673044._14
1619- let totalShortOpenInterestAfter = $t07240673044._15
1620- let liquidationPenalty = $t07240673044._16
1550+ let newPositionSize = $t07224072878._1
1551+ let newPositionMargin = $t07224072878._2
1552+ let newPositionOpenNotional = $t07224072878._3
1553+ let newPositionLstUpdCPF = $t07224072878._4
1554+ let positionBadDebt = $t07224072878._5
1555+ let realizedPnl = $t07224072878._6
1556+ let marginToTrader = $t07224072878._7
1557+ let quoteAssetReserveAfter = $t07224072878._8
1558+ let baseAssetReserveAfter = $t07224072878._9
1559+ let totalPositionSizeAfter = $t07224072878._10
1560+ let openInterestNotionalAfter = $t07224072878._11
1561+ let totalLongAfter = $t07224072878._12
1562+ let totalShortAfter = $t07224072878._13
1563+ let totalLongOpenInterestAfter = $t07224072878._14
1564+ let totalShortOpenInterestAfter = $t07224072878._15
1565+ let liquidationPenalty = $t07224072878._16
16211566 let feeToLiquidator = (liquidationPenalty / 2)
16221567 let feeToVault = (liquidationPenalty - feeToLiquidator)
16231568 let ammBalance = (cbalance() - liquidationPenalty)
16731618 then throw(((("Invalid funding block timestamp: " + toString(lastTimestamp())) + " < ") + toString(fundingBlockTimestamp)))
16741619 else {
16751620 let underlyingPrice = getOraclePrice()
1676- let $t07503175093 = getFunding()
1677- let shortPremiumFraction = $t07503175093._1
1678- let longPremiumFraction = $t07503175093._2
1679- updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice))
1621+ let $t07499175069 = getFunding()
1622+ let shortPremiumFraction = $t07499175069._1
1623+ let longPremiumFraction = $t07499175069._2
1624+ let premiumToVault = $t07499175069._3
1625+ let doPayFundingToVault = if ((premiumToVault > 0))
1626+ then {
1627+ let doPayFundingToVault = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(premiumToVault)], nil)
1628+ if ((doPayFundingToVault == doPayFundingToVault))
1629+ then nil
1630+ else throw("Strict value is not equal to itself.")
1631+ }
1632+ else nil
1633+ if ((doPayFundingToVault == doPayFundingToVault))
1634+ then updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice))
1635+ else throw("Strict value is not equal to itself.")
16801636 }
16811637 }
16821638 else throw("Strict value is not equal to itself.")
16881644 func syncTerminalPriceToOracle () = {
16891645 let _qtAstR = qtAstR()
16901646 let _bsAstR = bsAstR()
1691- let $t07552575891 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1692- let newQuoteAssetWeight = $t07552575891._1
1693- let newBaseAssetWeight = $t07552575891._2
1694- let marginToVault = $t07552575891._3
1647+ let $t07612076486 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1648+ let newQuoteAssetWeight = $t07612076486._1
1649+ let newBaseAssetWeight = $t07612076486._2
1650+ let marginToVault = $t07612076486._3
16951651 let marginToVaultAdj = if (if ((0 > marginToVault))
16961652 then (abs(marginToVault) > cbalance())
16971653 else false)
17061662 }
17071663 else nil
17081664 if ((doExchangePnL == doExchangePnL))
1709- then ((updateBalance((cbalance() + marginToVaultAdj)) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight)) ++ appendTwap(divd(muld(_qtAstR, newQuoteAssetWeight), muld(_bsAstR, newBaseAssetWeight))))
1665+ then (updateBalance((cbalance() + marginToVaultAdj)) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
17101666 else throw("Strict value is not equal to itself.")
17111667 }
17121668
17291685 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
17301686 if ((sync == sync))
17311687 then {
1732- let $t07705077174 = getPosition(_trader)
1733- let positionSize = $t07705077174._1
1734- let positionMargin = $t07705077174._2
1735- let pon = $t07705077174._3
1736- let positionLstUpdCPF = $t07705077174._4
1737- let positionTimestamp = $t07705077174._5
1738- let $t07717777278 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1739- let positionNotional = $t07717777278._1
1740- let unrealizedPnl = $t07717777278._2
1741- let $t07728177505 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
1742- let remainMargin = $t07728177505._1
1743- let badDebt = $t07728177505._2
1744- let fundingPayment = $t07728177505._3
1745- let rolloverFee = $t07728177505._4
1688+ let $t07803578159 = getPosition(_trader)
1689+ let positionSize = $t07803578159._1
1690+ let positionMargin = $t07803578159._2
1691+ let pon = $t07803578159._3
1692+ let positionLstUpdCPF = $t07803578159._4
1693+ let positionTimestamp = $t07803578159._5
1694+ let $t07816278263 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1695+ let positionNotional = $t07816278263._1
1696+ let unrealizedPnl = $t07816278263._2
1697+ let $t07826678490 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
1698+ let remainMargin = $t07826678490._1
1699+ let badDebt = $t07826678490._2
1700+ let fundingPayment = $t07826678490._3
1701+ let rolloverFee = $t07826678490._4
17461702 throw(((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)) + s(rolloverFee)))
17471703 }
17481704 else throw("Strict value is not equal to itself.")
17621718
17631719 @Callable(i)
17641720 func view_getTerminalAmmPrice () = {
1765- let $t07794178022 = getTerminalAmmState()
1766- let terminalQuoteAssetReserve = $t07794178022._1
1767- let terminalBaseAssetReserve = $t07794178022._2
1721+ let $t07921379294 = getTerminalAmmState()
1722+ let terminalQuoteAssetReserve = $t07921379294._1
1723+ let terminalBaseAssetReserve = $t07921379294._2
17681724 let price = divd(muld(terminalQuoteAssetReserve, qtAstW()), muld(terminalBaseAssetReserve, bsAstW()))
17691725 throw(toString(price))
17701726 }
17731729
17741730 @Callable(i)
17751731 func view_getFunding () = {
1776- let underlyingPrice = getOraclePrice()
1777- let $t07823778299 = getFunding()
1778- let shortPremiumFraction = $t07823778299._1
1779- let longPremiumFraction = $t07823778299._2
1780- let longFunding = divd(longPremiumFraction, underlyingPrice)
1781- let shortFunding = divd(shortPremiumFraction, underlyingPrice)
1782- throw((((s(longFunding) + s(shortFunding)) + s(getTwapSpotPrice())) + s(getOraclePrice())))
1732+ let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
1733+ if ((sync == sync))
1734+ then {
1735+ let underlyingPrice = getOraclePrice()
1736+ let $t07985379931 = getFunding()
1737+ let shortPremiumFraction = $t07985379931._1
1738+ let longPremiumFraction = $t07985379931._2
1739+ let premiumToVault = $t07985379931._3
1740+ let longFunding = divd(longPremiumFraction, underlyingPrice)
1741+ let shortFunding = divd(shortPremiumFraction, underlyingPrice)
1742+ throw(((((s(longFunding) + s(shortFunding)) + s(getSpotPrice())) + s(getOraclePrice())) + s(premiumToVault)))
1743+ }
1744+ else throw("Strict value is not equal to itself.")
17831745 }
17841746
17851747
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let k_baseOracle = "k_baseOracle"
55
66 let k_quoteOracle = "k_quoteOracle"
77
88 let k_balance = "k_balance"
99
1010 let k_sequence = "k_sequence"
1111
1212 let k_positionSize = "k_positionSize"
1313
1414 let k_positionMargin = "k_positionMargin"
1515
1616 let k_positionOpenNotional = "k_positionOpenNotional"
1717
1818 let k_positionLastUpdatedCumulativePremiumFraction = "k_positionFraction"
1919
2020 let k_positionSequence = "k_positionSequence"
21-
22-let k_positionAsset = "k_positionAsset"
2321
2422 let k_positionFee = "k_positionFee"
2523
2624 let k_positionLastUpdatedTimestamp = "k_positionTimestamp"
2725
2826 let k_initialized = "k_initialized"
2927
3028 let k_paused = "k_paused"
3129
3230 let k_closeOnly = "k_closeOnly"
3331
3432 let k_fee = "k_fee"
3533
3634 let k_rolloverFee = "k_rollover_fee"
3735
3836 let k_fundingPeriod = "k_fundingPeriod"
3937
4038 let k_initMarginRatio = "k_initMarginRatio"
4139
4240 let k_maintenanceMarginRatio = "k_mmr"
4341
4442 let k_liquidationFeeRatio = "k_liquidationFeeRatio"
4543
4644 let k_partialLiquidationRatio = "k_partLiquidationRatio"
4745
4846 let k_spreadLimit = "k_spreadLimit"
4947
5048 let k_maxPriceImpact = "k_maxPriceImpact"
5149
5250 let k_maxPriceSpread = "k_maxPriceSpread"
5351
5452 let k_maxOpenNotional = "k_maxOpenNotional"
5553
5654 let k_feeToStakersPercent = "k_feeToStakersPercent"
5755
5856 let k_maxOracleDelay = "k_maxOracleDelay"
5957
60-let k_lastDataStr = "k_lastDataStr"
61-
62-let k_lastMinuteId = "k_lastMinuteId"
63-
64-let k_twapDataLastCumulativePrice = "k_twapDataLastCumulativePrice"
65-
66-let k_twapDataLastPrice = "k_twapDataLastPrice"
67-
68-let k_twapDataPreviousMinuteId = "k_twapDataPreviousMinuteId"
58+let k_fundingMode = "k_fundingMode"
6959
7060 let k_latestLongCumulativePremiumFraction = "k_latestLongPremiumFraction"
7161
7262 let k_latestShortCumulativePremiumFraction = "k_latestShortPremiumFraction"
7363
7464 let k_nextFundingBlock = "k_nextFundingBlockMinTimestamp"
7565
7666 let k_longFundingRate = "k_longFundingRate"
7767
7868 let k_shortFundingRate = "k_shortFundingRate"
7969
8070 let k_quoteAssetReserve = "k_qtAstR"
8171
8272 let k_baseAssetReserve = "k_bsAstR"
8373
8474 let k_quoteAssetWeight = "k_qtAstW"
8575
8676 let k_baseAssetWeight = "k_bsAstW"
8777
8878 let k_totalPositionSize = "k_totalPositionSize"
8979
9080 let k_totalLongPositionSize = "k_totalLongPositionSize"
9181
9282 let k_totalShortPositionSize = "k_totalShortPositionSize"
9383
9484 let k_openInterestNotional = "k_openInterestNotional"
9585
9686 let k_openInterestShort = "k_openInterestShort"
9787
9888 let k_openInterestLong = "k_openInterestLong"
9989
10090 let k_lastTx = "k_lastTx"
10191
10292 let k_coordinatorAddress = "k_coordinatorAddress"
10393
10494 let k_vault_address = "k_vault_address"
10595
10696 let k_admin_address = "k_admin_address"
10797
10898 let k_quote_asset = "k_quote_asset"
10999
110100 let k_quote_staking = "k_quote_staking"
111101
112102 let k_staking_address = "k_staking_address"
113103
114104 let k_miner_address = "k_miner_address"
115105
116106 let k_orders_address = "k_orders_address"
117107
118108 let k_referral_address = "k_referral_address"
119109
120110 let k_exchange_address = "k_exchange_address"
121111
122112 let k_nft_manager_address = "k_nft_manager_address"
123113
124114 func toCompositeKey (_key,_address) = ((_key + "_") + _address)
125115
126116
127117 func coordinator () = valueOrErrorMessage(addressFromString(getStringValue(this, k_coordinatorAddress)), "Coordinator not set")
128118
129119
130120 func adminAddress () = addressFromString(getStringValue(coordinator(), k_admin_address))
131121
132122
133123 func quoteAsset () = fromBase58String(getStringValue(coordinator(), k_quote_asset))
134124
135125
136126 func quoteAssetStaking () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_quote_staking)), "Quote asset staking not set")
137127
138128
139129 func stakingAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_staking_address)), "Staking not set")
140130
141131
142132 func vaultAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_vault_address)), "Vault not set")
143133
144134
145135 func minerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_miner_address)), "Miner not set")
146136
147137
148138 func ordersAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_orders_address)), "Orders not set")
149139
150140
151141 func referralAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_referral_address)), "Referral not set")
152142
153143
154144 func nftManagerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_nft_manager_address)), "NFT Manager not set")
155145
156146
157147 let k_token_param = "k_token_param"
158148
159149 let k_token_type = "k_token_type"
160150
161151 let FEE_REDUCTION_TOKEN_TYPE = "fee_reduction"
162152
163153 let DIR_LONG = 1
164154
165155 let DIR_SHORT = 2
166156
167-let TWAP_INTERVAL = 15
168-
169157 let SECONDS = 1000
170158
171159 let DECIMAL_NUMBERS = 6
172160
173161 let DECIMAL_UNIT = (1 * (((((10 * 10) * 10) * 10) * 10) * 10))
174162
175163 let MINUTES_IN_YEAR = (525600 * DECIMAL_UNIT)
176164
177165 let ONE_DAY = (86400 * DECIMAL_UNIT)
178166
179167 let PNL_OPTION_SPOT = 1
180168
181169 let PNL_OPTION_ORACLE = 2
170+
171+let FUNDING_ASYMMETRIC = 1
172+
173+let FUNDING_SYMMETRIC = 2
182174
183175 func s (_x) = (toString(_x) + ",")
184176
185177
186178 func divd (_x,_y) = fraction(_x, DECIMAL_UNIT, _y, HALFEVEN)
187179
188180
189181 func muld (_x,_y) = fraction(_x, _y, DECIMAL_UNIT, HALFEVEN)
190182
191183
192184 func bdivd (_x,_y) = fraction(_x, toBigInt(DECIMAL_UNIT), _y, HALFEVEN)
193185
194186
195187 func bmuld (_x,_y) = fraction(_x, _y, toBigInt(DECIMAL_UNIT), HALFEVEN)
196188
197189
198190 func abs (_x) = if ((_x > 0))
199191 then _x
200192 else -(_x)
201193
202194
203195 func vmax (_x,_y) = if ((_x >= _y))
204196 then _x
205197 else _y
206-
207-
208-func listToStr (_list) = if ((size(_list) == 0))
209- then ""
210- else makeString(_list, ",")
211-
212-
213-func strToList (_str) = if ((_str == ""))
214- then nil
215- else split(_str, ",")
216-
217-
218-func pushToQueue (_list,_maxSize,_value) = if ((size(_list) > _maxSize))
219- then (removeByIndex(_list, 0) :+ _value)
220- else (_list :+ _value)
221198
222199
223200 func int (k) = valueOrErrorMessage(getInteger(this, k), ("no value for " + k))
224201
225202
226203 func intOr (k,def) = valueOrElse(getInteger(this, k), def)
227204
228205
229206 func strA (_address,_key) = {
230207 let val = valueOrErrorMessage(getString(_address, _key), ("No value for key " + _key))
231208 val
232209 }
233210
234211
235212 func intA (_address,_key) = {
236213 let val = valueOrErrorMessage(getInteger(_address, _key), ("No value for key " + _key))
237214 val
238215 }
239216
240217
241218 func cbalance () = int(k_balance)
242219
243220
244221 func fee () = int(k_fee)
245222
246223
247224 func rolloverFeeRate () = int(k_rolloverFee)
248225
249226
250227 func initMarginRatio () = int(k_initMarginRatio)
251228
252229
253230 func qtAstR () = int(k_quoteAssetReserve)
254231
255232
256233 func bsAstR () = int(k_baseAssetReserve)
257234
258235
259236 func qtAstW () = intOr(k_quoteAssetWeight, DECIMAL_UNIT)
260237
261238
262239 func bsAstW () = intOr(k_baseAssetWeight, DECIMAL_UNIT)
263240
264241
265242 func totalPositionSize () = int(k_totalPositionSize)
266243
267244
268245 func openInterestNotional () = int(k_openInterestNotional)
269246
270247
271248 func openInterestShort () = int(k_openInterestShort)
272249
273250
274251 func openInterestLong () = int(k_openInterestLong)
275252
276253
277254 func nextFundingBlockTimestamp () = int(k_nextFundingBlock)
278255
279256
280257 func fundingPeriodRaw () = int(k_fundingPeriod)
281258
282259
283260 func fundingPeriodDecimal () = (fundingPeriodRaw() * DECIMAL_UNIT)
284261
285262
286263 func fundingPeriodSeconds () = (fundingPeriodRaw() * SECONDS)
287264
288265
289266 func maintenanceMarginRatio () = int(k_maintenanceMarginRatio)
290267
291268
292269 func liquidationFeeRatio () = int(k_liquidationFeeRatio)
293270
294271
295272 func partialLiquidationRatio () = int(k_partialLiquidationRatio)
296273
297274
298275 func spreadLimit () = int(k_spreadLimit)
299276
300277
301278 func maxPriceImpact () = int(k_maxPriceImpact)
302279
303280
304281 func maxPriceSpread () = int(k_maxPriceSpread)
305282
306283
307284 func maxOpenNotional () = int(k_maxOpenNotional)
308285
309286
310287 func latestLongCumulativePremiumFraction () = int(k_latestLongCumulativePremiumFraction)
311288
312289
313290 func latestShortCumulativePremiumFraction () = int(k_latestShortCumulativePremiumFraction)
314291
315292
316293 func totalShortPositionSize () = int(k_totalShortPositionSize)
317294
318295
319296 func totalLongPositionSize () = int(k_totalLongPositionSize)
320297
321298
322299 func lastSequence () = intOr(k_sequence, 0)
323300
324301
325302 func feeToStakersPercent () = int(k_feeToStakersPercent)
326303
327304
328305 func maxOracleDelay () = int(k_maxOracleDelay)
329306
330307
308+func fundingMode () = intOr(k_fundingMode, FUNDING_ASYMMETRIC)
309+
310+
331311 func lastTimestamp () = lastBlock.timestamp
332312
333313
334314 func getActualCaller (i) = valueOrElse(getString(ordersAddress(), "k_sender"), toString(i.caller))
335315
336316
337317 func requireMoreMarginRatio (_marginRatio,_baseMarginRatio,_largerThanOrEqualTo) = {
338318 let remainingMarginRatio = (_marginRatio - _baseMarginRatio)
339319 if (if (_largerThanOrEqualTo)
340320 then (0 > remainingMarginRatio)
341321 else false)
342322 then throw(((("Invalid margin: " + toString(_marginRatio)) + " < ") + toString(_baseMarginRatio)))
343323 else if (if (!(_largerThanOrEqualTo))
344324 then (remainingMarginRatio >= 0)
345325 else false)
346326 then throw(((("Invalid margin: " + toString(_marginRatio)) + " > ") + toString(_baseMarginRatio)))
347327 else true
348328 }
349329
350330
351331 func latestCumulativePremiumFraction (_positionSize) = if ((_positionSize == 0))
352332 then throw("Should not be called with _positionSize == 0")
353333 else if ((_positionSize > 0))
354334 then latestLongCumulativePremiumFraction()
355335 else latestShortCumulativePremiumFraction()
356336
357337
358338 func getPosition (_trader) = {
359339 let positionSizeOpt = getInteger(this, toCompositeKey(k_positionSize, _trader))
360340 match positionSizeOpt {
361341 case positionSize: Int =>
362342 $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)))
363343 case _ =>
364344 $Tuple5(0, 0, 0, 0, 0)
365- }
366- }
367-
368-
369-func getPositionAsset (_trader) = {
370- let positionAssetOpt = getString(this, toCompositeKey(k_positionAsset, _trader))
371- match positionAssetOpt {
372- case positionAsset: String =>
373- positionAsset
374- case _ =>
375- toBase58String(quoteAsset())
376345 }
377346 }
378347
379348
380349 func getPositionFee (_trader) = {
381350 let positionFeeOpt = getInteger(this, toCompositeKey(k_positionFee, _trader))
382351 match positionFeeOpt {
383352 case positionFee: Int =>
384353 positionFee
385354 case _ =>
386355 fee()
387356 }
388357 }
389358
390359
391360 func requireOpenPosition (_trader) = if ((getPosition(_trader)._1 == 0))
392361 then throw("No open position")
393362 else true
394363
395364
396365 func getOracleData (key) = {
397366 let oracleDataStr = getString(this, key)
398367 if (if (isDefined(oracleDataStr))
399368 then (value(oracleDataStr) != "")
400369 else false)
401370 then {
402371 let oracleData = split(value(oracleDataStr), ",")
403372 let oracleAddress = valueOrErrorMessage(addressFromString(oracleData[0]), ("Invalid oracle address in: " + value(oracleDataStr)))
404373 let priceKey = oracleData[1]
405374 let blockKey = oracleData[2]
406375 let openKey = oracleData[3]
407376 $Tuple4(oracleAddress, priceKey, blockKey, openKey)
408377 }
409378 else unit
410379 }
411380
412381
413382 func initialized () = valueOrElse(getBoolean(this, k_initialized), false)
414383
415384
416385 func paused () = valueOrElse(getBoolean(this, k_paused), false)
417386
418387
419388 func closeOnly () = valueOrElse(getBoolean(this, k_closeOnly), false)
420389
421390
422391 func updateReserve (_isAdd,_quoteAssetAmount,_baseAssetAmount) = if (_isAdd)
423392 then {
424393 let newBase = (bsAstR() - _baseAssetAmount)
425394 if ((0 >= newBase))
426395 then throw("Tx lead to base asset reserve <= 0, revert")
427396 else $Tuple3((qtAstR() + _quoteAssetAmount), newBase, (totalPositionSize() + _baseAssetAmount))
428397 }
429398 else {
430399 let newQuote = (qtAstR() - _quoteAssetAmount)
431400 if ((0 >= newQuote))
432401 then throw("Tx lead to base quote reserve <= 0, revert")
433402 else $Tuple3(newQuote, (bsAstR() + _baseAssetAmount), (totalPositionSize() - _baseAssetAmount))
434403 }
435404
436405
437406 func calcInvariant (_qtAstR,_bsAstR) = {
438407 let bqtAstR = toBigInt(_qtAstR)
439408 let bbsAstR = toBigInt(_bsAstR)
440409 bmuld(bqtAstR, bbsAstR)
441410 }
442411
443412
444413 func swapInput (_isAdd,_quoteAssetAmount) = {
445414 let _qtAstR = qtAstR()
446415 let _bsAstR = bsAstR()
447416 let _qtAstW = qtAstW()
448417 let _bsAstW = bsAstW()
449418 let quoteAssetAmountAdjusted = divd(_quoteAssetAmount, _qtAstW)
450419 let k = calcInvariant(_qtAstR, _bsAstR)
451420 let quoteAssetReserveAfter = if (_isAdd)
452421 then (_qtAstR + quoteAssetAmountAdjusted)
453422 else (_qtAstR - quoteAssetAmountAdjusted)
454423 let baseAssetReserveAfter = toInt(bdivd(k, toBigInt(quoteAssetReserveAfter)))
455424 let amountBaseAssetBoughtAbs = abs((baseAssetReserveAfter - _bsAstR))
456425 let amountBaseAssetBought = if (_isAdd)
457426 then amountBaseAssetBoughtAbs
458427 else -(amountBaseAssetBoughtAbs)
459- let $t01672216892 = updateReserve(_isAdd, quoteAssetAmountAdjusted, amountBaseAssetBoughtAbs)
460- let quoteAssetReserveAfter1 = $t01672216892._1
461- let baseAssetReserveAfter1 = $t01672216892._2
462- let totalPositionSizeAfter1 = $t01672216892._3
428+ let $t01560115771 = updateReserve(_isAdd, quoteAssetAmountAdjusted, amountBaseAssetBoughtAbs)
429+ let quoteAssetReserveAfter1 = $t01560115771._1
430+ let baseAssetReserveAfter1 = $t01560115771._2
431+ let totalPositionSizeAfter1 = $t01560115771._3
463432 let priceBefore = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
464433 let marketPrice = divd(_quoteAssetAmount, amountBaseAssetBoughtAbs)
465434 let priceDiff = abs((priceBefore - marketPrice))
466435 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
467436 let maxPriceImpactValue = maxPriceImpact()
468437 if ((priceImpact > maxPriceImpactValue))
469438 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)))
470439 else $Tuple4(amountBaseAssetBought, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1)
471440 }
472441
473442
474443 func calcRolloverFee (_oldPositionMargin,_oldPositionLastUpdatedTimestamp) = {
475444 let positionMinutes = ((((lastTimestamp() - _oldPositionLastUpdatedTimestamp) / 1000) / 60) * DECIMAL_UNIT)
476445 let rolloverFee = divd(muld(muld(_oldPositionMargin, positionMinutes), rolloverFeeRate()), MINUTES_IN_YEAR)
477446 rolloverFee
478447 }
479448
480449
481450 func calcRemainMarginWithFundingPaymentAndRolloverFee (_oldPositionSize,_oldPositionMargin,_oldPositionCumulativePremiumFraction,_oldPositionLastUpdatedTimestamp,_marginDelta) = {
482451 let fundingPayment = if ((_oldPositionSize != 0))
483452 then {
484453 let _latestCumulativePremiumFraction = latestCumulativePremiumFraction(_oldPositionSize)
485454 muld((_latestCumulativePremiumFraction - _oldPositionCumulativePremiumFraction), _oldPositionSize)
486455 }
487456 else 0
488457 let rolloverFee = calcRolloverFee(_oldPositionMargin, _oldPositionLastUpdatedTimestamp)
489458 let signedMargin = (((_marginDelta - rolloverFee) - fundingPayment) + _oldPositionMargin)
490- let $t01914719274 = if ((0 > signedMargin))
459+ let $t01802618153 = if ((0 > signedMargin))
491460 then $Tuple2(0, abs(signedMargin))
492461 else $Tuple2(abs(signedMargin), 0)
493- let remainMargin = $t01914719274._1
494- let badDebt = $t01914719274._2
462+ let remainMargin = $t01802618153._1
463+ let badDebt = $t01802618153._2
495464 $Tuple4(remainMargin, badDebt, fundingPayment, rolloverFee)
496465 }
497466
498467
499468 func swapOutputWithReserves (_isAdd,_baseAssetAmount,_checkMaxPriceImpact,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight) = {
500469 let priceBefore = divd(muld(_quoteAssetReserve, _quoteAssetWeight), muld(_baseAssetReserve, _baseAssetWeight))
501470 if ((_baseAssetAmount == 0))
502471 then throw("Invalid base asset amount")
503472 else {
504473 let k = calcInvariant(_quoteAssetReserve, _baseAssetReserve)
505474 let baseAssetPoolAmountAfter = if (_isAdd)
506475 then (_baseAssetReserve + _baseAssetAmount)
507476 else (_baseAssetReserve - _baseAssetAmount)
508477 let quoteAssetAfter = toInt(bdivd(k, toBigInt(baseAssetPoolAmountAfter)))
509478 let quoteAssetDelta = abs((quoteAssetAfter - _quoteAssetReserve))
510479 let quoteAssetSold = muld(quoteAssetDelta, _quoteAssetWeight)
511480 let maxPriceImpactValue = maxPriceImpact()
512- let $t02053620698 = updateReserve(!(_isAdd), quoteAssetDelta, _baseAssetAmount)
513- let quoteAssetReserveAfter1 = $t02053620698._1
514- let baseAssetReserveAfter1 = $t02053620698._2
515- let totalPositionSizeAfter1 = $t02053620698._3
481+ let $t01941519577 = updateReserve(!(_isAdd), quoteAssetDelta, _baseAssetAmount)
482+ let quoteAssetReserveAfter1 = $t01941519577._1
483+ let baseAssetReserveAfter1 = $t01941519577._2
484+ let totalPositionSizeAfter1 = $t01941519577._3
516485 let marketPrice = divd(quoteAssetSold, _baseAssetAmount)
517486 let priceDiff = abs((priceBefore - marketPrice))
518487 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
519488 if (if ((priceImpact > maxPriceImpactValue))
520489 then _checkMaxPriceImpact
521490 else false)
522491 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)))
523492 else $Tuple7(quoteAssetSold, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1, (totalLongPositionSize() - (if (_isAdd)
524493 then abs(_baseAssetAmount)
525494 else 0)), (totalShortPositionSize() - (if (!(_isAdd))
526495 then abs(_baseAssetAmount)
527496 else 0)), priceImpact)
528497 }
529498 }
530499
531500
532501 func swapOutput (_isAdd,_baseAssetAmount,_checkMaxPriceImpact) = swapOutputWithReserves(_isAdd, _baseAssetAmount, _checkMaxPriceImpact, qtAstR(), qtAstW(), bsAstR(), bsAstW())
533502
534503
535504 func getOraclePriceValue (oracle,priceKey,blockKey) = {
536505 let lastValue = valueOrErrorMessage(getInteger(oracle, priceKey), ((("Can not get oracle price. Oracle: " + toString(oracle)) + " key: ") + priceKey))
537506 if ((blockKey != ""))
538507 then {
539508 let currentBlock = lastBlock.height
540509 let lastOracleBlock = valueOrErrorMessage(getInteger(oracle, blockKey), ((("Can not get oracle block. Oracle: " + toString(oracle)) + " key: ") + blockKey))
541510 if (((currentBlock - lastOracleBlock) > maxOracleDelay()))
542511 then throw(((("Oracle stale data. Last oracle block: " + toString(lastOracleBlock)) + " current block: ") + toString(currentBlock)))
543512 else lastValue
544513 }
545514 else lastValue
546515 }
547516
548517
549518 func getOraclePrice () = {
550519 let baseOracle = valueOrErrorMessage(getOracleData(k_baseOracle), "No base asset oracle data")
551520 let baseOraclePrice = getOraclePriceValue(baseOracle._1, baseOracle._2, baseOracle._3)
552521 let quoteOracle = getOracleData(k_quoteOracle)
553522 let quoteOraclePrice = if (isDefined(quoteOracle))
554523 then {
555524 let quoteOracleV = value(quoteOracle)
556525 getOraclePriceValue(quoteOracleV._1, quoteOracleV._2, quoteOracleV._3)
557526 }
558527 else DECIMAL_UNIT
559528 divd(baseOraclePrice, quoteOraclePrice)
560529 }
561530
562531
563532 func isMarketClosed () = {
564533 let baseOracle = valueOrErrorMessage(getOracleData(k_baseOracle), "No base asset oracle data")
565534 let oracle = baseOracle._1
566535 let openKey = baseOracle._4
567536 if ((openKey != ""))
568537 then {
569538 let isOpen = valueOrErrorMessage(getBoolean(oracle, openKey), ((("Can not get oracle is open/closed. Oracle: " + toString(oracle)) + " key: ") + openKey))
570539 !(isOpen)
571540 }
572541 else false
573542 }
574543
575544
576545 func absPriceDiff (_oraclePrice,_quoteAssetReserve,_baseAssetReserve,_qtAstW,_bsAstW) = {
577546 let priceAfter = divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW))
578547 let averagePrice = divd((_oraclePrice + priceAfter), (2 * DECIMAL_UNIT))
579548 let absPriceDiff = divd(abs((_oraclePrice - priceAfter)), averagePrice)
580549 absPriceDiff
581550 }
582551
583552
584553 func requireNotOverSpreadLimit (_quoteAssetReserve,_baseAssetReserve) = {
585554 let oraclePrice = getOraclePrice()
586555 let _qtAstW = qtAstW()
587556 let _bsAstW = bsAstW()
588557 let absPriceDiffBefore = absPriceDiff(oraclePrice, qtAstR(), bsAstR(), _qtAstW, _bsAstW)
589558 let absPriceDiffAfter = absPriceDiff(oraclePrice, _quoteAssetReserve, _baseAssetReserve, _qtAstW, _bsAstW)
590559 if (if ((absPriceDiffAfter > maxPriceSpread()))
591560 then (absPriceDiffAfter > absPriceDiffBefore)
592561 else false)
593562 then throw(((("Price spread " + toString(absPriceDiffAfter)) + " > max price spread ") + toString(maxPriceSpread())))
594563 else true
595564 }
596565
597566
598567 func requireNotOverMaxOpenNotional (_longOpenNotional,_shortOpenNotional) = {
599568 let _maxOpenNotional = maxOpenNotional()
600569 if ((_longOpenNotional > _maxOpenNotional))
601570 then throw(((("Long open notional " + toString(_longOpenNotional)) + " > max open notional ") + toString(_maxOpenNotional)))
602571 else if ((_shortOpenNotional > _maxOpenNotional))
603572 then throw(((("Short open notional " + toString(_shortOpenNotional)) + " > max open notional ") + toString(_maxOpenNotional)))
604573 else true
605574 }
606575
607576
608577 func getSpotPrice () = {
609578 let _quoteAssetReserve = qtAstR()
610579 let _baseAssetReserve = bsAstR()
611580 let _qtAstW = qtAstW()
612581 let _bsAstW = bsAstW()
613582 divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW))
614583 }
615584
616585
617586 func isOverFluctuationLimit () = {
618587 let oraclePrice = getOraclePrice()
619588 let currentPrice = getSpotPrice()
620589 (divd(abs((oraclePrice - currentPrice)), oraclePrice) > spreadLimit())
621590 }
622591
623592
624593 func getPositionAdjustedOpenNotional (_positionSize,_option,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight) = {
625594 let positionSizeAbs = abs(_positionSize)
626595 let isShort = (0 > _positionSize)
627596 let positionNotional = if ((_option == PNL_OPTION_SPOT))
628597 then {
629598 let outPositionNotional = swapOutputWithReserves(!(isShort), positionSizeAbs, false, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)._1
630599 outPositionNotional
631600 }
632601 else muld(positionSizeAbs, getOraclePrice())
633602 positionNotional
634603 }
635604
636605
637606 func getPositionNotionalAndUnrealizedPnlByValues (_positionSize,_positionOpenNotional,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight,_option) = if ((_positionSize == 0))
638607 then throw("Invalid position size")
639608 else {
640609 let isShort = (0 > _positionSize)
641610 let positionNotional = getPositionAdjustedOpenNotional(_positionSize, _option, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)
642611 let unrealizedPnl = if (isShort)
643612 then (_positionOpenNotional - positionNotional)
644613 else (positionNotional - _positionOpenNotional)
645614 $Tuple2(positionNotional, unrealizedPnl)
646615 }
647616
648617
649618 func getPositionNotionalAndUnrealizedPnl (_trader,_option) = {
650- let $t02857628704 = getPosition(_trader)
651- let positionSize = $t02857628704._1
652- let positionMargin = $t02857628704._2
653- let positionOpenNotional = $t02857628704._3
654- let positionLstUpdCPF = $t02857628704._4
619+ let $t02745527583 = getPosition(_trader)
620+ let positionSize = $t02745527583._1
621+ let positionMargin = $t02745527583._2
622+ let positionOpenNotional = $t02745527583._3
623+ let positionLstUpdCPF = $t02745527583._4
655624 getPositionNotionalAndUnrealizedPnlByValues(positionSize, positionOpenNotional, qtAstR(), qtAstW(), bsAstR(), bsAstW(), _option)
656625 }
657626
658627
659628 func calcMarginRatio (_remainMargin,_badDebt,_positionNotional) = divd((_remainMargin - _badDebt), _positionNotional)
660629
661630
662631 func getMarginRatioByOption (_trader,_option) = {
663- let $t02921929360 = getPosition(_trader)
664- let positionSize = $t02921929360._1
665- let positionMargin = $t02921929360._2
666- let pon = $t02921929360._3
667- let positionLastUpdatedCPF = $t02921929360._4
668- let positionTimestamp = $t02921929360._5
669- let $t02936629459 = getPositionNotionalAndUnrealizedPnl(_trader, _option)
670- let positionNotional = $t02936629459._1
671- let unrealizedPnl = $t02936629459._2
672- let $t02946429676 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLastUpdatedCPF, positionTimestamp, unrealizedPnl)
673- let remainMargin = $t02946429676._1
674- let badDebt = $t02946429676._2
632+ let $t02809828239 = getPosition(_trader)
633+ let positionSize = $t02809828239._1
634+ let positionMargin = $t02809828239._2
635+ let pon = $t02809828239._3
636+ let positionLastUpdatedCPF = $t02809828239._4
637+ let positionTimestamp = $t02809828239._5
638+ let $t02824528338 = getPositionNotionalAndUnrealizedPnl(_trader, _option)
639+ let positionNotional = $t02824528338._1
640+ let unrealizedPnl = $t02824528338._2
641+ let $t02834328555 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLastUpdatedCPF, positionTimestamp, unrealizedPnl)
642+ let remainMargin = $t02834328555._1
643+ let badDebt = $t02834328555._2
675644 calcMarginRatio(remainMargin, badDebt, positionNotional)
676645 }
677646
678647
679648 func getMarginRatio (_trader) = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
680649
681650
682651 func getPartialLiquidationAmount (_trader,_positionSize) = {
683652 let maximumRatio = vmax(partialLiquidationRatio(), (DECIMAL_UNIT - divd(getMarginRatio(_trader), maintenanceMarginRatio())))
684653 let maxExchangedPositionSize = muld(abs(_positionSize), maximumRatio)
685654 let swapResult = swapOutput((_positionSize > 0), maxExchangedPositionSize, false)
686655 let maxExchangedQuoteAssetAmount = swapResult._1
687656 let priceImpact = swapResult._7
688657 if ((maxPriceImpact() > priceImpact))
689658 then maxExchangedPositionSize
690659 else muld(abs(_positionSize), partialLiquidationRatio())
691660 }
692661
693662
694663 func internalClosePosition (_trader,_size,_fee,_minQuoteAssetAmount,_addToMargin,_checkMaxPriceImpact,_liquidate) = {
695- let $t03074330899 = getPosition(_trader)
696- let oldPositionSize = $t03074330899._1
697- let oldPositionMargin = $t03074330899._2
698- let oldPositionOpenNotional = $t03074330899._3
699- let oldPositionLstUpdCPF = $t03074330899._4
700- let oldPositionTimestamp = $t03074330899._5
664+ let $t02962229778 = getPosition(_trader)
665+ let oldPositionSize = $t02962229778._1
666+ let oldPositionMargin = $t02962229778._2
667+ let oldPositionOpenNotional = $t02962229778._3
668+ let oldPositionLstUpdCPF = $t02962229778._4
669+ let oldPositionTimestamp = $t02962229778._5
701670 let isLongPosition = (oldPositionSize > 0)
702671 let absOldPositionSize = abs(oldPositionSize)
703672 if (if ((absOldPositionSize >= _size))
704673 then (_size > 0)
705674 else false)
706675 then {
707676 let isPartialClose = (absOldPositionSize > _size)
708- let $t03119131642 = swapOutput((oldPositionSize > 0), _size, _checkMaxPriceImpact)
709- let exchangedQuoteAssetAmount = $t03119131642._1
710- let quoteAssetReserveAfter = $t03119131642._2
711- let baseAssetReserveAfter = $t03119131642._3
712- let totalPositionSizeAfter = $t03119131642._4
677+ let $t03007030521 = swapOutput((oldPositionSize > 0), _size, _checkMaxPriceImpact)
678+ let exchangedQuoteAssetAmount = $t03007030521._1
679+ let quoteAssetReserveAfter = $t03007030521._2
680+ let baseAssetReserveAfter = $t03007030521._3
681+ let totalPositionSizeAfter = $t03007030521._4
713682 let exchangedPositionSize = if ((oldPositionSize > 0))
714683 then -(_size)
715684 else _size
716- let $t03185732064 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
717- let oldPositionNotional = $t03185732064._1
718- let unrealizedPnl = $t03185732064._2
685+ let $t03073630943 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
686+ let oldPositionNotional = $t03073630943._1
687+ let unrealizedPnl = $t03073630943._2
719688 let realizedRatio = divd(abs(exchangedPositionSize), absOldPositionSize)
720689 let realizedPnl = muld(unrealizedPnl, realizedRatio)
721- let $t03240532651 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, unrealizedPnl)
722- let remainMarginBefore = $t03240532651._1
723- let x1 = $t03240532651._2
724- let x2 = $t03240532651._3
725- let rolloverFee = $t03240532651._4
690+ let $t03128431530 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, unrealizedPnl)
691+ let remainMarginBefore = $t03128431530._1
692+ let x1 = $t03128431530._2
693+ let x2 = $t03128431530._3
694+ let rolloverFee = $t03128431530._4
726695 let positionBadDebt = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, realizedPnl)._2
727696 let realizedCloseFee = muld(muld(oldPositionNotional, realizedRatio), _fee)
728697 let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
729698 let remainOpenNotional = if ((oldPositionSize > 0))
730699 then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
731700 else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
732701 let newPositionSize = (oldPositionSize + exchangedPositionSize)
733- let $t03405734443 = if ((newPositionSize == 0))
702+ let $t03293633322 = if ((newPositionSize == 0))
734703 then $Tuple2(0, 0)
735704 else $Tuple2(abs(remainOpenNotional), latestCumulativePremiumFraction(newPositionSize))
736- let newPositionOpenNotional = $t03405734443._1
737- let newPositionLstUpdCPF = $t03405734443._2
705+ let newPositionOpenNotional = $t03293633322._1
706+ let newPositionLstUpdCPF = $t03293633322._2
738707 let openNotionalDelta = (oldPositionOpenNotional - newPositionOpenNotional)
739708 let marginRatio = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
740709 let newPositionMarginWithSameRatio = if ((oldPositionSize > 0))
741710 then (muld((newPositionOpenNotional + unrealizedPnlAfter), marginRatio) - unrealizedPnlAfter)
742711 else (muld((newPositionOpenNotional - unrealizedPnlAfter), marginRatio) - unrealizedPnlAfter)
743712 let marginToTraderRaw = ((remainMarginBefore - (newPositionMarginWithSameRatio + unrealizedPnlAfter)) - realizedCloseFee)
744713 let marginToTrader = if ((0 > marginToTraderRaw))
745714 then if (_liquidate)
746715 then 0
747716 else throw("Invalid internalClosePosition params: unable to pay fee")
748717 else marginToTraderRaw
749718 let newPositionMargin = if (_addToMargin)
750719 then (newPositionMarginWithSameRatio + marginToTrader)
751720 else newPositionMarginWithSameRatio
752721 if (if ((_minQuoteAssetAmount != 0))
753722 then (_minQuoteAssetAmount > exchangedQuoteAssetAmount)
754723 else false)
755724 then throw(((("Limit error: " + toString(exchangedQuoteAssetAmount)) + " < ") + toString(_minQuoteAssetAmount)))
756725 else $Tuple17(newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, positionBadDebt, realizedPnl, if (if (_addToMargin)
757726 then isPartialClose
758727 else false)
759728 then 0
760729 else marginToTrader, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() - openNotionalDelta), (totalLongPositionSize() - (if (isLongPosition)
761730 then abs(exchangedPositionSize)
762731 else 0)), (totalShortPositionSize() - (if (!(isLongPosition))
763732 then abs(exchangedPositionSize)
764733 else 0)), (openInterestLong() - (if (isLongPosition)
765734 then openNotionalDelta
766735 else 0)), (openInterestShort() - (if (!(isLongPosition))
767736 then openNotionalDelta
768737 else 0)), (realizedCloseFee + rolloverFee), exchangedQuoteAssetAmount)
769738 }
770739 else throw(((("Invalid internalClosePosition params: invalid position size: " + toString(_size)) + " max: ") + toString(absOldPositionSize)))
771740 }
772741
773742
774-func getTwapSpotPrice () = {
775- let minuteId = ((lastTimestamp() / 1000) / 60)
776- let startMinuteId = (minuteId - TWAP_INTERVAL)
777- let listStr = valueOrElse(getString(this, k_lastDataStr), "")
778- let list = split(listStr, ",")
779- func filterFn (accumulator,next) = if ((startMinuteId >= valueOrErrorMessage(parseInt(next), ("getTwapSpotPrice: invalid int: " + listStr))))
780- then (accumulator :+ parseIntValue(next))
781- else accumulator
782-
783- let listF = {
784- let $l = list
785- let $s = size($l)
786- let $acc0 = nil
787- func $f0_1 ($a,$i) = if (($i >= $s))
788- then $a
789- else filterFn($a, $l[$i])
790-
791- func $f0_2 ($a,$i) = if (($i >= $s))
792- then $a
793- else throw("List size exceeds 20")
794-
795- $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)
796- }
797- let maxIndex = if ((size(listF) > 0))
798- then max(listF)
799- else valueOrErrorMessage(parseInt(list[0]), ("getTwapSpotPrice: invalid int: " + listStr))
800- let lastMinuteId = valueOrElse(getInteger(this, k_lastMinuteId), 0)
801- let endLastCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(lastMinuteId))), 0)
802- let endLastPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(lastMinuteId))), 0)
803- let nowCumulativePrice = (endLastCumulativePrice + ((minuteId - lastMinuteId) * endLastPrice))
804- let startLastCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(maxIndex))), 0)
805- let startLastPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(maxIndex))), 0)
806- let startCumulativePrice = (startLastCumulativePrice + ((startMinuteId - maxIndex) * startLastPrice))
807- ((nowCumulativePrice - startCumulativePrice) / TWAP_INTERVAL)
808- }
809-
810-
811743 func getTerminalAmmState () = {
812744 let _positionSize = totalPositionSize()
813745 if ((_positionSize == 0))
814746 then $Tuple2(qtAstR(), bsAstR())
815747 else {
816748 let direction = (_positionSize > 0)
817- let $t03918039359 = swapOutput(direction, abs(_positionSize), false)
818- let currentNetMarketValue = $t03918039359._1
819- let terminalQuoteAssetReserve = $t03918039359._2
820- let terminalBaseAssetReserve = $t03918039359._3
749+ let $t03655736736 = swapOutput(direction, abs(_positionSize), false)
750+ let currentNetMarketValue = $t03655736736._1
751+ let terminalQuoteAssetReserve = $t03655736736._2
752+ let terminalBaseAssetReserve = $t03655736736._3
821753 $Tuple2(terminalQuoteAssetReserve, terminalBaseAssetReserve)
822754 }
823755 }
824756
825757
826758 func getQuoteAssetWeight (baseAssetReserve,totalPositionSize,quoteAssetReserve,targetPrice) = {
827759 let b = toBigInt(baseAssetReserve)
828760 let sz = toBigInt(totalPositionSize)
829761 let q = toBigInt(quoteAssetReserve)
830762 let p = toBigInt(targetPrice)
831763 let k = bmuld(q, b)
832764 let newB = (b + sz)
833765 let newQ = bdivd(k, newB)
834766 let z = bdivd(newQ, newB)
835767 let result = bdivd(p, z)
836768 toInt(result)
837769 }
838770
839771
840772 func getSyncTerminalPrice (_terminalPrice,_qtAstR,_bsAstR) = {
841773 let _positionSize = totalPositionSize()
842774 if ((_positionSize == 0))
843775 then {
844776 let newQtAstW = divd(muld(_terminalPrice, _bsAstR), _qtAstR)
845777 $Tuple3(newQtAstW, DECIMAL_UNIT, 0)
846778 }
847779 else {
848780 let direction = (_positionSize > 0)
849781 let currentNetMarketValue = swapOutput(direction, abs(_positionSize), false)._1
850782 let newQtAstW = getQuoteAssetWeight(_bsAstR, _positionSize, _qtAstR, _terminalPrice)
851783 let newBsAstW = DECIMAL_UNIT
852784 let marginToVault = getPositionNotionalAndUnrealizedPnlByValues(_positionSize, currentNetMarketValue, _qtAstR, newQtAstW, _bsAstR, newBsAstW, PNL_OPTION_SPOT)._2
853785 $Tuple3(newQtAstW, newBsAstW, marginToVault)
854786 }
855787 }
856788
857789
858790 func getFunding () = {
859791 let underlyingPrice = getOraclePrice()
860- let spotTwapPrice = getTwapSpotPrice()
861- let premium = (spotTwapPrice - underlyingPrice)
792+ let spotPrice = getSpotPrice()
793+ let premium = (spotPrice - underlyingPrice)
862794 if (if (if ((totalShortPositionSize() == 0))
863795 then true
864796 else (totalLongPositionSize() == 0))
865797 then true
866798 else isMarketClosed())
867- then $Tuple2(0, 0)
799+ then $Tuple3(0, 0, 0)
868800 else if ((0 > premium))
869801 then {
870802 let shortPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY)
871- let longPremiumFraction = divd(muld(shortPremiumFraction, totalShortPositionSize()), totalLongPositionSize())
872- $Tuple2(shortPremiumFraction, longPremiumFraction)
803+ if ((fundingMode() == FUNDING_ASYMMETRIC))
804+ then {
805+ let longPremiumFraction = divd(muld(shortPremiumFraction, totalShortPositionSize()), totalLongPositionSize())
806+ $Tuple3(shortPremiumFraction, longPremiumFraction, 0)
807+ }
808+ else {
809+ let shortTotalPremiumFraction = abs(muld(shortPremiumFraction, totalShortPositionSize()))
810+ let longTotalPremiumFraction = abs(muld(shortPremiumFraction, totalLongPositionSize()))
811+ let premiumToVault = (shortTotalPremiumFraction - longTotalPremiumFraction)
812+ $Tuple3(shortPremiumFraction, shortPremiumFraction, premiumToVault)
813+ }
873814 }
874815 else {
875816 let longPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY)
876- let shortPremiumFraction = divd(muld(longPremiumFraction, totalLongPositionSize()), totalShortPositionSize())
877- $Tuple2(shortPremiumFraction, longPremiumFraction)
817+ if ((fundingMode() == FUNDING_ASYMMETRIC))
818+ then {
819+ let shortPremiumFraction = divd(muld(longPremiumFraction, totalLongPositionSize()), totalShortPositionSize())
820+ $Tuple3(shortPremiumFraction, longPremiumFraction, 0)
821+ }
822+ else {
823+ let longTotalPremiumFraction = abs(muld(longPremiumFraction, totalLongPositionSize()))
824+ let shortTotalPremiumFraction = abs(muld(longPremiumFraction, totalShortPositionSize()))
825+ let premiumToVault = (longTotalPremiumFraction - shortTotalPremiumFraction)
826+ $Tuple3(longPremiumFraction, longPremiumFraction, premiumToVault)
827+ }
878828 }
879829 }
880830
881831
882832 func getAdjustedFee (_artifactId,_baseFeeDiscount) = {
883833 let baseFeeRaw = fee()
884834 let baseFee = muld(baseFeeRaw, _baseFeeDiscount)
885- let $t04222042715 = if ((_artifactId != ""))
835+ let $t04045440949 = if ((_artifactId != ""))
886836 then {
887837 let artifactKind = strA(nftManagerAddress(), toCompositeKey(k_token_type, _artifactId))
888838 if ((artifactKind == FEE_REDUCTION_TOKEN_TYPE))
889839 then {
890840 let reduction = intA(nftManagerAddress(), toCompositeKey(k_token_param, _artifactId))
891841 let adjustedFee = muld(baseFee, reduction)
892842 $Tuple2(adjustedFee, true)
893843 }
894844 else throw("Invalid attached artifact")
895845 }
896846 else $Tuple2(baseFee, false)
897- let adjustedFee = $t04222042715._1
898- let burnArtifact = $t04222042715._2
847+ let adjustedFee = $t04045440949._1
848+ let burnArtifact = $t04045440949._2
899849 $Tuple2(adjustedFee, burnArtifact)
900850 }
901-
902-
903-func isSameAssetOrNoPosition (_trader,_assetId) = {
904- let oldPositionSize = getPosition(_trader)._1
905- if ((oldPositionSize == 0))
906- then true
907- else (getPositionAsset(_trader) == _assetId)
908- }
909-
910-
911-func isSameAsset (_trader,_assetId) = (getPositionAsset(_trader) == _assetId)
912851
913852
914853 func getForTraderWithArtifact (_trader,_artifactId) = {
915854 let doGetFeeDiscount = invoke(minerAddress(), "computeFeeDiscount", [_trader], nil)
916855 if ((doGetFeeDiscount == doGetFeeDiscount))
917856 then {
918857 let feeDiscount = match doGetFeeDiscount {
919858 case x: Int =>
920859 x
921860 case _ =>
922861 throw("Invalid computeFeeDiscount result")
923862 }
924- let $t04339543469 = getAdjustedFee(_artifactId, feeDiscount)
925- let adjustedFee = $t04339543469._1
926- let burnArtifact = $t04339543469._2
863+ let $t04129541369 = getAdjustedFee(_artifactId, feeDiscount)
864+ let adjustedFee = $t04129541369._1
865+ let burnArtifact = $t04129541369._2
927866 $Tuple2(adjustedFee, burnArtifact)
928867 }
929868 else throw("Strict value is not equal to itself.")
930869 }
931870
932871
933872 func getArtifactId (i) = {
934873 let artifactId = if ((size(i.payments) > 1))
935874 then toBase58String(valueOrErrorMessage(i.payments[1].assetId, "Invalid artifactId"))
936875 else ""
937876 artifactId
938877 }
939878
940879
941880 func distributeFee (_feeAmount) = {
942881 let feeToStakers = muld(_feeAmount, feeToStakersPercent())
943882 let feeToVault = (_feeAmount - feeToStakers)
944883 $Tuple2(feeToStakers, feeToVault)
945884 }
946885
947886
948-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)]
887+func updateSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee,_fundingMode) = [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), IntegerEntry(k_fundingMode, _fundingMode)]
949888
950889
951890 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)]
952891
953892
954893 func incrementPositionSequenceNumber (_isNewPosition,_address) = if (_isNewPosition)
955894 then {
956895 let currentSequence = lastSequence()
957896 [IntegerEntry(toCompositeKey(k_positionSequence, _address), (currentSequence + 1)), IntegerEntry(k_sequence, (currentSequence + 1))]
958897 }
959898 else nil
960899
961900
962901 func updatePositionFee (_isNewPosition,_address,_fee) = if (_isNewPosition)
963902 then [IntegerEntry(toCompositeKey(k_positionFee, _address), _fee)]
964903 else nil
965904
966905
967906 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)]
968907
969908
970-func appendTwap (_price) = {
971- let minuteId = ((lastTimestamp() / 1000) / 60)
972- let previousMinuteId = valueOrElse(getInteger(this, k_lastMinuteId), 0)
973- if ((previousMinuteId > minuteId))
974- then throw("TWAP out-of-order")
975- else {
976- let lastMinuteId = if ((previousMinuteId == 0))
977- then minuteId
978- else previousMinuteId
979- if ((minuteId > previousMinuteId))
980- then {
981- let prevCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(previousMinuteId))), 0)
982- let prevPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(previousMinuteId))), _price)
983- let lastCumulativePrice = (prevCumulativePrice + ((minuteId - lastMinuteId) * prevPrice))
984- let list = pushToQueue(strToList(valueOrElse(getString(this, k_lastDataStr), "")), TWAP_INTERVAL, toString(minuteId))
985-[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))]
986- }
987- else {
988- let twapDataPreviousMinuteId = valueOrElse(getInteger(this, toCompositeKey(k_twapDataPreviousMinuteId, toString(minuteId))), 0)
989- let prevCumulativePrice = valueOrElse(getInteger(this, toCompositeKey(k_twapDataLastCumulativePrice, toString(twapDataPreviousMinuteId))), 0)
990- let prevPrice = valueOrElse(getInteger(this, toCompositeKey(k_twapDataLastPrice, toString(twapDataPreviousMinuteId))), _price)
991- let lastCumulativePrice = (prevCumulativePrice + ((minuteId - twapDataPreviousMinuteId) * prevPrice))
992-[IntegerEntry(toCompositeKey(k_twapDataLastCumulativePrice, toString(minuteId)), lastCumulativePrice), IntegerEntry(toCompositeKey(k_twapDataLastPrice, toString(minuteId)), _price)]
993- }
994- }
995- }
996-
997-
998909 func updateAmmReserves (_qtAstR,_bsAstR) = [IntegerEntry(k_quoteAssetReserve, _qtAstR), IntegerEntry(k_baseAssetReserve, _bsAstR)]
999910
1000911
1001912 func updateAmmWeights (_qtAstW,_bsAstW) = [IntegerEntry(k_quoteAssetWeight, _qtAstW), IntegerEntry(k_baseAssetWeight, _bsAstW)]
1002913
1003914
1004915 func updateAmm (_qtAstR,_bsAstR,_totalPositionSizeAfter,_openInterestNotional,_totalLongPositionSize,_totalShortPositionSize,_totalLongOpenNotional,_totalShortOpenNotional) = {
1005916 let _qtAstW = qtAstW()
1006917 let _bsAstW = bsAstW()
1007918 if (((_totalLongPositionSize - _totalShortPositionSize) != _totalPositionSizeAfter))
1008919 then throw(((((("Invalid AMM state data: " + toString(_totalLongPositionSize)) + " + ") + toString(_totalShortPositionSize)) + " != ") + toString(_totalPositionSizeAfter)))
1009- 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))))
920+ 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)])
1010921 }
1011922
1012923
1013-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))]
924+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_positionFee, _address)), DeleteEntry(toCompositeKey(k_positionLastUpdatedTimestamp, _address))]
1014925
1015926
1016927 func withdraw (_address,_amount) = {
1017928 let balance = assetBalance(this, quoteAsset())
1018929 if ((_amount > balance))
1019930 then throw(((("Unable to withdraw " + toString(_amount)) + " from contract balance ") + toString(balance)))
1020931 else [ScriptTransfer(_address, _amount, quoteAsset())]
1021932 }
1022933
1023934
1024935 func updateBalance (i) = if ((0 > i))
1025936 then throw("Balance")
1026937 else [IntegerEntry(k_balance, i)]
1027938
1028939
1029940 func transferFee (i) = [ScriptTransfer(stakingAddress(), i, quoteAsset())]
1030941
1031942
1032943 func doBurnArtifact (_burnArtifact,i) = if (_burnArtifact)
1033944 then [Burn(valueOrErrorMessage(i.payments[1].assetId, "Invalid artifact"), 1)]
1034945 else nil
1035946
1036947
1037948 @Callable(i)
1038949 func pause () = if ((i.caller != adminAddress()))
1039950 then throw("Invalid pause params")
1040951 else [BooleanEntry(k_paused, true)]
1041952
1042953
1043954
1044955 @Callable(i)
1045956 func unpause () = if ((i.caller != adminAddress()))
1046957 then throw("Invalid unpause params")
1047958 else [BooleanEntry(k_paused, false)]
1048959
1049960
1050961
1051962 @Callable(i)
1052963 func setCloseOnly () = if ((i.caller != adminAddress()))
1053964 then throw("Invalid setCloseOnly params")
1054965 else [BooleanEntry(k_closeOnly, true)]
1055966
1056967
1057968
1058969 @Callable(i)
1059970 func unsetCloseOnly () = if ((i.caller != adminAddress()))
1060971 then throw("Invalid unsetCloseOnly params")
1061972 else [BooleanEntry(k_closeOnly, false)]
1062973
1063974
1064975
1065976 @Callable(i)
1066977 func addLiquidity (_quoteAssetAmount) = if (if ((i.caller != adminAddress()))
1067978 then true
1068979 else (0 >= _quoteAssetAmount))
1069980 then throw("Invalid addLiquidity params")
1070981 else {
1071982 let _qtAstR = qtAstR()
1072983 let _bsAstR = bsAstR()
1073984 let _qtAstW = qtAstW()
1074985 let _bsAstW = bsAstW()
1075986 let price = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
1076987 let qtAstRAfter = (_qtAstR + _quoteAssetAmount)
1077988 let baseAssetAmountToAdd = (divd(muld(qtAstRAfter, _qtAstW), price) - _bsAstR)
1078989 let bsAstRAfter = (_bsAstR + baseAssetAmountToAdd)
1079- let $t05287653027 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1080- let newQuoteAssetWeight = $t05287653027._1
1081- let newBaseAssetWeight = $t05287653027._2
1082- let marginToVault = $t05287653027._3
990+ let $t04926349414 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
991+ let newQuoteAssetWeight = $t04926349414._1
992+ let newBaseAssetWeight = $t04926349414._2
993+ let marginToVault = $t04926349414._3
1083994 let doExchangePnL = if ((marginToVault != 0))
1084995 then {
1085996 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
1086997 if ((doExchangePnL == doExchangePnL))
1087998 then nil
1088999 else throw("Strict value is not equal to itself.")
10891000 }
10901001 else nil
10911002 if ((doExchangePnL == doExchangePnL))
10921003 then (updateAmmReserves(qtAstRAfter, bsAstRAfter) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
10931004 else throw("Strict value is not equal to itself.")
10941005 }
10951006
10961007
10971008
10981009 @Callable(i)
10991010 func removeLiquidity (_quoteAssetAmount) = if (if ((i.caller != adminAddress()))
11001011 then true
11011012 else (_quoteAssetAmount >= 0))
11021013 then throw("Invalid removeLiquidity params")
11031014 else {
11041015 let _qtAstR = qtAstR()
11051016 let _bsAstR = bsAstR()
11061017 let _qtAstW = qtAstW()
11071018 let _bsAstW = bsAstW()
11081019 let price = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
11091020 let qtAstRAfter = (_qtAstR - _quoteAssetAmount)
11101021 let baseAssetAmountToRemove = abs((divd(muld(qtAstRAfter, _qtAstW), price) - _bsAstR))
11111022 let bsAstRAfter = (_bsAstR - baseAssetAmountToRemove)
1112- let $t05395954110 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1113- let newQuoteAssetWeight = $t05395954110._1
1114- let newBaseAssetWeight = $t05395954110._2
1115- let marginToVault = $t05395954110._3
1023+ let $t05051050661 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1024+ let newQuoteAssetWeight = $t05051050661._1
1025+ let newBaseAssetWeight = $t05051050661._2
1026+ let marginToVault = $t05051050661._3
11161027 let doExchangePnL = if ((marginToVault != 0))
11171028 then {
11181029 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
11191030 if ((doExchangePnL == doExchangePnL))
11201031 then nil
11211032 else throw("Strict value is not equal to itself.")
11221033 }
11231034 else nil
11241035 if ((doExchangePnL == doExchangePnL))
11251036 then (updateAmmReserves(qtAstRAfter, bsAstRAfter) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
11261037 else throw("Strict value is not equal to itself.")
11271038 }
11281039
11291040
11301041
11311042 @Callable(i)
1132-func changeSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee) = if ((i.caller != adminAddress()))
1043+func changeSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee,_fundingMode) = if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if ((0 >= _fundingPeriod))
1044+ then true
1045+ else (0 >= _initMarginRatio))
1046+ then true
1047+ else (0 >= _mmr))
1048+ then true
1049+ else (0 >= _liquidationFeeRatio))
1050+ then true
1051+ else (0 >= _fee))
1052+ then true
1053+ else (0 >= _spreadLimit))
1054+ then true
1055+ else (0 >= _maxPriceImpact))
1056+ then true
1057+ else (0 >= _partialLiquidationRatio))
1058+ then true
1059+ else (0 >= _maxPriceSpread))
1060+ then true
1061+ else (0 >= _maxOpenNotional))
1062+ then true
1063+ else (0 >= _feeToStakersPercent))
1064+ then true
1065+ else (_feeToStakersPercent > DECIMAL_UNIT))
1066+ then true
1067+ else (0 >= _maxOracleDelay))
1068+ then true
1069+ else (0 >= _rolloverFee))
1070+ then true
1071+ else if ((_fundingMode != FUNDING_SYMMETRIC))
1072+ then (_fundingMode != FUNDING_ASYMMETRIC)
1073+ else false)
1074+ then true
1075+ else !(initialized()))
1076+ then true
1077+ else (i.caller != adminAddress()))
11331078 then throw("Invalid changeSettings params")
1134- else updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread, _maxOpenNotional, _feeToStakersPercent, _maxOracleDelay, _rolloverFee)
1079+ else updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread, _maxOpenNotional, _feeToStakersPercent, _maxOracleDelay, _rolloverFee, _fundingMode)
11351080
11361081
11371082
11381083 @Callable(i)
1139-func initialize (_qtAstR,_bsAstR,_fundingPeriod,_initMarginRatio,_mmr,_liquidationFeeRatio,_fee,_baseOracleData,_quoteOracleData,_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 (if ((0 >= _qtAstR))
1084+func initialize (_qtAstR,_bsAstR,_fundingPeriod,_initMarginRatio,_mmr,_liquidationFeeRatio,_fee,_baseOracleData,_quoteOracleData,_coordinator,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee,_fundingMode) = if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if ((0 >= _qtAstR))
11401085 then true
11411086 else (0 >= _bsAstR))
11421087 then true
11431088 else (0 >= _fundingPeriod))
11441089 then true
11451090 else (0 >= _initMarginRatio))
11461091 then true
11471092 else (0 >= _mmr))
11481093 then true
11491094 else (0 >= _liquidationFeeRatio))
11501095 then true
11511096 else (0 >= _fee))
11521097 then true
11531098 else (0 >= _spreadLimit))
11541099 then true
11551100 else (0 >= _maxPriceImpact))
11561101 then true
11571102 else (0 >= _partialLiquidationRatio))
11581103 then true
11591104 else (0 >= _maxPriceSpread))
11601105 then true
11611106 else (0 >= _maxOpenNotional))
11621107 then true
11631108 else (0 >= _feeToStakersPercent))
11641109 then true
11651110 else (_feeToStakersPercent > DECIMAL_UNIT))
11661111 then true
11671112 else (0 >= _maxOracleDelay))
11681113 then true
11691114 else (0 >= _rolloverFee))
11701115 then true
1116+ else if ((_fundingMode != FUNDING_SYMMETRIC))
1117+ then (_fundingMode != FUNDING_ASYMMETRIC)
1118+ else false)
1119+ then true
11711120 else initialized())
11721121 then true
11731122 else (i.caller != this))
11741123 then throw("Invalid initialize parameters")
1175- 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_baseOracle, _baseOracleData), StringEntry(k_quoteOracle, _quoteOracleData), StringEntry(k_coordinatorAddress, toString(addressFromStringValue(_coordinator)))])
1124+ else ((((updateAmm(_qtAstR, _bsAstR, 0, 0, 0, 0, 0, 0) ++ updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread, _maxOpenNotional, _feeToStakersPercent, _maxOracleDelay, _rolloverFee, _fundingMode)) ++ updateFunding((lastTimestamp() + _fundingPeriod), 0, 0, 0, 0)) ++ updateBalance(0)) ++ [BooleanEntry(k_initialized, true), StringEntry(k_baseOracle, _baseOracleData), StringEntry(k_quoteOracle, _quoteOracleData), StringEntry(k_coordinatorAddress, toString(addressFromStringValue(_coordinator)))])
11761125
11771126
11781127
11791128 @Callable(i)
11801129 func increasePosition (_direction,_leverage,_minBaseAssetAmount,_refLink) = {
11811130 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
11821131 if ((sync == sync))
11831132 then {
11841133 let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
11851134 if ((ensureCalledOnce == ensureCalledOnce))
11861135 then {
11871136 let _trader = getActualCaller(i)
11881137 let _rawAmount = i.payments[0].amount
11891138 let _assetId = i.payments[0].assetId
11901139 let _assetIdStr = toBase58String(value(_assetId))
11911140 let isQuoteAsset = (_assetId == quoteAsset())
1192- if (if (if (if (if (if (if (if (if (if ((_direction != DIR_LONG))
1141+ if (if (if (if (if (if (if (if (if ((_direction != DIR_LONG))
11931142 then (_direction != DIR_SHORT)
11941143 else false)
11951144 then true
11961145 else (0 >= _rawAmount))
11971146 then true
11981147 else !(initialized()))
11991148 then true
12001149 else !(isQuoteAsset))
1201- then true
1202- else !(isSameAssetOrNoPosition(_trader, _assetIdStr)))
12031150 then true
12041151 else !(requireMoreMarginRatio(divd(DECIMAL_UNIT, _leverage), initMarginRatio(), true)))
12051152 then true
12061153 else paused())
12071154 then true
12081155 else closeOnly())
12091156 then true
12101157 else isMarketClosed())
12111158 then throw("Invalid increasePosition parameters")
12121159 else {
1213- let $t05788858037 = getForTraderWithArtifact(_trader, getArtifactId(i))
1214- let adjustedFee = $t05788858037._1
1215- let burnArtifact = $t05788858037._2
1160+ let $t05673156880 = getForTraderWithArtifact(_trader, getArtifactId(i))
1161+ let adjustedFee = $t05673156880._1
1162+ let burnArtifact = $t05673156880._2
12161163 let _amount = divd(_rawAmount, (muld(adjustedFee, _leverage) + DECIMAL_UNIT))
12171164 let distributeFeeAmount = (_rawAmount - _amount)
12181165 let referrerFeeAny = invoke(referralAddress(), "acceptPaymentWithLink", [_trader, _refLink], [AttachedPayment(quoteAsset(), distributeFeeAmount)])
12191166 if ((referrerFeeAny == referrerFeeAny))
12201167 then {
12211168 let referrerFee = match referrerFeeAny {
12221169 case x: Int =>
12231170 x
12241171 case _ =>
12251172 throw("Invalid referrerFee")
12261173 }
12271174 let feeAmount = (distributeFeeAmount - referrerFee)
1228- let $t05853358701 = getPosition(_trader)
1229- let oldPositionSize = $t05853358701._1
1230- let oldPositionMargin = $t05853358701._2
1231- let oldPositionOpenNotional = $t05853358701._3
1232- let oldPositionLstUpdCPF = $t05853358701._4
1233- let oldPositionTimestamp = $t05853358701._5
1175+ let $t05737657544 = getPosition(_trader)
1176+ let oldPositionSize = $t05737657544._1
1177+ let oldPositionMargin = $t05737657544._2
1178+ let oldPositionOpenNotional = $t05737657544._3
1179+ let oldPositionLstUpdCPF = $t05737657544._4
1180+ let oldPositionTimestamp = $t05737657544._5
12341181 let isNewPosition = (oldPositionSize == 0)
12351182 let isSameDirection = if ((oldPositionSize > 0))
12361183 then (_direction == DIR_LONG)
12371184 else (_direction == DIR_SHORT)
12381185 let expandExisting = if (!(isNewPosition))
12391186 then isSameDirection
12401187 else false
12411188 let isAdd = (_direction == DIR_LONG)
1242- let $t05899062111 = if (if (isNewPosition)
1189+ let $t05783360954 = if (if (isNewPosition)
12431190 then true
12441191 else expandExisting)
12451192 then {
12461193 let openNotional = muld(_amount, _leverage)
1247- let $t05949959672 = swapInput(isAdd, openNotional)
1248- let amountBaseAssetBought = $t05949959672._1
1249- let quoteAssetReserveAfter = $t05949959672._2
1250- let baseAssetReserveAfter = $t05949959672._3
1251- let totalPositionSizeAfter = $t05949959672._4
1194+ let $t05834258515 = swapInput(isAdd, openNotional)
1195+ let amountBaseAssetBought = $t05834258515._1
1196+ let quoteAssetReserveAfter = $t05834258515._2
1197+ let baseAssetReserveAfter = $t05834258515._3
1198+ let totalPositionSizeAfter = $t05834258515._4
12521199 if (if ((_minBaseAssetAmount != 0))
12531200 then (_minBaseAssetAmount > abs(amountBaseAssetBought))
12541201 else false)
12551202 then throw(((("Limit error: " + toString(abs(amountBaseAssetBought))) + " < ") + toString(_minBaseAssetAmount)))
12561203 else {
12571204 let newPositionSize = (oldPositionSize + amountBaseAssetBought)
12581205 let totalLongOpenInterestAfter = (openInterestLong() + (if ((newPositionSize > 0))
12591206 then openNotional
12601207 else 0))
12611208 let totalShortOpenInterestAfter = (openInterestShort() + (if ((0 > newPositionSize))
12621209 then openNotional
12631210 else 0))
1264- let $t06021860493 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
1265- let remainMargin = $t06021860493._1
1266- let x1 = $t06021860493._2
1267- let x2 = $t06021860493._3
1268- let rolloverFee = $t06021860493._4
1211+ let $t05906159336 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
1212+ let remainMargin = $t05906159336._1
1213+ let x1 = $t05906159336._2
1214+ let x2 = $t05906159336._3
1215+ let rolloverFee = $t05906159336._4
12691216 if (!(requireNotOverSpreadLimit(quoteAssetReserveAfter, baseAssetReserveAfter)))
12701217 then throw("Over max spread limit")
12711218 else if (!(requireNotOverMaxOpenNotional(totalLongOpenInterestAfter, totalShortOpenInterestAfter)))
12721219 then throw("Over max open notional")
12731220 else $Tuple14(newPositionSize, remainMargin, (oldPositionOpenNotional + openNotional), latestCumulativePremiumFraction(newPositionSize), lastTimestamp(), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() + openNotional), (totalLongPositionSize() + (if ((newPositionSize > 0))
12741221 then abs(amountBaseAssetBought)
12751222 else 0)), (totalShortPositionSize() + (if ((0 > newPositionSize))
12761223 then abs(amountBaseAssetBought)
12771224 else 0)), totalLongOpenInterestAfter, totalShortOpenInterestAfter, rolloverFee)
12781225 }
12791226 }
12801227 else {
12811228 let openNotional = muld(_amount, _leverage)
1282- let $t06181161927 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
1283- let oldPositionNotional = $t06181161927._1
1284- let unrealizedPnl = $t06181161927._2
1229+ let $t06065460770 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
1230+ let oldPositionNotional = $t06065460770._1
1231+ let unrealizedPnl = $t06065460770._2
12851232 if ((oldPositionNotional > openNotional))
12861233 then throw("Use decreasePosition to decrease position size")
12871234 else throw("Close position first")
12881235 }
1289- let newPositionSize = $t05899062111._1
1290- let newPositionRemainMargin = $t05899062111._2
1291- let newPositionOpenNotional = $t05899062111._3
1292- let newPositionLatestCPF = $t05899062111._4
1293- let newPositionTimestamp = $t05899062111._5
1294- let baseAssetReserveAfter = $t05899062111._6
1295- let quoteAssetReserveAfter = $t05899062111._7
1296- let totalPositionSizeAfter = $t05899062111._8
1297- let openInterestNotionalAfter = $t05899062111._9
1298- let totalLongAfter = $t05899062111._10
1299- let totalShortAfter = $t05899062111._11
1300- let totalLongOpenInterestAfter = $t05899062111._12
1301- let totalShortOpenInterestAfter = $t05899062111._13
1302- let rolloverFee = $t05899062111._14
1303- let $t06211762188 = distributeFee((feeAmount + rolloverFee))
1304- let feeToStakers = $t06211762188._1
1305- let feeToVault = $t06211762188._2
1236+ let newPositionSize = $t05783360954._1
1237+ let newPositionRemainMargin = $t05783360954._2
1238+ let newPositionOpenNotional = $t05783360954._3
1239+ let newPositionLatestCPF = $t05783360954._4
1240+ let newPositionTimestamp = $t05783360954._5
1241+ let baseAssetReserveAfter = $t05783360954._6
1242+ let quoteAssetReserveAfter = $t05783360954._7
1243+ let totalPositionSizeAfter = $t05783360954._8
1244+ let openInterestNotionalAfter = $t05783360954._9
1245+ let totalLongAfter = $t05783360954._10
1246+ let totalShortAfter = $t05783360954._11
1247+ let totalLongOpenInterestAfter = $t05783360954._12
1248+ let totalShortOpenInterestAfter = $t05783360954._13
1249+ let rolloverFee = $t05783360954._14
1250+ let $t06096061031 = distributeFee((feeAmount + rolloverFee))
1251+ let feeToStakers = $t06096061031._1
1252+ let feeToVault = $t06096061031._2
13061253 let stake = if ((_amount >= rolloverFee))
13071254 then invoke(vaultAddress(), "addLocked", nil, [AttachedPayment(quoteAsset(), (_amount - rolloverFee))])
13081255 else invoke(vaultAddress(), "withdrawLocked", [(rolloverFee - _amount)], nil)
13091256 if ((stake == stake))
13101257 then {
13111258 let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
13121259 if ((depositVault == depositVault))
13131260 then {
13141261 let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, feeAmount], nil)
13151262 if ((notifyFee == notifyFee))
13161263 then {
13171264 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
13181265 if ((notifyNotional == notifyNotional))
13191266 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) - rolloverFee))) ++ doBurnArtifact(burnArtifact, i))
13201267 else throw("Strict value is not equal to itself.")
13211268 }
13221269 else throw("Strict value is not equal to itself.")
13231270 }
13241271 else throw("Strict value is not equal to itself.")
13251272 }
13261273 else throw("Strict value is not equal to itself.")
13271274 }
13281275 else throw("Strict value is not equal to itself.")
13291276 }
13301277 }
13311278 else throw("Strict value is not equal to itself.")
13321279 }
13331280 else throw("Strict value is not equal to itself.")
13341281 }
13351282
13361283
13371284
13381285 @Callable(i)
13391286 func addMargin () = {
13401287 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
13411288 if ((sync == sync))
13421289 then {
13431290 let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
13441291 if ((ensureCalledOnce == ensureCalledOnce))
13451292 then {
13461293 let _trader = toString(i.caller)
13471294 let _amount = i.payments[0].amount
13481295 let _assetId = i.payments[0].assetId
13491296 let _assetIdStr = toBase58String(value(_assetId))
13501297 let isQuoteAsset = (_assetId == quoteAsset())
1351- if (if (if (if (if (if (if (!(isQuoteAsset))
1298+ if (if (if (if (if (if (!(isQuoteAsset))
13521299 then true
13531300 else !(requireOpenPosition(toString(i.caller))))
1354- then true
1355- else !(isSameAsset(_trader, _assetIdStr)))
13561301 then true
13571302 else !(initialized()))
13581303 then true
13591304 else paused())
13601305 then true
13611306 else closeOnly())
13621307 then true
13631308 else isMarketClosed())
13641309 then throw("Invalid addMargin parameters")
13651310 else {
1366- let $t06429964467 = getPosition(_trader)
1367- let oldPositionSize = $t06429964467._1
1368- let oldPositionMargin = $t06429964467._2
1369- let oldPositionOpenNotional = $t06429964467._3
1370- let oldPositionLstUpdCPF = $t06429964467._4
1371- let oldPositionTimestamp = $t06429964467._5
1311+ let $t06324663414 = getPosition(_trader)
1312+ let oldPositionSize = $t06324663414._1
1313+ let oldPositionMargin = $t06324663414._2
1314+ let oldPositionOpenNotional = $t06324663414._3
1315+ let oldPositionLstUpdCPF = $t06324663414._4
1316+ let oldPositionTimestamp = $t06324663414._5
13721317 let stake = invoke(vaultAddress(), "addLocked", nil, [AttachedPayment(quoteAsset(), _amount)])
13731318 if ((stake == stake))
13741319 then {
13751320 let rolloverFee = calcRolloverFee(oldPositionMargin, oldPositionTimestamp)
13761321 let doTransferFeeToStakers = if ((rolloverFee > 0))
13771322 then {
1378- let $t06475264811 = distributeFee(rolloverFee)
1379- let feeToStakers = $t06475264811._1
1380- let feeToVault = $t06475264811._2
1323+ let $t06369963758 = distributeFee(rolloverFee)
1324+ let feeToStakers = $t06369963758._1
1325+ let feeToVault = $t06369963758._2
13811326 let unstake = invoke(vaultAddress(), "withdrawLocked", [feeToStakers], nil)
13821327 if ((unstake == unstake))
13831328 then {
13841329 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
13851330 if ((lockBadDebt == lockBadDebt))
13861331 then transferFee(feeToStakers)
13871332 else throw("Strict value is not equal to itself.")
13881333 }
13891334 else throw("Strict value is not equal to itself.")
13901335 }
13911336 else nil
13921337 if ((doTransferFeeToStakers == doTransferFeeToStakers))
13931338 then ((updatePosition(_trader, oldPositionSize, ((oldPositionMargin - rolloverFee) + _amount), oldPositionOpenNotional, oldPositionLstUpdCPF, lastTimestamp()) ++ updateBalance(((cbalance() + _amount) - rolloverFee))) ++ doTransferFeeToStakers)
13941339 else throw("Strict value is not equal to itself.")
13951340 }
13961341 else throw("Strict value is not equal to itself.")
13971342 }
13981343 }
13991344 else throw("Strict value is not equal to itself.")
14001345 }
14011346 else throw("Strict value is not equal to itself.")
14021347 }
14031348
14041349
14051350
14061351 @Callable(i)
14071352 func removeMargin (_amount) = {
14081353 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
14091354 if ((sync == sync))
14101355 then {
14111356 let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
14121357 if ((ensureCalledOnce == ensureCalledOnce))
14131358 then {
14141359 let _trader = toString(i.caller)
14151360 if (if (if (if (if ((0 >= _amount))
14161361 then true
14171362 else !(requireOpenPosition(_trader)))
14181363 then true
14191364 else !(initialized()))
14201365 then true
14211366 else paused())
14221367 then true
14231368 else isMarketClosed())
14241369 then throw("Invalid removeMargin parameters")
14251370 else {
1426- let $t06592366091 = getPosition(_trader)
1427- let oldPositionSize = $t06592366091._1
1428- let oldPositionMargin = $t06592366091._2
1429- let oldPositionOpenNotional = $t06592366091._3
1430- let oldPositionLstUpdCPF = $t06592366091._4
1431- let oldPositionTimestamp = $t06592366091._5
1432- let $t06609766346 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, -(_amount))
1433- let remainMargin = $t06609766346._1
1434- let badDebt = $t06609766346._2
1435- let fundingPayment = $t06609766346._3
1436- let rolloverFee = $t06609766346._4
1371+ let $t06513165299 = getPosition(_trader)
1372+ let oldPositionSize = $t06513165299._1
1373+ let oldPositionMargin = $t06513165299._2
1374+ let oldPositionOpenNotional = $t06513165299._3
1375+ let oldPositionLstUpdCPF = $t06513165299._4
1376+ let oldPositionTimestamp = $t06513165299._5
1377+ let $t06530565554 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, -(_amount))
1378+ let remainMargin = $t06530565554._1
1379+ let badDebt = $t06530565554._2
1380+ let fundingPayment = $t06530565554._3
1381+ let rolloverFee = $t06530565554._4
14371382 if ((badDebt != 0))
14381383 then throw("Invalid removed margin amount")
14391384 else {
14401385 let marginRatio = calcMarginRatio(remainMargin, badDebt, oldPositionOpenNotional)
14411386 if (!(requireMoreMarginRatio(marginRatio, initMarginRatio(), true)))
14421387 then throw(((("Too much margin removed: " + toString(marginRatio)) + " < ") + toString(initMarginRatio())))
14431388 else {
1444- let $t06673266791 = distributeFee(rolloverFee)
1445- let feeToStakers = $t06673266791._1
1446- let feeToVault = $t06673266791._2
1389+ let $t06594065999 = distributeFee(rolloverFee)
1390+ let feeToStakers = $t06594065999._1
1391+ let feeToVault = $t06594065999._2
14471392 let doTransferFeeToStakers = if ((rolloverFee > 0))
14481393 then {
14491394 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
14501395 if ((lockBadDebt == lockBadDebt))
14511396 then transferFee(feeToStakers)
14521397 else throw("Strict value is not equal to itself.")
14531398 }
14541399 else nil
14551400 if ((doTransferFeeToStakers == doTransferFeeToStakers))
14561401 then {
14571402 let unstake = invoke(vaultAddress(), "withdrawLocked", [(_amount + feeToStakers)], nil)
14581403 if ((unstake == unstake))
14591404 then (((updatePosition(_trader, oldPositionSize, remainMargin, oldPositionOpenNotional, latestCumulativePremiumFraction(oldPositionSize), lastTimestamp()) ++ withdraw(i.caller, _amount)) ++ updateBalance(((cbalance() - _amount) - rolloverFee))) ++ doTransferFeeToStakers)
14601405 else throw("Strict value is not equal to itself.")
14611406 }
14621407 else throw("Strict value is not equal to itself.")
14631408 }
14641409 }
14651410 }
14661411 }
14671412 else throw("Strict value is not equal to itself.")
14681413 }
14691414 else throw("Strict value is not equal to itself.")
14701415 }
14711416
14721417
14731418
14741419 @Callable(i)
14751420 func closePosition (_size,_minQuoteAssetAmount,_addToMargin) = {
14761421 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
14771422 if ((sync == sync))
14781423 then {
14791424 let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
14801425 if ((ensureCalledOnce == ensureCalledOnce))
14811426 then {
14821427 let _trader = getActualCaller(i)
14831428 let _traderAddress = valueOrErrorMessage(addressFromString(_trader), "Invalid caller")
14841429 let positionFee = getPositionFee(_trader)
14851430 if (if (if (if (if (if (!(requireOpenPosition(_trader)))
14861431 then true
14871432 else !(initialized()))
14881433 then true
14891434 else paused())
14901435 then true
14911436 else (0 >= _size))
14921437 then true
14931438 else (0 > _minQuoteAssetAmount))
14941439 then true
14951440 else isMarketClosed())
14961441 then throw("Invalid closePosition parameters")
14971442 else {
14981443 let oldPositionTimestamp = getPosition(_trader)._5
1499- let $t06844869033 = internalClosePosition(_trader, _size, positionFee, _minQuoteAssetAmount, _addToMargin, true, true)
1500- let newPositionSize = $t06844869033._1
1501- let newPositionMargin = $t06844869033._2
1502- let newPositionOpenNotional = $t06844869033._3
1503- let newPositionLstUpdCPF = $t06844869033._4
1504- let positionBadDebt = $t06844869033._5
1505- let realizedPnl = $t06844869033._6
1506- let marginToTrader = $t06844869033._7
1507- let quoteAssetReserveAfter = $t06844869033._8
1508- let baseAssetReserveAfter = $t06844869033._9
1509- let totalPositionSizeAfter = $t06844869033._10
1510- let openInterestNotionalAfter = $t06844869033._11
1511- let totalLongAfter = $t06844869033._12
1512- let totalShortAfter = $t06844869033._13
1513- let totalLongOpenInterestAfter = $t06844869033._14
1514- let totalShortOpenInterestAfter = $t06844869033._15
1515- let realizedFee = $t06844869033._16
1444+ let $t06817468759 = internalClosePosition(_trader, _size, positionFee, _minQuoteAssetAmount, _addToMargin, true, true)
1445+ let newPositionSize = $t06817468759._1
1446+ let newPositionMargin = $t06817468759._2
1447+ let newPositionOpenNotional = $t06817468759._3
1448+ let newPositionLstUpdCPF = $t06817468759._4
1449+ let positionBadDebt = $t06817468759._5
1450+ let realizedPnl = $t06817468759._6
1451+ let marginToTrader = $t06817468759._7
1452+ let quoteAssetReserveAfter = $t06817468759._8
1453+ let baseAssetReserveAfter = $t06817468759._9
1454+ let totalPositionSizeAfter = $t06817468759._10
1455+ let openInterestNotionalAfter = $t06817468759._11
1456+ let totalLongAfter = $t06817468759._12
1457+ let totalShortAfter = $t06817468759._13
1458+ let totalLongOpenInterestAfter = $t06817468759._14
1459+ let totalShortOpenInterestAfter = $t06817468759._15
1460+ let realizedFee = $t06817468759._16
15161461 if ((positionBadDebt > 0))
15171462 then throw("Invalid closePosition parameters: bad debt")
15181463 else if ((oldPositionTimestamp >= lastTimestamp()))
15191464 then throw("Invalid closePosition parameters: wait at least 1 block before closing the position")
15201465 else {
15211466 let isPartialClose = (newPositionSize != 0)
15221467 let withdrawAmount = (marginToTrader + realizedFee)
15231468 let ammBalance = (cbalance() - withdrawAmount)
15241469 let ammNewBalance = if ((0 > ammBalance))
15251470 then 0
15261471 else ammBalance
15271472 let unstake = invoke(vaultAddress(), "withdrawLocked", [withdrawAmount], nil)
15281473 if ((unstake == unstake))
15291474 then {
1530- let $t06970569764 = distributeFee(realizedFee)
1531- let feeToStakers = $t06970569764._1
1532- let feeToVault = $t06970569764._2
1475+ let $t06943169490 = distributeFee(realizedFee)
1476+ let feeToStakers = $t06943169490._1
1477+ let feeToVault = $t06943169490._2
15331478 let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
15341479 if ((depositVault == depositVault))
15351480 then {
15361481 let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, realizedFee], nil)
15371482 if ((notifyFee == notifyFee))
15381483 then {
15391484 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
15401485 if ((notifyNotional == notifyNotional))
15411486 then (((((if (isPartialClose)
15421487 then updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, lastTimestamp())
15431488 else deletePosition(_trader)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ (if ((marginToTrader > 0))
15441489 then withdraw(_traderAddress, marginToTrader)
15451490 else nil)) ++ updateBalance(ammNewBalance)) ++ transferFee(feeToStakers))
15461491 else throw("Strict value is not equal to itself.")
15471492 }
15481493 else throw("Strict value is not equal to itself.")
15491494 }
15501495 else throw("Strict value is not equal to itself.")
15511496 }
15521497 else throw("Strict value is not equal to itself.")
15531498 }
15541499 }
15551500 }
15561501 else throw("Strict value is not equal to itself.")
15571502 }
15581503 else throw("Strict value is not equal to itself.")
15591504 }
15601505
15611506
15621507
15631508 @Callable(i)
15641509 func liquidate (_trader) = {
15651510 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
15661511 if ((sync == sync))
15671512 then {
15681513 let spotMarginRatio = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
15691514 let liquidationMarginRatio = if (isOverFluctuationLimit())
15701515 then {
15711516 let oracleMarginRatio = getMarginRatioByOption(_trader, PNL_OPTION_ORACLE)
15721517 vmax(spotMarginRatio, oracleMarginRatio)
15731518 }
15741519 else spotMarginRatio
15751520 if (if (if (if (if (!(requireMoreMarginRatio(liquidationMarginRatio, maintenanceMarginRatio(), false)))
15761521 then true
15771522 else !(requireOpenPosition(_trader)))
15781523 then true
15791524 else !(initialized()))
15801525 then true
15811526 else paused())
15821527 then true
15831528 else isMarketClosed())
15841529 then throw("Unable to liquidate")
15851530 else {
15861531 let isPartialLiquidation = if (if ((spotMarginRatio > liquidationFeeRatio()))
15871532 then (partialLiquidationRatio() > 0)
15881533 else false)
15891534 then (DECIMAL_UNIT > partialLiquidationRatio())
15901535 else false
15911536 let oldPositionSize = getPosition(_trader)._1
15921537 let positionSizeAbs = abs(oldPositionSize)
1593- let $t07207772400 = if (isPartialLiquidation)
1538+ let $t07191172234 = if (isPartialLiquidation)
15941539 then {
15951540 let liquidationSize = getPartialLiquidationAmount(_trader, oldPositionSize)
15961541 let liquidationRatio = divd(abs(liquidationSize), positionSizeAbs)
15971542 $Tuple2(liquidationRatio, abs(liquidationSize))
15981543 }
15991544 else $Tuple2(0, positionSizeAbs)
1600- let liquidationRatio = $t07207772400._1
1601- let liquidationSize = $t07207772400._2
1602- let $t07240673044 = internalClosePosition(_trader, if (isPartialLiquidation)
1545+ let liquidationRatio = $t07191172234._1
1546+ let liquidationSize = $t07191172234._2
1547+ let $t07224072878 = internalClosePosition(_trader, if (isPartialLiquidation)
16031548 then liquidationSize
16041549 else positionSizeAbs, liquidationFeeRatio(), 0, true, false, true)
1605- let newPositionSize = $t07240673044._1
1606- let newPositionMargin = $t07240673044._2
1607- let newPositionOpenNotional = $t07240673044._3
1608- let newPositionLstUpdCPF = $t07240673044._4
1609- let positionBadDebt = $t07240673044._5
1610- let realizedPnl = $t07240673044._6
1611- let marginToTrader = $t07240673044._7
1612- let quoteAssetReserveAfter = $t07240673044._8
1613- let baseAssetReserveAfter = $t07240673044._9
1614- let totalPositionSizeAfter = $t07240673044._10
1615- let openInterestNotionalAfter = $t07240673044._11
1616- let totalLongAfter = $t07240673044._12
1617- let totalShortAfter = $t07240673044._13
1618- let totalLongOpenInterestAfter = $t07240673044._14
1619- let totalShortOpenInterestAfter = $t07240673044._15
1620- let liquidationPenalty = $t07240673044._16
1550+ let newPositionSize = $t07224072878._1
1551+ let newPositionMargin = $t07224072878._2
1552+ let newPositionOpenNotional = $t07224072878._3
1553+ let newPositionLstUpdCPF = $t07224072878._4
1554+ let positionBadDebt = $t07224072878._5
1555+ let realizedPnl = $t07224072878._6
1556+ let marginToTrader = $t07224072878._7
1557+ let quoteAssetReserveAfter = $t07224072878._8
1558+ let baseAssetReserveAfter = $t07224072878._9
1559+ let totalPositionSizeAfter = $t07224072878._10
1560+ let openInterestNotionalAfter = $t07224072878._11
1561+ let totalLongAfter = $t07224072878._12
1562+ let totalShortAfter = $t07224072878._13
1563+ let totalLongOpenInterestAfter = $t07224072878._14
1564+ let totalShortOpenInterestAfter = $t07224072878._15
1565+ let liquidationPenalty = $t07224072878._16
16211566 let feeToLiquidator = (liquidationPenalty / 2)
16221567 let feeToVault = (liquidationPenalty - feeToLiquidator)
16231568 let ammBalance = (cbalance() - liquidationPenalty)
16241569 let newAmmBalance = if ((0 > ammBalance))
16251570 then 0
16261571 else ammBalance
16271572 let lockBadDebt = if ((positionBadDebt > 0))
16281573 then {
16291574 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [(positionBadDebt + liquidationPenalty)], nil)
16301575 if ((lockBadDebt == lockBadDebt))
16311576 then nil
16321577 else throw("Strict value is not equal to itself.")
16331578 }
16341579 else nil
16351580 if ((lockBadDebt == lockBadDebt))
16361581 then {
16371582 let unstake = invoke(vaultAddress(), "withdrawLocked", [liquidationPenalty], nil)
16381583 if ((unstake == unstake))
16391584 then {
16401585 let depositInsurance = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
16411586 if ((depositInsurance == depositInsurance))
16421587 then {
16431588 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
16441589 if ((notifyNotional == notifyNotional))
16451590 then ((((if (isPartialLiquidation)
16461591 then updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, lastTimestamp())
16471592 else deletePosition(_trader)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ withdraw(i.caller, feeToLiquidator)) ++ updateBalance(newAmmBalance))
16481593 else throw("Strict value is not equal to itself.")
16491594 }
16501595 else throw("Strict value is not equal to itself.")
16511596 }
16521597 else throw("Strict value is not equal to itself.")
16531598 }
16541599 else throw("Strict value is not equal to itself.")
16551600 }
16561601 }
16571602 else throw("Strict value is not equal to itself.")
16581603 }
16591604
16601605
16611606
16621607 @Callable(i)
16631608 func payFunding () = {
16641609 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
16651610 if ((sync == sync))
16661611 then {
16671612 let fundingBlockTimestamp = nextFundingBlockTimestamp()
16681613 if (if (if ((fundingBlockTimestamp > lastTimestamp()))
16691614 then true
16701615 else !(initialized()))
16711616 then true
16721617 else paused())
16731618 then throw(((("Invalid funding block timestamp: " + toString(lastTimestamp())) + " < ") + toString(fundingBlockTimestamp)))
16741619 else {
16751620 let underlyingPrice = getOraclePrice()
1676- let $t07503175093 = getFunding()
1677- let shortPremiumFraction = $t07503175093._1
1678- let longPremiumFraction = $t07503175093._2
1679- updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice))
1621+ let $t07499175069 = getFunding()
1622+ let shortPremiumFraction = $t07499175069._1
1623+ let longPremiumFraction = $t07499175069._2
1624+ let premiumToVault = $t07499175069._3
1625+ let doPayFundingToVault = if ((premiumToVault > 0))
1626+ then {
1627+ let doPayFundingToVault = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(premiumToVault)], nil)
1628+ if ((doPayFundingToVault == doPayFundingToVault))
1629+ then nil
1630+ else throw("Strict value is not equal to itself.")
1631+ }
1632+ else nil
1633+ if ((doPayFundingToVault == doPayFundingToVault))
1634+ then updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice))
1635+ else throw("Strict value is not equal to itself.")
16801636 }
16811637 }
16821638 else throw("Strict value is not equal to itself.")
16831639 }
16841640
16851641
16861642
16871643 @Callable(i)
16881644 func syncTerminalPriceToOracle () = {
16891645 let _qtAstR = qtAstR()
16901646 let _bsAstR = bsAstR()
1691- let $t07552575891 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1692- let newQuoteAssetWeight = $t07552575891._1
1693- let newBaseAssetWeight = $t07552575891._2
1694- let marginToVault = $t07552575891._3
1647+ let $t07612076486 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1648+ let newQuoteAssetWeight = $t07612076486._1
1649+ let newBaseAssetWeight = $t07612076486._2
1650+ let marginToVault = $t07612076486._3
16951651 let marginToVaultAdj = if (if ((0 > marginToVault))
16961652 then (abs(marginToVault) > cbalance())
16971653 else false)
16981654 then -(cbalance())
16991655 else marginToVault
17001656 let doExchangePnL = if ((marginToVaultAdj != 0))
17011657 then {
17021658 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVaultAdj], nil)
17031659 if ((doExchangePnL == doExchangePnL))
17041660 then nil
17051661 else throw("Strict value is not equal to itself.")
17061662 }
17071663 else nil
17081664 if ((doExchangePnL == doExchangePnL))
1709- then ((updateBalance((cbalance() + marginToVaultAdj)) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight)) ++ appendTwap(divd(muld(_qtAstR, newQuoteAssetWeight), muld(_bsAstR, newBaseAssetWeight))))
1665+ then (updateBalance((cbalance() + marginToVaultAdj)) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
17101666 else throw("Strict value is not equal to itself.")
17111667 }
17121668
17131669
17141670
17151671 @Callable(i)
17161672 func ensureCalledOnce () = if ((i.caller != this))
17171673 then throw("Invalid saveCurrentTxId parameters")
17181674 else {
17191675 let lastTx = valueOrElse(getString(this, k_lastTx), "")
17201676 if ((lastTx != toBase58String(i.transactionId)))
17211677 then [StringEntry(k_lastTx, lastTx)]
17221678 else throw("Can not call vAMM methods twice in one tx")
17231679 }
17241680
17251681
17261682
17271683 @Callable(i)
17281684 func view_calcRemainMarginWithFundingPayment (_trader) = {
17291685 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
17301686 if ((sync == sync))
17311687 then {
1732- let $t07705077174 = getPosition(_trader)
1733- let positionSize = $t07705077174._1
1734- let positionMargin = $t07705077174._2
1735- let pon = $t07705077174._3
1736- let positionLstUpdCPF = $t07705077174._4
1737- let positionTimestamp = $t07705077174._5
1738- let $t07717777278 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1739- let positionNotional = $t07717777278._1
1740- let unrealizedPnl = $t07717777278._2
1741- let $t07728177505 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
1742- let remainMargin = $t07728177505._1
1743- let badDebt = $t07728177505._2
1744- let fundingPayment = $t07728177505._3
1745- let rolloverFee = $t07728177505._4
1688+ let $t07803578159 = getPosition(_trader)
1689+ let positionSize = $t07803578159._1
1690+ let positionMargin = $t07803578159._2
1691+ let pon = $t07803578159._3
1692+ let positionLstUpdCPF = $t07803578159._4
1693+ let positionTimestamp = $t07803578159._5
1694+ let $t07816278263 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1695+ let positionNotional = $t07816278263._1
1696+ let unrealizedPnl = $t07816278263._2
1697+ let $t07826678490 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
1698+ let remainMargin = $t07826678490._1
1699+ let badDebt = $t07826678490._2
1700+ let fundingPayment = $t07826678490._3
1701+ let rolloverFee = $t07826678490._4
17461702 throw(((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)) + s(rolloverFee)))
17471703 }
17481704 else throw("Strict value is not equal to itself.")
17491705 }
17501706
17511707
17521708
17531709 @Callable(i)
17541710 func view_getPegAdjustCost (_price) = {
17551711 let _qtAstR = qtAstR()
17561712 let _bsAstR = bsAstR()
17571713 let result = getSyncTerminalPrice(_price, _qtAstR, _bsAstR)
17581714 throw(toString(result._3))
17591715 }
17601716
17611717
17621718
17631719 @Callable(i)
17641720 func view_getTerminalAmmPrice () = {
1765- let $t07794178022 = getTerminalAmmState()
1766- let terminalQuoteAssetReserve = $t07794178022._1
1767- let terminalBaseAssetReserve = $t07794178022._2
1721+ let $t07921379294 = getTerminalAmmState()
1722+ let terminalQuoteAssetReserve = $t07921379294._1
1723+ let terminalBaseAssetReserve = $t07921379294._2
17681724 let price = divd(muld(terminalQuoteAssetReserve, qtAstW()), muld(terminalBaseAssetReserve, bsAstW()))
17691725 throw(toString(price))
17701726 }
17711727
17721728
17731729
17741730 @Callable(i)
17751731 func view_getFunding () = {
1776- let underlyingPrice = getOraclePrice()
1777- let $t07823778299 = getFunding()
1778- let shortPremiumFraction = $t07823778299._1
1779- let longPremiumFraction = $t07823778299._2
1780- let longFunding = divd(longPremiumFraction, underlyingPrice)
1781- let shortFunding = divd(shortPremiumFraction, underlyingPrice)
1782- throw((((s(longFunding) + s(shortFunding)) + s(getTwapSpotPrice())) + s(getOraclePrice())))
1732+ let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
1733+ if ((sync == sync))
1734+ then {
1735+ let underlyingPrice = getOraclePrice()
1736+ let $t07985379931 = getFunding()
1737+ let shortPremiumFraction = $t07985379931._1
1738+ let longPremiumFraction = $t07985379931._2
1739+ let premiumToVault = $t07985379931._3
1740+ let longFunding = divd(longPremiumFraction, underlyingPrice)
1741+ let shortFunding = divd(shortPremiumFraction, underlyingPrice)
1742+ throw(((((s(longFunding) + s(shortFunding)) + s(getSpotPrice())) + s(getOraclePrice())) + s(premiumToVault)))
1743+ }
1744+ else throw("Strict value is not equal to itself.")
17831745 }
17841746
17851747
17861748
17871749 @Callable(i)
17881750 func computeSpotPrice () = {
17891751 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
17901752 if ((sync == sync))
17911753 then {
17921754 let result = getSpotPrice()
17931755 $Tuple2(nil, result)
17941756 }
17951757 else throw("Strict value is not equal to itself.")
17961758 }
17971759
17981760
17991761
18001762 @Callable(i)
18011763 func computeFeeForTraderWithArtifact (_trader,_artifactId) = {
18021764 let result = getForTraderWithArtifact(_trader, _artifactId)
18031765 $Tuple2(nil, result)
18041766 }
18051767
18061768
18071769 @Verifier(tx)
18081770 func verify () = {
18091771 let coordinatorStr = getString(this, k_coordinatorAddress)
18101772 if (isDefined(coordinatorStr))
18111773 then {
18121774 let admin = getString(addressFromStringValue(value(coordinatorStr)), k_admin_address)
18131775 if (isDefined(admin))
18141776 then valueOrElse(getBoolean(addressFromStringValue(value(admin)), ((("status_" + toString(this)) + "_") + toBase58String(tx.id))), false)
18151777 else throw("unable to verify: admin not set in coordinator")
18161778 }
18171779 else sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
18181780 }
18191781

github/deemru/w8io/3ef1775 
285.84 ms