tx · bEJqq6exgPMc4rQXTRWyrEpf3ktx1kTtoMrh4qy9czr

3N8G95pEaYEhZ4U3m3UrzpEzwBFn5vvXsZH:  -0.06000000 Waves

2022.09.13 17:23 [2227444] smart account 3N8G95pEaYEhZ4U3m3UrzpEzwBFn5vvXsZH > SELF 0.00000000 Waves

{ "type": 13, "id": "bEJqq6exgPMc4rQXTRWyrEpf3ktx1kTtoMrh4qy9czr", "fee": 6000000, "feeAssetId": null, "timestamp": 1663079120666, "version": 2, "chainId": 84, "sender": "3N8G95pEaYEhZ4U3m3UrzpEzwBFn5vvXsZH", "senderPublicKey": "Hj6oyH6As5UWo8fZ1K4hPsEY7nxH3MvhBqDD6axiwjXs", "proofs": [ "j9YEdf14ZwgAHZwmURa4E3BciaJcG38zjAiwB4maeeLSrHYcprsZXrSdUy1mt2aqnMgWCZWvYc2SLrq7rQ2K6iB" ], "script": "base64:BgJtCAISABIAEgMKAQESAwoBARILCgkBAQEBAQEBAQESEAoOAQEBAQEBAQgICAEBAQESAwoBARIFCgMBAQESBgoEAQEBCBIAEgMKAQESABIDCgEIEgASBAoCCAESAwoBARIDCgEIEgMKAQgSAwoBAYcBAAlrX29yYV9rZXkCCWtfb3JhX2tleQAPa19vcmFfYmxvY2tfa2V5Ag9rX29yYV9ibG9ja19rZXkABWtfb3JhAgVrX29yYQAJa19iYWxhbmNlAglrX2JhbGFuY2UADmtfcG9zaXRpb25TaXplAg5rX3Bvc2l0aW9uU2l6ZQAQa19wb3NpdGlvbk1hcmdpbgIQa19wb3NpdGlvbk1hcmdpbgAWa19wb3NpdGlvbk9wZW5Ob3Rpb25hbAIWa19wb3NpdGlvbk9wZW5Ob3Rpb25hbAAua19wb3NpdGlvbkxhc3RVcGRhdGVkQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgISa19wb3NpdGlvbkZyYWN0aW9uABRrX3Bvc2l0aW9uQ2xvc2VkRGF0ZQIUa19wb3NpdGlvbkNsb3NlZERhdGUADWtfaW5pdGlhbGl6ZWQCDWtfaW5pdGlhbGl6ZWQACGtfcGF1c2VkAghrX3BhdXNlZAAFa19mZWUCBWtfZmVlAA9rX2Z1bmRpbmdQZXJpb2QCD2tfZnVuZGluZ1BlcmlvZAARa19pbml0TWFyZ2luUmF0aW8CEWtfaW5pdE1hcmdpblJhdGlvABhrX21haW50ZW5hbmNlTWFyZ2luUmF0aW8CBWtfbW1yABVrX2xpcXVpZGF0aW9uRmVlUmF0aW8CFWtfbGlxdWlkYXRpb25GZWVSYXRpbwAZa19wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwIWa19wYXJ0TGlxdWlkYXRpb25SYXRpbwANa19zcHJlYWRMaW1pdAINa19zcHJlYWRMaW1pdAAQa19tYXhQcmljZUltcGFjdAIQa19tYXhQcmljZUltcGFjdAAQa19tYXhQcmljZVNwcmVhZAIQa19tYXhQcmljZVNwcmVhZAANa19sYXN0RGF0YVN0cgINa19sYXN0RGF0YVN0cgAOa19sYXN0TWludXRlSWQCDmtfbGFzdE1pbnV0ZUlkAB1rX3R3YXBEYXRhTGFzdEN1bXVsYXRpdmVQcmljZQIda190d2FwRGF0YUxhc3RDdW11bGF0aXZlUHJpY2UAE2tfdHdhcERhdGFMYXN0UHJpY2UCE2tfdHdhcERhdGFMYXN0UHJpY2UAGmtfdHdhcERhdGFQcmV2aW91c01pbnV0ZUlkAhprX3R3YXBEYXRhUHJldmlvdXNNaW51dGVJZAAla19sYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgIba19sYXRlc3RMb25nUHJlbWl1bUZyYWN0aW9uACZrX2xhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgIca19sYXRlc3RTaG9ydFByZW1pdW1GcmFjdGlvbgASa19uZXh0RnVuZGluZ0Jsb2NrAh5rX25leHRGdW5kaW5nQmxvY2tNaW5UaW1lc3RhbXAAEWtfbG9uZ0Z1bmRpbmdSYXRlAhFrX2xvbmdGdW5kaW5nUmF0ZQASa19zaG9ydEZ1bmRpbmdSYXRlAhJrX3Nob3J0RnVuZGluZ1JhdGUAE2tfcXVvdGVBc3NldFJlc2VydmUCCGtfcXRBc3RSABJrX2Jhc2VBc3NldFJlc2VydmUCCGtfYnNBc3RSABNrX3RvdGFsUG9zaXRpb25TaXplAhNrX3RvdGFsUG9zaXRpb25TaXplABdrX3RvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQIXa190b3RhbExvbmdQb3NpdGlvblNpemUAGGtfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQIYa190b3RhbFNob3J0UG9zaXRpb25TaXplABRrX2N1bXVsYXRpdmVOb3Rpb25hbAIUa19jdW11bGF0aXZlTm90aW9uYWwAFmtfb3BlbkludGVyZXN0Tm90aW9uYWwCFmtfb3BlbkludGVyZXN0Tm90aW9uYWwAFGtfY29vcmRpbmF0b3JBZGRyZXNzAhRrX2Nvb3JkaW5hdG9yQWRkcmVzcwATa19pbnN1cmFuY2VfYWRkcmVzcwITa19pbnN1cmFuY2VfYWRkcmVzcwAPa19hZG1pbl9hZGRyZXNzAg9rX2FkbWluX2FkZHJlc3MAEmtfYWRtaW5fcHVibGljX2tleQISa19hZG1pbl9wdWJsaWNfa2V5AA1rX3F1b3RlX2Fzc2V0Ag1rX3F1b3RlX2Fzc2V0AA9rX3F1b3RlX3N0YWtpbmcCD2tfcXVvdGVfc3Rha2luZwARa19zdGFraW5nX2FkZHJlc3MCEWtfc3Rha2luZ19hZGRyZXNzAA9rX21pbmVyX2FkZHJlc3MCD2tfbWluZXJfYWRkcmVzcwAQa19vcmRlcnNfYWRkcmVzcwIQa19vcmRlcnNfYWRkcmVzcwASa19yZWZlcnJhbF9hZGRyZXNzAhJrX3JlZmVycmFsX2FkZHJlc3MBC2Nvb3JkaW5hdG9yAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIFBHRoaXMFFGtfY29vcmRpbmF0b3JBZGRyZXNzAhNDb29yZGluYXRvciBub3Qgc2V0AQxhZG1pbkFkZHJlc3MACQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFD2tfYWRtaW5fYWRkcmVzcwEOYWRtaW5QdWJsaWNLZXkACQDZBAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFEmtfYWRtaW5fcHVibGljX2tleQEKcXVvdGVBc3NldAAJANkEAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUNa19xdW90ZV9hc3NldAERcXVvdGVBc3NldFN0YWtpbmcACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUPa19xdW90ZV9zdGFraW5nAhtRdW90ZSBhc3NldCBzdGFraW5nIG5vdCBzZXQBDnN0YWtpbmdBZGRyZXNzAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFEWtfc3Rha2luZ19hZGRyZXNzAg9TdGFraW5nIG5vdCBzZXQBEGluc3VyYW5jZUFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUTa19pbnN1cmFuY2VfYWRkcmVzcwIRSW5zdXJhbmNlIG5vdCBzZXQBDG1pbmVyQWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABQ9rX21pbmVyX2FkZHJlc3MCDU1pbmVyIG5vdCBzZXQBDW9yZGVyc0FkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUQa19vcmRlcnNfYWRkcmVzcwIOT3JkZXJzIG5vdCBzZXQBD3JlZmVycmFsQWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABRJrX3JlZmVycmFsX2FkZHJlc3MCEFJlZmVycmFsIG5vdCBzZXQACERJUl9MT05HAAEACURJUl9TSE9SVAACAA1UV0FQX0lOVEVSVkFMAA8AD09SQUNMRV9JTlRFUlZBTAAPAAdTRUNPTkRTAOgHAAxERUNJTUFMX1VOSVQJAGgCAAEJAGgCCQBoAgkAaAIJAGgCCQBoAgAKAAoACgAKAAoACgAHT05FX0RBWQkAaAIAgKMFBQxERUNJTUFMX1VOSVQACEFMTF9GRUVTAGQAD1BOTF9PUFRJT05fU1BPVAABABFQTkxfT1BUSU9OX09SQUNMRQACAQFzAQJfeAkArAICCQCkAwEFAl94AgEsAQRkaXZkAgJfeAJfeQkAbgQFAl94BQxERUNJTUFMX1VOSVQFAl95BQhIQUxGRVZFTgEEbXVsZAICX3gCX3kJAG4EBQJfeAUCX3kFDERFQ0lNQUxfVU5JVAUISEFMRkVWRU4BA2FicwECX3gDCQBmAgUCX3gAAAUCX3gJAQEtAQUCX3gBBHZtYXgCAl94Al95AwkAZwIFAl94BQJfeQUCX3gFAl95AQ50b0NvbXBvc2l0ZUtleQIEX2tleQhfYWRkcmVzcwkArAICCQCsAgIFBF9rZXkCAV8FCF9hZGRyZXNzAQlsaXN0VG9TdHIBBV9saXN0CgEFX2pvaW4CC2FjY3VtdWxhdG9yA3ZhbAkArAICCQCsAgIFC2FjY3VtdWxhdG9yBQN2YWwCASwECm5ld0xpc3RTdHIKAAIkbAUFX2xpc3QKAAIkcwkAkAMBBQIkbAoABSRhY2MwAgAKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBBV9qb2luAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAyMAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQEC25ld0xpc3RTdHJVCQCzAgIFCm5ld0xpc3RTdHIAAQQLbmV3TGlzdFN0clIDCQAAAgkArwICBQtuZXdMaXN0U3RyVQABAgEsCQCwAgIFC25ld0xpc3RTdHJVAAEFC25ld0xpc3RTdHJVBQtuZXdMaXN0U3RyUgEJc3RyVG9MaXN0AQRfc3RyCQC1CQIFBF9zdHICASwBC3B1c2hUb1F1ZXVlAwVfbGlzdAhfbWF4U2l6ZQZfdmFsdWUDCQBmAgkAkAMBBQVfbGlzdAUIX21heFNpemUJAM0IAgkA0QgCBQVfbGlzdAAABQZfdmFsdWUJAM0IAgUFX2xpc3QFBl92YWx1ZQEDaW50AQFrCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUEdGhpcwUBawkArAICAg1ubyB2YWx1ZSBmb3IgBQFrAQhjYmFsYW5jZQAJAQNpbnQBBQlrX2JhbGFuY2UBA2ZlZQAJAQNpbnQBBQVrX2ZlZQEPaW5pdE1hcmdpblJhdGlvAAkBA2ludAEFEWtfaW5pdE1hcmdpblJhdGlvAQZxdEFzdFIACQEDaW50AQUTa19xdW90ZUFzc2V0UmVzZXJ2ZQEGYnNBc3RSAAkBA2ludAEFEmtfYmFzZUFzc2V0UmVzZXJ2ZQERdG90YWxQb3NpdGlvblNpemUACQEDaW50AQUTa190b3RhbFBvc2l0aW9uU2l6ZQESY3VtdWxhdGl2ZU5vdGlvbmFsAAkBA2ludAEFFGtfY3VtdWxhdGl2ZU5vdGlvbmFsARRvcGVuSW50ZXJlc3ROb3Rpb25hbAAJAQNpbnQBBRZrX29wZW5JbnRlcmVzdE5vdGlvbmFsARluZXh0RnVuZGluZ0Jsb2NrVGltZXN0YW1wAAkBA2ludAEFEmtfbmV4dEZ1bmRpbmdCbG9jawEQZnVuZGluZ1BlcmlvZFJhdwAJAQNpbnQBBQ9rX2Z1bmRpbmdQZXJpb2QBFGZ1bmRpbmdQZXJpb2REZWNpbWFsAAkAaAIJARBmdW5kaW5nUGVyaW9kUmF3AAUMREVDSU1BTF9VTklUARRmdW5kaW5nUGVyaW9kU2Vjb25kcwAJAGgCCQEQZnVuZGluZ1BlcmlvZFJhdwAFB1NFQ09ORFMBFm1haW50ZW5hbmNlTWFyZ2luUmF0aW8ACQEDaW50AQUYa19tYWludGVuYW5jZU1hcmdpblJhdGlvARNsaXF1aWRhdGlvbkZlZVJhdGlvAAkBA2ludAEFFWtfbGlxdWlkYXRpb25GZWVSYXRpbwEXcGFydGlhbExpcXVpZGF0aW9uUmF0aW8ACQEDaW50AQUZa19wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwELc3ByZWFkTGltaXQACQEDaW50AQUNa19zcHJlYWRMaW1pdAEObWF4UHJpY2VJbXBhY3QACQEDaW50AQUQa19tYXhQcmljZUltcGFjdAEObWF4UHJpY2VTcHJlYWQACQEDaW50AQUQa19tYXhQcmljZVNwcmVhZAEjbGF0ZXN0TG9uZ0N1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24ACQEDaW50AQUla19sYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEkbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAAkBA2ludAEFJmtfbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAkBA2ludAEFGGtfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQEVdG90YWxMb25nUG9zaXRpb25TaXplAAkBA2ludAEFF2tfdG90YWxMb25nUG9zaXRpb25TaXplAQ9nZXRBY3R1YWxDYWxsZXIBAWkJAQt2YWx1ZU9yRWxzZQIJAJ0IAgkBDW9yZGVyc0FkZHJlc3MAAghrX3NlbmRlcgkApQgBCAUBaQZjYWxsZXIBFnJlcXVpcmVNb3JlTWFyZ2luUmF0aW8DDF9tYXJnaW5SYXRpbxBfYmFzZU1hcmdpblJhdGlvFF9sYXJnZXJUaGFuT3JFcXVhbFRvBBRyZW1haW5pbmdNYXJnaW5SYXRpbwkAZQIFDF9tYXJnaW5SYXRpbwUQX2Jhc2VNYXJnaW5SYXRpbwMDBRRfbGFyZ2VyVGhhbk9yRXF1YWxUbwkAZgIAAAUUcmVtYWluaW5nTWFyZ2luUmF0aW8HCQACAQIOSW52YWxpZCBtYXJnaW4DAwkBASEBBRRfbGFyZ2VyVGhhbk9yRXF1YWxUbwkAZwIFFHJlbWFpbmluZ01hcmdpblJhdGlvAAAHCQACAQIOSW52YWxpZCBtYXJnaW4GAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAQ1fcG9zaXRpb25TaXplAwkAAAIFDV9wb3NpdGlvblNpemUAAAkAAgECLFNob3VsZCBub3QgYmUgY2FsbGVkIHdpdGggX3Bvc2l0aW9uU2l6ZSA9PSAwAwkAZgIFDV9wb3NpdGlvblNpemUAAAkBI2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAAkBJGxhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgABC2dldFBvc2l0aW9uAQdfdHJhZGVyBA9wb3NpdGlvblNpemVPcHQJAJoIAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUOa19wb3NpdGlvblNpemUFB190cmFkZXIEByRtYXRjaDAFD3Bvc2l0aW9uU2l6ZU9wdAMJAAECBQckbWF0Y2gwAgNJbnQEDHBvc2l0aW9uU2l6ZQUHJG1hdGNoMAkAlgoEBQxwb3NpdGlvblNpemUJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFEGtfcG9zaXRpb25NYXJnaW4FB190cmFkZXIJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFFmtfcG9zaXRpb25PcGVuTm90aW9uYWwFB190cmFkZXIJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFLmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FB190cmFkZXIJAJYKBAAAAAAAAAAAARNyZXF1aXJlT3BlblBvc2l0aW9uAQdfdHJhZGVyAwkAAAIICQELZ2V0UG9zaXRpb24BBQdfdHJhZGVyAl8xAAAJAAIBAhBObyBvcGVuIHBvc2l0aW9uBgELaW5pdGlhbGl6ZWQACQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMFDWtfaW5pdGlhbGl6ZWQHAQZwYXVzZWQACQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMFCGtfcGF1c2VkBwENdXBkYXRlUmVzZXJ2ZQMGX2lzQWRkEV9xdW90ZUFzc2V0QW1vdW50EF9iYXNlQXNzZXRBbW91bnQDBQZfaXNBZGQEB25ld0Jhc2UJAGUCCQEGYnNBc3RSAAUQX2Jhc2VBc3NldEFtb3VudAMJAGcCAAAFB25ld0Jhc2UJAAIBAipUeCBsZWFkIHRvIGJhc2UgYXNzZXQgcmVzZXJ2ZSA8PSAwLCByZXZlcnQJAJYKBAkAZAIJAQZxdEFzdFIABRFfcXVvdGVBc3NldEFtb3VudAUHbmV3QmFzZQkAZAIJARF0b3RhbFBvc2l0aW9uU2l6ZQAFEF9iYXNlQXNzZXRBbW91bnQJAGQCCQESY3VtdWxhdGl2ZU5vdGlvbmFsAAURX3F1b3RlQXNzZXRBbW91bnQECG5ld1F1b3RlCQBlAgkBBnF0QXN0UgAFEV9xdW90ZUFzc2V0QW1vdW50AwkAZwIAAAUIbmV3UXVvdGUJAAIBAipUeCBsZWFkIHRvIGJhc2UgcXVvdGUgcmVzZXJ2ZSA8PSAwLCByZXZlcnQJAJYKBAUIbmV3UXVvdGUJAGQCCQEGYnNBc3RSAAUQX2Jhc2VBc3NldEFtb3VudAkAZQIJARF0b3RhbFBvc2l0aW9uU2l6ZQAFEF9iYXNlQXNzZXRBbW91bnQJAGUCCQESY3VtdWxhdGl2ZU5vdGlvbmFsAAURX3F1b3RlQXNzZXRBbW91bnQBCXN3YXBJbnB1dAIGX2lzQWRkEV9xdW90ZUFzc2V0QW1vdW50BAdfcXRBc3RSCQEGcXRBc3RSAAQHX2JzQXN0UgkBBmJzQXN0UgAEAWsJAQRtdWxkAgUHX3F0QXN0UgUHX2JzQXN0UgQWcXVvdGVBc3NldFJlc2VydmVBZnRlcgMFBl9pc0FkZAkAZAIFB19xdEFzdFIFEV9xdW90ZUFzc2V0QW1vdW50CQBlAgUHX3F0QXN0UgURX3F1b3RlQXNzZXRBbW91bnQEFWJhc2VBc3NldFJlc2VydmVBZnRlcgkBBGRpdmQCBQFrBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBBhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMJAQNhYnMBCQBlAgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBQdfYnNBc3RSBBVhbW91bnRCYXNlQXNzZXRCb3VnaHQDBQZfaXNBZGQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwkBAS0BBRhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMEDSR0MDEyODE2MTMwMDkJAQ11cGRhdGVSZXNlcnZlAwUGX2lzQWRkBRFfcXVvdGVBc3NldEFtb3VudAUYYW1vdW50QmFzZUFzc2V0Qm91Z2h0QWJzBBdxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyMQgFDSR0MDEyODE2MTMwMDkCXzEEFmJhc2VBc3NldFJlc2VydmVBZnRlcjEIBQ0kdDAxMjgxNjEzMDA5Al8yBBd0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyMQgFDSR0MDEyODE2MTMwMDkCXzMEGGN1bXVsYXRpdmVOb3Rpb25hbEFmdGVyMQgFDSR0MDEyODE2MTMwMDkCXzQEC3ByaWNlQmVmb3JlCQEEZGl2ZAIFB19xdEFzdFIFB19ic0FzdFIEC21hcmtldFByaWNlCQEEZGl2ZAIFEV9xdW90ZUFzc2V0QW1vdW50BRhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMECXByaWNlRGlmZgkBA2FicwEJAGUCBQtwcmljZUJlZm9yZQULbWFya2V0UHJpY2UEC3ByaWNlSW1wYWN0CQBlAgUMREVDSU1BTF9VTklUCQEEZGl2ZAIFC3ByaWNlQmVmb3JlCQBkAgULcHJpY2VCZWZvcmUFCXByaWNlRGlmZgQTbWF4UHJpY2VJbXBhY3RWYWx1ZQkBDm1heFByaWNlSW1wYWN0AAMJAGYCBQtwcmljZUltcGFjdAUTbWF4UHJpY2VJbXBhY3RWYWx1ZQkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgINUHJpY2UgaW1wYWN0IAkApAMBBQtwcmljZUltcGFjdAIUID4gbWF4IHByaWNlIGltcGFjdCAJAKQDAQUTbWF4UHJpY2VJbXBhY3RWYWx1ZQIVIGJlZm9yZSBxdW90ZSBhc3NldDogCQCkAwEFB19xdEFzdFICFCBiZWZvcmUgYmFzZSBhc3NldDogCQCkAwEFB19ic0FzdFICISBxdW90ZSBhc3NldCBhbW91bnQgdG8gZXhjaGFuZ2U6IAkApAMBBRFfcXVvdGVBc3NldEFtb3VudAIPIHByaWNlIGJlZm9yZTogCQCkAwEFC3ByaWNlQmVmb3JlAg4gbWFya2V0UHJpY2U6IAkApAMBBQttYXJrZXRQcmljZQkAlwoFBRVhbW91bnRCYXNlQXNzZXRCb3VnaHQFF3F1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIxBRZiYXNlQXNzZXRSZXNlcnZlQWZ0ZXIxBRd0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyMQUYY3VtdWxhdGl2ZU5vdGlvbmFsQWZ0ZXIxASJjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50BBBfb2xkUG9zaXRpb25TaXplEl9vbGRQb3NpdGlvbk1hcmdpbiVfb2xkUG9zaXRpb25DdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uDF9tYXJnaW5EZWx0YQQOZnVuZGluZ1BheW1lbnQDCQECIT0CBRBfb2xkUG9zaXRpb25TaXplAAAEIF9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uCQEfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEFEF9vbGRQb3NpdGlvblNpemUJAQRtdWxkAgkAZQIFIF9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBSVfb2xkUG9zaXRpb25DdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBRBfb2xkUG9zaXRpb25TaXplAAAEDHNpZ25lZE1hcmdpbgkAZAIJAGUCBQxfbWFyZ2luRGVsdGEFDmZ1bmRpbmdQYXltZW50BRJfb2xkUG9zaXRpb25NYXJnaW4EDSR0MDE0NTAwMTQ2MjcDCQBmAgAABQxzaWduZWRNYXJnaW4JAJQKAgAACQEDYWJzAQUMc2lnbmVkTWFyZ2luCQCUCgIJAQNhYnMBBQxzaWduZWRNYXJnaW4AAAQMcmVtYWluTWFyZ2luCAUNJHQwMTQ1MDAxNDYyNwJfMQQHYmFkRGVidAgFDSR0MDE0NTAwMTQ2MjcCXzIJAJUKAwUMcmVtYWluTWFyZ2luBQdiYWREZWJ0BQ5mdW5kaW5nUGF5bWVudAEWc3dhcE91dHB1dFdpdGhSZXNlcnZlcwUGX2lzQWRkEF9iYXNlQXNzZXRBbW91bnQUX2NoZWNrTWF4UHJpY2VJbXBhY3QSX3F1b3RlQXNzZXRSZXNlcnZlEV9iYXNlQXNzZXRSZXNlcnZlBAtwcmljZUJlZm9yZQkBBGRpdmQCBRJfcXVvdGVBc3NldFJlc2VydmUFEV9iYXNlQXNzZXRSZXNlcnZlAwkAAAIFEF9iYXNlQXNzZXRBbW91bnQAAAkAAgECGUludmFsaWQgYmFzZSBhc3NldCBhbW91bnQEAWsJAQRtdWxkAgUSX3F1b3RlQXNzZXRSZXNlcnZlBRFfYmFzZUFzc2V0UmVzZXJ2ZQQYYmFzZUFzc2V0UG9vbEFtb3VudEFmdGVyAwUGX2lzQWRkCQBkAgURX2Jhc2VBc3NldFJlc2VydmUFEF9iYXNlQXNzZXRBbW91bnQJAGUCBRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldEFtb3VudAQPcXVvdGVBc3NldEFmdGVyCQEEZGl2ZAIFAWsFGGJhc2VBc3NldFBvb2xBbW91bnRBZnRlcgQOcXVvdGVBc3NldFNvbGQJAQNhYnMBCQBlAgUPcXVvdGVBc3NldEFmdGVyBRJfcXVvdGVBc3NldFJlc2VydmUEE21heFByaWNlSW1wYWN0VmFsdWUJAQ5tYXhQcmljZUltcGFjdAAEDSR0MDE1NjA0MTU3OTcJAQ11cGRhdGVSZXNlcnZlAwkBASEBBQZfaXNBZGQFDnF1b3RlQXNzZXRTb2xkBRBfYmFzZUFzc2V0QW1vdW50BBdxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyMQgFDSR0MDE1NjA0MTU3OTcCXzEEFmJhc2VBc3NldFJlc2VydmVBZnRlcjEIBQ0kdDAxNTYwNDE1Nzk3Al8yBBd0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyMQgFDSR0MDE1NjA0MTU3OTcCXzMEGGN1bXVsYXRpdmVOb3Rpb25hbEFmdGVyMQgFDSR0MDE1NjA0MTU3OTcCXzQEC21hcmtldFByaWNlCQEEZGl2ZAIFDnF1b3RlQXNzZXRTb2xkBRBfYmFzZUFzc2V0QW1vdW50BAlwcmljZURpZmYJAQNhYnMBCQBlAgULcHJpY2VCZWZvcmUFC21hcmtldFByaWNlBAtwcmljZUltcGFjdAkAZQIFDERFQ0lNQUxfVU5JVAkBBGRpdmQCBQtwcmljZUJlZm9yZQkAZAIFC3ByaWNlQmVmb3JlBQlwcmljZURpZmYDAwkAZgIFC3ByaWNlSW1wYWN0BRNtYXhQcmljZUltcGFjdFZhbHVlBRRfY2hlY2tNYXhQcmljZUltcGFjdAcJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgICDVByaWNlIGltcGFjdCAJAKQDAQULcHJpY2VJbXBhY3QCFCA+IG1heCBwcmljZSBpbXBhY3QgCQCkAwEFE21heFByaWNlSW1wYWN0VmFsdWUCFSBiZWZvcmUgcXVvdGUgYXNzZXQ6IAkApAMBBRJfcXVvdGVBc3NldFJlc2VydmUCFCBiZWZvcmUgYmFzZSBhc3NldDogCQCkAwEFEV9iYXNlQXNzZXRSZXNlcnZlAiAgYmFzZSBhc3NldCBhbW91bnQgdG8gZXhjaGFuZ2U6IAkApAMBBRBfYmFzZUFzc2V0QW1vdW50Ag8gcHJpY2UgYmVmb3JlOiAJAKQDAQULcHJpY2VCZWZvcmUCDyBtYXJrZXQgcHJpY2U6IAkApAMBBQttYXJrZXRQcmljZQkAmgoIBQ5xdW90ZUFzc2V0U29sZAUXcXVvdGVBc3NldFJlc2VydmVBZnRlcjEFFmJhc2VBc3NldFJlc2VydmVBZnRlcjEFF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxBRhjdW11bGF0aXZlTm90aW9uYWxBZnRlcjEJAGUCCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAMFBl9pc0FkZAkBA2FicwEFEF9iYXNlQXNzZXRBbW91bnQAAAkAZQIJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAMJAQEhAQUGX2lzQWRkCQEDYWJzAQUQX2Jhc2VBc3NldEFtb3VudAAABQtwcmljZUltcGFjdAEKc3dhcE91dHB1dAMGX2lzQWRkEF9iYXNlQXNzZXRBbW91bnQUX2NoZWNrTWF4UHJpY2VJbXBhY3QJARZzd2FwT3V0cHV0V2l0aFJlc2VydmVzBQUGX2lzQWRkBRBfYmFzZUFzc2V0QW1vdW50BRRfY2hlY2tNYXhQcmljZUltcGFjdAkBBnF0QXN0UgAJAQZic0FzdFIAARJnZXRPcmFjbGVUd2FwUHJpY2UABAZvcmFjbGUJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCBQR0aGlzBQVrX29yYQIABAhwcmljZUtleQkBEUBleHRyTmF0aXZlKDEwNTMpAgUEdGhpcwUJa19vcmFfa2V5BAhibG9ja0tleQkBEUBleHRyTmF0aXZlKDEwNTMpAgUEdGhpcwUPa19vcmFfYmxvY2tfa2V5BAlsYXN0VmFsdWUJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBQZvcmFjbGUFCHByaWNlS2V5CQCsAgIJAKwCAgkArAICAiJDYW4gbm90IGdldCBvcmFjbGUgcHJpY2UuIE9yYWNsZTogCQClCAEFBm9yYWNsZQIGIGtleTogBQhwcmljZUtleQUJbGFzdFZhbHVlARlyZXF1aXJlTm90T3ZlclNwcmVhZExpbWl0AhJfcXVvdGVBc3NldFJlc2VydmURX2Jhc2VBc3NldFJlc2VydmUEC29yYWNsZVByaWNlCQESZ2V0T3JhY2xlVHdhcFByaWNlAAQKcHJpY2VBZnRlcgkBBGRpdmQCBRJfcXVvdGVBc3NldFJlc2VydmUFEV9iYXNlQXNzZXRSZXNlcnZlBAxhdmVyYWdlUHJpY2UJAQRkaXZkAgkAZAIFC29yYWNsZVByaWNlBQpwcmljZUFmdGVyCQBoAgACBQxERUNJTUFMX1VOSVQEDGFic1ByaWNlRGlmZgkBBGRpdmQCCQEDYWJzAQkAZQIFC29yYWNsZVByaWNlBQpwcmljZUFmdGVyBQxhdmVyYWdlUHJpY2UDCQBmAgUMYWJzUHJpY2VEaWZmCQEObWF4UHJpY2VTcHJlYWQACQACAQkArAICCQCsAgIJAKwCAgINUHJpY2Ugc3ByZWFkIAkApAMBBQxhYnNQcmljZURpZmYCFCA+IG1heCBwcmljZSBzcHJlYWQgCQCkAwEJAQ5tYXhQcmljZVNwcmVhZAAGAQxnZXRTcG90UHJpY2UABBJfcXVvdGVBc3NldFJlc2VydmUJAQZxdEFzdFIABBFfYmFzZUFzc2V0UmVzZXJ2ZQkBBmJzQXN0UgAJAQRkaXZkAgUSX3F1b3RlQXNzZXRSZXNlcnZlBRFfYmFzZUFzc2V0UmVzZXJ2ZQEWaXNPdmVyRmx1Y3R1YXRpb25MaW1pdAAEC29yYWNsZVByaWNlCQESZ2V0T3JhY2xlVHdhcFByaWNlAAQMY3VycmVudFByaWNlCQEMZ2V0U3BvdFByaWNlAAkAZgIJAQRkaXZkAgkBA2FicwEJAGUCBQtvcmFjbGVQcmljZQUMY3VycmVudFByaWNlBQtvcmFjbGVQcmljZQkBC3NwcmVhZExpbWl0AAEfZ2V0UG9zaXRpb25BZGp1c3RlZE9wZW5Ob3Rpb25hbAQNX3Bvc2l0aW9uU2l6ZQdfb3B0aW9uEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfYmFzZUFzc2V0UmVzZXJ2ZQQPcG9zaXRpb25TaXplQWJzCQEDYWJzAQUNX3Bvc2l0aW9uU2l6ZQQHaXNTaG9ydAkAZgIAAAUNX3Bvc2l0aW9uU2l6ZQQQcG9zaXRpb25Ob3Rpb25hbAMJAAACBQdfb3B0aW9uBQ9QTkxfT1BUSU9OX1NQT1QEDSR0MDE5MDE1MTkxODYJARZzd2FwT3V0cHV0V2l0aFJlc2VydmVzBQkBASEBBQdpc1Nob3J0BQ9wb3NpdGlvblNpemVBYnMHBRJfcXVvdGVBc3NldFJlc2VydmUFEV9iYXNlQXNzZXRSZXNlcnZlBBNvdXRQb3NpdGlvbk5vdGlvbmFsCAUNJHQwMTkwMTUxOTE4NgJfMQQCeDEIBQ0kdDAxOTAxNTE5MTg2Al8yBAJ4MggFDSR0MDE5MDE1MTkxODYCXzMEAngzCAUNJHQwMTkwMTUxOTE4NgJfNAUTb3V0UG9zaXRpb25Ob3Rpb25hbAkBBG11bGQCBQ9wb3NpdGlvblNpemVBYnMJARJnZXRPcmFjbGVUd2FwUHJpY2UABRBwb3NpdGlvbk5vdGlvbmFsAStnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubEJ5VmFsdWVzBQ1fcG9zaXRpb25TaXplFV9wb3NpdGlvbk9wZW5Ob3Rpb25hbBJfcXVvdGVBc3NldFJlc2VydmURX2Jhc2VBc3NldFJlc2VydmUHX29wdGlvbgMJAAACBQ1fcG9zaXRpb25TaXplAAAJAAIBAhVJbnZhbGlkIHBvc2l0aW9uIHNpemUEB2lzU2hvcnQJAGYCAAAFDV9wb3NpdGlvblNpemUEEHBvc2l0aW9uTm90aW9uYWwJAR9nZXRQb3NpdGlvbkFkanVzdGVkT3Blbk5vdGlvbmFsBAUNX3Bvc2l0aW9uU2l6ZQUHX29wdGlvbgUSX3F1b3RlQXNzZXRSZXNlcnZlBRFfYmFzZUFzc2V0UmVzZXJ2ZQQNdW5yZWFsaXplZFBubAMFB2lzU2hvcnQJAGUCBRVfcG9zaXRpb25PcGVuTm90aW9uYWwFEHBvc2l0aW9uTm90aW9uYWwJAGUCBRBwb3NpdGlvbk5vdGlvbmFsBRVfcG9zaXRpb25PcGVuTm90aW9uYWwJAJQKAgUQcG9zaXRpb25Ob3Rpb25hbAUNdW5yZWFsaXplZFBubAEjZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmwCB190cmFkZXIHX29wdGlvbgQNJHQwMjA1MDMyMDYzMQkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgQMcG9zaXRpb25TaXplCAUNJHQwMjA1MDMyMDYzMQJfMQQOcG9zaXRpb25NYXJnaW4IBQ0kdDAyMDUwMzIwNjMxAl8yBBRwb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDIwNTAzMjA2MzECXzMEEXBvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwMjA1MDMyMDYzMQJfNAkBK2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sQnlWYWx1ZXMFBQxwb3NpdGlvblNpemUFFHBvc2l0aW9uT3Blbk5vdGlvbmFsCQEGcXRBc3RSAAkBBmJzQXN0UgAFB19vcHRpb24BD2NhbGNNYXJnaW5SYXRpbwMNX3JlbWFpbk1hcmdpbghfYmFkRGVidBFfcG9zaXRpb25Ob3Rpb25hbAkBBGRpdmQCCQBlAgUNX3JlbWFpbk1hcmdpbgUIX2JhZERlYnQFEV9wb3NpdGlvbk5vdGlvbmFsARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAgdfdHJhZGVyB19vcHRpb24EDSR0MDIxMTEyMjEyMjMJAQtnZXRQb3NpdGlvbgEFB190cmFkZXIEDHBvc2l0aW9uU2l6ZQgFDSR0MDIxMTEyMjEyMjMCXzEEDnBvc2l0aW9uTWFyZ2luCAUNJHQwMjExMTIyMTIyMwJfMgQDcG9uCAUNJHQwMjExMTIyMTIyMwJfMwQRcG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDAyMTExMjIxMjIzAl80BA0kdDAyMTIyOTIxMzIyCQEjZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmwCBQdfdHJhZGVyBQdfb3B0aW9uBBBwb3NpdGlvbk5vdGlvbmFsCAUNJHQwMjEyMjkyMTMyMgJfMQQNdW5yZWFsaXplZFBubAgFDSR0MDIxMjI5MjEzMjICXzIEDSR0MDIxMzI3MjE0OTMJASJjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50BAUMcG9zaXRpb25TaXplBQ5wb3NpdGlvbk1hcmdpbgURcG9zaXRpb25Mc3RVcGRDUEYFDXVucmVhbGl6ZWRQbmwEDHJlbWFpbk1hcmdpbggFDSR0MDIxMzI3MjE0OTMCXzEEB2JhZERlYnQIBQ0kdDAyMTMyNzIxNDkzAl8yCQEPY2FsY01hcmdpblJhdGlvAwUMcmVtYWluTWFyZ2luBQdiYWREZWJ0BRBwb3NpdGlvbk5vdGlvbmFsAQ5nZXRNYXJnaW5SYXRpbwEHX3RyYWRlcgkBFmdldE1hcmdpblJhdGlvQnlPcHRpb24CBQdfdHJhZGVyBQ9QTkxfT1BUSU9OX1NQT1QBG2dldFBhcnRpYWxMaXF1aWRhdGlvbkFtb3VudAIHX3RyYWRlcg1fcG9zaXRpb25TaXplBAxtYXhpbXVtUmF0aW8JAQR2bWF4AgkBF3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAAkAZQIFDERFQ0lNQUxfVU5JVAkBBGRpdmQCCQEOZ2V0TWFyZ2luUmF0aW8BBQdfdHJhZGVyCQEWbWFpbnRlbmFuY2VNYXJnaW5SYXRpbwAEGG1heEV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQkBBG11bGQCCQEDYWJzAQUNX3Bvc2l0aW9uU2l6ZQUMbWF4aW11bVJhdGlvBApzd2FwUmVzdWx0CQEKc3dhcE91dHB1dAMJAGYCBQ1fcG9zaXRpb25TaXplAAAFGG1heEV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQcEHG1heEV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQIBQpzd2FwUmVzdWx0Al8xBAtwcmljZUltcGFjdAgFCnN3YXBSZXN1bHQCXzgDCQBmAgkBDm1heFByaWNlSW1wYWN0AAULcHJpY2VJbXBhY3QFHG1heEV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQEFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQkBBG11bGQCCQEDYWJzAQUNX3Bvc2l0aW9uU2l6ZQkBF3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAAQZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAgJAQpzd2FwT3V0cHV0AwkAZgIFDV9wb3NpdGlvblNpemUAAAUVZXhjaGFuZ2VkUG9zaXRpb25TaXplBwJfMQUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAEVaW50ZXJuYWxDbG9zZVBvc2l0aW9uAgdfdHJhZGVyFF9jaGVja01heFByaWNlSW1wYWN0BA0kdDAyMjcyNjIyODU0CQELZ2V0UG9zaXRpb24BBQdfdHJhZGVyBAxwb3NpdGlvblNpemUIBQ0kdDAyMjcyNjIyODU0Al8xBA5wb3NpdGlvbk1hcmdpbggFDSR0MDIyNzI2MjI4NTQCXzIEFHBvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwMjI3MjYyMjg1NAJfMwQRcG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDAyMjcyNjIyODU0Al80BA11bnJlYWxpemVkUG5sCAkBI2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sAgUHX3RyYWRlcgUPUE5MX09QVElPTl9TUE9UAl8yBA0kdDAyMjk0OTIzMTE3CQEiY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudAQFDHBvc2l0aW9uU2l6ZQUOcG9zaXRpb25NYXJnaW4FEXBvc2l0aW9uTHN0VXBkQ1BGBQ11bnJlYWxpemVkUG5sBAxyZW1haW5NYXJnaW4IBQ0kdDAyMjk0OTIzMTE3Al8xBAdiYWREZWJ0CAUNJHQwMjI5NDkyMzExNwJfMgQVZXhjaGFuZ2VkUG9zaXRpb25TaXplCQEBLQEFDHBvc2l0aW9uU2l6ZQQLcmVhbGl6ZWRQbmwFDXVucmVhbGl6ZWRQbmwEDW1hcmdpblRvVmF1bHQJAQEtAQUMcmVtYWluTWFyZ2luBA0kdDAyMzI0NDIzNTU1CQEKc3dhcE91dHB1dAMJAGYCBQxwb3NpdGlvblNpemUAAAkBA2FicwEFDHBvc2l0aW9uU2l6ZQUUX2NoZWNrTWF4UHJpY2VJbXBhY3QEGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQIBQ0kdDAyMzI0NDIzNTU1Al8xBBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwMjMyNDQyMzU1NQJfMgQVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwMjMyNDQyMzU1NQJfMwQWdG90YWxQb3NpdGlvblNpemVBZnRlcggFDSR0MDIzMjQ0MjM1NTUCXzQEF2N1bXVsYXRpdmVOb3Rpb25hbEFmdGVyCAUNJHQwMjMyNDQyMzU1NQJfNQQOdG90YWxMb25nQWZ0ZXIIBQ0kdDAyMzI0NDIzNTU1Al82BA90b3RhbFNob3J0QWZ0ZXIIBQ0kdDAyMzI0NDIzNTU1Al83BBlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyCQBlAgkBFG9wZW5JbnRlcmVzdE5vdGlvbmFsAAUUcG9zaXRpb25PcGVuTm90aW9uYWwJAJ4KDAUVZXhjaGFuZ2VkUG9zaXRpb25TaXplBQdiYWREZWJ0BQtyZWFsaXplZFBubAUNbWFyZ2luVG9WYXVsdAUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBRZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyBRdjdW11bGF0aXZlTm90aW9uYWxBZnRlcgUZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcgUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAUOdG90YWxMb25nQWZ0ZXIFD3RvdGFsU2hvcnRBZnRlcgEQZ2V0VHdhcFNwb3RQcmljZQAECG1pbnV0ZUlkCQBpAgkAaQIIBQlsYXN0QmxvY2sJdGltZXN0YW1wAOgHADwEDXN0YXJ0TWludXRlSWQJAGUCBQhtaW51dGVJZAUNVFdBUF9JTlRFUlZBTAQHbGlzdFN0cgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzBQ1rX2xhc3REYXRhU3RyAgAEBGxpc3QJALUJAgUHbGlzdFN0cgIBLAoBCGZpbHRlckZuAgthY2N1bXVsYXRvcgRuZXh0AwkAZwIFDXN0YXJ0TWludXRlSWQJAQ1wYXJzZUludFZhbHVlAQUEbmV4dAkAzQgCBQthY2N1bXVsYXRvcgkBDXBhcnNlSW50VmFsdWUBBQRuZXh0BQthY2N1bXVsYXRvcgQFbGlzdEYKAAIkbAUEbGlzdAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEIZmlsdGVyRm4CBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDIwCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoACwAMAA0ADgAPABAAEQASABMAFAQIbWF4SW5kZXgDCQBmAgkAkAMBBQVsaXN0RgAACQCWAwEFBWxpc3RGCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUEbGlzdAAABAxsYXN0TWludXRlSWQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwUOa19sYXN0TWludXRlSWQAAAQWZW5kTGFzdEN1bXVsYXRpdmVQcmljZQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQCsAgIJAKwCAgUda190d2FwRGF0YUxhc3RDdW11bGF0aXZlUHJpY2UCAV8JAKQDAQUMbGFzdE1pbnV0ZUlkAAAEDGVuZExhc3RQcmljZQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQCsAgIJAKwCAgUTa190d2FwRGF0YUxhc3RQcmljZQIBXwkApAMBBQxsYXN0TWludXRlSWQAAAQSbm93Q3VtdWxhdGl2ZVByaWNlCQBkAgUWZW5kTGFzdEN1bXVsYXRpdmVQcmljZQkAaAIJAGUCBQhtaW51dGVJZAUMbGFzdE1pbnV0ZUlkBQxlbmRMYXN0UHJpY2UEGHN0YXJ0TGFzdEN1bXVsYXRpdmVQcmljZQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQCsAgIJAKwCAgUda190d2FwRGF0YUxhc3RDdW11bGF0aXZlUHJpY2UCAV8JAKQDAQUIbWF4SW5kZXgAAAQOc3RhcnRMYXN0UHJpY2UJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkArAICCQCsAgIFE2tfdHdhcERhdGFMYXN0UHJpY2UCAV8JAKQDAQUIbWF4SW5kZXgAAAQUc3RhcnRDdW11bGF0aXZlUHJpY2UJAGQCBRhzdGFydExhc3RDdW11bGF0aXZlUHJpY2UJAGgCCQBlAgUNc3RhcnRNaW51dGVJZAUIbWF4SW5kZXgFDnN0YXJ0TGFzdFByaWNlCQBpAgkAZQIFEm5vd0N1bXVsYXRpdmVQcmljZQUUc3RhcnRDdW11bGF0aXZlUHJpY2UFDVRXQVBfSU5URVJWQUwBEGdldFBlZ0FkanVzdENvc3QBBl9wcmljZQQNX3Bvc2l0aW9uU2l6ZQkBEXRvdGFsUG9zaXRpb25TaXplAAQJZGlyZWN0aW9uCQBmAgUNX3Bvc2l0aW9uU2l6ZQAABBVjdXJyZW50TmV0TWFya2V0VmFsdWUICQEKc3dhcE91dHB1dAMFCWRpcmVjdGlvbgkBA2FicwEFDV9wb3NpdGlvblNpemUHAl8xBBBiYXNlQXNzZXRSZXNlcnZlCQEGYnNBc3RSAAQUbmV3UXVvdGVBc3NldFJlc2VydmUJAQRtdWxkAgUQYmFzZUFzc2V0UmVzZXJ2ZQUGX3ByaWNlBARjb3N0CAkBK2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sQnlWYWx1ZXMFBQ1fcG9zaXRpb25TaXplBRVjdXJyZW50TmV0TWFya2V0VmFsdWUFFG5ld1F1b3RlQXNzZXRSZXNlcnZlBRBiYXNlQXNzZXRSZXNlcnZlBQ9QTkxfT1BUSU9OX1NQT1QCXzIJAJQKAgUUbmV3UXVvdGVBc3NldFJlc2VydmUFBGNvc3QBDnVwZGF0ZVNldHRpbmdzCRBfaW5pdE1hcmdpblJhdGlvBF9tbXIUX2xpcXVpZGF0aW9uRmVlUmF0aW8OX2Z1bmRpbmdQZXJpb2QEX2ZlZQxfc3ByZWFkTGltaXQPX21heFByaWNlSW1wYWN0GF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbw9fbWF4UHJpY2VTcHJlYWQJAMwIAgkBDEludGVnZXJFbnRyeQIFEWtfaW5pdE1hcmdpblJhdGlvBRBfaW5pdE1hcmdpblJhdGlvCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRhrX21haW50ZW5hbmNlTWFyZ2luUmF0aW8FBF9tbXIJAMwIAgkBDEludGVnZXJFbnRyeQIFFWtfbGlxdWlkYXRpb25GZWVSYXRpbwUUX2xpcXVpZGF0aW9uRmVlUmF0aW8JAMwIAgkBDEludGVnZXJFbnRyeQIFD2tfZnVuZGluZ1BlcmlvZAUOX2Z1bmRpbmdQZXJpb2QJAMwIAgkBDEludGVnZXJFbnRyeQIFBWtfZmVlBQRfZmVlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ1rX3NwcmVhZExpbWl0BQxfc3ByZWFkTGltaXQJAMwIAgkBDEludGVnZXJFbnRyeQIFEGtfbWF4UHJpY2VJbXBhY3QFD19tYXhQcmljZUltcGFjdAkAzAgCCQEMSW50ZWdlckVudHJ5AgUZa19wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwUYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRBrX21heFByaWNlU3ByZWFkBQ9fbWF4UHJpY2VTcHJlYWQFA25pbAENdXBkYXRlRnVuZGluZwURX25leHRGdW5kaW5nQmxvY2skX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uJV9sYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24QX2xvbmdGdW5kaW5nUmF0ZRFfc2hvcnRGdW5kaW5nUmF0ZQkAzAgCCQEMSW50ZWdlckVudHJ5AgUSa19uZXh0RnVuZGluZ0Jsb2NrBRFfbmV4dEZ1bmRpbmdCbG9jawkAzAgCCQEMSW50ZWdlckVudHJ5AgUla19sYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUkX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uCQDMCAIJAQxJbnRlZ2VyRW50cnkCBSZrX2xhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUlX2xhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkAzAgCCQEMSW50ZWdlckVudHJ5AgURa19sb25nRnVuZGluZ1JhdGUFEF9sb25nRnVuZGluZ1JhdGUJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfc2hvcnRGdW5kaW5nUmF0ZQURX3Nob3J0RnVuZGluZ1JhdGUFA25pbAEOdXBkYXRlUG9zaXRpb24FCF9hZGRyZXNzBV9zaXplB19tYXJnaW4NX29wZW5Ob3Rpb25hbCBfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUOa19wb3NpdGlvblNpemUFCF9hZGRyZXNzBQVfc2l6ZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUQa19wb3NpdGlvbk1hcmdpbgUIX2FkZHJlc3MFB19tYXJnaW4JAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFFmtfcG9zaXRpb25PcGVuTm90aW9uYWwFCF9hZGRyZXNzBQ1fb3Blbk5vdGlvbmFsCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQhfYWRkcmVzcwUgX2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FA25pbAEKYXBwZW5kVHdhcAEFcHJpY2UECG1pbnV0ZUlkCQBpAgkAaQIIBQlsYXN0QmxvY2sJdGltZXN0YW1wAOgHADwEEHByZXZpb3VzTWludXRlSWQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwUOa19sYXN0TWludXRlSWQAAAMJAGYCBRBwcmV2aW91c01pbnV0ZUlkBQhtaW51dGVJZAkAAgECEVRXQVAgb3V0LW9mLW9yZGVyBAxsYXN0TWludXRlSWQDCQAAAgUQcHJldmlvdXNNaW51dGVJZAAABQhtaW51dGVJZAUQcHJldmlvdXNNaW51dGVJZAMJAGYCBQhtaW51dGVJZAUQcHJldmlvdXNNaW51dGVJZAQTcHJldkN1bXVsYXRpdmVQcmljZQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQCsAgIJAKwCAgUda190d2FwRGF0YUxhc3RDdW11bGF0aXZlUHJpY2UCAV8JAKQDAQUQcHJldmlvdXNNaW51dGVJZAAABAlwcmV2UHJpY2UJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkArAICCQCsAgIFE2tfdHdhcERhdGFMYXN0UHJpY2UCAV8JAKQDAQUQcHJldmlvdXNNaW51dGVJZAUFcHJpY2UEE2xhc3RDdW11bGF0aXZlUHJpY2UJAGQCBRNwcmV2Q3VtdWxhdGl2ZVByaWNlCQBoAgkAZQIFCG1pbnV0ZUlkBQxsYXN0TWludXRlSWQFCXByZXZQcmljZQQEbGlzdAkBC3B1c2hUb1F1ZXVlAwkBCXN0clRvTGlzdAEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwUNa19sYXN0RGF0YVN0cgIABQ1UV0FQX0lOVEVSVkFMCQCkAwEFCG1pbnV0ZUlkCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBR1rX3R3YXBEYXRhTGFzdEN1bXVsYXRpdmVQcmljZQkApAMBBQhtaW51dGVJZAUTbGFzdEN1bXVsYXRpdmVQcmljZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUTa190d2FwRGF0YUxhc3RQcmljZQkApAMBBQhtaW51dGVJZAUFcHJpY2UJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFGmtfdHdhcERhdGFQcmV2aW91c01pbnV0ZUlkCQCkAwEFCG1pbnV0ZUlkBRBwcmV2aW91c01pbnV0ZUlkCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ5rX2xhc3RNaW51dGVJZAUIbWludXRlSWQJAMwIAgkBC1N0cmluZ0VudHJ5AgUNa19sYXN0RGF0YVN0cgkBCWxpc3RUb1N0cgEFBGxpc3QFA25pbAQYdHdhcERhdGFQcmV2aW91c01pbnV0ZUlkCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFGmtfdHdhcERhdGFQcmV2aW91c01pbnV0ZUlkCQCkAwEFCG1pbnV0ZUlkAAAEE3ByZXZDdW11bGF0aXZlUHJpY2UJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUda190d2FwRGF0YUxhc3RDdW11bGF0aXZlUHJpY2UJAKQDAQUYdHdhcERhdGFQcmV2aW91c01pbnV0ZUlkAAAECXByZXZQcmljZQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBRNrX3R3YXBEYXRhTGFzdFByaWNlCQCkAwEFGHR3YXBEYXRhUHJldmlvdXNNaW51dGVJZAUFcHJpY2UEE2xhc3RDdW11bGF0aXZlUHJpY2UJAGQCBRNwcmV2Q3VtdWxhdGl2ZVByaWNlCQBoAgkAZQIFCG1pbnV0ZUlkBRh0d2FwRGF0YVByZXZpb3VzTWludXRlSWQFCXByZXZQcmljZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUda190d2FwRGF0YUxhc3RDdW11bGF0aXZlUHJpY2UJAKQDAQUIbWludXRlSWQFE2xhc3RDdW11bGF0aXZlUHJpY2UJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFE2tfdHdhcERhdGFMYXN0UHJpY2UJAKQDAQUIbWludXRlSWQFBXByaWNlBQNuaWwBEXVwZGF0ZUFtbVJlc2VydmVzAgdfcXRBc3RSB19ic0FzdFIJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tfcXVvdGVBc3NldFJlc2VydmUFB19xdEFzdFIJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfYmFzZUFzc2V0UmVzZXJ2ZQUHX2JzQXN0UgUDbmlsAQl1cGRhdGVBbW0HB19xdEFzdFIHX2JzQXN0UhdfdG90YWxQb3NpdGlvblNpemVBZnRlchhfY3VtdWxhdGl2ZU5vdGlvbmFsQWZ0ZXIVX29wZW5JbnRlcmVzdE5vdGlvbmFsFl90b3RhbExvbmdQb3NpdGlvblNpemUXX3RvdGFsU2hvcnRQb3NpdGlvblNpemUDCQECIT0CCQBlAgUWX3RvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQUXX3RvdGFsU2hvcnRQb3NpdGlvblNpemUFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgICGEludmFsaWQgQU1NIHN0YXRlIGRhdGE6IAkApAMBBRZfdG90YWxMb25nUG9zaXRpb25TaXplAgQgKyAgCQCkAwEFF190b3RhbFNob3J0UG9zaXRpb25TaXplAgQgIT0gCQCkAwEFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQDOCAIJAM4IAgkBEXVwZGF0ZUFtbVJlc2VydmVzAgUHX3F0QXN0UgUHX2JzQXN0UgkAzAgCCQEMSW50ZWdlckVudHJ5AgUTa190b3RhbFBvc2l0aW9uU2l6ZQUXX3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIJAMwIAgkBDEludGVnZXJFbnRyeQIFFGtfY3VtdWxhdGl2ZU5vdGlvbmFsBRhfY3VtdWxhdGl2ZU5vdGlvbmFsQWZ0ZXIJAMwIAgkBDEludGVnZXJFbnRyeQIFFmtfb3BlbkludGVyZXN0Tm90aW9uYWwFFV9vcGVuSW50ZXJlc3ROb3Rpb25hbAkAzAgCCQEMSW50ZWdlckVudHJ5AgUXa190b3RhbExvbmdQb3NpdGlvblNpemUFFl90b3RhbExvbmdQb3NpdGlvblNpemUJAMwIAgkBDEludGVnZXJFbnRyeQIFGGtfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQUXX3RvdGFsU2hvcnRQb3NpdGlvblNpemUFA25pbAkBCmFwcGVuZFR3YXABCQEEZGl2ZAIFB19xdEFzdFIFB19ic0FzdFIBDmRlbGV0ZVBvc2l0aW9uAQhfYWRkcmVzcwkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBQ5rX3Bvc2l0aW9uU2l6ZQUIX2FkZHJlc3MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBDnRvQ29tcG9zaXRlS2V5AgUQa19wb3NpdGlvbk1hcmdpbgUIX2FkZHJlc3MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBDnRvQ29tcG9zaXRlS2V5AgUWa19wb3NpdGlvbk9wZW5Ob3Rpb25hbAUIX2FkZHJlc3MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBDnRvQ29tcG9zaXRlS2V5AgUua19wb3NpdGlvbkxhc3RVcGRhdGVkQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUIX2FkZHJlc3MJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFFGtfcG9zaXRpb25DbG9zZWREYXRlBQhfYWRkcmVzcwgFCWxhc3RCbG9jawl0aW1lc3RhbXAFA25pbAEId2l0aGRyYXcCCF9hZGRyZXNzB19hbW91bnQEB2JhbGFuY2UJAPAHAgUEdGhpcwkBCnF1b3RlQXNzZXQAAwkAZgIFB19hbW91bnQFB2JhbGFuY2UJAAIBCQCsAgIJAKwCAgkArAICAhNVbmFibGUgdG8gd2l0aGRyYXcgCQCkAwEFB19hbW91bnQCFyBmcm9tIGNvbnRyYWN0IGJhbGFuY2UgCQCkAwEFB2JhbGFuY2UJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwUIX2FkZHJlc3MFB19hbW91bnQJAQpxdW90ZUFzc2V0AAUDbmlsAQ11cGRhdGVCYWxhbmNlAQFpAwkAZgIAAAUBaQkAAgECB0JhbGFuY2UJAMwIAgkBDEludGVnZXJFbnRyeQIFCWtfYmFsYW5jZQUBaQUDbmlsAQt0cmFuc2ZlckZlZQEBaQkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCQEOc3Rha2luZ0FkZHJlc3MABQFpCQEKcXVvdGVBc3NldAAFA25pbBMBaQEFcGF1c2UAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECGkludmFsaWQgdG9nZ2xlUGF1c2UgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQhrX3BhdXNlZAYFA25pbAFpAQd1bnBhdXNlAAMJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAJAAIBAhpJbnZhbGlkIHRvZ2dsZVBhdXNlIHBhcmFtcwkAzAgCCQEMQm9vbGVhbkVudHJ5AgUIa19wYXVzZWQHBQNuaWwBaQEMYWRkTGlxdWlkaXR5ARFfcXVvdGVBc3NldEFtb3VudAMDCQECIT0CCAUBaQZjYWxsZXIJAQxhZG1pbkFkZHJlc3MABgkAZwIAAAURX3F1b3RlQXNzZXRBbW91bnQJAAIBAhtJbnZhbGlkIGFkZExpcXVpZGl0eSBwYXJhbXMEB19xdEFzdFIJAQZxdEFzdFIABAdfYnNBc3RSCQEGYnNBc3RSAAQFcHJpY2UJAQRkaXZkAgUHX3F0QXN0UgUHX2JzQXN0UgQUYmFzZUFzc2V0QW1vdW50VG9BZGQJAQRkaXZkAgURX3F1b3RlQXNzZXRBbW91bnQFBXByaWNlBAtxdEFzdFJBZnRlcgkAZAIFB19xdEFzdFIFEV9xdW90ZUFzc2V0QW1vdW50BAtic0FzdFJBZnRlcgkAZAIFB19ic0FzdFIFFGJhc2VBc3NldEFtb3VudFRvQWRkCQERdXBkYXRlQW1tUmVzZXJ2ZXMCBQtxdEFzdFJBZnRlcgULYnNBc3RSQWZ0ZXIBaQEPcmVtb3ZlTGlxdWlkaXR5ARFfcXVvdGVBc3NldEFtb3VudAMDCQECIT0CCAUBaQZjYWxsZXIJAQxhZG1pbkFkZHJlc3MABgkAZwIAAAURX3F1b3RlQXNzZXRBbW91bnQJAAIBAh5JbnZhbGlkIHJlbW92ZUxpcXVpZGl0eSBwYXJhbXMEB19xdEFzdFIJAQZxdEFzdFIABAdfYnNBc3RSCQEGYnNBc3RSAAQFcHJpY2UJAQRkaXZkAgUHX3F0QXN0UgUHX2JzQXN0UgQXYmFzZUFzc2V0QW1vdW50VG9SZW1vdmUJAQRkaXZkAgURX3F1b3RlQXNzZXRBbW91bnQFBXByaWNlBAtxdEFzdFJBZnRlcgkAZQIFB19xdEFzdFIFEV9xdW90ZUFzc2V0QW1vdW50BAtic0FzdFJBZnRlcgkAZQIFB19ic0FzdFIFF2Jhc2VBc3NldEFtb3VudFRvUmVtb3ZlCQERdXBkYXRlQW1tUmVzZXJ2ZXMCBQtxdEFzdFJBZnRlcgULYnNBc3RSQWZ0ZXIBaQEOY2hhbmdlU2V0dGluZ3MJEF9pbml0TWFyZ2luUmF0aW8EX21tchRfbGlxdWlkYXRpb25GZWVSYXRpbw5fZnVuZGluZ1BlcmlvZARfZmVlDF9zcHJlYWRMaW1pdA9fbWF4UHJpY2VJbXBhY3QYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvD19tYXhQcmljZVNwcmVhZAMJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAJAAIBAh1JbnZhbGlkIGNoYW5nZVNldHRpbmdzIHBhcmFtcwkBDnVwZGF0ZVNldHRpbmdzCQUQX2luaXRNYXJnaW5SYXRpbwUEX21tcgUUX2xpcXVpZGF0aW9uRmVlUmF0aW8FDl9mdW5kaW5nUGVyaW9kBQRfZmVlBQxfc3ByZWFkTGltaXQFD19tYXhQcmljZUltcGFjdAUYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvBQ9fbWF4UHJpY2VTcHJlYWQBaQEKaW5pdGlhbGl6ZQ4HX3F0QXN0UgdfYnNBc3RSDl9mdW5kaW5nUGVyaW9kEF9pbml0TWFyZ2luUmF0aW8EX21tchRfbGlxdWlkYXRpb25GZWVSYXRpbwRfZmVlB19vcmFjbGUKX29yYWNsZUtleQxfY29vcmRpbmF0b3IMX3NwcmVhZExpbWl0D19tYXhQcmljZUltcGFjdBhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8PX21heFByaWNlU3ByZWFkAwMDAwMDAwMDAwMDCQBnAgAABQdfcXRBc3RSBgkAZwIAAAUHX2JzQXN0UgYJAGcCAAAFDl9mdW5kaW5nUGVyaW9kBgkAZwIAAAUQX2luaXRNYXJnaW5SYXRpbwYJAGcCAAAFBF9tbXIGCQBnAgAABRRfbGlxdWlkYXRpb25GZWVSYXRpbwYJAGcCAAAFBF9mZWUGCQBnAgAABQxfc3ByZWFkTGltaXQGCQBnAgAABQ9fbWF4UHJpY2VJbXBhY3QGCQBnAgAABRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8GCQBnAgAABQ9fbWF4UHJpY2VTcHJlYWQGCQELaW5pdGlhbGl6ZWQACQACAQIdSW52YWxpZCBpbml0aWFsaXplIHBhcmFtZXRlcnMJAM4IAgkAzggCCQDOCAIJAM4IAgkBCXVwZGF0ZUFtbQcFB19xdEFzdFIFB19ic0FzdFIAAAAAAAAAAAAACQEOdXBkYXRlU2V0dGluZ3MJBRBfaW5pdE1hcmdpblJhdGlvBQRfbW1yBRRfbGlxdWlkYXRpb25GZWVSYXRpbwUOX2Z1bmRpbmdQZXJpb2QFBF9mZWUFDF9zcHJlYWRMaW1pdAUPX21heFByaWNlSW1wYWN0BRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8FD19tYXhQcmljZVNwcmVhZAkBDXVwZGF0ZUZ1bmRpbmcFCQBkAggFCWxhc3RCbG9jawl0aW1lc3RhbXAFDl9mdW5kaW5nUGVyaW9kAAAAAAAAAAAJAQ11cGRhdGVCYWxhbmNlAQAACQDMCAIJAQxCb29sZWFuRW50cnkCBQ1rX2luaXRpYWxpemVkBgkAzAgCCQELU3RyaW5nRW50cnkCBQVrX29yYQUHX29yYWNsZQkAzAgCCQELU3RyaW5nRW50cnkCBQlrX29yYV9rZXkFCl9vcmFjbGVLZXkJAMwIAgkBC1N0cmluZ0VudHJ5AgUUa19jb29yZGluYXRvckFkZHJlc3MFDF9jb29yZGluYXRvcgUDbmlsAWkBEnNldEluaXRNYXJnaW5SYXRpbwEQX2luaXRNYXJnaW5SYXRpbwMDCQBnAgAABRBfaW5pdE1hcmdpblJhdGlvBgkBASEBCQELaW5pdGlhbGl6ZWQACQACAQIlSW52YWxpZCBzZXRJbml0TWFyZ2luUmF0aW8gcGFyYW1ldGVycwkBDnVwZGF0ZVNldHRpbmdzCQUQX2luaXRNYXJnaW5SYXRpbwkBFm1haW50ZW5hbmNlTWFyZ2luUmF0aW8ACQETbGlxdWlkYXRpb25GZWVSYXRpbwAJARBmdW5kaW5nUGVyaW9kUmF3AAkBA2ZlZQAJAQtzcHJlYWRMaW1pdAAJAQ5tYXhQcmljZUltcGFjdAAJARdwYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwAJAQ5tYXhQcmljZVNwcmVhZAABaQEQZGVjcmVhc2VQb3NpdGlvbgMHX2Ftb3VudAlfbGV2ZXJhZ2UTX21pbkJhc2VBc3NldEFtb3VudAMDAwMDCQBnAgAABQdfYW1vdW50BgkBASEBCQELaW5pdGlhbGl6ZWQABgkBASEBCQEWcmVxdWlyZU1vcmVNYXJnaW5SYXRpbwMJAQRkaXZkAgUMREVDSU1BTF9VTklUBQlfbGV2ZXJhZ2UJAQ9pbml0TWFyZ2luUmF0aW8ABgYJAQEhAQkBE3JlcXVpcmVPcGVuUG9zaXRpb24BCQClCAEIBQFpBmNhbGxlcgYJAQZwYXVzZWQACQACAQIjSW52YWxpZCBkZWNyZWFzZVBvc2l0aW9uIHBhcmFtZXRlcnMEDSR0MDM2MDczMzYyMjUJAQtnZXRQb3NpdGlvbgEJAKUIAQgFAWkGY2FsbGVyBA9vbGRQb3NpdGlvblNpemUIBQ0kdDAzNjA3MzM2MjI1Al8xBBFvbGRQb3NpdGlvbk1hcmdpbggFDSR0MDM2MDczMzYyMjUCXzIEF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwMzYwNzMzNjIyNQJfMwQUb2xkUG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDAzNjA3MzM2MjI1Al80BApfZGlyZWN0aW9uAwkAZgIFD29sZFBvc2l0aW9uU2l6ZQAABQlESVJfU0hPUlQFCERJUl9MT05HBAVpc0FkZAkAAAIFCl9kaXJlY3Rpb24FCERJUl9MT05HBAxvcGVuTm90aW9uYWwJAQRtdWxkAgUHX2Ftb3VudAUJX2xldmVyYWdlBA0kdDAzNjM5ODM2NTE0CQEjZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmwCCQClCAEIBQFpBmNhbGxlcgUPUE5MX09QVElPTl9TUE9UBBNvbGRQb3NpdGlvbk5vdGlvbmFsCAUNJHQwMzYzOTgzNjUxNAJfMQQNdW5yZWFsaXplZFBubAgFDSR0MDM2Mzk4MzY1MTQCXzIEDSR0MDM2NTIwMzkwNjkDCQBmAgUTb2xkUG9zaXRpb25Ob3Rpb25hbAUMb3Blbk5vdGlvbmFsBA0kdDAzNjg5NzM3MTE2CQEJc3dhcElucHV0AgUFaXNBZGQFDG9wZW5Ob3Rpb25hbAQVZXhjaGFuZ2VkUG9zaXRpb25TaXplCAUNJHQwMzY4OTczNzExNgJfMQQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDM2ODk3MzcxMTYCXzIEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDM2ODk3MzcxMTYCXzMEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDAzNjg5NzM3MTE2Al80BBdjdW11bGF0aXZlTm90aW9uYWxBZnRlcggFDSR0MDM2ODk3MzcxMTYCXzUEGGV4Y2hhbmdlZFBvc2l0aW9uU2l6ZUFicwkBA2FicwEFFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQMDCQECIT0CBRNfbWluQmFzZUFzc2V0QW1vdW50AAAJAGYCBRNfbWluQmFzZUFzc2V0QW1vdW50BRhleGNoYW5nZWRQb3NpdGlvblNpemVBYnMHCQACAQkArAICCQCsAgIJAKwCAgIlVG9vIGxpdHRsZSBiYXNlIGFzc2V0IGV4Y2hhbmdlZCwgZ290IAkApAMBBRhleGNoYW5nZWRQb3NpdGlvblNpemVBYnMCCiBleHBlY3RlZCAJAKQDAQUTX21pbkJhc2VBc3NldEFtb3VudAQLcmVhbGl6ZWRQbmwJAQRkaXZkAgkBBG11bGQCBQ11bnJlYWxpemVkUG5sBRhleGNoYW5nZWRQb3NpdGlvblNpemVBYnMJAQNhYnMBBQ9vbGRQb3NpdGlvblNpemUEDSR0MDM3NTUzMzc3OTgJASJjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50BAUPb2xkUG9zaXRpb25TaXplBRFvbGRQb3NpdGlvbk1hcmdpbgUUb2xkUG9zaXRpb25Mc3RVcGRDUEYFC3JlYWxpemVkUG5sBAxyZW1haW5NYXJnaW4IBQ0kdDAzNzU1MzM3Nzk4Al8xBAdiYWREZWJ0CAUNJHQwMzc1NTMzNzc5OAJfMgQOZnVuZGluZ1BheW1lbnQIBQ0kdDAzNzU1MzM3Nzk4Al8zBBlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50BQxvcGVuTm90aW9uYWwEEnVucmVhbGl6ZWRQbmxBZnRlcgkAZQIFDXVucmVhbGl6ZWRQbmwFC3JlYWxpemVkUG5sBBJyZW1haW5PcGVuTm90aW9uYWwDCQBmAgUPb2xkUG9zaXRpb25TaXplAAAJAGUCCQBlAgUTb2xkUG9zaXRpb25Ob3Rpb25hbAUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAUSdW5yZWFsaXplZFBubEFmdGVyCQBlAgkAZAIFEnVucmVhbGl6ZWRQbmxBZnRlcgUTb2xkUG9zaXRpb25Ob3Rpb25hbAUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAQPbmV3UG9zaXRpb25TaXplCQBkAgUPb2xkUG9zaXRpb25TaXplBRVleGNoYW5nZWRQb3NpdGlvblNpemUJAJ0KCwUPbmV3UG9zaXRpb25TaXplBQxyZW1haW5NYXJnaW4JAQNhYnMBBRJyZW1haW5PcGVuTm90aW9uYWwJAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAQUPbmV3UG9zaXRpb25TaXplBRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIFF2N1bXVsYXRpdmVOb3Rpb25hbEFmdGVyCQBlAgkBFG9wZW5JbnRlcmVzdE5vdGlvbmFsAAUMb3Blbk5vdGlvbmFsCQBlAgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQADCQBmAgUPbmV3UG9zaXRpb25TaXplAAAJAQNhYnMBBRVleGNoYW5nZWRQb3NpdGlvblNpemUAAAkAZQIJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAMJAGYCAAAFD25ld1Bvc2l0aW9uU2l6ZQkBA2FicwEFFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQAACQACAQIUQ2xvc2UgcG9zaXRpb24gZmlyc3QED25ld1Bvc2l0aW9uU2l6ZQgFDSR0MDM2NTIwMzkwNjkCXzEEF25ld1Bvc2l0aW9uUmVtYWluTWFyZ2luCAUNJHQwMzY1MjAzOTA2OQJfMgQXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDAzNjUyMDM5MDY5Al8zBBRuZXdQb3NpdGlvbkxhdGVzdENQRggFDSR0MDM2NTIwMzkwNjkCXzQEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDM2NTIwMzkwNjkCXzUEFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDAzNjUyMDM5MDY5Al82BBZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCAUNJHQwMzY1MjAzOTA2OQJfNwQXY3VtdWxhdGl2ZU5vdGlvbmFsQWZ0ZXIIBQ0kdDAzNjUyMDM5MDY5Al84BBlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyCAUNJHQwMzY1MjAzOTA2OQJfOQQOdG90YWxMb25nQWZ0ZXIIBQ0kdDAzNjUyMDM5MDY5A18xMAQPdG90YWxTaG9ydEFmdGVyCAUNJHQwMzY1MjAzOTA2OQNfMTEEDm5vdGlmeU5vdGlvbmFsCQD8BwQJAQxtaW5lckFkZHJlc3MAAg5ub3RpZnlOb3Rpb25hbAkAzAgCCQClCAEIBQFpBmNhbGxlcgkAzAgCBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUDbmlsBQNuaWwDCQAAAgUObm90aWZ5Tm90aW9uYWwFDm5vdGlmeU5vdGlvbmFsCQDOCAIJAQ51cGRhdGVQb3NpdGlvbgUJAKUIAQgFAWkGY2FsbGVyBQ9uZXdQb3NpdGlvblNpemUFF25ld1Bvc2l0aW9uUmVtYWluTWFyZ2luBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUUbmV3UG9zaXRpb25MYXRlc3RDUEYJAQl1cGRhdGVBbW0HBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIFF2N1bXVsYXRpdmVOb3Rpb25hbEFmdGVyBRlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyBQ50b3RhbExvbmdBZnRlcgUPdG90YWxTaG9ydEFmdGVyCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBEGluY3JlYXNlUG9zaXRpb24ECl9kaXJlY3Rpb24JX2xldmVyYWdlE19taW5CYXNlQXNzZXRBbW91bnQIX3JlZkxpbmsECl9yYXdBbW91bnQICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50AwMDAwMDAwkBAiE9AgUKX2RpcmVjdGlvbgUIRElSX0xPTkcJAQIhPQIFCl9kaXJlY3Rpb24FCURJUl9TSE9SVAcGCQBnAgAABQpfcmF3QW1vdW50BgkBASEBCQELaW5pdGlhbGl6ZWQABgkBAiE9AggJAJEDAggFAWkIcGF5bWVudHMAAAdhc3NldElkCQEKcXVvdGVBc3NldAAGCQEBIQEJARZyZXF1aXJlTW9yZU1hcmdpblJhdGlvAwkBBGRpdmQCBQxERUNJTUFMX1VOSVQFCV9sZXZlcmFnZQkBD2luaXRNYXJnaW5SYXRpbwAGBgkBBnBhdXNlZAAJAAIBAiNJbnZhbGlkIGluY3JlYXNlUG9zaXRpb24gcGFyYW1ldGVycwQHX3RyYWRlcgkApQgBCAUBaQZjYWxsZXIEDHJhd0ZlZUFtb3VudAkBBG11bGQCBQpfcmF3QW1vdW50CQEDZmVlAAQOcmVmZXJyZXJGZWVBbnkJAPwHBAkBD3JlZmVycmFsQWRkcmVzcwACFWFjY2VwdFBheW1lbnRXaXRoTGluawkAzAgCBQdfdHJhZGVyCQDMCAIFCF9yZWZMaW5rBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUMcmF3RmVlQW1vdW50BQNuaWwDCQAAAgUOcmVmZXJyZXJGZWVBbnkFDnJlZmVycmVyRmVlQW55BAtyZWZlcnJlckZlZQQHJG1hdGNoMAUOcmVmZXJyZXJGZWVBbnkDCQABAgUHJG1hdGNoMAIDSW50BAF4BQckbWF0Y2gwBQF4CQACAQITSW52YWxpZCByZWZlcnJlckZlZQQHX2Ftb3VudAkAZQIFCl9yYXdBbW91bnQFDHJhd0ZlZUFtb3VudAQJZmVlQW1vdW50CQBlAgUMcmF3RmVlQW1vdW50BQtyZWZlcnJlckZlZQQNJHQwNDA1OTg0MDczOAkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgQPb2xkUG9zaXRpb25TaXplCAUNJHQwNDA1OTg0MDczOAJfMQQRb2xkUG9zaXRpb25NYXJnaW4IBQ0kdDA0MDU5ODQwNzM4Al8yBBdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDQwNTk4NDA3MzgCXzMEFG9sZFBvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwNDA1OTg0MDczOAJfNAQNaXNOZXdQb3NpdGlvbgkAAAIFD29sZFBvc2l0aW9uU2l6ZQAABA9pc1NhbWVEaXJlY3Rpb24DCQBmAgUPb2xkUG9zaXRpb25TaXplAAAJAAACBQpfZGlyZWN0aW9uBQhESVJfTE9ORwkAAAIFCl9kaXJlY3Rpb24FCURJUl9TSE9SVAQOZXhwYW5kRXhpc3RpbmcDCQEBIQEFDWlzTmV3UG9zaXRpb24FD2lzU2FtZURpcmVjdGlvbgcEBWlzQWRkCQAAAgUKX2RpcmVjdGlvbgUIRElSX0xPTkcEDSR0MDQxMDI3NDM1OTUDAwUNaXNOZXdQb3NpdGlvbgYFDmV4cGFuZEV4aXN0aW5nBAxvcGVuTm90aW9uYWwJAQRtdWxkAgUHX2Ftb3VudAUJX2xldmVyYWdlBA0kdDA0MTQ1MTQxNjU3CQEJc3dhcElucHV0AgUFaXNBZGQFDG9wZW5Ob3Rpb25hbAQVYW1vdW50QmFzZUFzc2V0Qm91Z2h0CAUNJHQwNDE0NTE0MTY1NwJfMQQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDQxNDUxNDE2NTcCXzIEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDQxNDUxNDE2NTcCXzMEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDA0MTQ1MTQxNjU3Al80BBdjdW11bGF0aXZlTm90aW9uYWxBZnRlcggFDSR0MDQxNDUxNDE2NTcCXzUDAwkBAiE9AgUTX21pbkJhc2VBc3NldEFtb3VudAAACQBmAgUTX21pbkJhc2VBc3NldEFtb3VudAkBA2FicwEFFWFtb3VudEJhc2VBc3NldEJvdWdodAcJAAIBCQCsAgIJAKwCAgkArAICAg1MaW1pdCBlcnJvcjogCQCkAwEJAQNhYnMBBRVhbW91bnRCYXNlQXNzZXRCb3VnaHQCAyA8IAkApAMBBRNfbWluQmFzZUFzc2V0QW1vdW50BA9uZXdQb3NpdGlvblNpemUJAGQCBQ9vbGRQb3NpdGlvblNpemUFFWFtb3VudEJhc2VBc3NldEJvdWdodAQZaW5jcmVhc2VNYXJnaW5SZXF1aXJlbWVudAkBBGRpdmQCBQxvcGVuTm90aW9uYWwFCV9sZXZlcmFnZQQNJHQwNDIwMzg0MjI3NwkBImNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnQEBQ9vbGRQb3NpdGlvblNpemUFEW9sZFBvc2l0aW9uTWFyZ2luBRRvbGRQb3NpdGlvbkxzdFVwZENQRgUZaW5jcmVhc2VNYXJnaW5SZXF1aXJlbWVudAQMcmVtYWluTWFyZ2luCAUNJHQwNDIwMzg0MjI3NwJfMQQCeDEIBQ0kdDA0MjAzODQyMjc3Al8yBAJ4MggFDSR0MDQyMDM4NDIyNzcCXzMDCQEBIQEJARlyZXF1aXJlTm90T3ZlclNwcmVhZExpbWl0AgUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCQACAQIVT3ZlciBtYXggc3ByZWFkIGxpbWl0CQCdCgsFD25ld1Bvc2l0aW9uU2l6ZQUMcmVtYWluTWFyZ2luCQBkAgUXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwFDG9wZW5Ob3Rpb25hbAkBH2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24BBQ9uZXdQb3NpdGlvblNpemUFFWJhc2VBc3NldFJlc2VydmVBZnRlcgUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUWdG90YWxQb3NpdGlvblNpemVBZnRlcgUXY3VtdWxhdGl2ZU5vdGlvbmFsQWZ0ZXIJAGQCCQEUb3BlbkludGVyZXN0Tm90aW9uYWwABQxvcGVuTm90aW9uYWwJAGQCCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAMJAGYCBQ9uZXdQb3NpdGlvblNpemUAAAkBA2FicwEFFWFtb3VudEJhc2VBc3NldEJvdWdodAAACQBkAgkBFnRvdGFsU2hvcnRQb3NpdGlvblNpemUAAwkAZgIAAAUPbmV3UG9zaXRpb25TaXplCQEDYWJzAQUVYW1vdW50QmFzZUFzc2V0Qm91Z2h0AAAEDG9wZW5Ob3Rpb25hbAkBBG11bGQCBQdfYW1vdW50BQlfbGV2ZXJhZ2UEDSR0MDQzMjg4NDM0MDQJASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAIJAKUIAQgFAWkGY2FsbGVyBQ9QTkxfT1BUSU9OX1NQT1QEE29sZFBvc2l0aW9uTm90aW9uYWwIBQ0kdDA0MzI4ODQzNDA0Al8xBA11bnJlYWxpemVkUG5sCAUNJHQwNDMyODg0MzQwNAJfMgMJAGYCBRNvbGRQb3NpdGlvbk5vdGlvbmFsBQxvcGVuTm90aW9uYWwJAAIBAi5Vc2UgZGVjcmVhc2VQb3NpdGlvbiB0byBkZWNyZWFzZSBwb3NpdGlvbiBzaXplCQACAQIUQ2xvc2UgcG9zaXRpb24gZmlyc3QED25ld1Bvc2l0aW9uU2l6ZQgFDSR0MDQxMDI3NDM1OTUCXzEEF25ld1Bvc2l0aW9uUmVtYWluTWFyZ2luCAUNJHQwNDEwMjc0MzU5NQJfMgQXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDA0MTAyNzQzNTk1Al8zBBRuZXdQb3NpdGlvbkxhdGVzdENQRggFDSR0MDQxMDI3NDM1OTUCXzQEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDQxMDI3NDM1OTUCXzUEFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA0MTAyNzQzNTk1Al82BBZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCAUNJHQwNDEwMjc0MzU5NQJfNwQXY3VtdWxhdGl2ZU5vdGlvbmFsQWZ0ZXIIBQ0kdDA0MTAyNzQzNTk1Al84BBlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyCAUNJHQwNDEwMjc0MzU5NQJfOQQOdG90YWxMb25nQWZ0ZXIIBQ0kdDA0MTAyNzQzNTk1A18xMAQPdG90YWxTaG9ydEFmdGVyCAUNJHQwNDEwMjc0MzU5NQNfMTEEDGZlZVRvU3Rha2VycwkAaQIFCWZlZUFtb3VudAACBA5mZWVUb0luc3VyYW5jZQkAZQIFCWZlZUFtb3VudAUMZmVlVG9TdGFrZXJzBAVzdGFrZQkA/AcECQERcXVvdGVBc3NldFN0YWtpbmcAAg5sb2NrTmV1dHJpbm9TUAkAzAgCCQClCAEJAQ5zdGFraW5nQWRkcmVzcwAJAMwIAgUIQUxMX0ZFRVMFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQdfYW1vdW50BQNuaWwDCQAAAgUFc3Rha2UFBXN0YWtlBBBkZXBvc2l0SW5zdXJhbmNlCQD8BwQJARBpbnN1cmFuY2VBZGRyZXNzAAIHZGVwb3NpdAUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQEKcXVvdGVBc3NldAAFDmZlZVRvSW5zdXJhbmNlBQNuaWwDCQAAAgUQZGVwb3NpdEluc3VyYW5jZQUQZGVwb3NpdEluc3VyYW5jZQQJbm90aWZ5RmVlCQD8BwQJAQxtaW5lckFkZHJlc3MAAgpub3RpZnlGZWVzCQDMCAIFB190cmFkZXIJAMwIAgUJZmVlQW1vdW50BQNuaWwFA25pbAMJAAACBQlub3RpZnlGZWUFCW5vdGlmeUZlZQQObm90aWZ5Tm90aW9uYWwJAPwHBAkBDG1pbmVyQWRkcmVzcwACDm5vdGlmeU5vdGlvbmFsCQDMCAIFB190cmFkZXIJAMwIAgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFA25pbAUDbmlsAwkAAAIFDm5vdGlmeU5vdGlvbmFsBQ5ub3RpZnlOb3Rpb25hbAkAzggCCQDOCAIJAM4IAgkBDnVwZGF0ZVBvc2l0aW9uBQUHX3RyYWRlcgUPbmV3UG9zaXRpb25TaXplBRduZXdQb3NpdGlvblJlbWFpbk1hcmdpbgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFFG5ld1Bvc2l0aW9uTGF0ZXN0Q1BGCQEJdXBkYXRlQW1tBwUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBRZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyBRdjdW11bGF0aXZlTm90aW9uYWxBZnRlcgUZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcgUOdG90YWxMb25nQWZ0ZXIFD3RvdGFsU2hvcnRBZnRlcgkBC3RyYW5zZmVyRmVlAQUMZmVlVG9TdGFrZXJzCQENdXBkYXRlQmFsYW5jZQEJAGQCCQEIY2JhbGFuY2UABQdfYW1vdW50CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCWFkZE1hcmdpbgAECl9yYXdBbW91bnQICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50AwMDAwkBAiE9AggJAJEDAggFAWkIcGF5bWVudHMAAAdhc3NldElkCQEKcXVvdGVBc3NldAAGCQEBIQEJARNyZXF1aXJlT3BlblBvc2l0aW9uAQkApQgBCAUBaQZjYWxsZXIGCQEBIQEJAQtpbml0aWFsaXplZAAGCQEGcGF1c2VkAAkAAgECHEludmFsaWQgYWRkTWFyZ2luIHBhcmFtZXRlcnMEB190cmFkZXIJAKUIAQgFAWkGY2FsbGVyBAxyYXdGZWVBbW91bnQJAQRtdWxkAgUKX3Jhd0Ftb3VudAkBA2ZlZQAEDnJlZmVycmVyRmVlQW55CQD8BwQJAQ9yZWZlcnJhbEFkZHJlc3MAAg1hY2NlcHRQYXltZW50CQDMCAIFB190cmFkZXIFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQxyYXdGZWVBbW91bnQFA25pbAMJAAACBQ5yZWZlcnJlckZlZUFueQUOcmVmZXJyZXJGZWVBbnkEC3JlZmVycmVyRmVlBAckbWF0Y2gwBQ5yZWZlcnJlckZlZUFueQMJAAECBQckbWF0Y2gwAgNJbnQEAXgFByRtYXRjaDAFAXgJAAIBAhNJbnZhbGlkIHJlZmVycmVyRmVlBAlmZWVBbW91bnQJAGUCBQxyYXdGZWVBbW91bnQFC3JlZmVycmVyRmVlBAdfYW1vdW50CQBlAgUKX3Jhd0Ftb3VudAUMcmF3RmVlQW1vdW50BA0kdDA0NTQ4ODQ1NjI4CQELZ2V0UG9zaXRpb24BBQdfdHJhZGVyBA9vbGRQb3NpdGlvblNpemUIBQ0kdDA0NTQ4ODQ1NjI4Al8xBBFvbGRQb3NpdGlvbk1hcmdpbggFDSR0MDQ1NDg4NDU2MjgCXzIEF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNDU0ODg0NTYyOAJfMwQUb2xkUG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA0NTQ4ODQ1NjI4Al80BAxmZWVUb1N0YWtlcnMJAGkCBQlmZWVBbW91bnQAAgQOZmVlVG9JbnN1cmFuY2UJAGUCBQlmZWVBbW91bnQFDGZlZVRvU3Rha2VycwQFc3Rha2UJAPwHBAkBEXF1b3RlQXNzZXRTdGFraW5nAAIObG9ja05ldXRyaW5vU1AJAMwIAgkApQgBCQEOc3Rha2luZ0FkZHJlc3MACQDMCAIFCEFMTF9GRUVTBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUHX2Ftb3VudAUDbmlsAwkAAAIFBXN0YWtlBQVzdGFrZQQQZGVwb3NpdEluc3VyYW5jZQkA/AcECQEQaW5zdXJhbmNlQWRkcmVzcwACB2RlcG9zaXQFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQ5mZWVUb0luc3VyYW5jZQUDbmlsAwkAAAIFEGRlcG9zaXRJbnN1cmFuY2UFEGRlcG9zaXRJbnN1cmFuY2UECW5vdGlmeUZlZQkA/AcECQEMbWluZXJBZGRyZXNzAAIKbm90aWZ5RmVlcwkAzAgCBQdfdHJhZGVyCQDMCAIFCWZlZUFtb3VudAUDbmlsBQNuaWwDCQAAAgUJbm90aWZ5RmVlBQlub3RpZnlGZWUJAM4IAgkAzggCCQEOdXBkYXRlUG9zaXRpb24FBQdfdHJhZGVyBQ9vbGRQb3NpdGlvblNpemUJAGQCBRFvbGRQb3NpdGlvbk1hcmdpbgUHX2Ftb3VudAUXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwFFG9sZFBvc2l0aW9uTHN0VXBkQ1BGCQELdHJhbnNmZXJGZWUBBQxmZWVUb1N0YWtlcnMJAQ11cGRhdGVCYWxhbmNlAQkAZAIJAQhjYmFsYW5jZQAFB19hbW91bnQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEMcmVtb3ZlTWFyZ2luAQdfYW1vdW50AwMDAwkAZwIAAAUHX2Ftb3VudAYJAQEhAQkBE3JlcXVpcmVPcGVuUG9zaXRpb24BCQClCAEIBQFpBmNhbGxlcgYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQZwYXVzZWQACQACAQIfSW52YWxpZCByZW1vdmVNYXJnaW4gcGFyYW1ldGVycwQNJHQwNDY2NTM0NjgwNQkBC2dldFBvc2l0aW9uAQkApQgBCAUBaQZjYWxsZXIED29sZFBvc2l0aW9uU2l6ZQgFDSR0MDQ2NjUzNDY4MDUCXzEEEW9sZFBvc2l0aW9uTWFyZ2luCAUNJHQwNDY2NTM0NjgwNQJfMgQXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDA0NjY1MzQ2ODA1Al8zBBRvbGRQb3NpdGlvbkxzdFVwZENQRggFDSR0MDQ2NjUzNDY4MDUCXzQEC21hcmdpbkRlbHRhCQEBLQEFB19hbW91bnQEDSR0MDQ2ODQyNDcwMjEJASJjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50BAUPb2xkUG9zaXRpb25TaXplBRFvbGRQb3NpdGlvbk1hcmdpbgUUb2xkUG9zaXRpb25Mc3RVcGRDUEYFC21hcmdpbkRlbHRhBAxyZW1haW5NYXJnaW4IBQ0kdDA0Njg0MjQ3MDIxAl8xBAdiYWREZWJ0CAUNJHQwNDY4NDI0NzAyMQJfMgMJAQIhPQIFB2JhZERlYnQAAAkAAgECHUludmFsaWQgcmVtb3ZlZCBtYXJnaW4gYW1vdW50BAttYXJnaW5SYXRpbwkBD2NhbGNNYXJnaW5SYXRpbwMFDHJlbWFpbk1hcmdpbgUHYmFkRGVidAUXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwDCQEBIQEJARZyZXF1aXJlTW9yZU1hcmdpblJhdGlvAwULbWFyZ2luUmF0aW8JAQ9pbml0TWFyZ2luUmF0aW8ABgkAAgEJAKwCAgkArAICCQCsAgICGVRvbyBtdWNoIG1hcmdpbiByZW1vdmVkOiAJAKQDAQULbWFyZ2luUmF0aW8CAyA8IAkApAMBCQEPaW5pdE1hcmdpblJhdGlvAAQHdW5zdGFrZQkA/AcECQERcXVvdGVBc3NldFN0YWtpbmcAAg51bmxvY2tOZXV0cmlubwkAzAgCBQdfYW1vdW50CQDMCAIJANgEAQkBCnF1b3RlQXNzZXQABQNuaWwFA25pbAMJAAACBQd1bnN0YWtlBQd1bnN0YWtlCQDOCAIJAM4IAgkBDnVwZGF0ZVBvc2l0aW9uBQkApQgBCAUBaQZjYWxsZXIFD29sZFBvc2l0aW9uU2l6ZQUMcmVtYWluTWFyZ2luBRdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAkBH2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24BBQ9vbGRQb3NpdGlvblNpemUJAQh3aXRoZHJhdwIIBQFpBmNhbGxlcgUHX2Ftb3VudAkBDXVwZGF0ZUJhbGFuY2UBCQBlAgkBCGNiYWxhbmNlAAUHX2Ftb3VudAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ1jbG9zZVBvc2l0aW9uAAQGY2FsbGVyCQEPZ2V0QWN0dWFsQ2FsbGVyAQUBaQQNY2FsbGVyQWRkcmVzcwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEFBmNhbGxlcgIOSW52YWxpZCBjYWxsZXIDAwMJAQEhAQkBE3JlcXVpcmVPcGVuUG9zaXRpb24BBQZjYWxsZXIGCQEBIQEJAQtpbml0aWFsaXplZAAGCQEGcGF1c2VkAAkAAgECIEludmFsaWQgY2xvc2VQb3NpdGlvbiBwYXJhbWV0ZXJzBA0kdDA0ODIyNDQ4NjAxCQEVaW50ZXJuYWxDbG9zZVBvc2l0aW9uAgUGY2FsbGVyBgQCeDEIBQ0kdDA0ODIyNDQ4NjAxAl8xBA9wb3NpdGlvbkJhZERlYnQIBQ0kdDA0ODIyNDQ4NjAxAl8yBAtyZWFsaXplZFBubAgFDSR0MDQ4MjI0NDg2MDECXzMEDW1hcmdpblRvVmF1bHQIBQ0kdDA0ODIyNDQ4NjAxAl80BBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNDgyMjQ0ODYwMQJfNQQVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNDgyMjQ0ODYwMQJfNgQWdG90YWxQb3NpdGlvblNpemVBZnRlcggFDSR0MDQ4MjI0NDg2MDECXzcEF2N1bXVsYXRpdmVOb3Rpb25hbEFmdGVyCAUNJHQwNDgyMjQ0ODYwMQJfOAQZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcggFDSR0MDQ4MjI0NDg2MDECXzkEAngyCAUNJHQwNDgyMjQ0ODYwMQNfMTAEDnRvdGFsTG9uZ0FmdGVyCAUNJHQwNDgyMjQ0ODYwMQNfMTEED3RvdGFsU2hvcnRBZnRlcggFDSR0MDQ4MjI0NDg2MDEDXzEyAwkAZgIFD3Bvc2l0aW9uQmFkRGVidAAACQACAQImVW5hYmxlIHRvIGNsb3NlIHBvc2l0aW9uIHdpdGggYmFkIGRlYnQEDndpdGhkcmF3QW1vdW50CQEDYWJzAQUNbWFyZ2luVG9WYXVsdAQKYW1tQmFsYW5jZQkAZQIJAQhjYmFsYW5jZQAFDndpdGhkcmF3QW1vdW50BA0kdDA0ODgxMDQ4OTUyAwkAZgIAAAUKYW1tQmFsYW5jZQkAlAoCAAAJAQNhYnMBBQphbW1CYWxhbmNlCQCUCgIFCmFtbUJhbGFuY2UAAAQNYW1tTmV3QmFsYW5jZQgFDSR0MDQ4ODEwNDg5NTICXzEEEGdldEZyb21JbnN1cmFuY2UIBQ0kdDA0ODgxMDQ4OTUyAl8yBAF4AwkAZgIFEGdldEZyb21JbnN1cmFuY2UAAAQRd2l0aGRyYXdJbnN1cmFuY2UJAPwHBAkBEGluc3VyYW5jZUFkZHJlc3MAAgh3aXRoZHJhdwkAzAgCBRBnZXRGcm9tSW5zdXJhbmNlBQNuaWwFA25pbAMJAAACBRF3aXRoZHJhd0luc3VyYW5jZQURd2l0aGRyYXdJbnN1cmFuY2UFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFAXgFAXgEB3Vuc3Rha2UJAPwHBAkBEXF1b3RlQXNzZXRTdGFraW5nAAIOdW5sb2NrTmV1dHJpbm8JAMwIAgkAZQIFDndpdGhkcmF3QW1vdW50BRBnZXRGcm9tSW5zdXJhbmNlCQDMCAIJANgEAQkBCnF1b3RlQXNzZXQABQNuaWwFA25pbAMJAAACBQd1bnN0YWtlBQd1bnN0YWtlBA5ub3RpZnlOb3Rpb25hbAkA/AcECQEMbWluZXJBZGRyZXNzAAIObm90aWZ5Tm90aW9uYWwJAMwIAgUGY2FsbGVyCQDMCAIAAAUDbmlsBQNuaWwDCQAAAgUObm90aWZ5Tm90aW9uYWwFDm5vdGlmeU5vdGlvbmFsCQDOCAIJAM4IAgkAzggCCQEOZGVsZXRlUG9zaXRpb24BBQZjYWxsZXIJAQl1cGRhdGVBbW0HBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIFF2N1bXVsYXRpdmVOb3Rpb25hbEFmdGVyBRlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyBQ50b3RhbExvbmdBZnRlcgUPdG90YWxTaG9ydEFmdGVyCQEId2l0aGRyYXcCBQ1jYWxsZXJBZGRyZXNzBQ53aXRoZHJhd0Ftb3VudAkBDXVwZGF0ZUJhbGFuY2UBBQ1hbW1OZXdCYWxhbmNlCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCWxpcXVpZGF0ZQEHX3RyYWRlcgQPc3BvdE1hcmdpblJhdGlvCQEWZ2V0TWFyZ2luUmF0aW9CeU9wdGlvbgIFB190cmFkZXIFD1BOTF9PUFRJT05fU1BPVAQLbWFyZ2luUmF0aW8DCQEWaXNPdmVyRmx1Y3R1YXRpb25MaW1pdAAEEW9yYWNsZU1hcmdpblJhdGlvCQEWZ2V0TWFyZ2luUmF0aW9CeU9wdGlvbgIFB190cmFkZXIFEVBOTF9PUFRJT05fT1JBQ0xFCQEEdm1heAIFD3Nwb3RNYXJnaW5SYXRpbwURb3JhY2xlTWFyZ2luUmF0aW8FD3Nwb3RNYXJnaW5SYXRpbwMDAwMJAQEhAQkBFnJlcXVpcmVNb3JlTWFyZ2luUmF0aW8DBQttYXJnaW5SYXRpbwkBFm1haW50ZW5hbmNlTWFyZ2luUmF0aW8ABwYJAQEhAQkBE3JlcXVpcmVPcGVuUG9zaXRpb24BBQdfdHJhZGVyBgkBASEBCQELaW5pdGlhbGl6ZWQABgkBBnBhdXNlZAAJAAIBAhNVbmFibGUgdG8gbGlxdWlkYXRlAwMDCQBmAgUPc3BvdE1hcmdpblJhdGlvCQETbGlxdWlkYXRpb25GZWVSYXRpbwAJAGYCCQEXcGFydGlhbExpcXVpZGF0aW9uUmF0aW8AAAAHCQBmAgUMREVDSU1BTF9VTklUCQEXcGFydGlhbExpcXVpZGF0aW9uUmF0aW8ABwQNJHQwNTEwMzI1MTE4MgkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgQPb2xkUG9zaXRpb25TaXplCAUNJHQwNTEwMzI1MTE4MgJfMQQRb2xkUG9zaXRpb25NYXJnaW4IBQ0kdDA1MTAzMjUxMTgyAl8yBBdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDUxMDMyNTExODICXzMEFG9sZFBvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwNTEwMzI1MTE4MgJfNAQKX2RpcmVjdGlvbgMJAGYCBQ9vbGRQb3NpdGlvblNpemUAAAUJRElSX1NIT1JUBQhESVJfTE9ORwQFaXNBZGQJAAACBQpfZGlyZWN0aW9uBQhESVJfTE9ORwQZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAkBG2dldFBhcnRpYWxMaXF1aWRhdGlvbkFtb3VudAIFB190cmFkZXIFD29sZFBvc2l0aW9uU2l6ZQQNJHQwNTE0MDc1MTUxMQkBI2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sAgUHX3RyYWRlcgUPUE5MX09QVElPTl9TUE9UBBNvbGRQb3NpdGlvbk5vdGlvbmFsCAUNJHQwNTE0MDc1MTUxMQJfMQQNdW5yZWFsaXplZFBubAgFDSR0MDUxNDA3NTE1MTECXzIEDSR0MDUxNTE5NTE4MDkJAQlzd2FwSW5wdXQCBQVpc0FkZAUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAQVZXhjaGFuZ2VkUG9zaXRpb25TaXplCAUNJHQwNTE1MTk1MTgwOQJfMQQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDUxNTE5NTE4MDkCXzIEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDUxNTE5NTE4MDkCXzMEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDA1MTUxOTUxODA5Al80BBdjdW11bGF0aXZlTm90aW9uYWxBZnRlcggFDSR0MDUxNTE5NTE4MDkCXzUEC3JlYWxpemVkUG5sCQEEZGl2ZAIJAQRtdWxkAgUNdW5yZWFsaXplZFBubAkBA2FicwEFFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQkBA2FicwEFD29sZFBvc2l0aW9uU2l6ZQQNJHQwNTE5MTY1MjE0OQkBImNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnQEBQ9vbGRQb3NpdGlvblNpemUFEW9sZFBvc2l0aW9uTWFyZ2luBRRvbGRQb3NpdGlvbkxzdFVwZENQRgULcmVhbGl6ZWRQbmwEDHJlbWFpbk1hcmdpbggFDSR0MDUxOTE2NTIxNDkCXzEEB2JhZERlYnQIBQ0kdDA1MTkxNjUyMTQ5Al8yBA5mdW5kaW5nUGF5bWVudAgFDSR0MDUxOTE2NTIxNDkCXzMEEnVucmVhbGl6ZWRQbmxBZnRlcgkAZQIFDXVucmVhbGl6ZWRQbmwFC3JlYWxpemVkUG5sBBJyZW1haW5PcGVuTm90aW9uYWwDCQBmAgUPb2xkUG9zaXRpb25TaXplAAAJAGUCCQBlAgUTb2xkUG9zaXRpb25Ob3Rpb25hbAUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAUSdW5yZWFsaXplZFBubEFmdGVyCQBlAgkAZAIFEnVucmVhbGl6ZWRQbmxBZnRlcgUTb2xkUG9zaXRpb25Ob3Rpb25hbAUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAQSbGlxdWlkYXRpb25QZW5hbHR5CQEEbXVsZAIFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQJARNsaXF1aWRhdGlvbkZlZVJhdGlvAAQPZmVlVG9MaXF1aWRhdG9yCQBpAgUSbGlxdWlkYXRpb25QZW5hbHR5AAIEDmZlZVRvSW5zdXJhbmNlCQBlAgUSbGlxdWlkYXRpb25QZW5hbHR5BQ9mZWVUb0xpcXVpZGF0b3IEEW5ld1Bvc2l0aW9uTWFyZ2luCQBlAgUMcmVtYWluTWFyZ2luBRJsaXF1aWRhdGlvblBlbmFsdHkED25ld1Bvc2l0aW9uU2l6ZQkAZAIFD29sZFBvc2l0aW9uU2l6ZQUVZXhjaGFuZ2VkUG9zaXRpb25TaXplBBduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAkBA2FicwEFEnJlbWFpbk9wZW5Ob3Rpb25hbAQUbmV3UG9zaXRpb25Mc3RVcGRDUEYJAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAQUPbmV3UG9zaXRpb25TaXplBBlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyCQBlAgkBFG9wZW5JbnRlcmVzdE5vdGlvbmFsAAUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAQKYW1tQmFsYW5jZQkAZQIJAQhjYmFsYW5jZQAFEmxpcXVpZGF0aW9uUGVuYWx0eQQNJHQwNTMzMjI1MzQ2NQMJAGYCAAAFCmFtbUJhbGFuY2UJAJQKAgAACQEDYWJzAQUKYW1tQmFsYW5jZQkAlAoCBQphbW1CYWxhbmNlAAAEDW5ld0FtbUJhbGFuY2UIBQ0kdDA1MzMyMjUzNDY1Al8xBBF0YWtlRnJvbUluc3VyYW5jZQgFDSR0MDUzMzIyNTM0NjUCXzIEAXgDCQBmAgURdGFrZUZyb21JbnN1cmFuY2UAAAQRd2l0aGRyYXdJbnN1cmFuY2UJAPwHBAkBEGluc3VyYW5jZUFkZHJlc3MAAgh3aXRoZHJhdwkAzAgCBRF0YWtlRnJvbUluc3VyYW5jZQUDbmlsBQNuaWwDCQAAAgURd2l0aGRyYXdJbnN1cmFuY2UFEXdpdGhkcmF3SW5zdXJhbmNlBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBQF4BQF4BAd1bnN0YWtlCQD8BwQJARFxdW90ZUFzc2V0U3Rha2luZwACDnVubG9ja05ldXRyaW5vCQDMCAIJAGUCBRJsaXF1aWRhdGlvblBlbmFsdHkFEXRha2VGcm9tSW5zdXJhbmNlCQDMCAIJANgEAQkBCnF1b3RlQXNzZXQABQNuaWwFA25pbAMJAAACBQd1bnN0YWtlBQd1bnN0YWtlBBBkZXBvc2l0SW5zdXJhbmNlCQD8BwQJARBpbnN1cmFuY2VBZGRyZXNzAAIHZGVwb3NpdAUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQEKcXVvdGVBc3NldAAFDmZlZVRvSW5zdXJhbmNlBQNuaWwDCQAAAgUQZGVwb3NpdEluc3VyYW5jZQUQZGVwb3NpdEluc3VyYW5jZQQObm90aWZ5Tm90aW9uYWwJAPwHBAkBDG1pbmVyQWRkcmVzcwACDm5vdGlmeU5vdGlvbmFsCQDMCAIFB190cmFkZXIJAMwIAgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFA25pbAUDbmlsAwkAAAIFDm5vdGlmeU5vdGlvbmFsBQ5ub3RpZnlOb3Rpb25hbAkAzggCCQDOCAIJAM4IAgkBDnVwZGF0ZVBvc2l0aW9uBQUHX3RyYWRlcgUPbmV3UG9zaXRpb25TaXplBRFuZXdQb3NpdGlvbk1hcmdpbgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFFG5ld1Bvc2l0aW9uTHN0VXBkQ1BGCQEJdXBkYXRlQW1tBwUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBRZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyBRdjdW11bGF0aXZlTm90aW9uYWxBZnRlcgUZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcgkAZQIJARV0b3RhbExvbmdQb3NpdGlvblNpemUAAwkAZgIFD25ld1Bvc2l0aW9uU2l6ZQAACQEDYWJzAQUVZXhjaGFuZ2VkUG9zaXRpb25TaXplAAAJAGUCCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQADCQBmAgAABQ9uZXdQb3NpdGlvblNpemUJAQNhYnMBBRVleGNoYW5nZWRQb3NpdGlvblNpemUAAAkBCHdpdGhkcmF3AggFAWkGY2FsbGVyBQ9mZWVUb0xpcXVpZGF0b3IJAQ11cGRhdGVCYWxhbmNlAQUNbmV3QW1tQmFsYW5jZQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgQNJHQwNTQ5MjE1NTM3NgkBFWludGVybmFsQ2xvc2VQb3NpdGlvbgIFB190cmFkZXIHBAJ4MQgFDSR0MDU0OTIxNTUzNzYCXzEEB2JhZERlYnQIBQ0kdDA1NDkyMTU1Mzc2Al8yBAJ4MggFDSR0MDU0OTIxNTUzNzYCXzMEAngzCAUNJHQwNTQ5MjE1NTM3NgJfNAQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDU0OTIxNTUzNzYCXzUEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDU0OTIxNTUzNzYCXzYEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDA1NDkyMTU1Mzc2Al83BBdjdW11bGF0aXZlTm90aW9uYWxBZnRlcggFDSR0MDU0OTIxNTUzNzYCXzgEGW9wZW5JbnRlcmVzdE5vdGlvbmFsQWZ0ZXIIBQ0kdDA1NDkyMTU1Mzc2Al85BBlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50CAUNJHQwNTQ5MjE1NTM3NgNfMTAEDnRvdGFsTG9uZ0FmdGVyCAUNJHQwNTQ5MjE1NTM3NgNfMTEED3RvdGFsU2hvcnRBZnRlcggFDSR0MDU0OTIxNTUzNzYDXzEyBBJsaXF1aWRhdGlvblBlbmFsdHkJAQRtdWxkAgUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAkBE2xpcXVpZGF0aW9uRmVlUmF0aW8ABA9mZWVUb0xpcXVpZGF0b3IJAGkCBRJsaXF1aWRhdGlvblBlbmFsdHkAAgQOZmVlVG9JbnN1cmFuY2UJAGUCBRJsaXF1aWRhdGlvblBlbmFsdHkFD2ZlZVRvTGlxdWlkYXRvcgQKYW1tQmFsYW5jZQkAZQIJAQhjYmFsYW5jZQAFEmxpcXVpZGF0aW9uUGVuYWx0eQQNJHQwNTU3ODg1NTkzMQMJAGYCAAAFCmFtbUJhbGFuY2UJAJQKAgAACQEDYWJzAQUKYW1tQmFsYW5jZQkAlAoCBQphbW1CYWxhbmNlAAAEDW5ld0FtbUJhbGFuY2UIBQ0kdDA1NTc4ODU1OTMxAl8xBBF0YWtlRnJvbUluc3VyYW5jZQgFDSR0MDU1Nzg4NTU5MzECXzIEAXgDCQBmAgURdGFrZUZyb21JbnN1cmFuY2UAAAQRd2l0aGRyYXdJbnN1cmFuY2UJAPwHBAkBEGluc3VyYW5jZUFkZHJlc3MAAgh3aXRoZHJhdwkAzAgCBRF0YWtlRnJvbUluc3VyYW5jZQUDbmlsBQNuaWwDCQAAAgURd2l0aGRyYXdJbnN1cmFuY2UFEXdpdGhkcmF3SW5zdXJhbmNlBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBQF4BQF4BAd1bnN0YWtlCQD8BwQJARFxdW90ZUFzc2V0U3Rha2luZwACDnVubG9ja05ldXRyaW5vCQDMCAIJAGUCBRJsaXF1aWRhdGlvblBlbmFsdHkFEXRha2VGcm9tSW5zdXJhbmNlCQDMCAIJANgEAQkBCnF1b3RlQXNzZXQABQNuaWwFA25pbAMJAAACBQd1bnN0YWtlBQd1bnN0YWtlBBBkZXBvc2l0SW5zdXJhbmNlCQD8BwQJARBpbnN1cmFuY2VBZGRyZXNzAAIHZGVwb3NpdAUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQEKcXVvdGVBc3NldAAFDmZlZVRvSW5zdXJhbmNlBQNuaWwDCQAAAgUQZGVwb3NpdEluc3VyYW5jZQUQZGVwb3NpdEluc3VyYW5jZQQObm90aWZ5Tm90aW9uYWwJAPwHBAkBDG1pbmVyQWRkcmVzcwACDm5vdGlmeU5vdGlvbmFsCQDMCAIFB190cmFkZXIJAMwIAgAABQNuaWwFA25pbAMJAAACBQ5ub3RpZnlOb3Rpb25hbAUObm90aWZ5Tm90aW9uYWwJAM4IAgkAzggCCQDOCAIJAQ5kZWxldGVQb3NpdGlvbgEFB190cmFkZXIJAQl1cGRhdGVBbW0HBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIFF2N1bXVsYXRpdmVOb3Rpb25hbEFmdGVyBRlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyBQ50b3RhbExvbmdBZnRlcgUPdG90YWxTaG9ydEFmdGVyCQEId2l0aGRyYXcCCAUBaQZjYWxsZXIFD2ZlZVRvTGlxdWlkYXRvcgkBDXVwZGF0ZUJhbGFuY2UBBQ1uZXdBbW1CYWxhbmNlCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCnBheUZ1bmRpbmcABBVmdW5kaW5nQmxvY2tUaW1lc3RhbXAJARluZXh0RnVuZGluZ0Jsb2NrVGltZXN0YW1wAAMDAwkAZgIFFWZ1bmRpbmdCbG9ja1RpbWVzdGFtcAgFCWxhc3RCbG9jawl0aW1lc3RhbXAGCQEBIQEJAQtpbml0aWFsaXplZAAGCQEGcGF1c2VkAAkAAgEJAKwCAgkArAICCQCsAgICIUludmFsaWQgZnVuZGluZyBibG9jayB0aW1lc3RhbXA6IAkApAMBCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAIDIDwgCQCkAwEFFWZ1bmRpbmdCbG9ja1RpbWVzdGFtcAQPdW5kZXJseWluZ1ByaWNlCQESZ2V0T3JhY2xlVHdhcFByaWNlAAQNc3BvdFR3YXBQcmljZQkBEGdldFR3YXBTcG90UHJpY2UABAdwcmVtaXVtCQBlAgUNc3BvdFR3YXBQcmljZQUPdW5kZXJseWluZ1ByaWNlBA0kdDA1NzUxOTU4ODU0AwMJAAACCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAAAAYJAAACCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAAACQCUCgIAAAAAAwkAZgIAAAUHcHJlbWl1bQQUc2hvcnRQcmVtaXVtRnJhY3Rpb24JAQRkaXZkAgkBBG11bGQCBQdwcmVtaXVtCQEUZnVuZGluZ1BlcmlvZERlY2ltYWwABQdPTkVfREFZBBNsb25nUHJlbWl1bUZyYWN0aW9uCQEEZGl2ZAIJAQRtdWxkAgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24JARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQAJAJQKAgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24FE2xvbmdQcmVtaXVtRnJhY3Rpb24EE2xvbmdQcmVtaXVtRnJhY3Rpb24JAQRkaXZkAgkBBG11bGQCBQdwcmVtaXVtCQEUZnVuZGluZ1BlcmlvZERlY2ltYWwABQdPTkVfREFZBBRzaG9ydFByZW1pdW1GcmFjdGlvbgkBBGRpdmQCCQEEbXVsZAIFE2xvbmdQcmVtaXVtRnJhY3Rpb24JARV0b3RhbExvbmdQb3NpdGlvblNpemUACQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAJAJQKAgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24FE2xvbmdQcmVtaXVtRnJhY3Rpb24EFHNob3J0UHJlbWl1bUZyYWN0aW9uCAUNJHQwNTc1MTk1ODg1NAJfMQQTbG9uZ1ByZW1pdW1GcmFjdGlvbggFDSR0MDU3NTE5NTg4NTQCXzIJAQ11cGRhdGVGdW5kaW5nBQkAZAIFFWZ1bmRpbmdCbG9ja1RpbWVzdGFtcAkBFGZ1bmRpbmdQZXJpb2RTZWNvbmRzAAkAZAIJASNsYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgAFE2xvbmdQcmVtaXVtRnJhY3Rpb24JAGQCCQEkbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAAUUc2hvcnRQcmVtaXVtRnJhY3Rpb24JAQRkaXZkAgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgUPdW5kZXJseWluZ1ByaWNlCQEEZGl2ZAIFFHNob3J0UHJlbWl1bUZyYWN0aW9uBQ91bmRlcmx5aW5nUHJpY2UBaQEOZm9yY2VNb3ZlQXNzZXQCB190cmFkZXIHX2Ftb3VudAMDCQECIT0CCQCnCAEJAQ5hZG1pblB1YmxpY0tleQAIBQFpBmNhbGxlcgYJAGYCAAAFB19hbW91bnQJAAIBAiFJbnZhbGlkIGZvcmNlTW92ZUFzc2V0IHBhcmFtZXRlcnMEB3Vuc3Rha2UJAPwHBAkBEXF1b3RlQXNzZXRTdGFraW5nAAIOdW5sb2NrTmV1dHJpbm8JAMwIAgUHX2Ftb3VudAkAzAgCCQDYBAEJAQpxdW90ZUFzc2V0AAUDbmlsBQNuaWwDCQAAAgUHdW5zdGFrZQUHdW5zdGFrZQkAzggCCQEId2l0aGRyYXcCCQERQGV4dHJOYXRpdmUoMTA2MikBBQdfdHJhZGVyBQdfYW1vdW50CQENdXBkYXRlQmFsYW5jZQEJAGUCCQEIY2JhbGFuY2UABQdfYW1vdW50CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCWFkanVzdFBlZwEGX3ByaWNlAwMJAQIhPQIJAKcIAQkBDmFkbWluUHVibGljS2V5AAgFAWkGY2FsbGVyBgkAZgIAAAUGX3ByaWNlCQACAQIcSW52YWxpZCBhZGp1c3RQZWcgcGFyYW1ldGVycwQNJHQwNTk4NTQ1OTk0MAkBEGdldFBlZ0FkanVzdENvc3QBBQZfcHJpY2UEFG5ld1F1b3RlQXNzZXRSZXNlcnZlCAUNJHQwNTk4NTQ1OTk0MAJfMQQNcGVnQ2hhbmdlQ29zdAgFDSR0MDU5ODU0NTk5NDACXzIDCQAAAgUNcGVnQ2hhbmdlQ29zdAAACQACAQIRTm90aGluZyB0byBhZGp1c3QDCQBmAgUNcGVnQ2hhbmdlQ29zdAAABBF3aXRoZHJhd0luc3VyYW5jZQkA/AcECQEQaW5zdXJhbmNlQWRkcmVzcwACCHdpdGhkcmF3CQDMCAIFDXBlZ0NoYW5nZUNvc3QFA25pbAUDbmlsAwkAAAIFEXdpdGhkcmF3SW5zdXJhbmNlBRF3aXRoZHJhd0luc3VyYW5jZQQFc3Rha2UJAPwHBAkBEXF1b3RlQXNzZXRTdGFraW5nAAIObG9ja05ldXRyaW5vU1AJAMwIAgkApQgBCQEOc3Rha2luZ0FkZHJlc3MACQDMCAIFCEFMTF9GRUVTBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUNcGVnQ2hhbmdlQ29zdAUDbmlsAwkAAAIFBXN0YWtlBQVzdGFrZQkAzggCCQENdXBkYXRlQmFsYW5jZQEJAGQCCQEIY2JhbGFuY2UABQ1wZWdDaGFuZ2VDb3N0CQERdXBkYXRlQW1tUmVzZXJ2ZXMCBRRuZXdRdW90ZUFzc2V0UmVzZXJ2ZQkBBmJzQXN0UgAJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4EB3Vuc3Rha2UJAPwHBAkBEXF1b3RlQXNzZXRTdGFraW5nAAIOdW5sb2NrTmV1dHJpbm8JAMwIAgkBA2FicwEFDXBlZ0NoYW5nZUNvc3QJAMwIAgkA2AQBCQEKcXVvdGVBc3NldAAFA25pbAUDbmlsAwkAAAIFB3Vuc3Rha2UFB3Vuc3Rha2UEEGRlcG9zaXRJbnN1cmFuY2UJAPwHBAkBEGluc3VyYW5jZUFkZHJlc3MAAgdkZXBvc2l0BQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAkBA2FicwEFDXBlZ0NoYW5nZUNvc3QFA25pbAMJAAACBRBkZXBvc2l0SW5zdXJhbmNlBRBkZXBvc2l0SW5zdXJhbmNlCQDOCAIJAQ11cGRhdGVCYWxhbmNlAQkAZQIJAQhjYmFsYW5jZQAJAQNhYnMBBQ1wZWdDaGFuZ2VDb3N0CQERdXBkYXRlQW1tUmVzZXJ2ZXMCBRRuZXdRdW90ZUFzc2V0UmVzZXJ2ZQkBBmJzQXN0UgAJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEFdl9nZXQBB190cmFkZXIEDSR0MDYxMTY1NjEyMjUJARVpbnRlcm5hbENsb3NlUG9zaXRpb24CBQdfdHJhZGVyBwQCeDEIBQ0kdDA2MTE2NTYxMjI1Al8xBAJ4MggFDSR0MDYxMTY1NjEyMjUCXzIEAngzCAUNJHQwNjExNjU2MTIyNQJfMwQCeDQIBQ0kdDA2MTE2NTYxMjI1Al80CQACAQkArAICCQCsAgIJAKwCAgkBAXMBBQJ4MgkBAXMBBQJ4MwkBAXMBBQJ4NAkBAXMBCQEOZ2V0TWFyZ2luUmF0aW8BBQdfdHJhZGVyAWkBJ3ZpZXdfY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudAEHX3RyYWRlcgQNJHQwNjEzNzI2MTQ4MwkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgQMcG9zaXRpb25TaXplCAUNJHQwNjEzNzI2MTQ4MwJfMQQOcG9zaXRpb25NYXJnaW4IBQ0kdDA2MTM3MjYxNDgzAl8yBANwb24IBQ0kdDA2MTM3MjYxNDgzAl8zBBFwb3NpdGlvbkxzdFVwZENQRggFDSR0MDYxMzcyNjE0ODMCXzQEDSR0MDYxNDg4NjE1ODkJASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAIFB190cmFkZXIFD1BOTF9PUFRJT05fU1BPVAQQcG9zaXRpb25Ob3Rpb25hbAgFDSR0MDYxNDg4NjE1ODkCXzEEDXVucmVhbGl6ZWRQbmwIBQ0kdDA2MTQ4ODYxNTg5Al8yBA0kdDA2MTU5NDYxNzc2CQEiY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudAQFDHBvc2l0aW9uU2l6ZQUOcG9zaXRpb25NYXJnaW4FEXBvc2l0aW9uTHN0VXBkQ1BGBQ11bnJlYWxpemVkUG5sBAxyZW1haW5NYXJnaW4IBQ0kdDA2MTU5NDYxNzc2Al8xBAdiYWREZWJ0CAUNJHQwNjE1OTQ2MTc3NgJfMgQOZnVuZGluZ1BheW1lbnQIBQ0kdDA2MTU5NDYxNzc2Al8zCQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAQFzAQUMcmVtYWluTWFyZ2luCQEBcwEFDmZ1bmRpbmdQYXltZW50CQEBcwEJAQ5nZXRNYXJnaW5SYXRpbwEFB190cmFkZXIJAQFzAQUNdW5yZWFsaXplZFBubAkBAXMBBQdiYWREZWJ0CQEBcwEFEHBvc2l0aW9uTm90aW9uYWwBaQEVdmlld19nZXRQZWdBZGp1c3RDb3N0AQZfcHJpY2UEBGNvc3QJARBnZXRQZWdBZGp1c3RDb3N0AQUGX3ByaWNlCQACAQkApAMBCAUEY29zdAJfMgECdHgBBnZlcmlmeQAJAPQDAwgFAnR4CWJvZHlCeXRlcwkAkQMCCAUCdHgGcHJvb2ZzAAAJAQ5hZG1pblB1YmxpY0tleQAnlyg5", "height": 2227444, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 6Znb8ZnUjQjNn75JbKbhqcFT1cCLEiTyMKVrWkqAPpcE Next: 9xBWq2iMwrFAqUthpiX2RaGhKCzGVCAZ2nqhuPz79Lhh Diff:
OldNewDifferences
9393
9494 let k_orders_address = "k_orders_address"
9595
96+let k_referral_address = "k_referral_address"
97+
9698 func coordinator () = valueOrErrorMessage(addressFromString(getStringValue(this, k_coordinatorAddress)), "Coordinator not set")
9799
98100
118120
119121
120122 func ordersAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_orders_address)), "Orders not set")
123+
124+
125+func referralAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_referral_address)), "Referral not set")
121126
122127
123128 let DIR_LONG = 1
337342 let amountBaseAssetBought = if (_isAdd)
338343 then amountBaseAssetBoughtAbs
339344 else -(amountBaseAssetBoughtAbs)
340- let $t01260512798 = updateReserve(_isAdd, _quoteAssetAmount, amountBaseAssetBoughtAbs)
341- let quoteAssetReserveAfter1 = $t01260512798._1
342- let baseAssetReserveAfter1 = $t01260512798._2
343- let totalPositionSizeAfter1 = $t01260512798._3
344- let cumulativeNotionalAfter1 = $t01260512798._4
345+ let $t01281613009 = updateReserve(_isAdd, _quoteAssetAmount, amountBaseAssetBoughtAbs)
346+ let quoteAssetReserveAfter1 = $t01281613009._1
347+ let baseAssetReserveAfter1 = $t01281613009._2
348+ let totalPositionSizeAfter1 = $t01281613009._3
349+ let cumulativeNotionalAfter1 = $t01281613009._4
345350 let priceBefore = divd(_qtAstR, _bsAstR)
346351 let marketPrice = divd(_quoteAssetAmount, amountBaseAssetBoughtAbs)
347352 let priceDiff = abs((priceBefore - marketPrice))
361366 }
362367 else 0
363368 let signedMargin = ((_marginDelta - fundingPayment) + _oldPositionMargin)
364- let $t01428914416 = if ((0 > signedMargin))
369+ let $t01450014627 = if ((0 > signedMargin))
365370 then $Tuple2(0, abs(signedMargin))
366371 else $Tuple2(abs(signedMargin), 0)
367- let remainMargin = $t01428914416._1
368- let badDebt = $t01428914416._2
372+ let remainMargin = $t01450014627._1
373+ let badDebt = $t01450014627._2
369374 $Tuple3(remainMargin, badDebt, fundingPayment)
370375 }
371376
382387 let quoteAssetAfter = divd(k, baseAssetPoolAmountAfter)
383388 let quoteAssetSold = abs((quoteAssetAfter - _quoteAssetReserve))
384389 let maxPriceImpactValue = maxPriceImpact()
385- let $t01539315586 = updateReserve(!(_isAdd), quoteAssetSold, _baseAssetAmount)
386- let quoteAssetReserveAfter1 = $t01539315586._1
387- let baseAssetReserveAfter1 = $t01539315586._2
388- let totalPositionSizeAfter1 = $t01539315586._3
389- let cumulativeNotionalAfter1 = $t01539315586._4
390+ let $t01560415797 = updateReserve(!(_isAdd), quoteAssetSold, _baseAssetAmount)
391+ let quoteAssetReserveAfter1 = $t01560415797._1
392+ let baseAssetReserveAfter1 = $t01560415797._2
393+ let totalPositionSizeAfter1 = $t01560415797._3
394+ let cumulativeNotionalAfter1 = $t01560415797._4
390395 let marketPrice = divd(quoteAssetSold, _baseAssetAmount)
391396 let priceDiff = abs((priceBefore - marketPrice))
392397 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
445450 let isShort = (0 > _positionSize)
446451 let positionNotional = if ((_option == PNL_OPTION_SPOT))
447452 then {
448- let $t01880418975 = swapOutputWithReserves(!(isShort), positionSizeAbs, false, _quoteAssetReserve, _baseAssetReserve)
449- let outPositionNotional = $t01880418975._1
450- let x1 = $t01880418975._2
451- let x2 = $t01880418975._3
452- let x3 = $t01880418975._4
453+ let $t01901519186 = swapOutputWithReserves(!(isShort), positionSizeAbs, false, _quoteAssetReserve, _baseAssetReserve)
454+ let outPositionNotional = $t01901519186._1
455+ let x1 = $t01901519186._2
456+ let x2 = $t01901519186._3
457+ let x3 = $t01901519186._4
453458 outPositionNotional
454459 }
455460 else muld(positionSizeAbs, getOracleTwapPrice())
457462 }
458463
459464
465+func getPositionNotionalAndUnrealizedPnlByValues (_positionSize,_positionOpenNotional,_quoteAssetReserve,_baseAssetReserve,_option) = if ((_positionSize == 0))
466+ then throw("Invalid position size")
467+ else {
468+ let isShort = (0 > _positionSize)
469+ let positionNotional = getPositionAdjustedOpenNotional(_positionSize, _option, _quoteAssetReserve, _baseAssetReserve)
470+ let unrealizedPnl = if (isShort)
471+ then (_positionOpenNotional - positionNotional)
472+ else (positionNotional - _positionOpenNotional)
473+ $Tuple2(positionNotional, unrealizedPnl)
474+ }
475+
476+
460477 func getPositionNotionalAndUnrealizedPnl (_trader,_option) = {
461- let $t01936919497 = getPosition(_trader)
462- let positionSize = $t01936919497._1
463- let positionMargin = $t01936919497._2
464- let positionOpenNotional = $t01936919497._3
465- let positionLstUpdCPF = $t01936919497._4
466- if ((positionSize == 0))
467- then throw("Invalid position size")
468- else {
469- let isShort = (0 > positionSize)
470- let positionNotional = getPositionAdjustedOpenNotional(positionSize, _option, qtAstR(), bsAstR())
471- let unrealizedPnl = if (isShort)
472- then (positionOpenNotional - positionNotional)
473- else (positionNotional - positionOpenNotional)
474- $Tuple2(positionNotional, unrealizedPnl)
475- }
478+ let $t02050320631 = getPosition(_trader)
479+ let positionSize = $t02050320631._1
480+ let positionMargin = $t02050320631._2
481+ let positionOpenNotional = $t02050320631._3
482+ let positionLstUpdCPF = $t02050320631._4
483+ getPositionNotionalAndUnrealizedPnlByValues(positionSize, positionOpenNotional, qtAstR(), bsAstR(), _option)
476484 }
477485
478486
480488
481489
482490 func getMarginRatioByOption (_trader,_option) = {
483- let $t02033020441 = getPosition(_trader)
484- let positionSize = $t02033020441._1
485- let positionMargin = $t02033020441._2
486- let pon = $t02033020441._3
487- let positionLstUpdCPF = $t02033020441._4
488- let $t02044720540 = getPositionNotionalAndUnrealizedPnl(_trader, _option)
489- let positionNotional = $t02044720540._1
490- let unrealizedPnl = $t02044720540._2
491- let $t02054520711 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
492- let remainMargin = $t02054520711._1
493- let badDebt = $t02054520711._2
491+ let $t02111221223 = getPosition(_trader)
492+ let positionSize = $t02111221223._1
493+ let positionMargin = $t02111221223._2
494+ let pon = $t02111221223._3
495+ let positionLstUpdCPF = $t02111221223._4
496+ let $t02122921322 = getPositionNotionalAndUnrealizedPnl(_trader, _option)
497+ let positionNotional = $t02122921322._1
498+ let unrealizedPnl = $t02122921322._2
499+ let $t02132721493 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
500+ let remainMargin = $t02132721493._1
501+ let badDebt = $t02132721493._2
494502 calcMarginRatio(remainMargin, badDebt, positionNotional)
495503 }
496504
515523
516524
517525 func internalClosePosition (_trader,_checkMaxPriceImpact) = {
518- let $t02189322021 = getPosition(_trader)
519- let positionSize = $t02189322021._1
520- let positionMargin = $t02189322021._2
521- let positionOpenNotional = $t02189322021._3
522- let positionLstUpdCPF = $t02189322021._4
526+ let $t02272622854 = getPosition(_trader)
527+ let positionSize = $t02272622854._1
528+ let positionMargin = $t02272622854._2
529+ let positionOpenNotional = $t02272622854._3
530+ let positionLstUpdCPF = $t02272622854._4
523531 let unrealizedPnl = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)._2
524- let $t02211622284 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
525- let remainMargin = $t02211622284._1
526- let badDebt = $t02211622284._2
532+ let $t02294923117 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
533+ let remainMargin = $t02294923117._1
534+ let badDebt = $t02294923117._2
527535 let exchangedPositionSize = -(positionSize)
528536 let realizedPnl = unrealizedPnl
529537 let marginToVault = -(remainMargin)
530- let $t02241122722 = swapOutput((positionSize > 0), abs(positionSize), _checkMaxPriceImpact)
531- let exchangedQuoteAssetAmount = $t02241122722._1
532- let quoteAssetReserveAfter = $t02241122722._2
533- let baseAssetReserveAfter = $t02241122722._3
534- let totalPositionSizeAfter = $t02241122722._4
535- let cumulativeNotionalAfter = $t02241122722._5
536- let totalLongAfter = $t02241122722._6
537- let totalShortAfter = $t02241122722._7
538+ let $t02324423555 = swapOutput((positionSize > 0), abs(positionSize), _checkMaxPriceImpact)
539+ let exchangedQuoteAssetAmount = $t02324423555._1
540+ let quoteAssetReserveAfter = $t02324423555._2
541+ let baseAssetReserveAfter = $t02324423555._3
542+ let totalPositionSizeAfter = $t02324423555._4
543+ let cumulativeNotionalAfter = $t02324423555._5
544+ let totalLongAfter = $t02324423555._6
545+ let totalShortAfter = $t02324423555._7
538546 let openInterestNotionalAfter = (openInterestNotional() - positionOpenNotional)
539547 $Tuple12(exchangedPositionSize, badDebt, realizedPnl, marginToVault, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, openInterestNotionalAfter, exchangedQuoteAssetAmount, totalLongAfter, totalShortAfter)
540548 }
574582 let startLastPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(maxIndex))), 0)
575583 let startCumulativePrice = (startLastCumulativePrice + ((startMinuteId - maxIndex) * startLastPrice))
576584 ((nowCumulativePrice - startCumulativePrice) / TWAP_INTERVAL)
585+ }
586+
587+
588+func getPegAdjustCost (_price) = {
589+ let _positionSize = totalPositionSize()
590+ let direction = (_positionSize > 0)
591+ let currentNetMarketValue = swapOutput(direction, abs(_positionSize), false)._1
592+ let baseAssetReserve = bsAstR()
593+ let newQuoteAssetReserve = muld(baseAssetReserve, _price)
594+ let cost = getPositionNotionalAndUnrealizedPnlByValues(_positionSize, currentNetMarketValue, newQuoteAssetReserve, baseAssetReserve, PNL_OPTION_SPOT)._2
595+ $Tuple2(newQuoteAssetReserve, cost)
577596 }
578597
579598
746765 else paused())
747766 then throw("Invalid decreasePosition parameters")
748767 else {
749- let $t03470134853 = getPosition(toString(i.caller))
750- let oldPositionSize = $t03470134853._1
751- let oldPositionMargin = $t03470134853._2
752- let oldPositionOpenNotional = $t03470134853._3
753- let oldPositionLstUpdCPF = $t03470134853._4
768+ let $t03607336225 = getPosition(toString(i.caller))
769+ let oldPositionSize = $t03607336225._1
770+ let oldPositionMargin = $t03607336225._2
771+ let oldPositionOpenNotional = $t03607336225._3
772+ let oldPositionLstUpdCPF = $t03607336225._4
754773 let _direction = if ((oldPositionSize > 0))
755774 then DIR_SHORT
756775 else DIR_LONG
757776 let isAdd = (_direction == DIR_LONG)
758777 let openNotional = muld(_amount, _leverage)
759- let $t03502635142 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
760- let oldPositionNotional = $t03502635142._1
761- let unrealizedPnl = $t03502635142._2
762- let $t03514837697 = if ((oldPositionNotional > openNotional))
778+ let $t03639836514 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
779+ let oldPositionNotional = $t03639836514._1
780+ let unrealizedPnl = $t03639836514._2
781+ let $t03652039069 = if ((oldPositionNotional > openNotional))
763782 then {
764- let $t03552535744 = swapInput(isAdd, openNotional)
765- let exchangedPositionSize = $t03552535744._1
766- let quoteAssetReserveAfter = $t03552535744._2
767- let baseAssetReserveAfter = $t03552535744._3
768- let totalPositionSizeAfter = $t03552535744._4
769- let cumulativeNotionalAfter = $t03552535744._5
783+ let $t03689737116 = swapInput(isAdd, openNotional)
784+ let exchangedPositionSize = $t03689737116._1
785+ let quoteAssetReserveAfter = $t03689737116._2
786+ let baseAssetReserveAfter = $t03689737116._3
787+ let totalPositionSizeAfter = $t03689737116._4
788+ let cumulativeNotionalAfter = $t03689737116._5
770789 let exchangedPositionSizeAbs = abs(exchangedPositionSize)
771790 if (if ((_minBaseAssetAmount != 0))
772791 then (_minBaseAssetAmount > exchangedPositionSizeAbs)
774793 then throw(((("Too little base asset exchanged, got " + toString(exchangedPositionSizeAbs)) + " expected ") + toString(_minBaseAssetAmount)))
775794 else {
776795 let realizedPnl = divd(muld(unrealizedPnl, exchangedPositionSizeAbs), abs(oldPositionSize))
777- let $t03618136426 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl)
778- let remainMargin = $t03618136426._1
779- let badDebt = $t03618136426._2
780- let fundingPayment = $t03618136426._3
796+ let $t03755337798 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl)
797+ let remainMargin = $t03755337798._1
798+ let badDebt = $t03755337798._2
799+ let fundingPayment = $t03755337798._3
781800 let exchangedQuoteAssetAmount = openNotional
782801 let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
783802 let remainOpenNotional = if ((oldPositionSize > 0))
792811 }
793812 }
794813 else throw("Close position first")
795- let newPositionSize = $t03514837697._1
796- let newPositionRemainMargin = $t03514837697._2
797- let newPositionOpenNotional = $t03514837697._3
798- let newPositionLatestCPF = $t03514837697._4
799- let baseAssetReserveAfter = $t03514837697._5
800- let quoteAssetReserveAfter = $t03514837697._6
801- let totalPositionSizeAfter = $t03514837697._7
802- let cumulativeNotionalAfter = $t03514837697._8
803- let openInterestNotionalAfter = $t03514837697._9
804- let totalLongAfter = $t03514837697._10
805- let totalShortAfter = $t03514837697._11
814+ let newPositionSize = $t03652039069._1
815+ let newPositionRemainMargin = $t03652039069._2
816+ let newPositionOpenNotional = $t03652039069._3
817+ let newPositionLatestCPF = $t03652039069._4
818+ let baseAssetReserveAfter = $t03652039069._5
819+ let quoteAssetReserveAfter = $t03652039069._6
820+ let totalPositionSizeAfter = $t03652039069._7
821+ let cumulativeNotionalAfter = $t03652039069._8
822+ let openInterestNotionalAfter = $t03652039069._9
823+ let totalLongAfter = $t03652039069._10
824+ let totalShortAfter = $t03652039069._11
806825 let notifyNotional = invoke(minerAddress(), "notifyNotional", [toString(i.caller), newPositionOpenNotional], nil)
807826 if ((notifyNotional == notifyNotional))
808827 then (updatePosition(toString(i.caller), newPositionSize, newPositionRemainMargin, newPositionOpenNotional, newPositionLatestCPF) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter))
812831
813832
814833 @Callable(i)
815-func increasePosition (_direction,_leverage,_minBaseAssetAmount) = {
834+func increasePosition (_direction,_leverage,_minBaseAssetAmount,_refLink) = {
816835 let _rawAmount = i.payments[0].amount
817836 if (if (if (if (if (if (if ((_direction != DIR_LONG))
818837 then (_direction != DIR_SHORT)
829848 else paused())
830849 then throw("Invalid increasePosition parameters")
831850 else {
832- let feeAmount = muld(_rawAmount, fee())
833- let _amount = (_rawAmount - feeAmount)
834- let $t03881538967 = getPosition(toString(i.caller))
835- let oldPositionSize = $t03881538967._1
836- let oldPositionMargin = $t03881538967._2
837- let oldPositionOpenNotional = $t03881538967._3
838- let oldPositionLstUpdCPF = $t03881538967._4
839- let isNewPosition = (oldPositionSize == 0)
840- let isSameDirection = if ((oldPositionSize > 0))
841- then (_direction == DIR_LONG)
842- else (_direction == DIR_SHORT)
843- let expandExisting = if (!(isNewPosition))
844- then isSameDirection
845- else false
846- let isAdd = (_direction == DIR_LONG)
847- let $t03925641824 = if (if (isNewPosition)
848- then true
849- else expandExisting)
851+ let _trader = toString(i.caller)
852+ let rawFeeAmount = muld(_rawAmount, fee())
853+ let referrerFeeAny = invoke(referralAddress(), "acceptPaymentWithLink", [_trader, _refLink], [AttachedPayment(quoteAsset(), rawFeeAmount)])
854+ if ((referrerFeeAny == referrerFeeAny))
850855 then {
851- let openNotional = muld(_amount, _leverage)
852- let $t03968039886 = swapInput(isAdd, openNotional)
853- let amountBaseAssetBought = $t03968039886._1
854- let quoteAssetReserveAfter = $t03968039886._2
855- let baseAssetReserveAfter = $t03968039886._3
856- let totalPositionSizeAfter = $t03968039886._4
857- let cumulativeNotionalAfter = $t03968039886._5
858- if (if ((_minBaseAssetAmount != 0))
859- then (_minBaseAssetAmount > abs(amountBaseAssetBought))
860- else false)
861- then throw(((("Limit error: " + toString(abs(amountBaseAssetBought))) + " < ") + toString(_minBaseAssetAmount)))
856+ let referrerFee = match referrerFeeAny {
857+ case x: Int =>
858+ x
859+ case _ =>
860+ throw("Invalid referrerFee")
861+ }
862+ let _amount = (_rawAmount - rawFeeAmount)
863+ let feeAmount = (rawFeeAmount - referrerFee)
864+ let $t04059840738 = getPosition(_trader)
865+ let oldPositionSize = $t04059840738._1
866+ let oldPositionMargin = $t04059840738._2
867+ let oldPositionOpenNotional = $t04059840738._3
868+ let oldPositionLstUpdCPF = $t04059840738._4
869+ let isNewPosition = (oldPositionSize == 0)
870+ let isSameDirection = if ((oldPositionSize > 0))
871+ then (_direction == DIR_LONG)
872+ else (_direction == DIR_SHORT)
873+ let expandExisting = if (!(isNewPosition))
874+ then isSameDirection
875+ else false
876+ let isAdd = (_direction == DIR_LONG)
877+ let $t04102743595 = if (if (isNewPosition)
878+ then true
879+ else expandExisting)
880+ then {
881+ let openNotional = muld(_amount, _leverage)
882+ let $t04145141657 = swapInput(isAdd, openNotional)
883+ let amountBaseAssetBought = $t04145141657._1
884+ let quoteAssetReserveAfter = $t04145141657._2
885+ let baseAssetReserveAfter = $t04145141657._3
886+ let totalPositionSizeAfter = $t04145141657._4
887+ let cumulativeNotionalAfter = $t04145141657._5
888+ if (if ((_minBaseAssetAmount != 0))
889+ then (_minBaseAssetAmount > abs(amountBaseAssetBought))
890+ else false)
891+ then throw(((("Limit error: " + toString(abs(amountBaseAssetBought))) + " < ") + toString(_minBaseAssetAmount)))
892+ else {
893+ let newPositionSize = (oldPositionSize + amountBaseAssetBought)
894+ let increaseMarginRequirement = divd(openNotional, _leverage)
895+ let $t04203842277 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, increaseMarginRequirement)
896+ let remainMargin = $t04203842277._1
897+ let x1 = $t04203842277._2
898+ let x2 = $t04203842277._3
899+ if (!(requireNotOverSpreadLimit(quoteAssetReserveAfter, baseAssetReserveAfter)))
900+ then throw("Over max spread limit")
901+ else $Tuple11(newPositionSize, remainMargin, (oldPositionOpenNotional + openNotional), latestCumulativePremiumFraction(newPositionSize), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, (openInterestNotional() + openNotional), (totalLongPositionSize() + (if ((newPositionSize > 0))
902+ then abs(amountBaseAssetBought)
903+ else 0)), (totalShortPositionSize() + (if ((0 > newPositionSize))
904+ then abs(amountBaseAssetBought)
905+ else 0)))
906+ }
907+ }
862908 else {
863- let newPositionSize = (oldPositionSize + amountBaseAssetBought)
864- let increaseMarginRequirement = divd(openNotional, _leverage)
865- let $t04026740506 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, increaseMarginRequirement)
866- let remainMargin = $t04026740506._1
867- let x1 = $t04026740506._2
868- let x2 = $t04026740506._3
869- if (!(requireNotOverSpreadLimit(quoteAssetReserveAfter, baseAssetReserveAfter)))
870- then throw("Over max spread limit")
871- else $Tuple11(newPositionSize, remainMargin, (oldPositionOpenNotional + openNotional), latestCumulativePremiumFraction(newPositionSize), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, (openInterestNotional() + openNotional), (totalLongPositionSize() + (if ((newPositionSize > 0))
872- then abs(amountBaseAssetBought)
873- else 0)), (totalShortPositionSize() + (if ((0 > newPositionSize))
874- then abs(amountBaseAssetBought)
875- else 0)))
909+ let openNotional = muld(_amount, _leverage)
910+ let $t04328843404 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
911+ let oldPositionNotional = $t04328843404._1
912+ let unrealizedPnl = $t04328843404._2
913+ if ((oldPositionNotional > openNotional))
914+ then throw("Use decreasePosition to decrease position size")
915+ else throw("Close position first")
876916 }
877- }
878- else {
879- let openNotional = muld(_amount, _leverage)
880- let $t04151741633 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
881- let oldPositionNotional = $t04151741633._1
882- let unrealizedPnl = $t04151741633._2
883- if ((oldPositionNotional > openNotional))
884- then throw("Use decreasePosition to decrease position size")
885- else throw("Close position first")
886- }
887- let newPositionSize = $t03925641824._1
888- let newPositionRemainMargin = $t03925641824._2
889- let newPositionOpenNotional = $t03925641824._3
890- let newPositionLatestCPF = $t03925641824._4
891- let baseAssetReserveAfter = $t03925641824._5
892- let quoteAssetReserveAfter = $t03925641824._6
893- let totalPositionSizeAfter = $t03925641824._7
894- let cumulativeNotionalAfter = $t03925641824._8
895- let openInterestNotionalAfter = $t03925641824._9
896- let totalLongAfter = $t03925641824._10
897- let totalShortAfter = $t03925641824._11
898- let feeToStakers = (feeAmount / 2)
899- let feeToInsurance = (feeAmount - feeToStakers)
900- let stake = invoke(quoteAssetStaking(), "lockNeutrinoSP", [toString(stakingAddress()), ALL_FEES], [AttachedPayment(quoteAsset(), _amount)])
901- if ((stake == stake))
902- then {
903- let depositInsurance = invoke(insuranceAddress(), "deposit", nil, [AttachedPayment(quoteAsset(), feeToInsurance)])
904- if ((depositInsurance == depositInsurance))
917+ let newPositionSize = $t04102743595._1
918+ let newPositionRemainMargin = $t04102743595._2
919+ let newPositionOpenNotional = $t04102743595._3
920+ let newPositionLatestCPF = $t04102743595._4
921+ let baseAssetReserveAfter = $t04102743595._5
922+ let quoteAssetReserveAfter = $t04102743595._6
923+ let totalPositionSizeAfter = $t04102743595._7
924+ let cumulativeNotionalAfter = $t04102743595._8
925+ let openInterestNotionalAfter = $t04102743595._9
926+ let totalLongAfter = $t04102743595._10
927+ let totalShortAfter = $t04102743595._11
928+ let feeToStakers = (feeAmount / 2)
929+ let feeToInsurance = (feeAmount - feeToStakers)
930+ let stake = invoke(quoteAssetStaking(), "lockNeutrinoSP", [toString(stakingAddress()), ALL_FEES], [AttachedPayment(quoteAsset(), _amount)])
931+ if ((stake == stake))
905932 then {
906- let notifyFee = invoke(minerAddress(), "notifyFees", [toString(i.caller), feeAmount], nil)
907- if ((notifyFee == notifyFee))
933+ let depositInsurance = invoke(insuranceAddress(), "deposit", nil, [AttachedPayment(quoteAsset(), feeToInsurance)])
934+ if ((depositInsurance == depositInsurance))
908935 then {
909- let notifyNotional = invoke(minerAddress(), "notifyNotional", [toString(i.caller), newPositionOpenNotional], nil)
910- if ((notifyNotional == notifyNotional))
911- then (((updatePosition(toString(i.caller), newPositionSize, newPositionRemainMargin, newPositionOpenNotional, newPositionLatestCPF) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter)) ++ transferFee(feeToStakers)) ++ updateBalance((cbalance() + _amount)))
936+ let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, feeAmount], nil)
937+ if ((notifyFee == notifyFee))
938+ then {
939+ let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
940+ if ((notifyNotional == notifyNotional))
941+ then (((updatePosition(_trader, newPositionSize, newPositionRemainMargin, newPositionOpenNotional, newPositionLatestCPF) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter)) ++ transferFee(feeToStakers)) ++ updateBalance((cbalance() + _amount)))
942+ else throw("Strict value is not equal to itself.")
943+ }
912944 else throw("Strict value is not equal to itself.")
913945 }
914946 else throw("Strict value is not equal to itself.")
933965 else paused())
934966 then throw("Invalid addMargin parameters")
935967 else {
936- let feeAmount = muld(_rawAmount, fee())
937- let _amount = (_rawAmount - feeAmount)
938- let $t04338043532 = getPosition(toString(i.caller))
939- let oldPositionSize = $t04338043532._1
940- let oldPositionMargin = $t04338043532._2
941- let oldPositionOpenNotional = $t04338043532._3
942- let oldPositionLstUpdCPF = $t04338043532._4
943- let feeToStakers = (feeAmount / 2)
944- let feeToInsurance = (feeAmount - feeToStakers)
945- let stake = invoke(quoteAssetStaking(), "lockNeutrinoSP", [toString(stakingAddress()), ALL_FEES], [AttachedPayment(quoteAsset(), _amount)])
946- if ((stake == stake))
968+ let _trader = toString(i.caller)
969+ let rawFeeAmount = muld(_rawAmount, fee())
970+ let referrerFeeAny = invoke(referralAddress(), "acceptPayment", [_trader], [AttachedPayment(quoteAsset(), rawFeeAmount)])
971+ if ((referrerFeeAny == referrerFeeAny))
947972 then {
948- let depositInsurance = invoke(insuranceAddress(), "deposit", nil, [AttachedPayment(quoteAsset(), feeToInsurance)])
949- if ((depositInsurance == depositInsurance))
973+ let referrerFee = match referrerFeeAny {
974+ case x: Int =>
975+ x
976+ case _ =>
977+ throw("Invalid referrerFee")
978+ }
979+ let feeAmount = (rawFeeAmount - referrerFee)
980+ let _amount = (_rawAmount - rawFeeAmount)
981+ let $t04548845628 = getPosition(_trader)
982+ let oldPositionSize = $t04548845628._1
983+ let oldPositionMargin = $t04548845628._2
984+ let oldPositionOpenNotional = $t04548845628._3
985+ let oldPositionLstUpdCPF = $t04548845628._4
986+ let feeToStakers = (feeAmount / 2)
987+ let feeToInsurance = (feeAmount - feeToStakers)
988+ let stake = invoke(quoteAssetStaking(), "lockNeutrinoSP", [toString(stakingAddress()), ALL_FEES], [AttachedPayment(quoteAsset(), _amount)])
989+ if ((stake == stake))
950990 then {
951- let notifyFee = invoke(minerAddress(), "notifyFees", [toString(i.caller), feeAmount], nil)
952- if ((notifyFee == notifyFee))
953- then ((updatePosition(toString(i.caller), oldPositionSize, (oldPositionMargin + _amount), oldPositionOpenNotional, oldPositionLstUpdCPF) ++ transferFee(feeToStakers)) ++ updateBalance((cbalance() + _amount)))
991+ let depositInsurance = invoke(insuranceAddress(), "deposit", nil, [AttachedPayment(quoteAsset(), feeToInsurance)])
992+ if ((depositInsurance == depositInsurance))
993+ then {
994+ let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, feeAmount], nil)
995+ if ((notifyFee == notifyFee))
996+ then ((updatePosition(_trader, oldPositionSize, (oldPositionMargin + _amount), oldPositionOpenNotional, oldPositionLstUpdCPF) ++ transferFee(feeToStakers)) ++ updateBalance((cbalance() + _amount)))
997+ else throw("Strict value is not equal to itself.")
998+ }
954999 else throw("Strict value is not equal to itself.")
9551000 }
9561001 else throw("Strict value is not equal to itself.")
9711016 else paused())
9721017 then throw("Invalid removeMargin parameters")
9731018 else {
974- let $t04458144733 = getPosition(toString(i.caller))
975- let oldPositionSize = $t04458144733._1
976- let oldPositionMargin = $t04458144733._2
977- let oldPositionOpenNotional = $t04458144733._3
978- let oldPositionLstUpdCPF = $t04458144733._4
1019+ let $t04665346805 = getPosition(toString(i.caller))
1020+ let oldPositionSize = $t04665346805._1
1021+ let oldPositionMargin = $t04665346805._2
1022+ let oldPositionOpenNotional = $t04665346805._3
1023+ let oldPositionLstUpdCPF = $t04665346805._4
9791024 let marginDelta = -(_amount)
980- let $t04477044949 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, marginDelta)
981- let remainMargin = $t04477044949._1
982- let badDebt = $t04477044949._2
1025+ let $t04684247021 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, marginDelta)
1026+ let remainMargin = $t04684247021._1
1027+ let badDebt = $t04684247021._2
9831028 if ((badDebt != 0))
9841029 then throw("Invalid removed margin amount")
9851030 else {
10081053 else paused())
10091054 then throw("Invalid closePosition parameters")
10101055 else {
1011- let $t04615246529 = internalClosePosition(caller, true)
1012- let x1 = $t04615246529._1
1013- let positionBadDebt = $t04615246529._2
1014- let realizedPnl = $t04615246529._3
1015- let marginToVault = $t04615246529._4
1016- let quoteAssetReserveAfter = $t04615246529._5
1017- let baseAssetReserveAfter = $t04615246529._6
1018- let totalPositionSizeAfter = $t04615246529._7
1019- let cumulativeNotionalAfter = $t04615246529._8
1020- let openInterestNotionalAfter = $t04615246529._9
1021- let x2 = $t04615246529._10
1022- let totalLongAfter = $t04615246529._11
1023- let totalShortAfter = $t04615246529._12
1056+ let $t04822448601 = internalClosePosition(caller, true)
1057+ let x1 = $t04822448601._1
1058+ let positionBadDebt = $t04822448601._2
1059+ let realizedPnl = $t04822448601._3
1060+ let marginToVault = $t04822448601._4
1061+ let quoteAssetReserveAfter = $t04822448601._5
1062+ let baseAssetReserveAfter = $t04822448601._6
1063+ let totalPositionSizeAfter = $t04822448601._7
1064+ let cumulativeNotionalAfter = $t04822448601._8
1065+ let openInterestNotionalAfter = $t04822448601._9
1066+ let x2 = $t04822448601._10
1067+ let totalLongAfter = $t04822448601._11
1068+ let totalShortAfter = $t04822448601._12
10241069 if ((positionBadDebt > 0))
10251070 then throw("Unable to close position with bad debt")
10261071 else {
10271072 let withdrawAmount = abs(marginToVault)
10281073 let ammBalance = (cbalance() - withdrawAmount)
1029- let $t04673846880 = if ((0 > ammBalance))
1074+ let $t04881048952 = if ((0 > ammBalance))
10301075 then $Tuple2(0, abs(ammBalance))
10311076 else $Tuple2(ammBalance, 0)
1032- let ammNewBalance = $t04673846880._1
1033- let getFromInsurance = $t04673846880._2
1077+ let ammNewBalance = $t04881048952._1
1078+ let getFromInsurance = $t04881048952._2
10341079 let x = if ((getFromInsurance > 0))
10351080 then {
10361081 let withdrawInsurance = invoke(insuranceAddress(), "withdraw", [getFromInsurance], nil)
10811126 then (DECIMAL_UNIT > partialLiquidationRatio())
10821127 else false)
10831128 then {
1084- let $t04896049110 = getPosition(_trader)
1085- let oldPositionSize = $t04896049110._1
1086- let oldPositionMargin = $t04896049110._2
1087- let oldPositionOpenNotional = $t04896049110._3
1088- let oldPositionLstUpdCPF = $t04896049110._4
1129+ let $t05103251182 = getPosition(_trader)
1130+ let oldPositionSize = $t05103251182._1
1131+ let oldPositionMargin = $t05103251182._2
1132+ let oldPositionOpenNotional = $t05103251182._3
1133+ let oldPositionLstUpdCPF = $t05103251182._4
10891134 let _direction = if ((oldPositionSize > 0))
10901135 then DIR_SHORT
10911136 else DIR_LONG
10921137 let isAdd = (_direction == DIR_LONG)
10931138 let exchangedQuoteAssetAmount = getPartialLiquidationAmount(_trader, oldPositionSize)
1094- let $t04933549439 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1095- let oldPositionNotional = $t04933549439._1
1096- let unrealizedPnl = $t04933549439._2
1097- let $t04944749737 = swapInput(isAdd, exchangedQuoteAssetAmount)
1098- let exchangedPositionSize = $t04944749737._1
1099- let quoteAssetReserveAfter = $t04944749737._2
1100- let baseAssetReserveAfter = $t04944749737._3
1101- let totalPositionSizeAfter = $t04944749737._4
1102- let cumulativeNotionalAfter = $t04944749737._5
1139+ let $t05140751511 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1140+ let oldPositionNotional = $t05140751511._1
1141+ let unrealizedPnl = $t05140751511._2
1142+ let $t05151951809 = swapInput(isAdd, exchangedQuoteAssetAmount)
1143+ let exchangedPositionSize = $t05151951809._1
1144+ let quoteAssetReserveAfter = $t05151951809._2
1145+ let baseAssetReserveAfter = $t05151951809._3
1146+ let totalPositionSizeAfter = $t05151951809._4
1147+ let cumulativeNotionalAfter = $t05151951809._5
11031148 let realizedPnl = divd(muld(unrealizedPnl, abs(exchangedPositionSize)), abs(oldPositionSize))
1104- let $t04984450077 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl)
1105- let remainMargin = $t04984450077._1
1106- let badDebt = $t04984450077._2
1107- let fundingPayment = $t04984450077._3
1149+ let $t05191652149 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl)
1150+ let remainMargin = $t05191652149._1
1151+ let badDebt = $t05191652149._2
1152+ let fundingPayment = $t05191652149._3
11081153 let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
11091154 let remainOpenNotional = if ((oldPositionSize > 0))
11101155 then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
11181163 let newPositionLstUpdCPF = latestCumulativePremiumFraction(newPositionSize)
11191164 let openInterestNotionalAfter = (openInterestNotional() - exchangedQuoteAssetAmount)
11201165 let ammBalance = (cbalance() - liquidationPenalty)
1121- let $t05125051393 = if ((0 > ammBalance))
1166+ let $t05332253465 = if ((0 > ammBalance))
11221167 then $Tuple2(0, abs(ammBalance))
11231168 else $Tuple2(ammBalance, 0)
1124- let newAmmBalance = $t05125051393._1
1125- let takeFromInsurance = $t05125051393._2
1169+ let newAmmBalance = $t05332253465._1
1170+ let takeFromInsurance = $t05332253465._2
11261171 let x = if ((takeFromInsurance > 0))
11271172 then {
11281173 let withdrawInsurance = invoke(insuranceAddress(), "withdraw", [takeFromInsurance], nil)
11551200 else throw("Strict value is not equal to itself.")
11561201 }
11571202 else {
1158- let $t05284953304 = internalClosePosition(_trader, false)
1159- let x1 = $t05284953304._1
1160- let badDebt = $t05284953304._2
1161- let x2 = $t05284953304._3
1162- let x3 = $t05284953304._4
1163- let quoteAssetReserveAfter = $t05284953304._5
1164- let baseAssetReserveAfter = $t05284953304._6
1165- let totalPositionSizeAfter = $t05284953304._7
1166- let cumulativeNotionalAfter = $t05284953304._8
1167- let openInterestNotionalAfter = $t05284953304._9
1168- let exchangedQuoteAssetAmount = $t05284953304._10
1169- let totalLongAfter = $t05284953304._11
1170- let totalShortAfter = $t05284953304._12
1203+ let $t05492155376 = internalClosePosition(_trader, false)
1204+ let x1 = $t05492155376._1
1205+ let badDebt = $t05492155376._2
1206+ let x2 = $t05492155376._3
1207+ let x3 = $t05492155376._4
1208+ let quoteAssetReserveAfter = $t05492155376._5
1209+ let baseAssetReserveAfter = $t05492155376._6
1210+ let totalPositionSizeAfter = $t05492155376._7
1211+ let cumulativeNotionalAfter = $t05492155376._8
1212+ let openInterestNotionalAfter = $t05492155376._9
1213+ let exchangedQuoteAssetAmount = $t05492155376._10
1214+ let totalLongAfter = $t05492155376._11
1215+ let totalShortAfter = $t05492155376._12
11711216 let liquidationPenalty = muld(exchangedQuoteAssetAmount, liquidationFeeRatio())
11721217 let feeToLiquidator = (liquidationPenalty / 2)
11731218 let feeToInsurance = (liquidationPenalty - feeToLiquidator)
11741219 let ammBalance = (cbalance() - liquidationPenalty)
1175- let $t05371653859 = if ((0 > ammBalance))
1220+ let $t05578855931 = if ((0 > ammBalance))
11761221 then $Tuple2(0, abs(ammBalance))
11771222 else $Tuple2(ammBalance, 0)
1178- let newAmmBalance = $t05371653859._1
1179- let takeFromInsurance = $t05371653859._2
1223+ let newAmmBalance = $t05578855931._1
1224+ let takeFromInsurance = $t05578855931._2
11801225 let x = if ((takeFromInsurance > 0))
11811226 then {
11821227 let withdrawInsurance = invoke(insuranceAddress(), "withdraw", [takeFromInsurance], nil)
12211266 let underlyingPrice = getOracleTwapPrice()
12221267 let spotTwapPrice = getTwapSpotPrice()
12231268 let premium = (spotTwapPrice - underlyingPrice)
1224- let $t05544756782 = if (if ((totalShortPositionSize() == 0))
1269+ let $t05751958854 = if (if ((totalShortPositionSize() == 0))
12251270 then true
12261271 else (totalLongPositionSize() == 0))
12271272 then $Tuple2(0, 0)
12361281 let shortPremiumFraction = divd(muld(longPremiumFraction, totalLongPositionSize()), totalShortPositionSize())
12371282 $Tuple2(shortPremiumFraction, longPremiumFraction)
12381283 }
1239- let shortPremiumFraction = $t05544756782._1
1240- let longPremiumFraction = $t05544756782._2
1284+ let shortPremiumFraction = $t05751958854._1
1285+ let longPremiumFraction = $t05751958854._2
12411286 updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice))
12421287 }
1243- }
1244-
1245-
1246-
1247-@Callable(i)
1248-func v_get (_trader) = {
1249- let $t05715757217 = internalClosePosition(_trader, false)
1250- let x1 = $t05715757217._1
1251- let x2 = $t05715757217._2
1252- let x3 = $t05715757217._3
1253- let x4 = $t05715757217._4
1254- throw((((s(x2) + s(x3)) + s(x4)) + s(getMarginRatio(_trader))))
1255- }
1256-
1257-
1258-
1259-@Callable(i)
1260-func view_calcRemainMarginWithFundingPayment (_trader) = {
1261- let $t05736457475 = getPosition(_trader)
1262- let positionSize = $t05736457475._1
1263- let positionMargin = $t05736457475._2
1264- let pon = $t05736457475._3
1265- let positionLstUpdCPF = $t05736457475._4
1266- let $t05748057581 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1267- let positionNotional = $t05748057581._1
1268- let unrealizedPnl = $t05748057581._2
1269- let $t05758657768 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
1270- let remainMargin = $t05758657768._1
1271- let badDebt = $t05758657768._2
1272- let fundingPayment = $t05758657768._3
1273- throw((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)))
12741288 }
12751289
12761290
12881302 }
12891303
12901304
1305+
1306+@Callable(i)
1307+func adjustPeg (_price) = if (if ((addressFromPublicKey(adminPublicKey()) != i.caller))
1308+ then true
1309+ else (0 > _price))
1310+ then throw("Invalid adjustPeg parameters")
1311+ else {
1312+ let $t05985459940 = getPegAdjustCost(_price)
1313+ let newQuoteAssetReserve = $t05985459940._1
1314+ let pegChangeCost = $t05985459940._2
1315+ if ((pegChangeCost == 0))
1316+ then throw("Nothing to adjust")
1317+ else if ((pegChangeCost > 0))
1318+ then {
1319+ let withdrawInsurance = invoke(insuranceAddress(), "withdraw", [pegChangeCost], nil)
1320+ if ((withdrawInsurance == withdrawInsurance))
1321+ then {
1322+ let stake = invoke(quoteAssetStaking(), "lockNeutrinoSP", [toString(stakingAddress()), ALL_FEES], [AttachedPayment(quoteAsset(), pegChangeCost)])
1323+ if ((stake == stake))
1324+ then (updateBalance((cbalance() + pegChangeCost)) ++ updateAmmReserves(newQuoteAssetReserve, bsAstR()))
1325+ else throw("Strict value is not equal to itself.")
1326+ }
1327+ else throw("Strict value is not equal to itself.")
1328+ }
1329+ else {
1330+ let unstake = invoke(quoteAssetStaking(), "unlockNeutrino", [abs(pegChangeCost), toBase58String(quoteAsset())], nil)
1331+ if ((unstake == unstake))
1332+ then {
1333+ let depositInsurance = invoke(insuranceAddress(), "deposit", nil, [AttachedPayment(quoteAsset(), abs(pegChangeCost))])
1334+ if ((depositInsurance == depositInsurance))
1335+ then (updateBalance((cbalance() - abs(pegChangeCost))) ++ updateAmmReserves(newQuoteAssetReserve, bsAstR()))
1336+ else throw("Strict value is not equal to itself.")
1337+ }
1338+ else throw("Strict value is not equal to itself.")
1339+ }
1340+ }
1341+
1342+
1343+
1344+@Callable(i)
1345+func v_get (_trader) = {
1346+ let $t06116561225 = internalClosePosition(_trader, false)
1347+ let x1 = $t06116561225._1
1348+ let x2 = $t06116561225._2
1349+ let x3 = $t06116561225._3
1350+ let x4 = $t06116561225._4
1351+ throw((((s(x2) + s(x3)) + s(x4)) + s(getMarginRatio(_trader))))
1352+ }
1353+
1354+
1355+
1356+@Callable(i)
1357+func view_calcRemainMarginWithFundingPayment (_trader) = {
1358+ let $t06137261483 = getPosition(_trader)
1359+ let positionSize = $t06137261483._1
1360+ let positionMargin = $t06137261483._2
1361+ let pon = $t06137261483._3
1362+ let positionLstUpdCPF = $t06137261483._4
1363+ let $t06148861589 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1364+ let positionNotional = $t06148861589._1
1365+ let unrealizedPnl = $t06148861589._2
1366+ let $t06159461776 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
1367+ let remainMargin = $t06159461776._1
1368+ let badDebt = $t06159461776._2
1369+ let fundingPayment = $t06159461776._3
1370+ throw((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)))
1371+ }
1372+
1373+
1374+
1375+@Callable(i)
1376+func view_getPegAdjustCost (_price) = {
1377+ let cost = getPegAdjustCost(_price)
1378+ throw(toString(cost._2))
1379+ }
1380+
1381+
12911382 @Verifier(tx)
12921383 func verify () = sigVerify(tx.bodyBytes, tx.proofs[0], adminPublicKey())
12931384
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let k_ora_key = "k_ora_key"
55
66 let k_ora_block_key = "k_ora_block_key"
77
88 let k_ora = "k_ora"
99
1010 let k_balance = "k_balance"
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_positionClosedDate = "k_positionClosedDate"
2121
2222 let k_initialized = "k_initialized"
2323
2424 let k_paused = "k_paused"
2525
2626 let k_fee = "k_fee"
2727
2828 let k_fundingPeriod = "k_fundingPeriod"
2929
3030 let k_initMarginRatio = "k_initMarginRatio"
3131
3232 let k_maintenanceMarginRatio = "k_mmr"
3333
3434 let k_liquidationFeeRatio = "k_liquidationFeeRatio"
3535
3636 let k_partialLiquidationRatio = "k_partLiquidationRatio"
3737
3838 let k_spreadLimit = "k_spreadLimit"
3939
4040 let k_maxPriceImpact = "k_maxPriceImpact"
4141
4242 let k_maxPriceSpread = "k_maxPriceSpread"
4343
4444 let k_lastDataStr = "k_lastDataStr"
4545
4646 let k_lastMinuteId = "k_lastMinuteId"
4747
4848 let k_twapDataLastCumulativePrice = "k_twapDataLastCumulativePrice"
4949
5050 let k_twapDataLastPrice = "k_twapDataLastPrice"
5151
5252 let k_twapDataPreviousMinuteId = "k_twapDataPreviousMinuteId"
5353
5454 let k_latestLongCumulativePremiumFraction = "k_latestLongPremiumFraction"
5555
5656 let k_latestShortCumulativePremiumFraction = "k_latestShortPremiumFraction"
5757
5858 let k_nextFundingBlock = "k_nextFundingBlockMinTimestamp"
5959
6060 let k_longFundingRate = "k_longFundingRate"
6161
6262 let k_shortFundingRate = "k_shortFundingRate"
6363
6464 let k_quoteAssetReserve = "k_qtAstR"
6565
6666 let k_baseAssetReserve = "k_bsAstR"
6767
6868 let k_totalPositionSize = "k_totalPositionSize"
6969
7070 let k_totalLongPositionSize = "k_totalLongPositionSize"
7171
7272 let k_totalShortPositionSize = "k_totalShortPositionSize"
7373
7474 let k_cumulativeNotional = "k_cumulativeNotional"
7575
7676 let k_openInterestNotional = "k_openInterestNotional"
7777
7878 let k_coordinatorAddress = "k_coordinatorAddress"
7979
8080 let k_insurance_address = "k_insurance_address"
8181
8282 let k_admin_address = "k_admin_address"
8383
8484 let k_admin_public_key = "k_admin_public_key"
8585
8686 let k_quote_asset = "k_quote_asset"
8787
8888 let k_quote_staking = "k_quote_staking"
8989
9090 let k_staking_address = "k_staking_address"
9191
9292 let k_miner_address = "k_miner_address"
9393
9494 let k_orders_address = "k_orders_address"
9595
96+let k_referral_address = "k_referral_address"
97+
9698 func coordinator () = valueOrErrorMessage(addressFromString(getStringValue(this, k_coordinatorAddress)), "Coordinator not set")
9799
98100
99101 func adminAddress () = addressFromString(getStringValue(coordinator(), k_admin_address))
100102
101103
102104 func adminPublicKey () = fromBase58String(getStringValue(coordinator(), k_admin_public_key))
103105
104106
105107 func quoteAsset () = fromBase58String(getStringValue(coordinator(), k_quote_asset))
106108
107109
108110 func quoteAssetStaking () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_quote_staking)), "Quote asset staking not set")
109111
110112
111113 func stakingAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_staking_address)), "Staking not set")
112114
113115
114116 func insuranceAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_insurance_address)), "Insurance not set")
115117
116118
117119 func minerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_miner_address)), "Miner not set")
118120
119121
120122 func ordersAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_orders_address)), "Orders not set")
123+
124+
125+func referralAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_referral_address)), "Referral not set")
121126
122127
123128 let DIR_LONG = 1
124129
125130 let DIR_SHORT = 2
126131
127132 let TWAP_INTERVAL = 15
128133
129134 let ORACLE_INTERVAL = 15
130135
131136 let SECONDS = 1000
132137
133138 let DECIMAL_UNIT = (1 * (((((10 * 10) * 10) * 10) * 10) * 10))
134139
135140 let ONE_DAY = (86400 * DECIMAL_UNIT)
136141
137142 let ALL_FEES = 100
138143
139144 let PNL_OPTION_SPOT = 1
140145
141146 let PNL_OPTION_ORACLE = 2
142147
143148 func s (_x) = (toString(_x) + ",")
144149
145150
146151 func divd (_x,_y) = fraction(_x, DECIMAL_UNIT, _y, HALFEVEN)
147152
148153
149154 func muld (_x,_y) = fraction(_x, _y, DECIMAL_UNIT, HALFEVEN)
150155
151156
152157 func abs (_x) = if ((_x > 0))
153158 then _x
154159 else -(_x)
155160
156161
157162 func vmax (_x,_y) = if ((_x >= _y))
158163 then _x
159164 else _y
160165
161166
162167 func toCompositeKey (_key,_address) = ((_key + "_") + _address)
163168
164169
165170 func listToStr (_list) = {
166171 func _join (accumulator,val) = ((accumulator + val) + ",")
167172
168173 let newListStr = {
169174 let $l = _list
170175 let $s = size($l)
171176 let $acc0 = ""
172177 func $f0_1 ($a,$i) = if (($i >= $s))
173178 then $a
174179 else _join($a, $l[$i])
175180
176181 func $f0_2 ($a,$i) = if (($i >= $s))
177182 then $a
178183 else throw("List size exceeds 20")
179184
180185 $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)
181186 }
182187 let newListStrU = dropRight(newListStr, 1)
183188 let newListStrR = if ((take(newListStrU, 1) == ","))
184189 then drop(newListStrU, 1)
185190 else newListStrU
186191 newListStrR
187192 }
188193
189194
190195 func strToList (_str) = split(_str, ",")
191196
192197
193198 func pushToQueue (_list,_maxSize,_value) = if ((size(_list) > _maxSize))
194199 then (removeByIndex(_list, 0) :+ _value)
195200 else (_list :+ _value)
196201
197202
198203 func int (k) = valueOrErrorMessage(getInteger(this, k), ("no value for " + k))
199204
200205
201206 func cbalance () = int(k_balance)
202207
203208
204209 func fee () = int(k_fee)
205210
206211
207212 func initMarginRatio () = int(k_initMarginRatio)
208213
209214
210215 func qtAstR () = int(k_quoteAssetReserve)
211216
212217
213218 func bsAstR () = int(k_baseAssetReserve)
214219
215220
216221 func totalPositionSize () = int(k_totalPositionSize)
217222
218223
219224 func cumulativeNotional () = int(k_cumulativeNotional)
220225
221226
222227 func openInterestNotional () = int(k_openInterestNotional)
223228
224229
225230 func nextFundingBlockTimestamp () = int(k_nextFundingBlock)
226231
227232
228233 func fundingPeriodRaw () = int(k_fundingPeriod)
229234
230235
231236 func fundingPeriodDecimal () = (fundingPeriodRaw() * DECIMAL_UNIT)
232237
233238
234239 func fundingPeriodSeconds () = (fundingPeriodRaw() * SECONDS)
235240
236241
237242 func maintenanceMarginRatio () = int(k_maintenanceMarginRatio)
238243
239244
240245 func liquidationFeeRatio () = int(k_liquidationFeeRatio)
241246
242247
243248 func partialLiquidationRatio () = int(k_partialLiquidationRatio)
244249
245250
246251 func spreadLimit () = int(k_spreadLimit)
247252
248253
249254 func maxPriceImpact () = int(k_maxPriceImpact)
250255
251256
252257 func maxPriceSpread () = int(k_maxPriceSpread)
253258
254259
255260 func latestLongCumulativePremiumFraction () = int(k_latestLongCumulativePremiumFraction)
256261
257262
258263 func latestShortCumulativePremiumFraction () = int(k_latestShortCumulativePremiumFraction)
259264
260265
261266 func totalShortPositionSize () = int(k_totalShortPositionSize)
262267
263268
264269 func totalLongPositionSize () = int(k_totalLongPositionSize)
265270
266271
267272 func getActualCaller (i) = valueOrElse(getString(ordersAddress(), "k_sender"), toString(i.caller))
268273
269274
270275 func requireMoreMarginRatio (_marginRatio,_baseMarginRatio,_largerThanOrEqualTo) = {
271276 let remainingMarginRatio = (_marginRatio - _baseMarginRatio)
272277 if (if (_largerThanOrEqualTo)
273278 then (0 > remainingMarginRatio)
274279 else false)
275280 then throw("Invalid margin")
276281 else if (if (!(_largerThanOrEqualTo))
277282 then (remainingMarginRatio >= 0)
278283 else false)
279284 then throw("Invalid margin")
280285 else true
281286 }
282287
283288
284289 func latestCumulativePremiumFraction (_positionSize) = if ((_positionSize == 0))
285290 then throw("Should not be called with _positionSize == 0")
286291 else if ((_positionSize > 0))
287292 then latestLongCumulativePremiumFraction()
288293 else latestShortCumulativePremiumFraction()
289294
290295
291296 func getPosition (_trader) = {
292297 let positionSizeOpt = getInteger(this, toCompositeKey(k_positionSize, _trader))
293298 match positionSizeOpt {
294299 case positionSize: Int =>
295300 $Tuple4(positionSize, getIntegerValue(this, toCompositeKey(k_positionMargin, _trader)), getIntegerValue(this, toCompositeKey(k_positionOpenNotional, _trader)), getIntegerValue(this, toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _trader)))
296301 case _ =>
297302 $Tuple4(0, 0, 0, 0)
298303 }
299304 }
300305
301306
302307 func requireOpenPosition (_trader) = if ((getPosition(_trader)._1 == 0))
303308 then throw("No open position")
304309 else true
305310
306311
307312 func initialized () = valueOrElse(getBoolean(this, k_initialized), false)
308313
309314
310315 func paused () = valueOrElse(getBoolean(this, k_paused), false)
311316
312317
313318 func updateReserve (_isAdd,_quoteAssetAmount,_baseAssetAmount) = if (_isAdd)
314319 then {
315320 let newBase = (bsAstR() - _baseAssetAmount)
316321 if ((0 >= newBase))
317322 then throw("Tx lead to base asset reserve <= 0, revert")
318323 else $Tuple4((qtAstR() + _quoteAssetAmount), newBase, (totalPositionSize() + _baseAssetAmount), (cumulativeNotional() + _quoteAssetAmount))
319324 }
320325 else {
321326 let newQuote = (qtAstR() - _quoteAssetAmount)
322327 if ((0 >= newQuote))
323328 then throw("Tx lead to base quote reserve <= 0, revert")
324329 else $Tuple4(newQuote, (bsAstR() + _baseAssetAmount), (totalPositionSize() - _baseAssetAmount), (cumulativeNotional() - _quoteAssetAmount))
325330 }
326331
327332
328333 func swapInput (_isAdd,_quoteAssetAmount) = {
329334 let _qtAstR = qtAstR()
330335 let _bsAstR = bsAstR()
331336 let k = muld(_qtAstR, _bsAstR)
332337 let quoteAssetReserveAfter = if (_isAdd)
333338 then (_qtAstR + _quoteAssetAmount)
334339 else (_qtAstR - _quoteAssetAmount)
335340 let baseAssetReserveAfter = divd(k, quoteAssetReserveAfter)
336341 let amountBaseAssetBoughtAbs = abs((baseAssetReserveAfter - _bsAstR))
337342 let amountBaseAssetBought = if (_isAdd)
338343 then amountBaseAssetBoughtAbs
339344 else -(amountBaseAssetBoughtAbs)
340- let $t01260512798 = updateReserve(_isAdd, _quoteAssetAmount, amountBaseAssetBoughtAbs)
341- let quoteAssetReserveAfter1 = $t01260512798._1
342- let baseAssetReserveAfter1 = $t01260512798._2
343- let totalPositionSizeAfter1 = $t01260512798._3
344- let cumulativeNotionalAfter1 = $t01260512798._4
345+ let $t01281613009 = updateReserve(_isAdd, _quoteAssetAmount, amountBaseAssetBoughtAbs)
346+ let quoteAssetReserveAfter1 = $t01281613009._1
347+ let baseAssetReserveAfter1 = $t01281613009._2
348+ let totalPositionSizeAfter1 = $t01281613009._3
349+ let cumulativeNotionalAfter1 = $t01281613009._4
345350 let priceBefore = divd(_qtAstR, _bsAstR)
346351 let marketPrice = divd(_quoteAssetAmount, amountBaseAssetBoughtAbs)
347352 let priceDiff = abs((priceBefore - marketPrice))
348353 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
349354 let maxPriceImpactValue = maxPriceImpact()
350355 if ((priceImpact > maxPriceImpactValue))
351356 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)))
352357 else $Tuple5(amountBaseAssetBought, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1, cumulativeNotionalAfter1)
353358 }
354359
355360
356361 func calcRemainMarginWithFundingPayment (_oldPositionSize,_oldPositionMargin,_oldPositionCumulativePremiumFraction,_marginDelta) = {
357362 let fundingPayment = if ((_oldPositionSize != 0))
358363 then {
359364 let _latestCumulativePremiumFraction = latestCumulativePremiumFraction(_oldPositionSize)
360365 muld((_latestCumulativePremiumFraction - _oldPositionCumulativePremiumFraction), _oldPositionSize)
361366 }
362367 else 0
363368 let signedMargin = ((_marginDelta - fundingPayment) + _oldPositionMargin)
364- let $t01428914416 = if ((0 > signedMargin))
369+ let $t01450014627 = if ((0 > signedMargin))
365370 then $Tuple2(0, abs(signedMargin))
366371 else $Tuple2(abs(signedMargin), 0)
367- let remainMargin = $t01428914416._1
368- let badDebt = $t01428914416._2
372+ let remainMargin = $t01450014627._1
373+ let badDebt = $t01450014627._2
369374 $Tuple3(remainMargin, badDebt, fundingPayment)
370375 }
371376
372377
373378 func swapOutputWithReserves (_isAdd,_baseAssetAmount,_checkMaxPriceImpact,_quoteAssetReserve,_baseAssetReserve) = {
374379 let priceBefore = divd(_quoteAssetReserve, _baseAssetReserve)
375380 if ((_baseAssetAmount == 0))
376381 then throw("Invalid base asset amount")
377382 else {
378383 let k = muld(_quoteAssetReserve, _baseAssetReserve)
379384 let baseAssetPoolAmountAfter = if (_isAdd)
380385 then (_baseAssetReserve + _baseAssetAmount)
381386 else (_baseAssetReserve - _baseAssetAmount)
382387 let quoteAssetAfter = divd(k, baseAssetPoolAmountAfter)
383388 let quoteAssetSold = abs((quoteAssetAfter - _quoteAssetReserve))
384389 let maxPriceImpactValue = maxPriceImpact()
385- let $t01539315586 = updateReserve(!(_isAdd), quoteAssetSold, _baseAssetAmount)
386- let quoteAssetReserveAfter1 = $t01539315586._1
387- let baseAssetReserveAfter1 = $t01539315586._2
388- let totalPositionSizeAfter1 = $t01539315586._3
389- let cumulativeNotionalAfter1 = $t01539315586._4
390+ let $t01560415797 = updateReserve(!(_isAdd), quoteAssetSold, _baseAssetAmount)
391+ let quoteAssetReserveAfter1 = $t01560415797._1
392+ let baseAssetReserveAfter1 = $t01560415797._2
393+ let totalPositionSizeAfter1 = $t01560415797._3
394+ let cumulativeNotionalAfter1 = $t01560415797._4
390395 let marketPrice = divd(quoteAssetSold, _baseAssetAmount)
391396 let priceDiff = abs((priceBefore - marketPrice))
392397 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
393398 if (if ((priceImpact > maxPriceImpactValue))
394399 then _checkMaxPriceImpact
395400 else false)
396401 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)))
397402 else $Tuple8(quoteAssetSold, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1, cumulativeNotionalAfter1, (totalLongPositionSize() - (if (_isAdd)
398403 then abs(_baseAssetAmount)
399404 else 0)), (totalShortPositionSize() - (if (!(_isAdd))
400405 then abs(_baseAssetAmount)
401406 else 0)), priceImpact)
402407 }
403408 }
404409
405410
406411 func swapOutput (_isAdd,_baseAssetAmount,_checkMaxPriceImpact) = swapOutputWithReserves(_isAdd, _baseAssetAmount, _checkMaxPriceImpact, qtAstR(), bsAstR())
407412
408413
409414 func getOracleTwapPrice () = {
410415 let oracle = valueOrErrorMessage(addressFromString(getStringValue(this, k_ora)), "")
411416 let priceKey = getStringValue(this, k_ora_key)
412417 let blockKey = getStringValue(this, k_ora_block_key)
413418 let lastValue = valueOrErrorMessage(getInteger(oracle, priceKey), ((("Can not get oracle price. Oracle: " + toString(oracle)) + " key: ") + priceKey))
414419 lastValue
415420 }
416421
417422
418423 func requireNotOverSpreadLimit (_quoteAssetReserve,_baseAssetReserve) = {
419424 let oraclePrice = getOracleTwapPrice()
420425 let priceAfter = divd(_quoteAssetReserve, _baseAssetReserve)
421426 let averagePrice = divd((oraclePrice + priceAfter), (2 * DECIMAL_UNIT))
422427 let absPriceDiff = divd(abs((oraclePrice - priceAfter)), averagePrice)
423428 if ((absPriceDiff > maxPriceSpread()))
424429 then throw(((("Price spread " + toString(absPriceDiff)) + " > max price spread ") + toString(maxPriceSpread())))
425430 else true
426431 }
427432
428433
429434 func getSpotPrice () = {
430435 let _quoteAssetReserve = qtAstR()
431436 let _baseAssetReserve = bsAstR()
432437 divd(_quoteAssetReserve, _baseAssetReserve)
433438 }
434439
435440
436441 func isOverFluctuationLimit () = {
437442 let oraclePrice = getOracleTwapPrice()
438443 let currentPrice = getSpotPrice()
439444 (divd(abs((oraclePrice - currentPrice)), oraclePrice) > spreadLimit())
440445 }
441446
442447
443448 func getPositionAdjustedOpenNotional (_positionSize,_option,_quoteAssetReserve,_baseAssetReserve) = {
444449 let positionSizeAbs = abs(_positionSize)
445450 let isShort = (0 > _positionSize)
446451 let positionNotional = if ((_option == PNL_OPTION_SPOT))
447452 then {
448- let $t01880418975 = swapOutputWithReserves(!(isShort), positionSizeAbs, false, _quoteAssetReserve, _baseAssetReserve)
449- let outPositionNotional = $t01880418975._1
450- let x1 = $t01880418975._2
451- let x2 = $t01880418975._3
452- let x3 = $t01880418975._4
453+ let $t01901519186 = swapOutputWithReserves(!(isShort), positionSizeAbs, false, _quoteAssetReserve, _baseAssetReserve)
454+ let outPositionNotional = $t01901519186._1
455+ let x1 = $t01901519186._2
456+ let x2 = $t01901519186._3
457+ let x3 = $t01901519186._4
453458 outPositionNotional
454459 }
455460 else muld(positionSizeAbs, getOracleTwapPrice())
456461 positionNotional
457462 }
458463
459464
465+func getPositionNotionalAndUnrealizedPnlByValues (_positionSize,_positionOpenNotional,_quoteAssetReserve,_baseAssetReserve,_option) = if ((_positionSize == 0))
466+ then throw("Invalid position size")
467+ else {
468+ let isShort = (0 > _positionSize)
469+ let positionNotional = getPositionAdjustedOpenNotional(_positionSize, _option, _quoteAssetReserve, _baseAssetReserve)
470+ let unrealizedPnl = if (isShort)
471+ then (_positionOpenNotional - positionNotional)
472+ else (positionNotional - _positionOpenNotional)
473+ $Tuple2(positionNotional, unrealizedPnl)
474+ }
475+
476+
460477 func getPositionNotionalAndUnrealizedPnl (_trader,_option) = {
461- let $t01936919497 = getPosition(_trader)
462- let positionSize = $t01936919497._1
463- let positionMargin = $t01936919497._2
464- let positionOpenNotional = $t01936919497._3
465- let positionLstUpdCPF = $t01936919497._4
466- if ((positionSize == 0))
467- then throw("Invalid position size")
468- else {
469- let isShort = (0 > positionSize)
470- let positionNotional = getPositionAdjustedOpenNotional(positionSize, _option, qtAstR(), bsAstR())
471- let unrealizedPnl = if (isShort)
472- then (positionOpenNotional - positionNotional)
473- else (positionNotional - positionOpenNotional)
474- $Tuple2(positionNotional, unrealizedPnl)
475- }
478+ let $t02050320631 = getPosition(_trader)
479+ let positionSize = $t02050320631._1
480+ let positionMargin = $t02050320631._2
481+ let positionOpenNotional = $t02050320631._3
482+ let positionLstUpdCPF = $t02050320631._4
483+ getPositionNotionalAndUnrealizedPnlByValues(positionSize, positionOpenNotional, qtAstR(), bsAstR(), _option)
476484 }
477485
478486
479487 func calcMarginRatio (_remainMargin,_badDebt,_positionNotional) = divd((_remainMargin - _badDebt), _positionNotional)
480488
481489
482490 func getMarginRatioByOption (_trader,_option) = {
483- let $t02033020441 = getPosition(_trader)
484- let positionSize = $t02033020441._1
485- let positionMargin = $t02033020441._2
486- let pon = $t02033020441._3
487- let positionLstUpdCPF = $t02033020441._4
488- let $t02044720540 = getPositionNotionalAndUnrealizedPnl(_trader, _option)
489- let positionNotional = $t02044720540._1
490- let unrealizedPnl = $t02044720540._2
491- let $t02054520711 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
492- let remainMargin = $t02054520711._1
493- let badDebt = $t02054520711._2
491+ let $t02111221223 = getPosition(_trader)
492+ let positionSize = $t02111221223._1
493+ let positionMargin = $t02111221223._2
494+ let pon = $t02111221223._3
495+ let positionLstUpdCPF = $t02111221223._4
496+ let $t02122921322 = getPositionNotionalAndUnrealizedPnl(_trader, _option)
497+ let positionNotional = $t02122921322._1
498+ let unrealizedPnl = $t02122921322._2
499+ let $t02132721493 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
500+ let remainMargin = $t02132721493._1
501+ let badDebt = $t02132721493._2
494502 calcMarginRatio(remainMargin, badDebt, positionNotional)
495503 }
496504
497505
498506 func getMarginRatio (_trader) = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
499507
500508
501509 func getPartialLiquidationAmount (_trader,_positionSize) = {
502510 let maximumRatio = vmax(partialLiquidationRatio(), (DECIMAL_UNIT - divd(getMarginRatio(_trader), maintenanceMarginRatio())))
503511 let maxExchangedPositionSize = muld(abs(_positionSize), maximumRatio)
504512 let swapResult = swapOutput((_positionSize > 0), maxExchangedPositionSize, false)
505513 let maxExchangedQuoteAssetAmount = swapResult._1
506514 let priceImpact = swapResult._8
507515 if ((maxPriceImpact() > priceImpact))
508516 then maxExchangedQuoteAssetAmount
509517 else {
510518 let exchangedPositionSize = muld(abs(_positionSize), partialLiquidationRatio())
511519 let exchangedQuoteAssetAmount = swapOutput((_positionSize > 0), exchangedPositionSize, false)._1
512520 exchangedQuoteAssetAmount
513521 }
514522 }
515523
516524
517525 func internalClosePosition (_trader,_checkMaxPriceImpact) = {
518- let $t02189322021 = getPosition(_trader)
519- let positionSize = $t02189322021._1
520- let positionMargin = $t02189322021._2
521- let positionOpenNotional = $t02189322021._3
522- let positionLstUpdCPF = $t02189322021._4
526+ let $t02272622854 = getPosition(_trader)
527+ let positionSize = $t02272622854._1
528+ let positionMargin = $t02272622854._2
529+ let positionOpenNotional = $t02272622854._3
530+ let positionLstUpdCPF = $t02272622854._4
523531 let unrealizedPnl = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)._2
524- let $t02211622284 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
525- let remainMargin = $t02211622284._1
526- let badDebt = $t02211622284._2
532+ let $t02294923117 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
533+ let remainMargin = $t02294923117._1
534+ let badDebt = $t02294923117._2
527535 let exchangedPositionSize = -(positionSize)
528536 let realizedPnl = unrealizedPnl
529537 let marginToVault = -(remainMargin)
530- let $t02241122722 = swapOutput((positionSize > 0), abs(positionSize), _checkMaxPriceImpact)
531- let exchangedQuoteAssetAmount = $t02241122722._1
532- let quoteAssetReserveAfter = $t02241122722._2
533- let baseAssetReserveAfter = $t02241122722._3
534- let totalPositionSizeAfter = $t02241122722._4
535- let cumulativeNotionalAfter = $t02241122722._5
536- let totalLongAfter = $t02241122722._6
537- let totalShortAfter = $t02241122722._7
538+ let $t02324423555 = swapOutput((positionSize > 0), abs(positionSize), _checkMaxPriceImpact)
539+ let exchangedQuoteAssetAmount = $t02324423555._1
540+ let quoteAssetReserveAfter = $t02324423555._2
541+ let baseAssetReserveAfter = $t02324423555._3
542+ let totalPositionSizeAfter = $t02324423555._4
543+ let cumulativeNotionalAfter = $t02324423555._5
544+ let totalLongAfter = $t02324423555._6
545+ let totalShortAfter = $t02324423555._7
538546 let openInterestNotionalAfter = (openInterestNotional() - positionOpenNotional)
539547 $Tuple12(exchangedPositionSize, badDebt, realizedPnl, marginToVault, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, openInterestNotionalAfter, exchangedQuoteAssetAmount, totalLongAfter, totalShortAfter)
540548 }
541549
542550
543551 func getTwapSpotPrice () = {
544552 let minuteId = ((lastBlock.timestamp / 1000) / 60)
545553 let startMinuteId = (minuteId - TWAP_INTERVAL)
546554 let listStr = valueOrElse(getString(this, k_lastDataStr), "")
547555 let list = split(listStr, ",")
548556 func filterFn (accumulator,next) = if ((startMinuteId >= parseIntValue(next)))
549557 then (accumulator :+ parseIntValue(next))
550558 else accumulator
551559
552560 let listF = {
553561 let $l = list
554562 let $s = size($l)
555563 let $acc0 = nil
556564 func $f0_1 ($a,$i) = if (($i >= $s))
557565 then $a
558566 else filterFn($a, $l[$i])
559567
560568 func $f0_2 ($a,$i) = if (($i >= $s))
561569 then $a
562570 else throw("List size exceeds 20")
563571
564572 $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)
565573 }
566574 let maxIndex = if ((size(listF) > 0))
567575 then max(listF)
568576 else parseIntValue(list[0])
569577 let lastMinuteId = valueOrElse(getInteger(this, k_lastMinuteId), 0)
570578 let endLastCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(lastMinuteId))), 0)
571579 let endLastPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(lastMinuteId))), 0)
572580 let nowCumulativePrice = (endLastCumulativePrice + ((minuteId - lastMinuteId) * endLastPrice))
573581 let startLastCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(maxIndex))), 0)
574582 let startLastPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(maxIndex))), 0)
575583 let startCumulativePrice = (startLastCumulativePrice + ((startMinuteId - maxIndex) * startLastPrice))
576584 ((nowCumulativePrice - startCumulativePrice) / TWAP_INTERVAL)
585+ }
586+
587+
588+func getPegAdjustCost (_price) = {
589+ let _positionSize = totalPositionSize()
590+ let direction = (_positionSize > 0)
591+ let currentNetMarketValue = swapOutput(direction, abs(_positionSize), false)._1
592+ let baseAssetReserve = bsAstR()
593+ let newQuoteAssetReserve = muld(baseAssetReserve, _price)
594+ let cost = getPositionNotionalAndUnrealizedPnlByValues(_positionSize, currentNetMarketValue, newQuoteAssetReserve, baseAssetReserve, PNL_OPTION_SPOT)._2
595+ $Tuple2(newQuoteAssetReserve, cost)
577596 }
578597
579598
580599 func updateSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread) = [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)]
581600
582601
583602 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)]
584603
585604
586605 func updatePosition (_address,_size,_margin,_openNotional,_latestCumulativePremiumFraction) = [IntegerEntry(toCompositeKey(k_positionSize, _address), _size), IntegerEntry(toCompositeKey(k_positionMargin, _address), _margin), IntegerEntry(toCompositeKey(k_positionOpenNotional, _address), _openNotional), IntegerEntry(toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _address), _latestCumulativePremiumFraction)]
587606
588607
589608 func appendTwap (price) = {
590609 let minuteId = ((lastBlock.timestamp / 1000) / 60)
591610 let previousMinuteId = valueOrElse(getInteger(this, k_lastMinuteId), 0)
592611 if ((previousMinuteId > minuteId))
593612 then throw("TWAP out-of-order")
594613 else {
595614 let lastMinuteId = if ((previousMinuteId == 0))
596615 then minuteId
597616 else previousMinuteId
598617 if ((minuteId > previousMinuteId))
599618 then {
600619 let prevCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(previousMinuteId))), 0)
601620 let prevPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(previousMinuteId))), price)
602621 let lastCumulativePrice = (prevCumulativePrice + ((minuteId - lastMinuteId) * prevPrice))
603622 let list = pushToQueue(strToList(valueOrElse(getString(this, k_lastDataStr), "")), TWAP_INTERVAL, toString(minuteId))
604623 [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))]
605624 }
606625 else {
607626 let twapDataPreviousMinuteId = valueOrElse(getInteger(this, toCompositeKey(k_twapDataPreviousMinuteId, toString(minuteId))), 0)
608627 let prevCumulativePrice = valueOrElse(getInteger(this, toCompositeKey(k_twapDataLastCumulativePrice, toString(twapDataPreviousMinuteId))), 0)
609628 let prevPrice = valueOrElse(getInteger(this, toCompositeKey(k_twapDataLastPrice, toString(twapDataPreviousMinuteId))), price)
610629 let lastCumulativePrice = (prevCumulativePrice + ((minuteId - twapDataPreviousMinuteId) * prevPrice))
611630 [IntegerEntry(toCompositeKey(k_twapDataLastCumulativePrice, toString(minuteId)), lastCumulativePrice), IntegerEntry(toCompositeKey(k_twapDataLastPrice, toString(minuteId)), price)]
612631 }
613632 }
614633 }
615634
616635
617636 func updateAmmReserves (_qtAstR,_bsAstR) = [IntegerEntry(k_quoteAssetReserve, _qtAstR), IntegerEntry(k_baseAssetReserve, _bsAstR)]
618637
619638
620639 func updateAmm (_qtAstR,_bsAstR,_totalPositionSizeAfter,_cumulativeNotionalAfter,_openInterestNotional,_totalLongPositionSize,_totalShortPositionSize) = if (((_totalLongPositionSize - _totalShortPositionSize) != _totalPositionSizeAfter))
621640 then throw(((((("Invalid AMM state data: " + toString(_totalLongPositionSize)) + " + ") + toString(_totalShortPositionSize)) + " != ") + toString(_totalPositionSizeAfter)))
622641 else ((updateAmmReserves(_qtAstR, _bsAstR) ++ [IntegerEntry(k_totalPositionSize, _totalPositionSizeAfter), IntegerEntry(k_cumulativeNotional, _cumulativeNotionalAfter), IntegerEntry(k_openInterestNotional, _openInterestNotional), IntegerEntry(k_totalLongPositionSize, _totalLongPositionSize), IntegerEntry(k_totalShortPositionSize, _totalShortPositionSize)]) ++ appendTwap(divd(_qtAstR, _bsAstR)))
623642
624643
625644 func deletePosition (_address) = [DeleteEntry(toCompositeKey(k_positionSize, _address)), DeleteEntry(toCompositeKey(k_positionMargin, _address)), DeleteEntry(toCompositeKey(k_positionOpenNotional, _address)), DeleteEntry(toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _address)), IntegerEntry(toCompositeKey(k_positionClosedDate, _address), lastBlock.timestamp)]
626645
627646
628647 func withdraw (_address,_amount) = {
629648 let balance = assetBalance(this, quoteAsset())
630649 if ((_amount > balance))
631650 then throw(((("Unable to withdraw " + toString(_amount)) + " from contract balance ") + toString(balance)))
632651 else [ScriptTransfer(_address, _amount, quoteAsset())]
633652 }
634653
635654
636655 func updateBalance (i) = if ((0 > i))
637656 then throw("Balance")
638657 else [IntegerEntry(k_balance, i)]
639658
640659
641660 func transferFee (i) = [ScriptTransfer(stakingAddress(), i, quoteAsset())]
642661
643662
644663 @Callable(i)
645664 func pause () = if ((i.caller != adminAddress()))
646665 then throw("Invalid togglePause params")
647666 else [BooleanEntry(k_paused, true)]
648667
649668
650669
651670 @Callable(i)
652671 func unpause () = if ((i.caller != adminAddress()))
653672 then throw("Invalid togglePause params")
654673 else [BooleanEntry(k_paused, false)]
655674
656675
657676
658677 @Callable(i)
659678 func addLiquidity (_quoteAssetAmount) = if (if ((i.caller != adminAddress()))
660679 then true
661680 else (0 >= _quoteAssetAmount))
662681 then throw("Invalid addLiquidity params")
663682 else {
664683 let _qtAstR = qtAstR()
665684 let _bsAstR = bsAstR()
666685 let price = divd(_qtAstR, _bsAstR)
667686 let baseAssetAmountToAdd = divd(_quoteAssetAmount, price)
668687 let qtAstRAfter = (_qtAstR + _quoteAssetAmount)
669688 let bsAstRAfter = (_bsAstR + baseAssetAmountToAdd)
670689 updateAmmReserves(qtAstRAfter, bsAstRAfter)
671690 }
672691
673692
674693
675694 @Callable(i)
676695 func removeLiquidity (_quoteAssetAmount) = if (if ((i.caller != adminAddress()))
677696 then true
678697 else (0 >= _quoteAssetAmount))
679698 then throw("Invalid removeLiquidity params")
680699 else {
681700 let _qtAstR = qtAstR()
682701 let _bsAstR = bsAstR()
683702 let price = divd(_qtAstR, _bsAstR)
684703 let baseAssetAmountToRemove = divd(_quoteAssetAmount, price)
685704 let qtAstRAfter = (_qtAstR - _quoteAssetAmount)
686705 let bsAstRAfter = (_bsAstR - baseAssetAmountToRemove)
687706 updateAmmReserves(qtAstRAfter, bsAstRAfter)
688707 }
689708
690709
691710
692711 @Callable(i)
693712 func changeSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread) = if ((i.caller != adminAddress()))
694713 then throw("Invalid changeSettings params")
695714 else updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread)
696715
697716
698717
699718 @Callable(i)
700719 func initialize (_qtAstR,_bsAstR,_fundingPeriod,_initMarginRatio,_mmr,_liquidationFeeRatio,_fee,_oracle,_oracleKey,_coordinator,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread) = if (if (if (if (if (if (if (if (if (if (if (if ((0 >= _qtAstR))
701720 then true
702721 else (0 >= _bsAstR))
703722 then true
704723 else (0 >= _fundingPeriod))
705724 then true
706725 else (0 >= _initMarginRatio))
707726 then true
708727 else (0 >= _mmr))
709728 then true
710729 else (0 >= _liquidationFeeRatio))
711730 then true
712731 else (0 >= _fee))
713732 then true
714733 else (0 >= _spreadLimit))
715734 then true
716735 else (0 >= _maxPriceImpact))
717736 then true
718737 else (0 >= _partialLiquidationRatio))
719738 then true
720739 else (0 >= _maxPriceSpread))
721740 then true
722741 else initialized())
723742 then throw("Invalid initialize parameters")
724743 else ((((updateAmm(_qtAstR, _bsAstR, 0, 0, 0, 0, 0) ++ updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread)) ++ updateFunding((lastBlock.timestamp + _fundingPeriod), 0, 0, 0, 0)) ++ updateBalance(0)) ++ [BooleanEntry(k_initialized, true), StringEntry(k_ora, _oracle), StringEntry(k_ora_key, _oracleKey), StringEntry(k_coordinatorAddress, _coordinator)])
725744
726745
727746
728747 @Callable(i)
729748 func setInitMarginRatio (_initMarginRatio) = if (if ((0 >= _initMarginRatio))
730749 then true
731750 else !(initialized()))
732751 then throw("Invalid setInitMarginRatio parameters")
733752 else updateSettings(_initMarginRatio, maintenanceMarginRatio(), liquidationFeeRatio(), fundingPeriodRaw(), fee(), spreadLimit(), maxPriceImpact(), partialLiquidationRatio(), maxPriceSpread())
734753
735754
736755
737756 @Callable(i)
738757 func decreasePosition (_amount,_leverage,_minBaseAssetAmount) = if (if (if (if (if ((0 >= _amount))
739758 then true
740759 else !(initialized()))
741760 then true
742761 else !(requireMoreMarginRatio(divd(DECIMAL_UNIT, _leverage), initMarginRatio(), true)))
743762 then true
744763 else !(requireOpenPosition(toString(i.caller))))
745764 then true
746765 else paused())
747766 then throw("Invalid decreasePosition parameters")
748767 else {
749- let $t03470134853 = getPosition(toString(i.caller))
750- let oldPositionSize = $t03470134853._1
751- let oldPositionMargin = $t03470134853._2
752- let oldPositionOpenNotional = $t03470134853._3
753- let oldPositionLstUpdCPF = $t03470134853._4
768+ let $t03607336225 = getPosition(toString(i.caller))
769+ let oldPositionSize = $t03607336225._1
770+ let oldPositionMargin = $t03607336225._2
771+ let oldPositionOpenNotional = $t03607336225._3
772+ let oldPositionLstUpdCPF = $t03607336225._4
754773 let _direction = if ((oldPositionSize > 0))
755774 then DIR_SHORT
756775 else DIR_LONG
757776 let isAdd = (_direction == DIR_LONG)
758777 let openNotional = muld(_amount, _leverage)
759- let $t03502635142 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
760- let oldPositionNotional = $t03502635142._1
761- let unrealizedPnl = $t03502635142._2
762- let $t03514837697 = if ((oldPositionNotional > openNotional))
778+ let $t03639836514 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
779+ let oldPositionNotional = $t03639836514._1
780+ let unrealizedPnl = $t03639836514._2
781+ let $t03652039069 = if ((oldPositionNotional > openNotional))
763782 then {
764- let $t03552535744 = swapInput(isAdd, openNotional)
765- let exchangedPositionSize = $t03552535744._1
766- let quoteAssetReserveAfter = $t03552535744._2
767- let baseAssetReserveAfter = $t03552535744._3
768- let totalPositionSizeAfter = $t03552535744._4
769- let cumulativeNotionalAfter = $t03552535744._5
783+ let $t03689737116 = swapInput(isAdd, openNotional)
784+ let exchangedPositionSize = $t03689737116._1
785+ let quoteAssetReserveAfter = $t03689737116._2
786+ let baseAssetReserveAfter = $t03689737116._3
787+ let totalPositionSizeAfter = $t03689737116._4
788+ let cumulativeNotionalAfter = $t03689737116._5
770789 let exchangedPositionSizeAbs = abs(exchangedPositionSize)
771790 if (if ((_minBaseAssetAmount != 0))
772791 then (_minBaseAssetAmount > exchangedPositionSizeAbs)
773792 else false)
774793 then throw(((("Too little base asset exchanged, got " + toString(exchangedPositionSizeAbs)) + " expected ") + toString(_minBaseAssetAmount)))
775794 else {
776795 let realizedPnl = divd(muld(unrealizedPnl, exchangedPositionSizeAbs), abs(oldPositionSize))
777- let $t03618136426 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl)
778- let remainMargin = $t03618136426._1
779- let badDebt = $t03618136426._2
780- let fundingPayment = $t03618136426._3
796+ let $t03755337798 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl)
797+ let remainMargin = $t03755337798._1
798+ let badDebt = $t03755337798._2
799+ let fundingPayment = $t03755337798._3
781800 let exchangedQuoteAssetAmount = openNotional
782801 let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
783802 let remainOpenNotional = if ((oldPositionSize > 0))
784803 then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
785804 else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
786805 let newPositionSize = (oldPositionSize + exchangedPositionSize)
787806 $Tuple11(newPositionSize, remainMargin, abs(remainOpenNotional), latestCumulativePremiumFraction(newPositionSize), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, (openInterestNotional() - openNotional), (totalLongPositionSize() - (if ((newPositionSize > 0))
788807 then abs(exchangedPositionSize)
789808 else 0)), (totalShortPositionSize() - (if ((0 > newPositionSize))
790809 then abs(exchangedPositionSize)
791810 else 0)))
792811 }
793812 }
794813 else throw("Close position first")
795- let newPositionSize = $t03514837697._1
796- let newPositionRemainMargin = $t03514837697._2
797- let newPositionOpenNotional = $t03514837697._3
798- let newPositionLatestCPF = $t03514837697._4
799- let baseAssetReserveAfter = $t03514837697._5
800- let quoteAssetReserveAfter = $t03514837697._6
801- let totalPositionSizeAfter = $t03514837697._7
802- let cumulativeNotionalAfter = $t03514837697._8
803- let openInterestNotionalAfter = $t03514837697._9
804- let totalLongAfter = $t03514837697._10
805- let totalShortAfter = $t03514837697._11
814+ let newPositionSize = $t03652039069._1
815+ let newPositionRemainMargin = $t03652039069._2
816+ let newPositionOpenNotional = $t03652039069._3
817+ let newPositionLatestCPF = $t03652039069._4
818+ let baseAssetReserveAfter = $t03652039069._5
819+ let quoteAssetReserveAfter = $t03652039069._6
820+ let totalPositionSizeAfter = $t03652039069._7
821+ let cumulativeNotionalAfter = $t03652039069._8
822+ let openInterestNotionalAfter = $t03652039069._9
823+ let totalLongAfter = $t03652039069._10
824+ let totalShortAfter = $t03652039069._11
806825 let notifyNotional = invoke(minerAddress(), "notifyNotional", [toString(i.caller), newPositionOpenNotional], nil)
807826 if ((notifyNotional == notifyNotional))
808827 then (updatePosition(toString(i.caller), newPositionSize, newPositionRemainMargin, newPositionOpenNotional, newPositionLatestCPF) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter))
809828 else throw("Strict value is not equal to itself.")
810829 }
811830
812831
813832
814833 @Callable(i)
815-func increasePosition (_direction,_leverage,_minBaseAssetAmount) = {
834+func increasePosition (_direction,_leverage,_minBaseAssetAmount,_refLink) = {
816835 let _rawAmount = i.payments[0].amount
817836 if (if (if (if (if (if (if ((_direction != DIR_LONG))
818837 then (_direction != DIR_SHORT)
819838 else false)
820839 then true
821840 else (0 >= _rawAmount))
822841 then true
823842 else !(initialized()))
824843 then true
825844 else (i.payments[0].assetId != quoteAsset()))
826845 then true
827846 else !(requireMoreMarginRatio(divd(DECIMAL_UNIT, _leverage), initMarginRatio(), true)))
828847 then true
829848 else paused())
830849 then throw("Invalid increasePosition parameters")
831850 else {
832- let feeAmount = muld(_rawAmount, fee())
833- let _amount = (_rawAmount - feeAmount)
834- let $t03881538967 = getPosition(toString(i.caller))
835- let oldPositionSize = $t03881538967._1
836- let oldPositionMargin = $t03881538967._2
837- let oldPositionOpenNotional = $t03881538967._3
838- let oldPositionLstUpdCPF = $t03881538967._4
839- let isNewPosition = (oldPositionSize == 0)
840- let isSameDirection = if ((oldPositionSize > 0))
841- then (_direction == DIR_LONG)
842- else (_direction == DIR_SHORT)
843- let expandExisting = if (!(isNewPosition))
844- then isSameDirection
845- else false
846- let isAdd = (_direction == DIR_LONG)
847- let $t03925641824 = if (if (isNewPosition)
848- then true
849- else expandExisting)
851+ let _trader = toString(i.caller)
852+ let rawFeeAmount = muld(_rawAmount, fee())
853+ let referrerFeeAny = invoke(referralAddress(), "acceptPaymentWithLink", [_trader, _refLink], [AttachedPayment(quoteAsset(), rawFeeAmount)])
854+ if ((referrerFeeAny == referrerFeeAny))
850855 then {
851- let openNotional = muld(_amount, _leverage)
852- let $t03968039886 = swapInput(isAdd, openNotional)
853- let amountBaseAssetBought = $t03968039886._1
854- let quoteAssetReserveAfter = $t03968039886._2
855- let baseAssetReserveAfter = $t03968039886._3
856- let totalPositionSizeAfter = $t03968039886._4
857- let cumulativeNotionalAfter = $t03968039886._5
858- if (if ((_minBaseAssetAmount != 0))
859- then (_minBaseAssetAmount > abs(amountBaseAssetBought))
860- else false)
861- then throw(((("Limit error: " + toString(abs(amountBaseAssetBought))) + " < ") + toString(_minBaseAssetAmount)))
856+ let referrerFee = match referrerFeeAny {
857+ case x: Int =>
858+ x
859+ case _ =>
860+ throw("Invalid referrerFee")
861+ }
862+ let _amount = (_rawAmount - rawFeeAmount)
863+ let feeAmount = (rawFeeAmount - referrerFee)
864+ let $t04059840738 = getPosition(_trader)
865+ let oldPositionSize = $t04059840738._1
866+ let oldPositionMargin = $t04059840738._2
867+ let oldPositionOpenNotional = $t04059840738._3
868+ let oldPositionLstUpdCPF = $t04059840738._4
869+ let isNewPosition = (oldPositionSize == 0)
870+ let isSameDirection = if ((oldPositionSize > 0))
871+ then (_direction == DIR_LONG)
872+ else (_direction == DIR_SHORT)
873+ let expandExisting = if (!(isNewPosition))
874+ then isSameDirection
875+ else false
876+ let isAdd = (_direction == DIR_LONG)
877+ let $t04102743595 = if (if (isNewPosition)
878+ then true
879+ else expandExisting)
880+ then {
881+ let openNotional = muld(_amount, _leverage)
882+ let $t04145141657 = swapInput(isAdd, openNotional)
883+ let amountBaseAssetBought = $t04145141657._1
884+ let quoteAssetReserveAfter = $t04145141657._2
885+ let baseAssetReserveAfter = $t04145141657._3
886+ let totalPositionSizeAfter = $t04145141657._4
887+ let cumulativeNotionalAfter = $t04145141657._5
888+ if (if ((_minBaseAssetAmount != 0))
889+ then (_minBaseAssetAmount > abs(amountBaseAssetBought))
890+ else false)
891+ then throw(((("Limit error: " + toString(abs(amountBaseAssetBought))) + " < ") + toString(_minBaseAssetAmount)))
892+ else {
893+ let newPositionSize = (oldPositionSize + amountBaseAssetBought)
894+ let increaseMarginRequirement = divd(openNotional, _leverage)
895+ let $t04203842277 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, increaseMarginRequirement)
896+ let remainMargin = $t04203842277._1
897+ let x1 = $t04203842277._2
898+ let x2 = $t04203842277._3
899+ if (!(requireNotOverSpreadLimit(quoteAssetReserveAfter, baseAssetReserveAfter)))
900+ then throw("Over max spread limit")
901+ else $Tuple11(newPositionSize, remainMargin, (oldPositionOpenNotional + openNotional), latestCumulativePremiumFraction(newPositionSize), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, (openInterestNotional() + openNotional), (totalLongPositionSize() + (if ((newPositionSize > 0))
902+ then abs(amountBaseAssetBought)
903+ else 0)), (totalShortPositionSize() + (if ((0 > newPositionSize))
904+ then abs(amountBaseAssetBought)
905+ else 0)))
906+ }
907+ }
862908 else {
863- let newPositionSize = (oldPositionSize + amountBaseAssetBought)
864- let increaseMarginRequirement = divd(openNotional, _leverage)
865- let $t04026740506 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, increaseMarginRequirement)
866- let remainMargin = $t04026740506._1
867- let x1 = $t04026740506._2
868- let x2 = $t04026740506._3
869- if (!(requireNotOverSpreadLimit(quoteAssetReserveAfter, baseAssetReserveAfter)))
870- then throw("Over max spread limit")
871- else $Tuple11(newPositionSize, remainMargin, (oldPositionOpenNotional + openNotional), latestCumulativePremiumFraction(newPositionSize), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, (openInterestNotional() + openNotional), (totalLongPositionSize() + (if ((newPositionSize > 0))
872- then abs(amountBaseAssetBought)
873- else 0)), (totalShortPositionSize() + (if ((0 > newPositionSize))
874- then abs(amountBaseAssetBought)
875- else 0)))
909+ let openNotional = muld(_amount, _leverage)
910+ let $t04328843404 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
911+ let oldPositionNotional = $t04328843404._1
912+ let unrealizedPnl = $t04328843404._2
913+ if ((oldPositionNotional > openNotional))
914+ then throw("Use decreasePosition to decrease position size")
915+ else throw("Close position first")
876916 }
877- }
878- else {
879- let openNotional = muld(_amount, _leverage)
880- let $t04151741633 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
881- let oldPositionNotional = $t04151741633._1
882- let unrealizedPnl = $t04151741633._2
883- if ((oldPositionNotional > openNotional))
884- then throw("Use decreasePosition to decrease position size")
885- else throw("Close position first")
886- }
887- let newPositionSize = $t03925641824._1
888- let newPositionRemainMargin = $t03925641824._2
889- let newPositionOpenNotional = $t03925641824._3
890- let newPositionLatestCPF = $t03925641824._4
891- let baseAssetReserveAfter = $t03925641824._5
892- let quoteAssetReserveAfter = $t03925641824._6
893- let totalPositionSizeAfter = $t03925641824._7
894- let cumulativeNotionalAfter = $t03925641824._8
895- let openInterestNotionalAfter = $t03925641824._9
896- let totalLongAfter = $t03925641824._10
897- let totalShortAfter = $t03925641824._11
898- let feeToStakers = (feeAmount / 2)
899- let feeToInsurance = (feeAmount - feeToStakers)
900- let stake = invoke(quoteAssetStaking(), "lockNeutrinoSP", [toString(stakingAddress()), ALL_FEES], [AttachedPayment(quoteAsset(), _amount)])
901- if ((stake == stake))
902- then {
903- let depositInsurance = invoke(insuranceAddress(), "deposit", nil, [AttachedPayment(quoteAsset(), feeToInsurance)])
904- if ((depositInsurance == depositInsurance))
917+ let newPositionSize = $t04102743595._1
918+ let newPositionRemainMargin = $t04102743595._2
919+ let newPositionOpenNotional = $t04102743595._3
920+ let newPositionLatestCPF = $t04102743595._4
921+ let baseAssetReserveAfter = $t04102743595._5
922+ let quoteAssetReserveAfter = $t04102743595._6
923+ let totalPositionSizeAfter = $t04102743595._7
924+ let cumulativeNotionalAfter = $t04102743595._8
925+ let openInterestNotionalAfter = $t04102743595._9
926+ let totalLongAfter = $t04102743595._10
927+ let totalShortAfter = $t04102743595._11
928+ let feeToStakers = (feeAmount / 2)
929+ let feeToInsurance = (feeAmount - feeToStakers)
930+ let stake = invoke(quoteAssetStaking(), "lockNeutrinoSP", [toString(stakingAddress()), ALL_FEES], [AttachedPayment(quoteAsset(), _amount)])
931+ if ((stake == stake))
905932 then {
906- let notifyFee = invoke(minerAddress(), "notifyFees", [toString(i.caller), feeAmount], nil)
907- if ((notifyFee == notifyFee))
933+ let depositInsurance = invoke(insuranceAddress(), "deposit", nil, [AttachedPayment(quoteAsset(), feeToInsurance)])
934+ if ((depositInsurance == depositInsurance))
908935 then {
909- let notifyNotional = invoke(minerAddress(), "notifyNotional", [toString(i.caller), newPositionOpenNotional], nil)
910- if ((notifyNotional == notifyNotional))
911- then (((updatePosition(toString(i.caller), newPositionSize, newPositionRemainMargin, newPositionOpenNotional, newPositionLatestCPF) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter)) ++ transferFee(feeToStakers)) ++ updateBalance((cbalance() + _amount)))
936+ let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, feeAmount], nil)
937+ if ((notifyFee == notifyFee))
938+ then {
939+ let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
940+ if ((notifyNotional == notifyNotional))
941+ then (((updatePosition(_trader, newPositionSize, newPositionRemainMargin, newPositionOpenNotional, newPositionLatestCPF) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter)) ++ transferFee(feeToStakers)) ++ updateBalance((cbalance() + _amount)))
942+ else throw("Strict value is not equal to itself.")
943+ }
912944 else throw("Strict value is not equal to itself.")
913945 }
914946 else throw("Strict value is not equal to itself.")
915947 }
916948 else throw("Strict value is not equal to itself.")
917949 }
918950 else throw("Strict value is not equal to itself.")
919951 }
920952 }
921953
922954
923955
924956 @Callable(i)
925957 func addMargin () = {
926958 let _rawAmount = i.payments[0].amount
927959 if (if (if (if ((i.payments[0].assetId != quoteAsset()))
928960 then true
929961 else !(requireOpenPosition(toString(i.caller))))
930962 then true
931963 else !(initialized()))
932964 then true
933965 else paused())
934966 then throw("Invalid addMargin parameters")
935967 else {
936- let feeAmount = muld(_rawAmount, fee())
937- let _amount = (_rawAmount - feeAmount)
938- let $t04338043532 = getPosition(toString(i.caller))
939- let oldPositionSize = $t04338043532._1
940- let oldPositionMargin = $t04338043532._2
941- let oldPositionOpenNotional = $t04338043532._3
942- let oldPositionLstUpdCPF = $t04338043532._4
943- let feeToStakers = (feeAmount / 2)
944- let feeToInsurance = (feeAmount - feeToStakers)
945- let stake = invoke(quoteAssetStaking(), "lockNeutrinoSP", [toString(stakingAddress()), ALL_FEES], [AttachedPayment(quoteAsset(), _amount)])
946- if ((stake == stake))
968+ let _trader = toString(i.caller)
969+ let rawFeeAmount = muld(_rawAmount, fee())
970+ let referrerFeeAny = invoke(referralAddress(), "acceptPayment", [_trader], [AttachedPayment(quoteAsset(), rawFeeAmount)])
971+ if ((referrerFeeAny == referrerFeeAny))
947972 then {
948- let depositInsurance = invoke(insuranceAddress(), "deposit", nil, [AttachedPayment(quoteAsset(), feeToInsurance)])
949- if ((depositInsurance == depositInsurance))
973+ let referrerFee = match referrerFeeAny {
974+ case x: Int =>
975+ x
976+ case _ =>
977+ throw("Invalid referrerFee")
978+ }
979+ let feeAmount = (rawFeeAmount - referrerFee)
980+ let _amount = (_rawAmount - rawFeeAmount)
981+ let $t04548845628 = getPosition(_trader)
982+ let oldPositionSize = $t04548845628._1
983+ let oldPositionMargin = $t04548845628._2
984+ let oldPositionOpenNotional = $t04548845628._3
985+ let oldPositionLstUpdCPF = $t04548845628._4
986+ let feeToStakers = (feeAmount / 2)
987+ let feeToInsurance = (feeAmount - feeToStakers)
988+ let stake = invoke(quoteAssetStaking(), "lockNeutrinoSP", [toString(stakingAddress()), ALL_FEES], [AttachedPayment(quoteAsset(), _amount)])
989+ if ((stake == stake))
950990 then {
951- let notifyFee = invoke(minerAddress(), "notifyFees", [toString(i.caller), feeAmount], nil)
952- if ((notifyFee == notifyFee))
953- then ((updatePosition(toString(i.caller), oldPositionSize, (oldPositionMargin + _amount), oldPositionOpenNotional, oldPositionLstUpdCPF) ++ transferFee(feeToStakers)) ++ updateBalance((cbalance() + _amount)))
991+ let depositInsurance = invoke(insuranceAddress(), "deposit", nil, [AttachedPayment(quoteAsset(), feeToInsurance)])
992+ if ((depositInsurance == depositInsurance))
993+ then {
994+ let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, feeAmount], nil)
995+ if ((notifyFee == notifyFee))
996+ then ((updatePosition(_trader, oldPositionSize, (oldPositionMargin + _amount), oldPositionOpenNotional, oldPositionLstUpdCPF) ++ transferFee(feeToStakers)) ++ updateBalance((cbalance() + _amount)))
997+ else throw("Strict value is not equal to itself.")
998+ }
954999 else throw("Strict value is not equal to itself.")
9551000 }
9561001 else throw("Strict value is not equal to itself.")
9571002 }
9581003 else throw("Strict value is not equal to itself.")
9591004 }
9601005 }
9611006
9621007
9631008
9641009 @Callable(i)
9651010 func removeMargin (_amount) = if (if (if (if ((0 >= _amount))
9661011 then true
9671012 else !(requireOpenPosition(toString(i.caller))))
9681013 then true
9691014 else !(initialized()))
9701015 then true
9711016 else paused())
9721017 then throw("Invalid removeMargin parameters")
9731018 else {
974- let $t04458144733 = getPosition(toString(i.caller))
975- let oldPositionSize = $t04458144733._1
976- let oldPositionMargin = $t04458144733._2
977- let oldPositionOpenNotional = $t04458144733._3
978- let oldPositionLstUpdCPF = $t04458144733._4
1019+ let $t04665346805 = getPosition(toString(i.caller))
1020+ let oldPositionSize = $t04665346805._1
1021+ let oldPositionMargin = $t04665346805._2
1022+ let oldPositionOpenNotional = $t04665346805._3
1023+ let oldPositionLstUpdCPF = $t04665346805._4
9791024 let marginDelta = -(_amount)
980- let $t04477044949 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, marginDelta)
981- let remainMargin = $t04477044949._1
982- let badDebt = $t04477044949._2
1025+ let $t04684247021 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, marginDelta)
1026+ let remainMargin = $t04684247021._1
1027+ let badDebt = $t04684247021._2
9831028 if ((badDebt != 0))
9841029 then throw("Invalid removed margin amount")
9851030 else {
9861031 let marginRatio = calcMarginRatio(remainMargin, badDebt, oldPositionOpenNotional)
9871032 if (!(requireMoreMarginRatio(marginRatio, initMarginRatio(), true)))
9881033 then throw(((("Too much margin removed: " + toString(marginRatio)) + " < ") + toString(initMarginRatio())))
9891034 else {
9901035 let unstake = invoke(quoteAssetStaking(), "unlockNeutrino", [_amount, toBase58String(quoteAsset())], nil)
9911036 if ((unstake == unstake))
9921037 then ((updatePosition(toString(i.caller), oldPositionSize, remainMargin, oldPositionOpenNotional, latestCumulativePremiumFraction(oldPositionSize)) ++ withdraw(i.caller, _amount)) ++ updateBalance((cbalance() - _amount)))
9931038 else throw("Strict value is not equal to itself.")
9941039 }
9951040 }
9961041 }
9971042
9981043
9991044
10001045 @Callable(i)
10011046 func closePosition () = {
10021047 let caller = getActualCaller(i)
10031048 let callerAddress = valueOrErrorMessage(addressFromString(caller), "Invalid caller")
10041049 if (if (if (!(requireOpenPosition(caller)))
10051050 then true
10061051 else !(initialized()))
10071052 then true
10081053 else paused())
10091054 then throw("Invalid closePosition parameters")
10101055 else {
1011- let $t04615246529 = internalClosePosition(caller, true)
1012- let x1 = $t04615246529._1
1013- let positionBadDebt = $t04615246529._2
1014- let realizedPnl = $t04615246529._3
1015- let marginToVault = $t04615246529._4
1016- let quoteAssetReserveAfter = $t04615246529._5
1017- let baseAssetReserveAfter = $t04615246529._6
1018- let totalPositionSizeAfter = $t04615246529._7
1019- let cumulativeNotionalAfter = $t04615246529._8
1020- let openInterestNotionalAfter = $t04615246529._9
1021- let x2 = $t04615246529._10
1022- let totalLongAfter = $t04615246529._11
1023- let totalShortAfter = $t04615246529._12
1056+ let $t04822448601 = internalClosePosition(caller, true)
1057+ let x1 = $t04822448601._1
1058+ let positionBadDebt = $t04822448601._2
1059+ let realizedPnl = $t04822448601._3
1060+ let marginToVault = $t04822448601._4
1061+ let quoteAssetReserveAfter = $t04822448601._5
1062+ let baseAssetReserveAfter = $t04822448601._6
1063+ let totalPositionSizeAfter = $t04822448601._7
1064+ let cumulativeNotionalAfter = $t04822448601._8
1065+ let openInterestNotionalAfter = $t04822448601._9
1066+ let x2 = $t04822448601._10
1067+ let totalLongAfter = $t04822448601._11
1068+ let totalShortAfter = $t04822448601._12
10241069 if ((positionBadDebt > 0))
10251070 then throw("Unable to close position with bad debt")
10261071 else {
10271072 let withdrawAmount = abs(marginToVault)
10281073 let ammBalance = (cbalance() - withdrawAmount)
1029- let $t04673846880 = if ((0 > ammBalance))
1074+ let $t04881048952 = if ((0 > ammBalance))
10301075 then $Tuple2(0, abs(ammBalance))
10311076 else $Tuple2(ammBalance, 0)
1032- let ammNewBalance = $t04673846880._1
1033- let getFromInsurance = $t04673846880._2
1077+ let ammNewBalance = $t04881048952._1
1078+ let getFromInsurance = $t04881048952._2
10341079 let x = if ((getFromInsurance > 0))
10351080 then {
10361081 let withdrawInsurance = invoke(insuranceAddress(), "withdraw", [getFromInsurance], nil)
10371082 if ((withdrawInsurance == withdrawInsurance))
10381083 then nil
10391084 else throw("Strict value is not equal to itself.")
10401085 }
10411086 else nil
10421087 if ((x == x))
10431088 then {
10441089 let unstake = invoke(quoteAssetStaking(), "unlockNeutrino", [(withdrawAmount - getFromInsurance), toBase58String(quoteAsset())], nil)
10451090 if ((unstake == unstake))
10461091 then {
10471092 let notifyNotional = invoke(minerAddress(), "notifyNotional", [caller, 0], nil)
10481093 if ((notifyNotional == notifyNotional))
10491094 then (((deletePosition(caller) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter)) ++ withdraw(callerAddress, withdrawAmount)) ++ updateBalance(ammNewBalance))
10501095 else throw("Strict value is not equal to itself.")
10511096 }
10521097 else throw("Strict value is not equal to itself.")
10531098 }
10541099 else throw("Strict value is not equal to itself.")
10551100 }
10561101 }
10571102 }
10581103
10591104
10601105
10611106 @Callable(i)
10621107 func liquidate (_trader) = {
10631108 let spotMarginRatio = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
10641109 let marginRatio = if (isOverFluctuationLimit())
10651110 then {
10661111 let oracleMarginRatio = getMarginRatioByOption(_trader, PNL_OPTION_ORACLE)
10671112 vmax(spotMarginRatio, oracleMarginRatio)
10681113 }
10691114 else spotMarginRatio
10701115 if (if (if (if (!(requireMoreMarginRatio(marginRatio, maintenanceMarginRatio(), false)))
10711116 then true
10721117 else !(requireOpenPosition(_trader)))
10731118 then true
10741119 else !(initialized()))
10751120 then true
10761121 else paused())
10771122 then throw("Unable to liquidate")
10781123 else if (if (if ((spotMarginRatio > liquidationFeeRatio()))
10791124 then (partialLiquidationRatio() > 0)
10801125 else false)
10811126 then (DECIMAL_UNIT > partialLiquidationRatio())
10821127 else false)
10831128 then {
1084- let $t04896049110 = getPosition(_trader)
1085- let oldPositionSize = $t04896049110._1
1086- let oldPositionMargin = $t04896049110._2
1087- let oldPositionOpenNotional = $t04896049110._3
1088- let oldPositionLstUpdCPF = $t04896049110._4
1129+ let $t05103251182 = getPosition(_trader)
1130+ let oldPositionSize = $t05103251182._1
1131+ let oldPositionMargin = $t05103251182._2
1132+ let oldPositionOpenNotional = $t05103251182._3
1133+ let oldPositionLstUpdCPF = $t05103251182._4
10891134 let _direction = if ((oldPositionSize > 0))
10901135 then DIR_SHORT
10911136 else DIR_LONG
10921137 let isAdd = (_direction == DIR_LONG)
10931138 let exchangedQuoteAssetAmount = getPartialLiquidationAmount(_trader, oldPositionSize)
1094- let $t04933549439 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1095- let oldPositionNotional = $t04933549439._1
1096- let unrealizedPnl = $t04933549439._2
1097- let $t04944749737 = swapInput(isAdd, exchangedQuoteAssetAmount)
1098- let exchangedPositionSize = $t04944749737._1
1099- let quoteAssetReserveAfter = $t04944749737._2
1100- let baseAssetReserveAfter = $t04944749737._3
1101- let totalPositionSizeAfter = $t04944749737._4
1102- let cumulativeNotionalAfter = $t04944749737._5
1139+ let $t05140751511 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1140+ let oldPositionNotional = $t05140751511._1
1141+ let unrealizedPnl = $t05140751511._2
1142+ let $t05151951809 = swapInput(isAdd, exchangedQuoteAssetAmount)
1143+ let exchangedPositionSize = $t05151951809._1
1144+ let quoteAssetReserveAfter = $t05151951809._2
1145+ let baseAssetReserveAfter = $t05151951809._3
1146+ let totalPositionSizeAfter = $t05151951809._4
1147+ let cumulativeNotionalAfter = $t05151951809._5
11031148 let realizedPnl = divd(muld(unrealizedPnl, abs(exchangedPositionSize)), abs(oldPositionSize))
1104- let $t04984450077 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl)
1105- let remainMargin = $t04984450077._1
1106- let badDebt = $t04984450077._2
1107- let fundingPayment = $t04984450077._3
1149+ let $t05191652149 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl)
1150+ let remainMargin = $t05191652149._1
1151+ let badDebt = $t05191652149._2
1152+ let fundingPayment = $t05191652149._3
11081153 let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
11091154 let remainOpenNotional = if ((oldPositionSize > 0))
11101155 then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
11111156 else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
11121157 let liquidationPenalty = muld(exchangedQuoteAssetAmount, liquidationFeeRatio())
11131158 let feeToLiquidator = (liquidationPenalty / 2)
11141159 let feeToInsurance = (liquidationPenalty - feeToLiquidator)
11151160 let newPositionMargin = (remainMargin - liquidationPenalty)
11161161 let newPositionSize = (oldPositionSize + exchangedPositionSize)
11171162 let newPositionOpenNotional = abs(remainOpenNotional)
11181163 let newPositionLstUpdCPF = latestCumulativePremiumFraction(newPositionSize)
11191164 let openInterestNotionalAfter = (openInterestNotional() - exchangedQuoteAssetAmount)
11201165 let ammBalance = (cbalance() - liquidationPenalty)
1121- let $t05125051393 = if ((0 > ammBalance))
1166+ let $t05332253465 = if ((0 > ammBalance))
11221167 then $Tuple2(0, abs(ammBalance))
11231168 else $Tuple2(ammBalance, 0)
1124- let newAmmBalance = $t05125051393._1
1125- let takeFromInsurance = $t05125051393._2
1169+ let newAmmBalance = $t05332253465._1
1170+ let takeFromInsurance = $t05332253465._2
11261171 let x = if ((takeFromInsurance > 0))
11271172 then {
11281173 let withdrawInsurance = invoke(insuranceAddress(), "withdraw", [takeFromInsurance], nil)
11291174 if ((withdrawInsurance == withdrawInsurance))
11301175 then nil
11311176 else throw("Strict value is not equal to itself.")
11321177 }
11331178 else nil
11341179 if ((x == x))
11351180 then {
11361181 let unstake = invoke(quoteAssetStaking(), "unlockNeutrino", [(liquidationPenalty - takeFromInsurance), toBase58String(quoteAsset())], nil)
11371182 if ((unstake == unstake))
11381183 then {
11391184 let depositInsurance = invoke(insuranceAddress(), "deposit", nil, [AttachedPayment(quoteAsset(), feeToInsurance)])
11401185 if ((depositInsurance == depositInsurance))
11411186 then {
11421187 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
11431188 if ((notifyNotional == notifyNotional))
11441189 then (((updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, openInterestNotionalAfter, (totalLongPositionSize() - (if ((newPositionSize > 0))
11451190 then abs(exchangedPositionSize)
11461191 else 0)), (totalShortPositionSize() - (if ((0 > newPositionSize))
11471192 then abs(exchangedPositionSize)
11481193 else 0)))) ++ withdraw(i.caller, feeToLiquidator)) ++ updateBalance(newAmmBalance))
11491194 else throw("Strict value is not equal to itself.")
11501195 }
11511196 else throw("Strict value is not equal to itself.")
11521197 }
11531198 else throw("Strict value is not equal to itself.")
11541199 }
11551200 else throw("Strict value is not equal to itself.")
11561201 }
11571202 else {
1158- let $t05284953304 = internalClosePosition(_trader, false)
1159- let x1 = $t05284953304._1
1160- let badDebt = $t05284953304._2
1161- let x2 = $t05284953304._3
1162- let x3 = $t05284953304._4
1163- let quoteAssetReserveAfter = $t05284953304._5
1164- let baseAssetReserveAfter = $t05284953304._6
1165- let totalPositionSizeAfter = $t05284953304._7
1166- let cumulativeNotionalAfter = $t05284953304._8
1167- let openInterestNotionalAfter = $t05284953304._9
1168- let exchangedQuoteAssetAmount = $t05284953304._10
1169- let totalLongAfter = $t05284953304._11
1170- let totalShortAfter = $t05284953304._12
1203+ let $t05492155376 = internalClosePosition(_trader, false)
1204+ let x1 = $t05492155376._1
1205+ let badDebt = $t05492155376._2
1206+ let x2 = $t05492155376._3
1207+ let x3 = $t05492155376._4
1208+ let quoteAssetReserveAfter = $t05492155376._5
1209+ let baseAssetReserveAfter = $t05492155376._6
1210+ let totalPositionSizeAfter = $t05492155376._7
1211+ let cumulativeNotionalAfter = $t05492155376._8
1212+ let openInterestNotionalAfter = $t05492155376._9
1213+ let exchangedQuoteAssetAmount = $t05492155376._10
1214+ let totalLongAfter = $t05492155376._11
1215+ let totalShortAfter = $t05492155376._12
11711216 let liquidationPenalty = muld(exchangedQuoteAssetAmount, liquidationFeeRatio())
11721217 let feeToLiquidator = (liquidationPenalty / 2)
11731218 let feeToInsurance = (liquidationPenalty - feeToLiquidator)
11741219 let ammBalance = (cbalance() - liquidationPenalty)
1175- let $t05371653859 = if ((0 > ammBalance))
1220+ let $t05578855931 = if ((0 > ammBalance))
11761221 then $Tuple2(0, abs(ammBalance))
11771222 else $Tuple2(ammBalance, 0)
1178- let newAmmBalance = $t05371653859._1
1179- let takeFromInsurance = $t05371653859._2
1223+ let newAmmBalance = $t05578855931._1
1224+ let takeFromInsurance = $t05578855931._2
11801225 let x = if ((takeFromInsurance > 0))
11811226 then {
11821227 let withdrawInsurance = invoke(insuranceAddress(), "withdraw", [takeFromInsurance], nil)
11831228 if ((withdrawInsurance == withdrawInsurance))
11841229 then nil
11851230 else throw("Strict value is not equal to itself.")
11861231 }
11871232 else nil
11881233 if ((x == x))
11891234 then {
11901235 let unstake = invoke(quoteAssetStaking(), "unlockNeutrino", [(liquidationPenalty - takeFromInsurance), toBase58String(quoteAsset())], nil)
11911236 if ((unstake == unstake))
11921237 then {
11931238 let depositInsurance = invoke(insuranceAddress(), "deposit", nil, [AttachedPayment(quoteAsset(), feeToInsurance)])
11941239 if ((depositInsurance == depositInsurance))
11951240 then {
11961241 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, 0], nil)
11971242 if ((notifyNotional == notifyNotional))
11981243 then (((deletePosition(_trader) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter)) ++ withdraw(i.caller, feeToLiquidator)) ++ updateBalance(newAmmBalance))
11991244 else throw("Strict value is not equal to itself.")
12001245 }
12011246 else throw("Strict value is not equal to itself.")
12021247 }
12031248 else throw("Strict value is not equal to itself.")
12041249 }
12051250 else throw("Strict value is not equal to itself.")
12061251 }
12071252 }
12081253
12091254
12101255
12111256 @Callable(i)
12121257 func payFunding () = {
12131258 let fundingBlockTimestamp = nextFundingBlockTimestamp()
12141259 if (if (if ((fundingBlockTimestamp > lastBlock.timestamp))
12151260 then true
12161261 else !(initialized()))
12171262 then true
12181263 else paused())
12191264 then throw(((("Invalid funding block timestamp: " + toString(lastBlock.timestamp)) + " < ") + toString(fundingBlockTimestamp)))
12201265 else {
12211266 let underlyingPrice = getOracleTwapPrice()
12221267 let spotTwapPrice = getTwapSpotPrice()
12231268 let premium = (spotTwapPrice - underlyingPrice)
1224- let $t05544756782 = if (if ((totalShortPositionSize() == 0))
1269+ let $t05751958854 = if (if ((totalShortPositionSize() == 0))
12251270 then true
12261271 else (totalLongPositionSize() == 0))
12271272 then $Tuple2(0, 0)
12281273 else if ((0 > premium))
12291274 then {
12301275 let shortPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY)
12311276 let longPremiumFraction = divd(muld(shortPremiumFraction, totalShortPositionSize()), totalLongPositionSize())
12321277 $Tuple2(shortPremiumFraction, longPremiumFraction)
12331278 }
12341279 else {
12351280 let longPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY)
12361281 let shortPremiumFraction = divd(muld(longPremiumFraction, totalLongPositionSize()), totalShortPositionSize())
12371282 $Tuple2(shortPremiumFraction, longPremiumFraction)
12381283 }
1239- let shortPremiumFraction = $t05544756782._1
1240- let longPremiumFraction = $t05544756782._2
1284+ let shortPremiumFraction = $t05751958854._1
1285+ let longPremiumFraction = $t05751958854._2
12411286 updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice))
12421287 }
1243- }
1244-
1245-
1246-
1247-@Callable(i)
1248-func v_get (_trader) = {
1249- let $t05715757217 = internalClosePosition(_trader, false)
1250- let x1 = $t05715757217._1
1251- let x2 = $t05715757217._2
1252- let x3 = $t05715757217._3
1253- let x4 = $t05715757217._4
1254- throw((((s(x2) + s(x3)) + s(x4)) + s(getMarginRatio(_trader))))
1255- }
1256-
1257-
1258-
1259-@Callable(i)
1260-func view_calcRemainMarginWithFundingPayment (_trader) = {
1261- let $t05736457475 = getPosition(_trader)
1262- let positionSize = $t05736457475._1
1263- let positionMargin = $t05736457475._2
1264- let pon = $t05736457475._3
1265- let positionLstUpdCPF = $t05736457475._4
1266- let $t05748057581 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1267- let positionNotional = $t05748057581._1
1268- let unrealizedPnl = $t05748057581._2
1269- let $t05758657768 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
1270- let remainMargin = $t05758657768._1
1271- let badDebt = $t05758657768._2
1272- let fundingPayment = $t05758657768._3
1273- throw((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)))
12741288 }
12751289
12761290
12771291
12781292 @Callable(i)
12791293 func forceMoveAsset (_trader,_amount) = if (if ((addressFromPublicKey(adminPublicKey()) != i.caller))
12801294 then true
12811295 else (0 > _amount))
12821296 then throw("Invalid forceMoveAsset parameters")
12831297 else {
12841298 let unstake = invoke(quoteAssetStaking(), "unlockNeutrino", [_amount, toBase58String(quoteAsset())], nil)
12851299 if ((unstake == unstake))
12861300 then (withdraw(addressFromStringValue(_trader), _amount) ++ updateBalance((cbalance() - _amount)))
12871301 else throw("Strict value is not equal to itself.")
12881302 }
12891303
12901304
1305+
1306+@Callable(i)
1307+func adjustPeg (_price) = if (if ((addressFromPublicKey(adminPublicKey()) != i.caller))
1308+ then true
1309+ else (0 > _price))
1310+ then throw("Invalid adjustPeg parameters")
1311+ else {
1312+ let $t05985459940 = getPegAdjustCost(_price)
1313+ let newQuoteAssetReserve = $t05985459940._1
1314+ let pegChangeCost = $t05985459940._2
1315+ if ((pegChangeCost == 0))
1316+ then throw("Nothing to adjust")
1317+ else if ((pegChangeCost > 0))
1318+ then {
1319+ let withdrawInsurance = invoke(insuranceAddress(), "withdraw", [pegChangeCost], nil)
1320+ if ((withdrawInsurance == withdrawInsurance))
1321+ then {
1322+ let stake = invoke(quoteAssetStaking(), "lockNeutrinoSP", [toString(stakingAddress()), ALL_FEES], [AttachedPayment(quoteAsset(), pegChangeCost)])
1323+ if ((stake == stake))
1324+ then (updateBalance((cbalance() + pegChangeCost)) ++ updateAmmReserves(newQuoteAssetReserve, bsAstR()))
1325+ else throw("Strict value is not equal to itself.")
1326+ }
1327+ else throw("Strict value is not equal to itself.")
1328+ }
1329+ else {
1330+ let unstake = invoke(quoteAssetStaking(), "unlockNeutrino", [abs(pegChangeCost), toBase58String(quoteAsset())], nil)
1331+ if ((unstake == unstake))
1332+ then {
1333+ let depositInsurance = invoke(insuranceAddress(), "deposit", nil, [AttachedPayment(quoteAsset(), abs(pegChangeCost))])
1334+ if ((depositInsurance == depositInsurance))
1335+ then (updateBalance((cbalance() - abs(pegChangeCost))) ++ updateAmmReserves(newQuoteAssetReserve, bsAstR()))
1336+ else throw("Strict value is not equal to itself.")
1337+ }
1338+ else throw("Strict value is not equal to itself.")
1339+ }
1340+ }
1341+
1342+
1343+
1344+@Callable(i)
1345+func v_get (_trader) = {
1346+ let $t06116561225 = internalClosePosition(_trader, false)
1347+ let x1 = $t06116561225._1
1348+ let x2 = $t06116561225._2
1349+ let x3 = $t06116561225._3
1350+ let x4 = $t06116561225._4
1351+ throw((((s(x2) + s(x3)) + s(x4)) + s(getMarginRatio(_trader))))
1352+ }
1353+
1354+
1355+
1356+@Callable(i)
1357+func view_calcRemainMarginWithFundingPayment (_trader) = {
1358+ let $t06137261483 = getPosition(_trader)
1359+ let positionSize = $t06137261483._1
1360+ let positionMargin = $t06137261483._2
1361+ let pon = $t06137261483._3
1362+ let positionLstUpdCPF = $t06137261483._4
1363+ let $t06148861589 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1364+ let positionNotional = $t06148861589._1
1365+ let unrealizedPnl = $t06148861589._2
1366+ let $t06159461776 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl)
1367+ let remainMargin = $t06159461776._1
1368+ let badDebt = $t06159461776._2
1369+ let fundingPayment = $t06159461776._3
1370+ throw((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)))
1371+ }
1372+
1373+
1374+
1375+@Callable(i)
1376+func view_getPegAdjustCost (_price) = {
1377+ let cost = getPegAdjustCost(_price)
1378+ throw(toString(cost._2))
1379+ }
1380+
1381+
12911382 @Verifier(tx)
12921383 func verify () = sigVerify(tx.bodyBytes, tx.proofs[0], adminPublicKey())
12931384

github/deemru/w8io/026f985 
348.59 ms