tx · BxLd2gxpKcBtngG9WzTXBqb8UDrB3pLvQkpxK7fUC2Rc 3PBYExCMcqwN9R8aD7Wpf3yZ4WVLqFm8zRU: -0.02100000 Waves 2023.02.18 16:25 [3520690] smart account 3PBYExCMcqwN9R8aD7Wpf3yZ4WVLqFm8zRU > SELF 0.00000000 Waves
{ "type": 13, "id": "BxLd2gxpKcBtngG9WzTXBqb8UDrB3pLvQkpxK7fUC2Rc", "fee": 2100000, "feeAssetId": null, "timestamp": 1676726791532, "version": 1, "sender": "3PBYExCMcqwN9R8aD7Wpf3yZ4WVLqFm8zRU", "senderPublicKey": "BYoHZ4bxnPJHfn7XyY794fQz3ZecR54uS8ZKV6dn7FTZ", "proofs": [ "2Ze716VV26b9KL5C89QVs2hQirDTMceD6SwHkF6ydCGTGuAKJtvFbYwHJ9i83E3T12aN92v7fN5xS2Vj2jctCL1S" ], "script": "base64:BgICCAKmAQAMa19iYXNlT3JhY2xlAgxrX2Jhc2VPcmFjbGUADWtfcXVvdGVPcmFjbGUCDWtfcXVvdGVPcmFjbGUACWtfYmFsYW5jZQIJa19iYWxhbmNlAAprX3NlcXVlbmNlAgprX3NlcXVlbmNlAA5rX3Bvc2l0aW9uU2l6ZQIOa19wb3NpdGlvblNpemUAEGtfcG9zaXRpb25NYXJnaW4CEGtfcG9zaXRpb25NYXJnaW4AFmtfcG9zaXRpb25PcGVuTm90aW9uYWwCFmtfcG9zaXRpb25PcGVuTm90aW9uYWwALmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24CEmtfcG9zaXRpb25GcmFjdGlvbgASa19wb3NpdGlvblNlcXVlbmNlAhJrX3Bvc2l0aW9uU2VxdWVuY2UAD2tfcG9zaXRpb25Bc3NldAIPa19wb3NpdGlvbkFzc2V0AA1rX3Bvc2l0aW9uRmVlAg1rX3Bvc2l0aW9uRmVlAB5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXACE2tfcG9zaXRpb25UaW1lc3RhbXAADWtfaW5pdGlhbGl6ZWQCDWtfaW5pdGlhbGl6ZWQACGtfcGF1c2VkAghrX3BhdXNlZAALa19jbG9zZU9ubHkCC2tfY2xvc2VPbmx5AAVrX2ZlZQIFa19mZWUADWtfcm9sbG92ZXJGZWUCDmtfcm9sbG92ZXJfZmVlAA9rX2Z1bmRpbmdQZXJpb2QCD2tfZnVuZGluZ1BlcmlvZAARa19pbml0TWFyZ2luUmF0aW8CEWtfaW5pdE1hcmdpblJhdGlvABhrX21haW50ZW5hbmNlTWFyZ2luUmF0aW8CBWtfbW1yABVrX2xpcXVpZGF0aW9uRmVlUmF0aW8CFWtfbGlxdWlkYXRpb25GZWVSYXRpbwAZa19wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwIWa19wYXJ0TGlxdWlkYXRpb25SYXRpbwANa19zcHJlYWRMaW1pdAINa19zcHJlYWRMaW1pdAAQa19tYXhQcmljZUltcGFjdAIQa19tYXhQcmljZUltcGFjdAAQa19tYXhQcmljZVNwcmVhZAIQa19tYXhQcmljZVNwcmVhZAARa19tYXhPcGVuTm90aW9uYWwCEWtfbWF4T3Blbk5vdGlvbmFsABVrX2ZlZVRvU3Rha2Vyc1BlcmNlbnQCFWtfZmVlVG9TdGFrZXJzUGVyY2VudAAQa19tYXhPcmFjbGVEZWxheQIQa19tYXhPcmFjbGVEZWxheQANa19mdW5kaW5nTW9kZQINa19mdW5kaW5nTW9kZQANa19sYXN0RGF0YVN0cgINa19sYXN0RGF0YVN0cgAOa19sYXN0TWludXRlSWQCDmtfbGFzdE1pbnV0ZUlkAB1rX3R3YXBEYXRhTGFzdEN1bXVsYXRpdmVQcmljZQIda190d2FwRGF0YUxhc3RDdW11bGF0aXZlUHJpY2UAE2tfdHdhcERhdGFMYXN0UHJpY2UCE2tfdHdhcERhdGFMYXN0UHJpY2UAGmtfdHdhcERhdGFQcmV2aW91c01pbnV0ZUlkAhprX3R3YXBEYXRhUHJldmlvdXNNaW51dGVJZAAla19sYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgIba19sYXRlc3RMb25nUHJlbWl1bUZyYWN0aW9uACZrX2xhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgIca19sYXRlc3RTaG9ydFByZW1pdW1GcmFjdGlvbgASa19uZXh0RnVuZGluZ0Jsb2NrAh5rX25leHRGdW5kaW5nQmxvY2tNaW5UaW1lc3RhbXAAEWtfbG9uZ0Z1bmRpbmdSYXRlAhFrX2xvbmdGdW5kaW5nUmF0ZQASa19zaG9ydEZ1bmRpbmdSYXRlAhJrX3Nob3J0RnVuZGluZ1JhdGUAE2tfcXVvdGVBc3NldFJlc2VydmUCCGtfcXRBc3RSABJrX2Jhc2VBc3NldFJlc2VydmUCCGtfYnNBc3RSABJrX3F1b3RlQXNzZXRXZWlnaHQCCGtfcXRBc3RXABFrX2Jhc2VBc3NldFdlaWdodAIIa19ic0FzdFcAE2tfdG90YWxQb3NpdGlvblNpemUCE2tfdG90YWxQb3NpdGlvblNpemUAF2tfdG90YWxMb25nUG9zaXRpb25TaXplAhdrX3RvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQAYa190b3RhbFNob3J0UG9zaXRpb25TaXplAhhrX3RvdGFsU2hvcnRQb3NpdGlvblNpemUAFmtfb3BlbkludGVyZXN0Tm90aW9uYWwCFmtfb3BlbkludGVyZXN0Tm90aW9uYWwAE2tfb3BlbkludGVyZXN0U2hvcnQCE2tfb3BlbkludGVyZXN0U2hvcnQAEmtfb3BlbkludGVyZXN0TG9uZwISa19vcGVuSW50ZXJlc3RMb25nAAhrX2xhc3RUeAIIa19sYXN0VHgAFGtfY29vcmRpbmF0b3JBZGRyZXNzAhRrX2Nvb3JkaW5hdG9yQWRkcmVzcwAPa192YXVsdF9hZGRyZXNzAg9rX3ZhdWx0X2FkZHJlc3MAD2tfYWRtaW5fYWRkcmVzcwIPa19hZG1pbl9hZGRyZXNzAA1rX3F1b3RlX2Fzc2V0Ag1rX3F1b3RlX2Fzc2V0AA9rX3F1b3RlX3N0YWtpbmcCD2tfcXVvdGVfc3Rha2luZwARa19zdGFraW5nX2FkZHJlc3MCEWtfc3Rha2luZ19hZGRyZXNzAA9rX21pbmVyX2FkZHJlc3MCD2tfbWluZXJfYWRkcmVzcwAQa19vcmRlcnNfYWRkcmVzcwIQa19vcmRlcnNfYWRkcmVzcwASa19yZWZlcnJhbF9hZGRyZXNzAhJrX3JlZmVycmFsX2FkZHJlc3MAEmtfZXhjaGFuZ2VfYWRkcmVzcwISa19leGNoYW5nZV9hZGRyZXNzABVrX25mdF9tYW5hZ2VyX2FkZHJlc3MCFWtfbmZ0X21hbmFnZXJfYWRkcmVzcwEOdG9Db21wb3NpdGVLZXkCBF9rZXkIX2FkZHJlc3MJAKwCAgkArAICBQRfa2V5AgFfBQhfYWRkcmVzcwELY29vcmRpbmF0b3IBBm1hcmtldAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIFBm1hcmtldAUUa19jb29yZGluYXRvckFkZHJlc3MCE0Nvb3JkaW5hdG9yIG5vdCBzZXQBDGFkbWluQWRkcmVzcwEGbWFya2V0CQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgEFBm1hcmtldAUPa19hZG1pbl9hZGRyZXNzAQpxdW90ZUFzc2V0AQZtYXJrZXQJANkEAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAQUGbWFya2V0BQ1rX3F1b3RlX2Fzc2V0ARFxdW90ZUFzc2V0U3Rha2luZwEGbWFya2V0CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAQUGbWFya2V0BQ9rX3F1b3RlX3N0YWtpbmcCG1F1b3RlIGFzc2V0IHN0YWtpbmcgbm90IHNldAEOc3Rha2luZ0FkZHJlc3MBBm1hcmtldAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgEFBm1hcmtldAURa19zdGFraW5nX2FkZHJlc3MCD1N0YWtpbmcgbm90IHNldAEMdmF1bHRBZGRyZXNzAQZtYXJrZXQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IBBQZtYXJrZXQFD2tfdmF1bHRfYWRkcmVzcwINVmF1bHQgbm90IHNldAEMbWluZXJBZGRyZXNzAQZtYXJrZXQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IBBQZtYXJrZXQFD2tfbWluZXJfYWRkcmVzcwINTWluZXIgbm90IHNldAENb3JkZXJzQWRkcmVzcwEGbWFya2V0CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAQUGbWFya2V0BRBrX29yZGVyc19hZGRyZXNzAg5PcmRlcnMgbm90IHNldAEPcmVmZXJyYWxBZGRyZXNzAQZtYXJrZXQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IBBQZtYXJrZXQFEmtfcmVmZXJyYWxfYWRkcmVzcwIQUmVmZXJyYWwgbm90IHNldAERbmZ0TWFuYWdlckFkZHJlc3MBBm1hcmtldAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgEFBm1hcmtldAUVa19uZnRfbWFuYWdlcl9hZGRyZXNzAhNORlQgTWFuYWdlciBub3Qgc2V0AA1rX3Rva2VuX3BhcmFtAg1rX3Rva2VuX3BhcmFtAAxrX3Rva2VuX3R5cGUCDGtfdG9rZW5fdHlwZQAYRkVFX1JFRFVDVElPTl9UT0tFTl9UWVBFAg1mZWVfcmVkdWN0aW9uAAhESVJfTE9ORwABAAlESVJfU0hPUlQAAgANVFdBUF9JTlRFUlZBTAAPAAdTRUNPTkRTAOgHAA9ERUNJTUFMX05VTUJFUlMABgAMREVDSU1BTF9VTklUCQBoAgABCQBoAgkAaAIJAGgCCQBoAgkAaAIACgAKAAoACgAKAAoAD01JTlVURVNfSU5fWUVBUgkAaAIAoIogBQxERUNJTUFMX1VOSVQAB09ORV9EQVkJAGgCAICjBQUMREVDSU1BTF9VTklUAA9QTkxfT1BUSU9OX1NQT1QAAQARUE5MX09QVElPTl9PUkFDTEUAAgASRlVORElOR19BU1lNTUVUUklDAAEAEUZVTkRJTkdfU1lNTUVUUklDAAIBAXMBAl94CQCsAgIJAKQDAQUCX3gCASwBBGRpdmQCAl94Al95CQBuBAUCX3gFDERFQ0lNQUxfVU5JVAUCX3kFCEhBTEZFVkVOAQRtdWxkAgJfeAJfeQkAbgQFAl94BQJfeQUMREVDSU1BTF9VTklUBQhIQUxGRVZFTgEFYmRpdmQCAl94Al95CQC9AgQFAl94CQC2AgEFDERFQ0lNQUxfVU5JVAUCX3kFCEhBTEZFVkVOAQVibXVsZAICX3gCX3kJAL0CBAUCX3gFAl95CQC2AgEFDERFQ0lNQUxfVU5JVAUISEFMRkVWRU4BA2FicwECX3gDCQBmAgUCX3gAAAUCX3gJAQEtAQUCX3gBBHZtYXgCAl94Al95AwkAZwIFAl94BQJfeQUCX3gFAl95AQlsaXN0VG9TdHIBBV9saXN0AwkAAAIJAJADAQUFX2xpc3QAAAIACQC5CQIFBV9saXN0AgEsAQlzdHJUb0xpc3QBBF9zdHIDCQAAAgUEX3N0cgIABQNuaWwJALUJAgUEX3N0cgIBLAELcHVzaFRvUXVldWUDBV9saXN0CF9tYXhTaXplBl92YWx1ZQMJAGYCCQCQAwEFBV9saXN0BQhfbWF4U2l6ZQkAzQgCCQDRCAIFBV9saXN0AAAFBl92YWx1ZQkAzQgCBQVfbGlzdAUGX3ZhbHVlAQNpbnQCBm1hcmtldAFrCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUGbWFya2V0BQFrCQCsAgICDW5vIHZhbHVlIGZvciAFAWsBBWludE9yAwZtYXJrZXQBawNkZWYJAQt2YWx1ZU9yRWxzZQIJAJoIAgUGbWFya2V0BQFrBQNkZWYBBHN0ckECCF9hZGRyZXNzBF9rZXkEA3ZhbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFCF9hZGRyZXNzBQRfa2V5CQCsAgICEU5vIHZhbHVlIGZvciBrZXkgBQRfa2V5BQN2YWwBBGludEECCF9hZGRyZXNzBF9rZXkEA3ZhbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFCF9hZGRyZXNzBQRfa2V5CQCsAgICEU5vIHZhbHVlIGZvciBrZXkgBQRfa2V5BQN2YWwBCGNiYWxhbmNlAQZtYXJrZXQJAQNpbnQCBQZtYXJrZXQFCWtfYmFsYW5jZQEDZmVlAQZtYXJrZXQJAQNpbnQCBQZtYXJrZXQFBWtfZmVlAQ9yb2xsb3ZlckZlZVJhdGUBBm1hcmtldAkBA2ludAIFBm1hcmtldAUNa19yb2xsb3ZlckZlZQEPaW5pdE1hcmdpblJhdGlvAQZtYXJrZXQJAQNpbnQCBQZtYXJrZXQFEWtfaW5pdE1hcmdpblJhdGlvAQZxdEFzdFIBBm1hcmtldAkBA2ludAIFBm1hcmtldAUTa19xdW90ZUFzc2V0UmVzZXJ2ZQEGYnNBc3RSAQZtYXJrZXQJAQNpbnQCBQZtYXJrZXQFEmtfYmFzZUFzc2V0UmVzZXJ2ZQEGcXRBc3RXAQZtYXJrZXQJAQVpbnRPcgMFBm1hcmtldAUSa19xdW90ZUFzc2V0V2VpZ2h0BQxERUNJTUFMX1VOSVQBBmJzQXN0VwEGbWFya2V0CQEFaW50T3IDBQZtYXJrZXQFEWtfYmFzZUFzc2V0V2VpZ2h0BQxERUNJTUFMX1VOSVQBEXRvdGFsUG9zaXRpb25TaXplAQZtYXJrZXQJAQNpbnQCBQZtYXJrZXQFE2tfdG90YWxQb3NpdGlvblNpemUBFG9wZW5JbnRlcmVzdE5vdGlvbmFsAQZtYXJrZXQJAQNpbnQCBQZtYXJrZXQFFmtfb3BlbkludGVyZXN0Tm90aW9uYWwBEW9wZW5JbnRlcmVzdFNob3J0AQZtYXJrZXQJAQNpbnQCBQZtYXJrZXQFE2tfb3BlbkludGVyZXN0U2hvcnQBEG9wZW5JbnRlcmVzdExvbmcBBm1hcmtldAkBA2ludAIFBm1hcmtldAUSa19vcGVuSW50ZXJlc3RMb25nARluZXh0RnVuZGluZ0Jsb2NrVGltZXN0YW1wAQZtYXJrZXQJAQNpbnQCBQZtYXJrZXQFEmtfbmV4dEZ1bmRpbmdCbG9jawEQZnVuZGluZ1BlcmlvZFJhdwEGbWFya2V0CQEDaW50AgUGbWFya2V0BQ9rX2Z1bmRpbmdQZXJpb2QBFGZ1bmRpbmdQZXJpb2REZWNpbWFsAQZtYXJrZXQJAGgCCQEQZnVuZGluZ1BlcmlvZFJhdwEFBm1hcmtldAUMREVDSU1BTF9VTklUARRmdW5kaW5nUGVyaW9kU2Vjb25kcwEGbWFya2V0CQBoAgkBEGZ1bmRpbmdQZXJpb2RSYXcBBQZtYXJrZXQFB1NFQ09ORFMBFm1haW50ZW5hbmNlTWFyZ2luUmF0aW8BBm1hcmtldAkBA2ludAIFBm1hcmtldAUYa19tYWludGVuYW5jZU1hcmdpblJhdGlvARNsaXF1aWRhdGlvbkZlZVJhdGlvAQZtYXJrZXQJAQNpbnQCBQZtYXJrZXQFFWtfbGlxdWlkYXRpb25GZWVSYXRpbwEXcGFydGlhbExpcXVpZGF0aW9uUmF0aW8BBm1hcmtldAkBA2ludAIFBm1hcmtldAUZa19wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwELc3ByZWFkTGltaXQBBm1hcmtldAkBA2ludAIFBm1hcmtldAUNa19zcHJlYWRMaW1pdAEObWF4UHJpY2VJbXBhY3QBBm1hcmtldAkBA2ludAIFBm1hcmtldAUQa19tYXhQcmljZUltcGFjdAEObWF4UHJpY2VTcHJlYWQBBm1hcmtldAkBA2ludAIFBm1hcmtldAUQa19tYXhQcmljZVNwcmVhZAEPbWF4T3Blbk5vdGlvbmFsAQZtYXJrZXQJAQNpbnQCBQZtYXJrZXQFEWtfbWF4T3Blbk5vdGlvbmFsASNsYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEGbWFya2V0CQEDaW50AgUGbWFya2V0BSVrX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uASRsYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24BBm1hcmtldAkBA2ludAIFBm1hcmtldAUma19sYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24BFnRvdGFsU2hvcnRQb3NpdGlvblNpemUBBm1hcmtldAkBA2ludAIFBm1hcmtldAUYa190b3RhbFNob3J0UG9zaXRpb25TaXplARV0b3RhbExvbmdQb3NpdGlvblNpemUBBm1hcmtldAkBA2ludAIFBm1hcmtldAUXa190b3RhbExvbmdQb3NpdGlvblNpemUBDGxhc3RTZXF1ZW5jZQEGbWFya2V0CQEFaW50T3IDBQZtYXJrZXQFCmtfc2VxdWVuY2UAAAETZmVlVG9TdGFrZXJzUGVyY2VudAEGbWFya2V0CQEDaW50AgUGbWFya2V0BRVrX2ZlZVRvU3Rha2Vyc1BlcmNlbnQBDm1heE9yYWNsZURlbGF5AQZtYXJrZXQJAQNpbnQCBQZtYXJrZXQFEGtfbWF4T3JhY2xlRGVsYXkBC2Z1bmRpbmdNb2RlAQZtYXJrZXQJAQVpbnRPcgMFBm1hcmtldAUNa19mdW5kaW5nTW9kZQUSRlVORElOR19BU1lNTUVUUklDAQ1sYXN0VGltZXN0YW1wAAgFCWxhc3RCbG9jawl0aW1lc3RhbXABD2dldEFjdHVhbENhbGxlcgIGbWFya2V0AWkJAQt2YWx1ZU9yRWxzZQIJAJ0IAgkBDW9yZGVyc0FkZHJlc3MBBQZtYXJrZXQCCGtfc2VuZGVyCQClCAEIBQFpBmNhbGxlcgEWcmVxdWlyZU1vcmVNYXJnaW5SYXRpbwMMX21hcmdpblJhdGlvEF9iYXNlTWFyZ2luUmF0aW8UX2xhcmdlclRoYW5PckVxdWFsVG8EFHJlbWFpbmluZ01hcmdpblJhdGlvCQBlAgUMX21hcmdpblJhdGlvBRBfYmFzZU1hcmdpblJhdGlvAwMFFF9sYXJnZXJUaGFuT3JFcXVhbFRvCQBmAgAABRRyZW1haW5pbmdNYXJnaW5SYXRpbwcGAwMJAQEhAQUUX2xhcmdlclRoYW5PckVxdWFsVG8JAGcCBRRyZW1haW5pbmdNYXJnaW5SYXRpbwAABwYGAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAgZtYXJrZXQNX3Bvc2l0aW9uU2l6ZQMJAAACBQ1fcG9zaXRpb25TaXplAAAJAAIBAixTaG91bGQgbm90IGJlIGNhbGxlZCB3aXRoIF9wb3NpdGlvblNpemUgPT0gMAMJAGYCBQ1fcG9zaXRpb25TaXplAAAJASNsYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEFBm1hcmtldAkBJGxhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEFBm1hcmtldAELZ2V0UG9zaXRpb24CBm1hcmtldAdfdHJhZGVyBA9wb3NpdGlvblNpemVPcHQJAJoIAgUGbWFya2V0CQEOdG9Db21wb3NpdGVLZXkCBQ5rX3Bvc2l0aW9uU2l6ZQUHX3RyYWRlcgQHJG1hdGNoMAUPcG9zaXRpb25TaXplT3B0AwkAAQIFByRtYXRjaDACA0ludAQMcG9zaXRpb25TaXplBQckbWF0Y2gwCQCXCgUFDHBvc2l0aW9uU2l6ZQkBEUBleHRyTmF0aXZlKDEwNTApAgUGbWFya2V0CQEOdG9Db21wb3NpdGVLZXkCBRBrX3Bvc2l0aW9uTWFyZ2luBQdfdHJhZGVyCQERQGV4dHJOYXRpdmUoMTA1MCkCBQZtYXJrZXQJAQ50b0NvbXBvc2l0ZUtleQIFFmtfcG9zaXRpb25PcGVuTm90aW9uYWwFB190cmFkZXIJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBm1hcmtldAkBDnRvQ29tcG9zaXRlS2V5AgUua19wb3NpdGlvbkxhc3RVcGRhdGVkQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUHX3RyYWRlcgkBEUBleHRyTmF0aXZlKDEwNTApAgUGbWFya2V0CQEOdG9Db21wb3NpdGVLZXkCBR5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAFB190cmFkZXIJAJcKBQAAAAAAAAAAAAABEGdldFBvc2l0aW9uQXNzZXQCBm1hcmtldAdfdHJhZGVyBBBwb3NpdGlvbkFzc2V0T3B0CQCdCAIFBm1hcmtldAkBDnRvQ29tcG9zaXRlS2V5AgUPa19wb3NpdGlvbkFzc2V0BQdfdHJhZGVyBAckbWF0Y2gwBRBwb3NpdGlvbkFzc2V0T3B0AwkAAQIFByRtYXRjaDACBlN0cmluZwQNcG9zaXRpb25Bc3NldAUHJG1hdGNoMAUNcG9zaXRpb25Bc3NldAkA2AQBCQEKcXVvdGVBc3NldAEFBm1hcmtldAEOZ2V0UG9zaXRpb25GZWUCBm1hcmtldAdfdHJhZGVyBA5wb3NpdGlvbkZlZU9wdAkAmggCBQZtYXJrZXQJAQ50b0NvbXBvc2l0ZUtleQIFDWtfcG9zaXRpb25GZWUFB190cmFkZXIEByRtYXRjaDAFDnBvc2l0aW9uRmVlT3B0AwkAAQIFByRtYXRjaDACA0ludAQLcG9zaXRpb25GZWUFByRtYXRjaDAFC3Bvc2l0aW9uRmVlCQEDZmVlAQUGbWFya2V0ARNyZXF1aXJlT3BlblBvc2l0aW9uAgZtYXJrZXQHX3RyYWRlcgMJAAACCAkBC2dldFBvc2l0aW9uAgUGbWFya2V0BQdfdHJhZGVyAl8xAAAHBgENZ2V0T3JhY2xlRGF0YQIGbWFya2V0A2tleQQNb3JhY2xlRGF0YVN0cgkAnQgCBQZtYXJrZXQFA2tleQMDCQEJaXNEZWZpbmVkAQUNb3JhY2xlRGF0YVN0cgkBAiE9AgkBBXZhbHVlAQUNb3JhY2xlRGF0YVN0cgIABwQKb3JhY2xlRGF0YQkAtQkCCQEFdmFsdWUBBQ1vcmFjbGVEYXRhU3RyAgEsBA1vcmFjbGVBZGRyZXNzCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkAkQMCBQpvcmFjbGVEYXRhAAAJAKwCAgIbSW52YWxpZCBvcmFjbGUgYWRkcmVzcyBpbjogCQEFdmFsdWUBBQ1vcmFjbGVEYXRhU3RyBAhwcmljZUtleQkAkQMCBQpvcmFjbGVEYXRhAAEECGJsb2NrS2V5CQCRAwIFCm9yYWNsZURhdGEAAgQHb3BlbktleQkAkQMCBQpvcmFjbGVEYXRhAAMJAJYKBAUNb3JhY2xlQWRkcmVzcwUIcHJpY2VLZXkFCGJsb2NrS2V5BQdvcGVuS2V5BQR1bml0AQtpbml0aWFsaXplZAEGbWFya2V0CQELdmFsdWVPckVsc2UCCQCbCAIFBm1hcmtldAUNa19pbml0aWFsaXplZAcBBnBhdXNlZAEGbWFya2V0CQELdmFsdWVPckVsc2UCCQCbCAIFBm1hcmtldAUIa19wYXVzZWQHAQljbG9zZU9ubHkBBm1hcmtldAkBC3ZhbHVlT3JFbHNlAgkAmwgCBQZtYXJrZXQFC2tfY2xvc2VPbmx5BwENdXBkYXRlUmVzZXJ2ZQQGbWFya2V0Bl9pc0FkZBFfcXVvdGVBc3NldEFtb3VudBBfYmFzZUFzc2V0QW1vdW50AwUGX2lzQWRkBAduZXdCYXNlCQBlAgkBBmJzQXN0UgEFBm1hcmtldAUQX2Jhc2VBc3NldEFtb3VudAMJAGcCAAAFB25ld0Jhc2UJAAIBAipUeCBsZWFkIHRvIGJhc2UgYXNzZXQgcmVzZXJ2ZSA8PSAwLCByZXZlcnQJAJUKAwkAZAIJAQZxdEFzdFIBBQZtYXJrZXQFEV9xdW90ZUFzc2V0QW1vdW50BQduZXdCYXNlCQBkAgkBEXRvdGFsUG9zaXRpb25TaXplAQUGbWFya2V0BRBfYmFzZUFzc2V0QW1vdW50BAhuZXdRdW90ZQkAZQIJAQZxdEFzdFIBBQZtYXJrZXQFEV9xdW90ZUFzc2V0QW1vdW50AwkAZwIAAAUIbmV3UXVvdGUJAAIBAipUeCBsZWFkIHRvIGJhc2UgcXVvdGUgcmVzZXJ2ZSA8PSAwLCByZXZlcnQJAJUKAwUIbmV3UXVvdGUJAGQCCQEGYnNBc3RSAQUGbWFya2V0BRBfYmFzZUFzc2V0QW1vdW50CQBlAgkBEXRvdGFsUG9zaXRpb25TaXplAQUGbWFya2V0BRBfYmFzZUFzc2V0QW1vdW50AQ1jYWxjSW52YXJpYW50AgdfcXRBc3RSB19ic0FzdFIEB2JxdEFzdFIJALYCAQUHX3F0QXN0UgQHYmJzQXN0UgkAtgIBBQdfYnNBc3RSCQEFYm11bGQCBQdicXRBc3RSBQdiYnNBc3RSAQlzd2FwSW5wdXQDBm1hcmtldAZfaXNBZGQRX3F1b3RlQXNzZXRBbW91bnQEB19xdEFzdFIJAQZxdEFzdFIBBQZtYXJrZXQEB19ic0FzdFIJAQZic0FzdFIBBQZtYXJrZXQEB19xdEFzdFcJAQZxdEFzdFcBBQZtYXJrZXQEB19ic0FzdFcJAQZic0FzdFcBBQZtYXJrZXQEGHF1b3RlQXNzZXRBbW91bnRBZGp1c3RlZAkBBGRpdmQCBRFfcXVvdGVBc3NldEFtb3VudAUHX3F0QXN0VwQBawkBDWNhbGNJbnZhcmlhbnQCBQdfcXRBc3RSBQdfYnNBc3RSBBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyAwUGX2lzQWRkCQBkAgUHX3F0QXN0UgUYcXVvdGVBc3NldEFtb3VudEFkanVzdGVkCQBlAgUHX3F0QXN0UgUYcXVvdGVBc3NldEFtb3VudEFkanVzdGVkBBViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIJAKADAQkBBWJkaXZkAgUBawkAtgIBBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBBhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMJAQNhYnMBCQBlAgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBQdfYnNBc3RSBBVhbW91bnRCYXNlQXNzZXRCb3VnaHQDBQZfaXNBZGQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwkBAS0BBRhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMEBXR1cGxlCQENdXBkYXRlUmVzZXJ2ZQQFBm1hcmtldAUGX2lzQWRkBRhxdW90ZUFzc2V0QW1vdW50QWRqdXN0ZWQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwQXcXVvdGVBc3NldFJlc2VydmVBZnRlcjEIBQV0dXBsZQJfMQQWYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyMQgFBXR1cGxlAl8yBBd0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyMQgFBXR1cGxlAl8zBAtwcmljZUJlZm9yZQkBBGRpdmQCCQEEbXVsZAIFB19xdEFzdFIFB19xdEFzdFcJAQRtdWxkAgUHX2JzQXN0UgUHX2JzQXN0VwQLbWFya2V0UHJpY2UJAQRkaXZkAgURX3F1b3RlQXNzZXRBbW91bnQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwQJcHJpY2VEaWZmCQEDYWJzAQkAZQIFC3ByaWNlQmVmb3JlBQttYXJrZXRQcmljZQQLcHJpY2VJbXBhY3QJAGUCBQxERUNJTUFMX1VOSVQJAQRkaXZkAgULcHJpY2VCZWZvcmUJAGQCBQtwcmljZUJlZm9yZQUJcHJpY2VEaWZmBBNtYXhQcmljZUltcGFjdFZhbHVlCQEObWF4UHJpY2VJbXBhY3QBBQZtYXJrZXQDCQBmAgULcHJpY2VJbXBhY3QFE21heFByaWNlSW1wYWN0VmFsdWUJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgICDVByaWNlIGltcGFjdCAJAKQDAQULcHJpY2VJbXBhY3QCFCA+IG1heCBwcmljZSBpbXBhY3QgCQCkAwEFE21heFByaWNlSW1wYWN0VmFsdWUCFSBiZWZvcmUgcXVvdGUgYXNzZXQ6IAkApAMBBQdfcXRBc3RSAhQgYmVmb3JlIGJhc2UgYXNzZXQ6IAkApAMBBQdfYnNBc3RSAiEgcXVvdGUgYXNzZXQgYW1vdW50IHRvIGV4Y2hhbmdlOiAJAKQDAQURX3F1b3RlQXNzZXRBbW91bnQCDyBwcmljZSBiZWZvcmU6IAkApAMBBQtwcmljZUJlZm9yZQIOIG1hcmtldFByaWNlOiAJAKQDAQULbWFya2V0UHJpY2UJAJYKBAUVYW1vdW50QmFzZUFzc2V0Qm91Z2h0BRdxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyMQUWYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyMQUXdG90YWxQb3NpdGlvblNpemVBZnRlcjEBD2NhbGNSb2xsb3ZlckZlZQMGbWFya2V0El9vbGRQb3NpdGlvbk1hcmdpbiBfb2xkUG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAQPcG9zaXRpb25NaW51dGVzCQBoAgkAaQIJAGkCCQBlAgkBDWxhc3RUaW1lc3RhbXAABSBfb2xkUG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcADoBwA8BQxERUNJTUFMX1VOSVQEC3JvbGxvdmVyRmVlCQEEZGl2ZAIJAQRtdWxkAgkBBG11bGQCBRJfb2xkUG9zaXRpb25NYXJnaW4FD3Bvc2l0aW9uTWludXRlcwkBD3JvbGxvdmVyRmVlUmF0ZQEFBm1hcmtldAUPTUlOVVRFU19JTl9ZRUFSBQtyb2xsb3ZlckZlZQEwY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudEFuZFJvbGxvdmVyRmVlBgZtYXJrZXQQX29sZFBvc2l0aW9uU2l6ZRJfb2xkUG9zaXRpb25NYXJnaW4lX29sZFBvc2l0aW9uQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbiBfb2xkUG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAxfbWFyZ2luRGVsdGEEDmZ1bmRpbmdQYXltZW50AwkBAiE9AgUQX29sZFBvc2l0aW9uU2l6ZQAABCBfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkBH2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24CBQZtYXJrZXQFEF9vbGRQb3NpdGlvblNpemUJAQRtdWxkAgkAZQIFIF9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBSVfb2xkUG9zaXRpb25DdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBRBfb2xkUG9zaXRpb25TaXplAAAEC3JvbGxvdmVyRmVlCQEPY2FsY1JvbGxvdmVyRmVlAwUGbWFya2V0BRJfb2xkUG9zaXRpb25NYXJnaW4FIF9vbGRQb3NpdGlvbkxhc3RVcGRhdGVkVGltZXN0YW1wBAxzaWduZWRNYXJnaW4JAGQCCQBlAgkAZQIFDF9tYXJnaW5EZWx0YQULcm9sbG92ZXJGZWUFDmZ1bmRpbmdQYXltZW50BRJfb2xkUG9zaXRpb25NYXJnaW4EBXR1cGxlAwkAZgIAAAUMc2lnbmVkTWFyZ2luCQCUCgIAAAkBA2FicwEFDHNpZ25lZE1hcmdpbgkAlAoCCQEDYWJzAQUMc2lnbmVkTWFyZ2luAAAEDHJlbWFpbk1hcmdpbggFBXR1cGxlAl8xBAdiYWREZWJ0CAUFdHVwbGUCXzIJAJYKBAUMcmVtYWluTWFyZ2luBQdiYWREZWJ0BQ5mdW5kaW5nUGF5bWVudAULcm9sbG92ZXJGZWUBFnN3YXBPdXRwdXRXaXRoUmVzZXJ2ZXMIBm1hcmtldAZfaXNBZGQQX2Jhc2VBc3NldEFtb3VudBRfY2hlY2tNYXhQcmljZUltcGFjdBJfcXVvdGVBc3NldFJlc2VydmURX3F1b3RlQXNzZXRXZWlnaHQRX2Jhc2VBc3NldFJlc2VydmUQX2Jhc2VBc3NldFdlaWdodAQLcHJpY2VCZWZvcmUJAQRkaXZkAgkBBG11bGQCBRJfcXVvdGVBc3NldFJlc2VydmUFEV9xdW90ZUFzc2V0V2VpZ2h0CQEEbXVsZAIFEV9iYXNlQXNzZXRSZXNlcnZlBRBfYmFzZUFzc2V0V2VpZ2h0AwkAAAIFEF9iYXNlQXNzZXRBbW91bnQAAAkAAgECGUludmFsaWQgYmFzZSBhc3NldCBhbW91bnQEAWsJAQ1jYWxjSW52YXJpYW50AgUSX3F1b3RlQXNzZXRSZXNlcnZlBRFfYmFzZUFzc2V0UmVzZXJ2ZQQYYmFzZUFzc2V0UG9vbEFtb3VudEFmdGVyAwUGX2lzQWRkCQBkAgURX2Jhc2VBc3NldFJlc2VydmUFEF9iYXNlQXNzZXRBbW91bnQJAGUCBRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldEFtb3VudAQPcXVvdGVBc3NldEFmdGVyCQCgAwEJAQViZGl2ZAIFAWsJALYCAQUYYmFzZUFzc2V0UG9vbEFtb3VudEFmdGVyBA9xdW90ZUFzc2V0RGVsdGEJAQNhYnMBCQBlAgUPcXVvdGVBc3NldEFmdGVyBRJfcXVvdGVBc3NldFJlc2VydmUEDnF1b3RlQXNzZXRTb2xkCQEEbXVsZAIFD3F1b3RlQXNzZXREZWx0YQURX3F1b3RlQXNzZXRXZWlnaHQEE21heFByaWNlSW1wYWN0VmFsdWUJAQ5tYXhQcmljZUltcGFjdAEFBm1hcmtldAQFdHVwbGUJAQ11cGRhdGVSZXNlcnZlBAUGbWFya2V0CQEBIQEFBl9pc0FkZAUPcXVvdGVBc3NldERlbHRhBRBfYmFzZUFzc2V0QW1vdW50BBdxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyMQgFBXR1cGxlAl8xBBZiYXNlQXNzZXRSZXNlcnZlQWZ0ZXIxCAUFdHVwbGUCXzIEF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxCAUFdHVwbGUCXzMEC21hcmtldFByaWNlCQEEZGl2ZAIFDnF1b3RlQXNzZXRTb2xkBRBfYmFzZUFzc2V0QW1vdW50BAlwcmljZURpZmYJAQNhYnMBCQBlAgULcHJpY2VCZWZvcmUFC21hcmtldFByaWNlBAtwcmljZUltcGFjdAkAZQIFDERFQ0lNQUxfVU5JVAkBBGRpdmQCBQtwcmljZUJlZm9yZQkAZAIFC3ByaWNlQmVmb3JlBQlwcmljZURpZmYDAwkAZgIFC3ByaWNlSW1wYWN0BRNtYXhQcmljZUltcGFjdFZhbHVlBRRfY2hlY2tNYXhQcmljZUltcGFjdAcJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgICDVByaWNlIGltcGFjdCAJAKQDAQULcHJpY2VJbXBhY3QCFCA+IG1heCBwcmljZSBpbXBhY3QgCQCkAwEFE21heFByaWNlSW1wYWN0VmFsdWUCFSBiZWZvcmUgcXVvdGUgYXNzZXQ6IAkApAMBBRJfcXVvdGVBc3NldFJlc2VydmUCFCBiZWZvcmUgYmFzZSBhc3NldDogCQCkAwEFEV9iYXNlQXNzZXRSZXNlcnZlAiAgYmFzZSBhc3NldCBhbW91bnQgdG8gZXhjaGFuZ2U6IAkApAMBBRBfYmFzZUFzc2V0QW1vdW50Ag8gcHJpY2UgYmVmb3JlOiAJAKQDAQULcHJpY2VCZWZvcmUCDyBtYXJrZXQgcHJpY2U6IAkApAMBBQttYXJrZXRQcmljZQkAmQoHBQ5xdW90ZUFzc2V0U29sZAUXcXVvdGVBc3NldFJlc2VydmVBZnRlcjEFFmJhc2VBc3NldFJlc2VydmVBZnRlcjEFF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxCQBlAgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQEFBm1hcmtldAMFBl9pc0FkZAkBA2FicwEFEF9iYXNlQXNzZXRBbW91bnQAAAkAZQIJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAQUGbWFya2V0AwkBASEBBQZfaXNBZGQJAQNhYnMBBRBfYmFzZUFzc2V0QW1vdW50AAAFC3ByaWNlSW1wYWN0AQpzd2FwT3V0cHV0BAZtYXJrZXQGX2lzQWRkEF9iYXNlQXNzZXRBbW91bnQUX2NoZWNrTWF4UHJpY2VJbXBhY3QJARZzd2FwT3V0cHV0V2l0aFJlc2VydmVzCAUGbWFya2V0BQZfaXNBZGQFEF9iYXNlQXNzZXRBbW91bnQFFF9jaGVja01heFByaWNlSW1wYWN0CQEGcXRBc3RSAQUGbWFya2V0CQEGcXRBc3RXAQUGbWFya2V0CQEGYnNBc3RSAQUGbWFya2V0CQEGYnNBc3RXAQUGbWFya2V0ARNnZXRPcmFjbGVQcmljZVZhbHVlBAZtYXJrZXQGb3JhY2xlCHByaWNlS2V5CGJsb2NrS2V5BAlsYXN0VmFsdWUJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBQZvcmFjbGUFCHByaWNlS2V5CQCsAgIJAKwCAgkArAICAiJDYW4gbm90IGdldCBvcmFjbGUgcHJpY2UuIE9yYWNsZTogCQClCAEFBm9yYWNsZQIGIGtleTogBQhwcmljZUtleQMJAQIhPQIFCGJsb2NrS2V5AgAEDGN1cnJlbnRCbG9jawgFCWxhc3RCbG9jawZoZWlnaHQED2xhc3RPcmFjbGVCbG9jawkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFBm9yYWNsZQUIYmxvY2tLZXkJAKwCAgkArAICCQCsAgICIkNhbiBub3QgZ2V0IG9yYWNsZSBibG9jay4gT3JhY2xlOiAJAKUIAQUGb3JhY2xlAgYga2V5OiAFCGJsb2NrS2V5AwkAZgIJAGUCBQxjdXJyZW50QmxvY2sFD2xhc3RPcmFjbGVCbG9jawkBDm1heE9yYWNsZURlbGF5AQUGbWFya2V0CQACAQkArAICCQCsAgIJAKwCAgImT3JhY2xlIHN0YWxlIGRhdGEuIExhc3Qgb3JhY2xlIGJsb2NrOiAJAKQDAQUPbGFzdE9yYWNsZUJsb2NrAhAgY3VycmVudCBibG9jazogCQCkAwEFDGN1cnJlbnRCbG9jawUJbGFzdFZhbHVlBQlsYXN0VmFsdWUBDmdldE9yYWNsZVByaWNlAQZtYXJrZXQECmJhc2VPcmFjbGUJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkBDWdldE9yYWNsZURhdGECBQZtYXJrZXQFDGtfYmFzZU9yYWNsZQIZTm8gYmFzZSBhc3NldCBvcmFjbGUgZGF0YQQPYmFzZU9yYWNsZVByaWNlCQETZ2V0T3JhY2xlUHJpY2VWYWx1ZQQFBm1hcmtldAgFCmJhc2VPcmFjbGUCXzEIBQpiYXNlT3JhY2xlAl8yCAUKYmFzZU9yYWNsZQJfMwQLcXVvdGVPcmFjbGUJAQ1nZXRPcmFjbGVEYXRhAgUGbWFya2V0BQ1rX3F1b3RlT3JhY2xlBBBxdW90ZU9yYWNsZVByaWNlAwkBCWlzRGVmaW5lZAEFC3F1b3RlT3JhY2xlBAxxdW90ZU9yYWNsZVYJAQV2YWx1ZQEFC3F1b3RlT3JhY2xlCQETZ2V0T3JhY2xlUHJpY2VWYWx1ZQQFBm1hcmtldAgFDHF1b3RlT3JhY2xlVgJfMQgFDHF1b3RlT3JhY2xlVgJfMggFDHF1b3RlT3JhY2xlVgJfMwUMREVDSU1BTF9VTklUCQEEZGl2ZAIFD2Jhc2VPcmFjbGVQcmljZQUQcXVvdGVPcmFjbGVQcmljZQEOaXNNYXJrZXRDbG9zZWQBBm1hcmtldAQKYmFzZU9yYWNsZQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQENZ2V0T3JhY2xlRGF0YQIFBm1hcmtldAUMa19iYXNlT3JhY2xlAhlObyBiYXNlIGFzc2V0IG9yYWNsZSBkYXRhBAZvcmFjbGUIBQpiYXNlT3JhY2xlAl8xBAdvcGVuS2V5CAUKYmFzZU9yYWNsZQJfNAMJAQIhPQIFB29wZW5LZXkCAAQGaXNPcGVuCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJsIAgUGb3JhY2xlBQdvcGVuS2V5CQCsAgIJAKwCAgkArAICAitDYW4gbm90IGdldCBvcmFjbGUgaXMgb3Blbi9jbG9zZWQuIE9yYWNsZTogCQClCAEFBm9yYWNsZQIGIGtleTogBQdvcGVuS2V5CQEBIQEFBmlzT3BlbgcBDGFic1ByaWNlRGlmZgUMX29yYWNsZVByaWNlEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfYmFzZUFzc2V0UmVzZXJ2ZQdfcXRBc3RXB19ic0FzdFcECnByaWNlQWZ0ZXIJAQRkaXZkAgkBBG11bGQCBRJfcXVvdGVBc3NldFJlc2VydmUFB19xdEFzdFcJAQRtdWxkAgURX2Jhc2VBc3NldFJlc2VydmUFB19ic0FzdFcEDGF2ZXJhZ2VQcmljZQkBBGRpdmQCCQBkAgUMX29yYWNsZVByaWNlBQpwcmljZUFmdGVyCQBoAgACBQxERUNJTUFMX1VOSVQEDGFic1ByaWNlRGlmZgkBBGRpdmQCCQEDYWJzAQkAZQIFDF9vcmFjbGVQcmljZQUKcHJpY2VBZnRlcgUMYXZlcmFnZVByaWNlBQxhYnNQcmljZURpZmYBGXJlcXVpcmVOb3RPdmVyU3ByZWFkTGltaXQDBm1hcmtldBJfcXVvdGVBc3NldFJlc2VydmURX2Jhc2VBc3NldFJlc2VydmUEC29yYWNsZVByaWNlCQEOZ2V0T3JhY2xlUHJpY2UBBQZtYXJrZXQEB19xdEFzdFcJAQZxdEFzdFcBBQZtYXJrZXQEB19ic0FzdFcJAQZic0FzdFcBBQZtYXJrZXQEEmFic1ByaWNlRGlmZkJlZm9yZQkBDGFic1ByaWNlRGlmZgUFC29yYWNsZVByaWNlCQEGcXRBc3RSAQUGbWFya2V0CQEGYnNBc3RSAQUGbWFya2V0BQdfcXRBc3RXBQdfYnNBc3RXBBFhYnNQcmljZURpZmZBZnRlcgkBDGFic1ByaWNlRGlmZgUFC29yYWNsZVByaWNlBRJfcXVvdGVBc3NldFJlc2VydmUFEV9iYXNlQXNzZXRSZXNlcnZlBQdfcXRBc3RXBQdfYnNBc3RXAwMJAGYCBRFhYnNQcmljZURpZmZBZnRlcgkBDm1heFByaWNlU3ByZWFkAQUGbWFya2V0CQBmAgURYWJzUHJpY2VEaWZmQWZ0ZXIFEmFic1ByaWNlRGlmZkJlZm9yZQcJAAIBCQCsAgIJAKwCAgkArAICAg1QcmljZSBzcHJlYWQgCQCkAwEFEWFic1ByaWNlRGlmZkFmdGVyAhQgPiBtYXggcHJpY2Ugc3ByZWFkIAkApAMBCQEObWF4UHJpY2VTcHJlYWQBBQZtYXJrZXQGAR1yZXF1aXJlTm90T3Zlck1heE9wZW5Ob3Rpb25hbAMGbWFya2V0EV9sb25nT3Blbk5vdGlvbmFsEl9zaG9ydE9wZW5Ob3Rpb25hbAQQX21heE9wZW5Ob3Rpb25hbAkBD21heE9wZW5Ob3Rpb25hbAEFBm1hcmtldAMJAGYCBRFfbG9uZ09wZW5Ob3Rpb25hbAUQX21heE9wZW5Ob3Rpb25hbAkAAgEJAKwCAgkArAICCQCsAgICE0xvbmcgb3BlbiBub3Rpb25hbCAJAKQDAQURX2xvbmdPcGVuTm90aW9uYWwCFSA+IG1heCBvcGVuIG5vdGlvbmFsIAkApAMBBRBfbWF4T3Blbk5vdGlvbmFsAwkAZgIFEl9zaG9ydE9wZW5Ob3Rpb25hbAUQX21heE9wZW5Ob3Rpb25hbAkAAgEJAKwCAgkArAICCQCsAgICFFNob3J0IG9wZW4gbm90aW9uYWwgCQCkAwEFEl9zaG9ydE9wZW5Ob3Rpb25hbAIVID4gbWF4IG9wZW4gbm90aW9uYWwgCQCkAwEFEF9tYXhPcGVuTm90aW9uYWwGAQxnZXRTcG90UHJpY2UBBm1hcmtldAQSX3F1b3RlQXNzZXRSZXNlcnZlCQEGcXRBc3RSAQUGbWFya2V0BBFfYmFzZUFzc2V0UmVzZXJ2ZQkBBmJzQXN0UgEFBm1hcmtldAQHX3F0QXN0VwkBBnF0QXN0VwEFBm1hcmtldAQHX2JzQXN0VwkBBmJzQXN0VwEFBm1hcmtldAkBBGRpdmQCCQEEbXVsZAIFEl9xdW90ZUFzc2V0UmVzZXJ2ZQUHX3F0QXN0VwkBBG11bGQCBRFfYmFzZUFzc2V0UmVzZXJ2ZQUHX2JzQXN0VwEWaXNPdmVyRmx1Y3R1YXRpb25MaW1pdAEGbWFya2V0BAtvcmFjbGVQcmljZQkBDmdldE9yYWNsZVByaWNlAQUGbWFya2V0BAxjdXJyZW50UHJpY2UJAQxnZXRTcG90UHJpY2UBBQZtYXJrZXQJAGYCCQEEZGl2ZAIJAQNhYnMBCQBlAgULb3JhY2xlUHJpY2UFDGN1cnJlbnRQcmljZQULb3JhY2xlUHJpY2UJAQtzcHJlYWRMaW1pdAEFBm1hcmtldAEfZ2V0UG9zaXRpb25BZGp1c3RlZE9wZW5Ob3Rpb25hbAcGbWFya2V0DV9wb3NpdGlvblNpemUHX29wdGlvbhJfcXVvdGVBc3NldFJlc2VydmURX3F1b3RlQXNzZXRXZWlnaHQRX2Jhc2VBc3NldFJlc2VydmUQX2Jhc2VBc3NldFdlaWdodAQPcG9zaXRpb25TaXplQWJzCQEDYWJzAQUNX3Bvc2l0aW9uU2l6ZQQHaXNTaG9ydAkAZgIAAAUNX3Bvc2l0aW9uU2l6ZQQQcG9zaXRpb25Ob3Rpb25hbAMJAAACBQdfb3B0aW9uBQ9QTkxfT1BUSU9OX1NQT1QEE291dFBvc2l0aW9uTm90aW9uYWwICQEWc3dhcE91dHB1dFdpdGhSZXNlcnZlcwgFBm1hcmtldAkBASEBBQdpc1Nob3J0BQ9wb3NpdGlvblNpemVBYnMHBRJfcXVvdGVBc3NldFJlc2VydmUFEV9xdW90ZUFzc2V0V2VpZ2h0BRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldFdlaWdodAJfMQUTb3V0UG9zaXRpb25Ob3Rpb25hbAkBBG11bGQCBQ9wb3NpdGlvblNpemVBYnMJAQ5nZXRPcmFjbGVQcmljZQEFBm1hcmtldAUQcG9zaXRpb25Ob3Rpb25hbAErZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmxCeVZhbHVlcwgGbWFya2V0DV9wb3NpdGlvblNpemUVX3Bvc2l0aW9uT3Blbk5vdGlvbmFsEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfcXVvdGVBc3NldFdlaWdodBFfYmFzZUFzc2V0UmVzZXJ2ZRBfYmFzZUFzc2V0V2VpZ2h0B19vcHRpb24DCQAAAgUNX3Bvc2l0aW9uU2l6ZQAACQACAQIVSW52YWxpZCBwb3NpdGlvbiBzaXplBAdpc1Nob3J0CQBmAgAABQ1fcG9zaXRpb25TaXplBBBwb3NpdGlvbk5vdGlvbmFsCQEfZ2V0UG9zaXRpb25BZGp1c3RlZE9wZW5Ob3Rpb25hbAcFBm1hcmtldAUNX3Bvc2l0aW9uU2l6ZQUHX29wdGlvbgUSX3F1b3RlQXNzZXRSZXNlcnZlBRFfcXVvdGVBc3NldFdlaWdodAURX2Jhc2VBc3NldFJlc2VydmUFEF9iYXNlQXNzZXRXZWlnaHQEDXVucmVhbGl6ZWRQbmwDBQdpc1Nob3J0CQBlAgUVX3Bvc2l0aW9uT3Blbk5vdGlvbmFsBRBwb3NpdGlvbk5vdGlvbmFsCQBlAgUQcG9zaXRpb25Ob3Rpb25hbAUVX3Bvc2l0aW9uT3Blbk5vdGlvbmFsCQCUCgIFEHBvc2l0aW9uTm90aW9uYWwFDXVucmVhbGl6ZWRQbmwBI2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sAwZtYXJrZXQHX3RyYWRlcgdfb3B0aW9uBAV0dXBsZQkBC2dldFBvc2l0aW9uAgUGbWFya2V0BQdfdHJhZGVyBAxwb3NpdGlvblNpemUIBQV0dXBsZQJfMQQOcG9zaXRpb25NYXJnaW4IBQV0dXBsZQJfMgQUcG9zaXRpb25PcGVuTm90aW9uYWwIBQV0dXBsZQJfMwQRcG9zaXRpb25Mc3RVcGRDUEYIBQV0dXBsZQJfNAkBK2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sQnlWYWx1ZXMIBQZtYXJrZXQFDHBvc2l0aW9uU2l6ZQUUcG9zaXRpb25PcGVuTm90aW9uYWwJAQZxdEFzdFIBBQZtYXJrZXQJAQZxdEFzdFcBBQZtYXJrZXQJAQZic0FzdFIBBQZtYXJrZXQJAQZic0FzdFcBBQZtYXJrZXQFB19vcHRpb24BD2NhbGNNYXJnaW5SYXRpbwMNX3JlbWFpbk1hcmdpbghfYmFkRGVidBFfcG9zaXRpb25Ob3Rpb25hbAkBBGRpdmQCCQBlAgUNX3JlbWFpbk1hcmdpbgUIX2JhZERlYnQFEV9wb3NpdGlvbk5vdGlvbmFsARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAwZtYXJrZXQHX3RyYWRlcgdfb3B0aW9uBAZ0dXBsZTEJAQtnZXRQb3NpdGlvbgIFBm1hcmtldAUHX3RyYWRlcgQMcG9zaXRpb25TaXplCAUGdHVwbGUxAl8xBA5wb3NpdGlvbk1hcmdpbggFBnR1cGxlMQJfMgQDcG9uCAUGdHVwbGUxAl8zBBZwb3NpdGlvbkxhc3RVcGRhdGVkQ1BGCAUGdHVwbGUxAl80BBFwb3NpdGlvblRpbWVzdGFtcAgFBnR1cGxlMQJfNQQGdHVwbGUyCQEjZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmwDBQZtYXJrZXQFB190cmFkZXIFB19vcHRpb24EEHBvc2l0aW9uTm90aW9uYWwIBQZ0dXBsZTICXzEEDXVucmVhbGl6ZWRQbmwIBQZ0dXBsZTICXzIEBnR1cGxlMwkBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQYFBm1hcmtldAUMcG9zaXRpb25TaXplBQ5wb3NpdGlvbk1hcmdpbgUWcG9zaXRpb25MYXN0VXBkYXRlZENQRgURcG9zaXRpb25UaW1lc3RhbXAFDXVucmVhbGl6ZWRQbmwEDHJlbWFpbk1hcmdpbggFBnR1cGxlMwJfMQQHYmFkRGVidAgFBnR1cGxlMwJfMgkBD2NhbGNNYXJnaW5SYXRpbwMFDHJlbWFpbk1hcmdpbgUHYmFkRGVidAUQcG9zaXRpb25Ob3Rpb25hbAEOZ2V0TWFyZ2luUmF0aW8CBm1hcmtldAdfdHJhZGVyCQEWZ2V0TWFyZ2luUmF0aW9CeU9wdGlvbgMFBm1hcmtldAUHX3RyYWRlcgUPUE5MX09QVElPTl9TUE9UAQlsaXF1aWRhdGUCBm1hcmtldAZ0cmFkZXIEDW1hcmtldEFkZHJlc3MJARFAZXh0ck5hdGl2ZSgxMDYyKQEFBm1hcmtldAQEc3luYwkA/AcEBQ1tYXJrZXRBZGRyZXNzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBA9zcG90TWFyZ2luUmF0aW8JARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAwUNbWFya2V0QWRkcmVzcwUGdHJhZGVyBQ9QTkxfT1BUSU9OX1NQT1QEFmxpcXVpZGF0aW9uTWFyZ2luUmF0aW8DCQEWaXNPdmVyRmx1Y3R1YXRpb25MaW1pdAEFDW1hcmtldEFkZHJlc3MEEW9yYWNsZU1hcmdpblJhdGlvCQEWZ2V0TWFyZ2luUmF0aW9CeU9wdGlvbgMFDW1hcmtldEFkZHJlc3MFBnRyYWRlcgURUE5MX09QVElPTl9PUkFDTEUJAQR2bWF4AgUPc3BvdE1hcmdpblJhdGlvBRFvcmFjbGVNYXJnaW5SYXRpbwUPc3BvdE1hcmdpblJhdGlvBBBtYWludE1hcmdpblJhdGlvCQEWbWFpbnRlbmFuY2VNYXJnaW5SYXRpbwEFDW1hcmtldEFkZHJlc3MEBWFsbG93AwMDCQEWcmVxdWlyZU1vcmVNYXJnaW5SYXRpbwMFFmxpcXVpZGF0aW9uTWFyZ2luUmF0aW8FEG1haW50TWFyZ2luUmF0aW8HCQETcmVxdWlyZU9wZW5Qb3NpdGlvbgIFDW1hcmtldEFkZHJlc3MFBnRyYWRlcgcJAQtpbml0aWFsaXplZAEFDW1hcmtldEFkZHJlc3MHCQEBIQEJAQZwYXVzZWQBBQ1tYXJrZXRBZGRyZXNzBwQDcmVzAwUFYWxsb3cAAQAABBRyZW1haW5pbmdNYXJnaW5SYXRpbwkAZQIFFmxpcXVpZGF0aW9uTWFyZ2luUmF0aW8FEG1haW50TWFyZ2luUmF0aW8JAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCkAwEFA3JlcwIBOwkApAMBBRZsaXF1aWRhdGlvbk1hcmdpblJhdGlvAgE7CQCkAwEFEG1haW50TWFyZ2luUmF0aW8CATsJAKQDAQUUcmVtYWluaW5nTWFyZ2luUmF0aW8JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4AAF3mcGU=", "chainId": 87, "height": 3520690, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 81NbskXGTc4mMRF2LA86EuzMnvKu8jDBLEKnJJptKHHA Next: 9PnJMJqpzJ6m4zbg6Mmiph7zhnxNqH4q2hebamr4eimw Diff:
Old | New | Differences | |
---|---|---|---|
348 | 348 | if (if (_largerThanOrEqualTo) | |
349 | 349 | then (0 > remainingMarginRatio) | |
350 | 350 | else false) | |
351 | - | then | |
351 | + | then true | |
352 | 352 | else if (if (!(_largerThanOrEqualTo)) | |
353 | 353 | then (remainingMarginRatio >= 0) | |
354 | 354 | else false) | |
355 | - | then | |
355 | + | then true | |
356 | 356 | else true | |
357 | 357 | } | |
358 | 358 | ||
398 | 398 | ||
399 | 399 | ||
400 | 400 | func requireOpenPosition (market,_trader) = if ((getPosition(market, _trader)._1 == 0)) | |
401 | - | then | |
401 | + | then false | |
402 | 402 | else true | |
403 | 403 | ||
404 | 404 | ||
701 | 701 | } | |
702 | 702 | else spotMarginRatio | |
703 | 703 | let maintMarginRatio = maintenanceMarginRatio(marketAddress) | |
704 | - | let allow = if (if (if ( | |
704 | + | let allow = if (if (if (requireMoreMarginRatio(liquidationMarginRatio, maintMarginRatio, false)) | |
705 | 705 | then requireOpenPosition(marketAddress, trader) | |
706 | 706 | else false) | |
707 | 707 | then initialized(marketAddress) | |
708 | 708 | else false) | |
709 | 709 | then !(paused(marketAddress)) | |
710 | - | else false) | |
711 | - | then !(isMarketClosed(marketAddress)) | |
712 | 710 | else false | |
713 | 711 | let res = if (allow) | |
714 | 712 | then 1 |
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 6 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | 4 | let k_baseOracle = "k_baseOracle" | |
5 | 5 | ||
6 | 6 | let k_quoteOracle = "k_quoteOracle" | |
7 | 7 | ||
8 | 8 | let k_balance = "k_balance" | |
9 | 9 | ||
10 | 10 | let k_sequence = "k_sequence" | |
11 | 11 | ||
12 | 12 | let k_positionSize = "k_positionSize" | |
13 | 13 | ||
14 | 14 | let k_positionMargin = "k_positionMargin" | |
15 | 15 | ||
16 | 16 | let k_positionOpenNotional = "k_positionOpenNotional" | |
17 | 17 | ||
18 | 18 | let k_positionLastUpdatedCumulativePremiumFraction = "k_positionFraction" | |
19 | 19 | ||
20 | 20 | let k_positionSequence = "k_positionSequence" | |
21 | 21 | ||
22 | 22 | let k_positionAsset = "k_positionAsset" | |
23 | 23 | ||
24 | 24 | let k_positionFee = "k_positionFee" | |
25 | 25 | ||
26 | 26 | let k_positionLastUpdatedTimestamp = "k_positionTimestamp" | |
27 | 27 | ||
28 | 28 | let k_initialized = "k_initialized" | |
29 | 29 | ||
30 | 30 | let k_paused = "k_paused" | |
31 | 31 | ||
32 | 32 | let k_closeOnly = "k_closeOnly" | |
33 | 33 | ||
34 | 34 | let k_fee = "k_fee" | |
35 | 35 | ||
36 | 36 | let k_rolloverFee = "k_rollover_fee" | |
37 | 37 | ||
38 | 38 | let k_fundingPeriod = "k_fundingPeriod" | |
39 | 39 | ||
40 | 40 | let k_initMarginRatio = "k_initMarginRatio" | |
41 | 41 | ||
42 | 42 | let k_maintenanceMarginRatio = "k_mmr" | |
43 | 43 | ||
44 | 44 | let k_liquidationFeeRatio = "k_liquidationFeeRatio" | |
45 | 45 | ||
46 | 46 | let k_partialLiquidationRatio = "k_partLiquidationRatio" | |
47 | 47 | ||
48 | 48 | let k_spreadLimit = "k_spreadLimit" | |
49 | 49 | ||
50 | 50 | let k_maxPriceImpact = "k_maxPriceImpact" | |
51 | 51 | ||
52 | 52 | let k_maxPriceSpread = "k_maxPriceSpread" | |
53 | 53 | ||
54 | 54 | let k_maxOpenNotional = "k_maxOpenNotional" | |
55 | 55 | ||
56 | 56 | let k_feeToStakersPercent = "k_feeToStakersPercent" | |
57 | 57 | ||
58 | 58 | let k_maxOracleDelay = "k_maxOracleDelay" | |
59 | 59 | ||
60 | 60 | let k_fundingMode = "k_fundingMode" | |
61 | 61 | ||
62 | 62 | let k_lastDataStr = "k_lastDataStr" | |
63 | 63 | ||
64 | 64 | let k_lastMinuteId = "k_lastMinuteId" | |
65 | 65 | ||
66 | 66 | let k_twapDataLastCumulativePrice = "k_twapDataLastCumulativePrice" | |
67 | 67 | ||
68 | 68 | let k_twapDataLastPrice = "k_twapDataLastPrice" | |
69 | 69 | ||
70 | 70 | let k_twapDataPreviousMinuteId = "k_twapDataPreviousMinuteId" | |
71 | 71 | ||
72 | 72 | let k_latestLongCumulativePremiumFraction = "k_latestLongPremiumFraction" | |
73 | 73 | ||
74 | 74 | let k_latestShortCumulativePremiumFraction = "k_latestShortPremiumFraction" | |
75 | 75 | ||
76 | 76 | let k_nextFundingBlock = "k_nextFundingBlockMinTimestamp" | |
77 | 77 | ||
78 | 78 | let k_longFundingRate = "k_longFundingRate" | |
79 | 79 | ||
80 | 80 | let k_shortFundingRate = "k_shortFundingRate" | |
81 | 81 | ||
82 | 82 | let k_quoteAssetReserve = "k_qtAstR" | |
83 | 83 | ||
84 | 84 | let k_baseAssetReserve = "k_bsAstR" | |
85 | 85 | ||
86 | 86 | let k_quoteAssetWeight = "k_qtAstW" | |
87 | 87 | ||
88 | 88 | let k_baseAssetWeight = "k_bsAstW" | |
89 | 89 | ||
90 | 90 | let k_totalPositionSize = "k_totalPositionSize" | |
91 | 91 | ||
92 | 92 | let k_totalLongPositionSize = "k_totalLongPositionSize" | |
93 | 93 | ||
94 | 94 | let k_totalShortPositionSize = "k_totalShortPositionSize" | |
95 | 95 | ||
96 | 96 | let k_openInterestNotional = "k_openInterestNotional" | |
97 | 97 | ||
98 | 98 | let k_openInterestShort = "k_openInterestShort" | |
99 | 99 | ||
100 | 100 | let k_openInterestLong = "k_openInterestLong" | |
101 | 101 | ||
102 | 102 | let k_lastTx = "k_lastTx" | |
103 | 103 | ||
104 | 104 | let k_coordinatorAddress = "k_coordinatorAddress" | |
105 | 105 | ||
106 | 106 | let k_vault_address = "k_vault_address" | |
107 | 107 | ||
108 | 108 | let k_admin_address = "k_admin_address" | |
109 | 109 | ||
110 | 110 | let k_quote_asset = "k_quote_asset" | |
111 | 111 | ||
112 | 112 | let k_quote_staking = "k_quote_staking" | |
113 | 113 | ||
114 | 114 | let k_staking_address = "k_staking_address" | |
115 | 115 | ||
116 | 116 | let k_miner_address = "k_miner_address" | |
117 | 117 | ||
118 | 118 | let k_orders_address = "k_orders_address" | |
119 | 119 | ||
120 | 120 | let k_referral_address = "k_referral_address" | |
121 | 121 | ||
122 | 122 | let k_exchange_address = "k_exchange_address" | |
123 | 123 | ||
124 | 124 | let k_nft_manager_address = "k_nft_manager_address" | |
125 | 125 | ||
126 | 126 | func toCompositeKey (_key,_address) = ((_key + "_") + _address) | |
127 | 127 | ||
128 | 128 | ||
129 | 129 | func coordinator (market) = valueOrErrorMessage(addressFromString(getStringValue(market, k_coordinatorAddress)), "Coordinator not set") | |
130 | 130 | ||
131 | 131 | ||
132 | 132 | func adminAddress (market) = addressFromString(getStringValue(coordinator(market), k_admin_address)) | |
133 | 133 | ||
134 | 134 | ||
135 | 135 | func quoteAsset (market) = fromBase58String(getStringValue(coordinator(market), k_quote_asset)) | |
136 | 136 | ||
137 | 137 | ||
138 | 138 | func quoteAssetStaking (market) = valueOrErrorMessage(addressFromString(getStringValue(coordinator(market), k_quote_staking)), "Quote asset staking not set") | |
139 | 139 | ||
140 | 140 | ||
141 | 141 | func stakingAddress (market) = valueOrErrorMessage(addressFromString(getStringValue(coordinator(market), k_staking_address)), "Staking not set") | |
142 | 142 | ||
143 | 143 | ||
144 | 144 | func vaultAddress (market) = valueOrErrorMessage(addressFromString(getStringValue(coordinator(market), k_vault_address)), "Vault not set") | |
145 | 145 | ||
146 | 146 | ||
147 | 147 | func minerAddress (market) = valueOrErrorMessage(addressFromString(getStringValue(coordinator(market), k_miner_address)), "Miner not set") | |
148 | 148 | ||
149 | 149 | ||
150 | 150 | func ordersAddress (market) = valueOrErrorMessage(addressFromString(getStringValue(coordinator(market), k_orders_address)), "Orders not set") | |
151 | 151 | ||
152 | 152 | ||
153 | 153 | func referralAddress (market) = valueOrErrorMessage(addressFromString(getStringValue(coordinator(market), k_referral_address)), "Referral not set") | |
154 | 154 | ||
155 | 155 | ||
156 | 156 | func nftManagerAddress (market) = valueOrErrorMessage(addressFromString(getStringValue(coordinator(market), k_nft_manager_address)), "NFT Manager not set") | |
157 | 157 | ||
158 | 158 | ||
159 | 159 | let k_token_param = "k_token_param" | |
160 | 160 | ||
161 | 161 | let k_token_type = "k_token_type" | |
162 | 162 | ||
163 | 163 | let FEE_REDUCTION_TOKEN_TYPE = "fee_reduction" | |
164 | 164 | ||
165 | 165 | let DIR_LONG = 1 | |
166 | 166 | ||
167 | 167 | let DIR_SHORT = 2 | |
168 | 168 | ||
169 | 169 | let TWAP_INTERVAL = 15 | |
170 | 170 | ||
171 | 171 | let SECONDS = 1000 | |
172 | 172 | ||
173 | 173 | let DECIMAL_NUMBERS = 6 | |
174 | 174 | ||
175 | 175 | let DECIMAL_UNIT = (1 * (((((10 * 10) * 10) * 10) * 10) * 10)) | |
176 | 176 | ||
177 | 177 | let MINUTES_IN_YEAR = (525600 * DECIMAL_UNIT) | |
178 | 178 | ||
179 | 179 | let ONE_DAY = (86400 * DECIMAL_UNIT) | |
180 | 180 | ||
181 | 181 | let PNL_OPTION_SPOT = 1 | |
182 | 182 | ||
183 | 183 | let PNL_OPTION_ORACLE = 2 | |
184 | 184 | ||
185 | 185 | let FUNDING_ASYMMETRIC = 1 | |
186 | 186 | ||
187 | 187 | let FUNDING_SYMMETRIC = 2 | |
188 | 188 | ||
189 | 189 | func s (_x) = (toString(_x) + ",") | |
190 | 190 | ||
191 | 191 | ||
192 | 192 | func divd (_x,_y) = fraction(_x, DECIMAL_UNIT, _y, HALFEVEN) | |
193 | 193 | ||
194 | 194 | ||
195 | 195 | func muld (_x,_y) = fraction(_x, _y, DECIMAL_UNIT, HALFEVEN) | |
196 | 196 | ||
197 | 197 | ||
198 | 198 | func bdivd (_x,_y) = fraction(_x, toBigInt(DECIMAL_UNIT), _y, HALFEVEN) | |
199 | 199 | ||
200 | 200 | ||
201 | 201 | func bmuld (_x,_y) = fraction(_x, _y, toBigInt(DECIMAL_UNIT), HALFEVEN) | |
202 | 202 | ||
203 | 203 | ||
204 | 204 | func abs (_x) = if ((_x > 0)) | |
205 | 205 | then _x | |
206 | 206 | else -(_x) | |
207 | 207 | ||
208 | 208 | ||
209 | 209 | func vmax (_x,_y) = if ((_x >= _y)) | |
210 | 210 | then _x | |
211 | 211 | else _y | |
212 | 212 | ||
213 | 213 | ||
214 | 214 | func listToStr (_list) = if ((size(_list) == 0)) | |
215 | 215 | then "" | |
216 | 216 | else makeString(_list, ",") | |
217 | 217 | ||
218 | 218 | ||
219 | 219 | func strToList (_str) = if ((_str == "")) | |
220 | 220 | then nil | |
221 | 221 | else split(_str, ",") | |
222 | 222 | ||
223 | 223 | ||
224 | 224 | func pushToQueue (_list,_maxSize,_value) = if ((size(_list) > _maxSize)) | |
225 | 225 | then (removeByIndex(_list, 0) :+ _value) | |
226 | 226 | else (_list :+ _value) | |
227 | 227 | ||
228 | 228 | ||
229 | 229 | func int (market,k) = valueOrErrorMessage(getInteger(market, k), ("no value for " + k)) | |
230 | 230 | ||
231 | 231 | ||
232 | 232 | func intOr (market,k,def) = valueOrElse(getInteger(market, k), def) | |
233 | 233 | ||
234 | 234 | ||
235 | 235 | func strA (_address,_key) = { | |
236 | 236 | let val = valueOrErrorMessage(getString(_address, _key), ("No value for key " + _key)) | |
237 | 237 | val | |
238 | 238 | } | |
239 | 239 | ||
240 | 240 | ||
241 | 241 | func intA (_address,_key) = { | |
242 | 242 | let val = valueOrErrorMessage(getInteger(_address, _key), ("No value for key " + _key)) | |
243 | 243 | val | |
244 | 244 | } | |
245 | 245 | ||
246 | 246 | ||
247 | 247 | func cbalance (market) = int(market, k_balance) | |
248 | 248 | ||
249 | 249 | ||
250 | 250 | func fee (market) = int(market, k_fee) | |
251 | 251 | ||
252 | 252 | ||
253 | 253 | func rolloverFeeRate (market) = int(market, k_rolloverFee) | |
254 | 254 | ||
255 | 255 | ||
256 | 256 | func initMarginRatio (market) = int(market, k_initMarginRatio) | |
257 | 257 | ||
258 | 258 | ||
259 | 259 | func qtAstR (market) = int(market, k_quoteAssetReserve) | |
260 | 260 | ||
261 | 261 | ||
262 | 262 | func bsAstR (market) = int(market, k_baseAssetReserve) | |
263 | 263 | ||
264 | 264 | ||
265 | 265 | func qtAstW (market) = intOr(market, k_quoteAssetWeight, DECIMAL_UNIT) | |
266 | 266 | ||
267 | 267 | ||
268 | 268 | func bsAstW (market) = intOr(market, k_baseAssetWeight, DECIMAL_UNIT) | |
269 | 269 | ||
270 | 270 | ||
271 | 271 | func totalPositionSize (market) = int(market, k_totalPositionSize) | |
272 | 272 | ||
273 | 273 | ||
274 | 274 | func openInterestNotional (market) = int(market, k_openInterestNotional) | |
275 | 275 | ||
276 | 276 | ||
277 | 277 | func openInterestShort (market) = int(market, k_openInterestShort) | |
278 | 278 | ||
279 | 279 | ||
280 | 280 | func openInterestLong (market) = int(market, k_openInterestLong) | |
281 | 281 | ||
282 | 282 | ||
283 | 283 | func nextFundingBlockTimestamp (market) = int(market, k_nextFundingBlock) | |
284 | 284 | ||
285 | 285 | ||
286 | 286 | func fundingPeriodRaw (market) = int(market, k_fundingPeriod) | |
287 | 287 | ||
288 | 288 | ||
289 | 289 | func fundingPeriodDecimal (market) = (fundingPeriodRaw(market) * DECIMAL_UNIT) | |
290 | 290 | ||
291 | 291 | ||
292 | 292 | func fundingPeriodSeconds (market) = (fundingPeriodRaw(market) * SECONDS) | |
293 | 293 | ||
294 | 294 | ||
295 | 295 | func maintenanceMarginRatio (market) = int(market, k_maintenanceMarginRatio) | |
296 | 296 | ||
297 | 297 | ||
298 | 298 | func liquidationFeeRatio (market) = int(market, k_liquidationFeeRatio) | |
299 | 299 | ||
300 | 300 | ||
301 | 301 | func partialLiquidationRatio (market) = int(market, k_partialLiquidationRatio) | |
302 | 302 | ||
303 | 303 | ||
304 | 304 | func spreadLimit (market) = int(market, k_spreadLimit) | |
305 | 305 | ||
306 | 306 | ||
307 | 307 | func maxPriceImpact (market) = int(market, k_maxPriceImpact) | |
308 | 308 | ||
309 | 309 | ||
310 | 310 | func maxPriceSpread (market) = int(market, k_maxPriceSpread) | |
311 | 311 | ||
312 | 312 | ||
313 | 313 | func maxOpenNotional (market) = int(market, k_maxOpenNotional) | |
314 | 314 | ||
315 | 315 | ||
316 | 316 | func latestLongCumulativePremiumFraction (market) = int(market, k_latestLongCumulativePremiumFraction) | |
317 | 317 | ||
318 | 318 | ||
319 | 319 | func latestShortCumulativePremiumFraction (market) = int(market, k_latestShortCumulativePremiumFraction) | |
320 | 320 | ||
321 | 321 | ||
322 | 322 | func totalShortPositionSize (market) = int(market, k_totalShortPositionSize) | |
323 | 323 | ||
324 | 324 | ||
325 | 325 | func totalLongPositionSize (market) = int(market, k_totalLongPositionSize) | |
326 | 326 | ||
327 | 327 | ||
328 | 328 | func lastSequence (market) = intOr(market, k_sequence, 0) | |
329 | 329 | ||
330 | 330 | ||
331 | 331 | func feeToStakersPercent (market) = int(market, k_feeToStakersPercent) | |
332 | 332 | ||
333 | 333 | ||
334 | 334 | func maxOracleDelay (market) = int(market, k_maxOracleDelay) | |
335 | 335 | ||
336 | 336 | ||
337 | 337 | func fundingMode (market) = intOr(market, k_fundingMode, FUNDING_ASYMMETRIC) | |
338 | 338 | ||
339 | 339 | ||
340 | 340 | func lastTimestamp () = lastBlock.timestamp | |
341 | 341 | ||
342 | 342 | ||
343 | 343 | func getActualCaller (market,i) = valueOrElse(getString(ordersAddress(market), "k_sender"), toString(i.caller)) | |
344 | 344 | ||
345 | 345 | ||
346 | 346 | func requireMoreMarginRatio (_marginRatio,_baseMarginRatio,_largerThanOrEqualTo) = { | |
347 | 347 | let remainingMarginRatio = (_marginRatio - _baseMarginRatio) | |
348 | 348 | if (if (_largerThanOrEqualTo) | |
349 | 349 | then (0 > remainingMarginRatio) | |
350 | 350 | else false) | |
351 | - | then | |
351 | + | then true | |
352 | 352 | else if (if (!(_largerThanOrEqualTo)) | |
353 | 353 | then (remainingMarginRatio >= 0) | |
354 | 354 | else false) | |
355 | - | then | |
355 | + | then true | |
356 | 356 | else true | |
357 | 357 | } | |
358 | 358 | ||
359 | 359 | ||
360 | 360 | func latestCumulativePremiumFraction (market,_positionSize) = if ((_positionSize == 0)) | |
361 | 361 | then throw("Should not be called with _positionSize == 0") | |
362 | 362 | else if ((_positionSize > 0)) | |
363 | 363 | then latestLongCumulativePremiumFraction(market) | |
364 | 364 | else latestShortCumulativePremiumFraction(market) | |
365 | 365 | ||
366 | 366 | ||
367 | 367 | func getPosition (market,_trader) = { | |
368 | 368 | let positionSizeOpt = getInteger(market, toCompositeKey(k_positionSize, _trader)) | |
369 | 369 | match positionSizeOpt { | |
370 | 370 | case positionSize: Int => | |
371 | 371 | $Tuple5(positionSize, getIntegerValue(market, toCompositeKey(k_positionMargin, _trader)), getIntegerValue(market, toCompositeKey(k_positionOpenNotional, _trader)), getIntegerValue(market, toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _trader)), getIntegerValue(market, toCompositeKey(k_positionLastUpdatedTimestamp, _trader))) | |
372 | 372 | case _ => | |
373 | 373 | $Tuple5(0, 0, 0, 0, 0) | |
374 | 374 | } | |
375 | 375 | } | |
376 | 376 | ||
377 | 377 | ||
378 | 378 | func getPositionAsset (market,_trader) = { | |
379 | 379 | let positionAssetOpt = getString(market, toCompositeKey(k_positionAsset, _trader)) | |
380 | 380 | match positionAssetOpt { | |
381 | 381 | case positionAsset: String => | |
382 | 382 | positionAsset | |
383 | 383 | case _ => | |
384 | 384 | toBase58String(quoteAsset(market)) | |
385 | 385 | } | |
386 | 386 | } | |
387 | 387 | ||
388 | 388 | ||
389 | 389 | func getPositionFee (market,_trader) = { | |
390 | 390 | let positionFeeOpt = getInteger(market, toCompositeKey(k_positionFee, _trader)) | |
391 | 391 | match positionFeeOpt { | |
392 | 392 | case positionFee: Int => | |
393 | 393 | positionFee | |
394 | 394 | case _ => | |
395 | 395 | fee(market) | |
396 | 396 | } | |
397 | 397 | } | |
398 | 398 | ||
399 | 399 | ||
400 | 400 | func requireOpenPosition (market,_trader) = if ((getPosition(market, _trader)._1 == 0)) | |
401 | - | then | |
401 | + | then false | |
402 | 402 | else true | |
403 | 403 | ||
404 | 404 | ||
405 | 405 | func getOracleData (market,key) = { | |
406 | 406 | let oracleDataStr = getString(market, key) | |
407 | 407 | if (if (isDefined(oracleDataStr)) | |
408 | 408 | then (value(oracleDataStr) != "") | |
409 | 409 | else false) | |
410 | 410 | then { | |
411 | 411 | let oracleData = split(value(oracleDataStr), ",") | |
412 | 412 | let oracleAddress = valueOrErrorMessage(addressFromString(oracleData[0]), ("Invalid oracle address in: " + value(oracleDataStr))) | |
413 | 413 | let priceKey = oracleData[1] | |
414 | 414 | let blockKey = oracleData[2] | |
415 | 415 | let openKey = oracleData[3] | |
416 | 416 | $Tuple4(oracleAddress, priceKey, blockKey, openKey) | |
417 | 417 | } | |
418 | 418 | else unit | |
419 | 419 | } | |
420 | 420 | ||
421 | 421 | ||
422 | 422 | func initialized (market) = valueOrElse(getBoolean(market, k_initialized), false) | |
423 | 423 | ||
424 | 424 | ||
425 | 425 | func paused (market) = valueOrElse(getBoolean(market, k_paused), false) | |
426 | 426 | ||
427 | 427 | ||
428 | 428 | func closeOnly (market) = valueOrElse(getBoolean(market, k_closeOnly), false) | |
429 | 429 | ||
430 | 430 | ||
431 | 431 | func updateReserve (market,_isAdd,_quoteAssetAmount,_baseAssetAmount) = if (_isAdd) | |
432 | 432 | then { | |
433 | 433 | let newBase = (bsAstR(market) - _baseAssetAmount) | |
434 | 434 | if ((0 >= newBase)) | |
435 | 435 | then throw("Tx lead to base asset reserve <= 0, revert") | |
436 | 436 | else $Tuple3((qtAstR(market) + _quoteAssetAmount), newBase, (totalPositionSize(market) + _baseAssetAmount)) | |
437 | 437 | } | |
438 | 438 | else { | |
439 | 439 | let newQuote = (qtAstR(market) - _quoteAssetAmount) | |
440 | 440 | if ((0 >= newQuote)) | |
441 | 441 | then throw("Tx lead to base quote reserve <= 0, revert") | |
442 | 442 | else $Tuple3(newQuote, (bsAstR(market) + _baseAssetAmount), (totalPositionSize(market) - _baseAssetAmount)) | |
443 | 443 | } | |
444 | 444 | ||
445 | 445 | ||
446 | 446 | func calcInvariant (_qtAstR,_bsAstR) = { | |
447 | 447 | let bqtAstR = toBigInt(_qtAstR) | |
448 | 448 | let bbsAstR = toBigInt(_bsAstR) | |
449 | 449 | bmuld(bqtAstR, bbsAstR) | |
450 | 450 | } | |
451 | 451 | ||
452 | 452 | ||
453 | 453 | func swapInput (market,_isAdd,_quoteAssetAmount) = { | |
454 | 454 | let _qtAstR = qtAstR(market) | |
455 | 455 | let _bsAstR = bsAstR(market) | |
456 | 456 | let _qtAstW = qtAstW(market) | |
457 | 457 | let _bsAstW = bsAstW(market) | |
458 | 458 | let quoteAssetAmountAdjusted = divd(_quoteAssetAmount, _qtAstW) | |
459 | 459 | let k = calcInvariant(_qtAstR, _bsAstR) | |
460 | 460 | let quoteAssetReserveAfter = if (_isAdd) | |
461 | 461 | then (_qtAstR + quoteAssetAmountAdjusted) | |
462 | 462 | else (_qtAstR - quoteAssetAmountAdjusted) | |
463 | 463 | let baseAssetReserveAfter = toInt(bdivd(k, toBigInt(quoteAssetReserveAfter))) | |
464 | 464 | let amountBaseAssetBoughtAbs = abs((baseAssetReserveAfter - _bsAstR)) | |
465 | 465 | let amountBaseAssetBought = if (_isAdd) | |
466 | 466 | then amountBaseAssetBoughtAbs | |
467 | 467 | else -(amountBaseAssetBoughtAbs) | |
468 | 468 | let tuple = updateReserve(market, _isAdd, quoteAssetAmountAdjusted, amountBaseAssetBoughtAbs) | |
469 | 469 | let quoteAssetReserveAfter1 = tuple._1 | |
470 | 470 | let baseAssetReserveAfter1 = tuple._2 | |
471 | 471 | let totalPositionSizeAfter1 = tuple._3 | |
472 | 472 | let priceBefore = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW)) | |
473 | 473 | let marketPrice = divd(_quoteAssetAmount, amountBaseAssetBoughtAbs) | |
474 | 474 | let priceDiff = abs((priceBefore - marketPrice)) | |
475 | 475 | let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff))) | |
476 | 476 | let maxPriceImpactValue = maxPriceImpact(market) | |
477 | 477 | if ((priceImpact > maxPriceImpactValue)) | |
478 | 478 | 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))) | |
479 | 479 | else $Tuple4(amountBaseAssetBought, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1) | |
480 | 480 | } | |
481 | 481 | ||
482 | 482 | ||
483 | 483 | func calcRolloverFee (market,_oldPositionMargin,_oldPositionLastUpdatedTimestamp) = { | |
484 | 484 | let positionMinutes = ((((lastTimestamp() - _oldPositionLastUpdatedTimestamp) / 1000) / 60) * DECIMAL_UNIT) | |
485 | 485 | let rolloverFee = divd(muld(muld(_oldPositionMargin, positionMinutes), rolloverFeeRate(market)), MINUTES_IN_YEAR) | |
486 | 486 | rolloverFee | |
487 | 487 | } | |
488 | 488 | ||
489 | 489 | ||
490 | 490 | func calcRemainMarginWithFundingPaymentAndRolloverFee (market,_oldPositionSize,_oldPositionMargin,_oldPositionCumulativePremiumFraction,_oldPositionLastUpdatedTimestamp,_marginDelta) = { | |
491 | 491 | let fundingPayment = if ((_oldPositionSize != 0)) | |
492 | 492 | then { | |
493 | 493 | let _latestCumulativePremiumFraction = latestCumulativePremiumFraction(market, _oldPositionSize) | |
494 | 494 | muld((_latestCumulativePremiumFraction - _oldPositionCumulativePremiumFraction), _oldPositionSize) | |
495 | 495 | } | |
496 | 496 | else 0 | |
497 | 497 | let rolloverFee = calcRolloverFee(market, _oldPositionMargin, _oldPositionLastUpdatedTimestamp) | |
498 | 498 | let signedMargin = (((_marginDelta - rolloverFee) - fundingPayment) + _oldPositionMargin) | |
499 | 499 | let tuple = if ((0 > signedMargin)) | |
500 | 500 | then $Tuple2(0, abs(signedMargin)) | |
501 | 501 | else $Tuple2(abs(signedMargin), 0) | |
502 | 502 | let remainMargin = tuple._1 | |
503 | 503 | let badDebt = tuple._2 | |
504 | 504 | $Tuple4(remainMargin, badDebt, fundingPayment, rolloverFee) | |
505 | 505 | } | |
506 | 506 | ||
507 | 507 | ||
508 | 508 | func swapOutputWithReserves (market,_isAdd,_baseAssetAmount,_checkMaxPriceImpact,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight) = { | |
509 | 509 | let priceBefore = divd(muld(_quoteAssetReserve, _quoteAssetWeight), muld(_baseAssetReserve, _baseAssetWeight)) | |
510 | 510 | if ((_baseAssetAmount == 0)) | |
511 | 511 | then throw("Invalid base asset amount") | |
512 | 512 | else { | |
513 | 513 | let k = calcInvariant(_quoteAssetReserve, _baseAssetReserve) | |
514 | 514 | let baseAssetPoolAmountAfter = if (_isAdd) | |
515 | 515 | then (_baseAssetReserve + _baseAssetAmount) | |
516 | 516 | else (_baseAssetReserve - _baseAssetAmount) | |
517 | 517 | let quoteAssetAfter = toInt(bdivd(k, toBigInt(baseAssetPoolAmountAfter))) | |
518 | 518 | let quoteAssetDelta = abs((quoteAssetAfter - _quoteAssetReserve)) | |
519 | 519 | let quoteAssetSold = muld(quoteAssetDelta, _quoteAssetWeight) | |
520 | 520 | let maxPriceImpactValue = maxPriceImpact(market) | |
521 | 521 | let tuple = updateReserve(market, !(_isAdd), quoteAssetDelta, _baseAssetAmount) | |
522 | 522 | let quoteAssetReserveAfter1 = tuple._1 | |
523 | 523 | let baseAssetReserveAfter1 = tuple._2 | |
524 | 524 | let totalPositionSizeAfter1 = tuple._3 | |
525 | 525 | let marketPrice = divd(quoteAssetSold, _baseAssetAmount) | |
526 | 526 | let priceDiff = abs((priceBefore - marketPrice)) | |
527 | 527 | let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff))) | |
528 | 528 | if (if ((priceImpact > maxPriceImpactValue)) | |
529 | 529 | then _checkMaxPriceImpact | |
530 | 530 | else false) | |
531 | 531 | 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))) | |
532 | 532 | else $Tuple7(quoteAssetSold, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1, (totalLongPositionSize(market) - (if (_isAdd) | |
533 | 533 | then abs(_baseAssetAmount) | |
534 | 534 | else 0)), (totalShortPositionSize(market) - (if (!(_isAdd)) | |
535 | 535 | then abs(_baseAssetAmount) | |
536 | 536 | else 0)), priceImpact) | |
537 | 537 | } | |
538 | 538 | } | |
539 | 539 | ||
540 | 540 | ||
541 | 541 | func swapOutput (market,_isAdd,_baseAssetAmount,_checkMaxPriceImpact) = swapOutputWithReserves(market, _isAdd, _baseAssetAmount, _checkMaxPriceImpact, qtAstR(market), qtAstW(market), bsAstR(market), bsAstW(market)) | |
542 | 542 | ||
543 | 543 | ||
544 | 544 | func getOraclePriceValue (market,oracle,priceKey,blockKey) = { | |
545 | 545 | let lastValue = valueOrErrorMessage(getInteger(oracle, priceKey), ((("Can not get oracle price. Oracle: " + toString(oracle)) + " key: ") + priceKey)) | |
546 | 546 | if ((blockKey != "")) | |
547 | 547 | then { | |
548 | 548 | let currentBlock = lastBlock.height | |
549 | 549 | let lastOracleBlock = valueOrErrorMessage(getInteger(oracle, blockKey), ((("Can not get oracle block. Oracle: " + toString(oracle)) + " key: ") + blockKey)) | |
550 | 550 | if (((currentBlock - lastOracleBlock) > maxOracleDelay(market))) | |
551 | 551 | then throw(((("Oracle stale data. Last oracle block: " + toString(lastOracleBlock)) + " current block: ") + toString(currentBlock))) | |
552 | 552 | else lastValue | |
553 | 553 | } | |
554 | 554 | else lastValue | |
555 | 555 | } | |
556 | 556 | ||
557 | 557 | ||
558 | 558 | func getOraclePrice (market) = { | |
559 | 559 | let baseOracle = valueOrErrorMessage(getOracleData(market, k_baseOracle), "No base asset oracle data") | |
560 | 560 | let baseOraclePrice = getOraclePriceValue(market, baseOracle._1, baseOracle._2, baseOracle._3) | |
561 | 561 | let quoteOracle = getOracleData(market, k_quoteOracle) | |
562 | 562 | let quoteOraclePrice = if (isDefined(quoteOracle)) | |
563 | 563 | then { | |
564 | 564 | let quoteOracleV = value(quoteOracle) | |
565 | 565 | getOraclePriceValue(market, quoteOracleV._1, quoteOracleV._2, quoteOracleV._3) | |
566 | 566 | } | |
567 | 567 | else DECIMAL_UNIT | |
568 | 568 | divd(baseOraclePrice, quoteOraclePrice) | |
569 | 569 | } | |
570 | 570 | ||
571 | 571 | ||
572 | 572 | func isMarketClosed (market) = { | |
573 | 573 | let baseOracle = valueOrErrorMessage(getOracleData(market, k_baseOracle), "No base asset oracle data") | |
574 | 574 | let oracle = baseOracle._1 | |
575 | 575 | let openKey = baseOracle._4 | |
576 | 576 | if ((openKey != "")) | |
577 | 577 | then { | |
578 | 578 | let isOpen = valueOrErrorMessage(getBoolean(oracle, openKey), ((("Can not get oracle is open/closed. Oracle: " + toString(oracle)) + " key: ") + openKey)) | |
579 | 579 | !(isOpen) | |
580 | 580 | } | |
581 | 581 | else false | |
582 | 582 | } | |
583 | 583 | ||
584 | 584 | ||
585 | 585 | func absPriceDiff (_oraclePrice,_quoteAssetReserve,_baseAssetReserve,_qtAstW,_bsAstW) = { | |
586 | 586 | let priceAfter = divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW)) | |
587 | 587 | let averagePrice = divd((_oraclePrice + priceAfter), (2 * DECIMAL_UNIT)) | |
588 | 588 | let absPriceDiff = divd(abs((_oraclePrice - priceAfter)), averagePrice) | |
589 | 589 | absPriceDiff | |
590 | 590 | } | |
591 | 591 | ||
592 | 592 | ||
593 | 593 | func requireNotOverSpreadLimit (market,_quoteAssetReserve,_baseAssetReserve) = { | |
594 | 594 | let oraclePrice = getOraclePrice(market) | |
595 | 595 | let _qtAstW = qtAstW(market) | |
596 | 596 | let _bsAstW = bsAstW(market) | |
597 | 597 | let absPriceDiffBefore = absPriceDiff(oraclePrice, qtAstR(market), bsAstR(market), _qtAstW, _bsAstW) | |
598 | 598 | let absPriceDiffAfter = absPriceDiff(oraclePrice, _quoteAssetReserve, _baseAssetReserve, _qtAstW, _bsAstW) | |
599 | 599 | if (if ((absPriceDiffAfter > maxPriceSpread(market))) | |
600 | 600 | then (absPriceDiffAfter > absPriceDiffBefore) | |
601 | 601 | else false) | |
602 | 602 | then throw(((("Price spread " + toString(absPriceDiffAfter)) + " > max price spread ") + toString(maxPriceSpread(market)))) | |
603 | 603 | else true | |
604 | 604 | } | |
605 | 605 | ||
606 | 606 | ||
607 | 607 | func requireNotOverMaxOpenNotional (market,_longOpenNotional,_shortOpenNotional) = { | |
608 | 608 | let _maxOpenNotional = maxOpenNotional(market) | |
609 | 609 | if ((_longOpenNotional > _maxOpenNotional)) | |
610 | 610 | then throw(((("Long open notional " + toString(_longOpenNotional)) + " > max open notional ") + toString(_maxOpenNotional))) | |
611 | 611 | else if ((_shortOpenNotional > _maxOpenNotional)) | |
612 | 612 | then throw(((("Short open notional " + toString(_shortOpenNotional)) + " > max open notional ") + toString(_maxOpenNotional))) | |
613 | 613 | else true | |
614 | 614 | } | |
615 | 615 | ||
616 | 616 | ||
617 | 617 | func getSpotPrice (market) = { | |
618 | 618 | let _quoteAssetReserve = qtAstR(market) | |
619 | 619 | let _baseAssetReserve = bsAstR(market) | |
620 | 620 | let _qtAstW = qtAstW(market) | |
621 | 621 | let _bsAstW = bsAstW(market) | |
622 | 622 | divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW)) | |
623 | 623 | } | |
624 | 624 | ||
625 | 625 | ||
626 | 626 | func isOverFluctuationLimit (market) = { | |
627 | 627 | let oraclePrice = getOraclePrice(market) | |
628 | 628 | let currentPrice = getSpotPrice(market) | |
629 | 629 | (divd(abs((oraclePrice - currentPrice)), oraclePrice) > spreadLimit(market)) | |
630 | 630 | } | |
631 | 631 | ||
632 | 632 | ||
633 | 633 | func getPositionAdjustedOpenNotional (market,_positionSize,_option,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight) = { | |
634 | 634 | let positionSizeAbs = abs(_positionSize) | |
635 | 635 | let isShort = (0 > _positionSize) | |
636 | 636 | let positionNotional = if ((_option == PNL_OPTION_SPOT)) | |
637 | 637 | then { | |
638 | 638 | let outPositionNotional = swapOutputWithReserves(market, !(isShort), positionSizeAbs, false, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)._1 | |
639 | 639 | outPositionNotional | |
640 | 640 | } | |
641 | 641 | else muld(positionSizeAbs, getOraclePrice(market)) | |
642 | 642 | positionNotional | |
643 | 643 | } | |
644 | 644 | ||
645 | 645 | ||
646 | 646 | func getPositionNotionalAndUnrealizedPnlByValues (market,_positionSize,_positionOpenNotional,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight,_option) = if ((_positionSize == 0)) | |
647 | 647 | then throw("Invalid position size") | |
648 | 648 | else { | |
649 | 649 | let isShort = (0 > _positionSize) | |
650 | 650 | let positionNotional = getPositionAdjustedOpenNotional(market, _positionSize, _option, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight) | |
651 | 651 | let unrealizedPnl = if (isShort) | |
652 | 652 | then (_positionOpenNotional - positionNotional) | |
653 | 653 | else (positionNotional - _positionOpenNotional) | |
654 | 654 | $Tuple2(positionNotional, unrealizedPnl) | |
655 | 655 | } | |
656 | 656 | ||
657 | 657 | ||
658 | 658 | func getPositionNotionalAndUnrealizedPnl (market,_trader,_option) = { | |
659 | 659 | let tuple = getPosition(market, _trader) | |
660 | 660 | let positionSize = tuple._1 | |
661 | 661 | let positionMargin = tuple._2 | |
662 | 662 | let positionOpenNotional = tuple._3 | |
663 | 663 | let positionLstUpdCPF = tuple._4 | |
664 | 664 | getPositionNotionalAndUnrealizedPnlByValues(market, positionSize, positionOpenNotional, qtAstR(market), qtAstW(market), bsAstR(market), bsAstW(market), _option) | |
665 | 665 | } | |
666 | 666 | ||
667 | 667 | ||
668 | 668 | func calcMarginRatio (_remainMargin,_badDebt,_positionNotional) = divd((_remainMargin - _badDebt), _positionNotional) | |
669 | 669 | ||
670 | 670 | ||
671 | 671 | func getMarginRatioByOption (market,_trader,_option) = { | |
672 | 672 | let tuple1 = getPosition(market, _trader) | |
673 | 673 | let positionSize = tuple1._1 | |
674 | 674 | let positionMargin = tuple1._2 | |
675 | 675 | let pon = tuple1._3 | |
676 | 676 | let positionLastUpdatedCPF = tuple1._4 | |
677 | 677 | let positionTimestamp = tuple1._5 | |
678 | 678 | let tuple2 = getPositionNotionalAndUnrealizedPnl(market, _trader, _option) | |
679 | 679 | let positionNotional = tuple2._1 | |
680 | 680 | let unrealizedPnl = tuple2._2 | |
681 | 681 | let tuple3 = calcRemainMarginWithFundingPaymentAndRolloverFee(market, positionSize, positionMargin, positionLastUpdatedCPF, positionTimestamp, unrealizedPnl) | |
682 | 682 | let remainMargin = tuple3._1 | |
683 | 683 | let badDebt = tuple3._2 | |
684 | 684 | calcMarginRatio(remainMargin, badDebt, positionNotional) | |
685 | 685 | } | |
686 | 686 | ||
687 | 687 | ||
688 | 688 | func getMarginRatio (market,_trader) = getMarginRatioByOption(market, _trader, PNL_OPTION_SPOT) | |
689 | 689 | ||
690 | 690 | ||
691 | 691 | func liquidate (market,trader) = { | |
692 | 692 | let marketAddress = addressFromStringValue(market) | |
693 | 693 | let sync = invoke(marketAddress, "syncTerminalPriceToOracle", nil, nil) | |
694 | 694 | if ((sync == sync)) | |
695 | 695 | then { | |
696 | 696 | let spotMarginRatio = getMarginRatioByOption(marketAddress, trader, PNL_OPTION_SPOT) | |
697 | 697 | let liquidationMarginRatio = if (isOverFluctuationLimit(marketAddress)) | |
698 | 698 | then { | |
699 | 699 | let oracleMarginRatio = getMarginRatioByOption(marketAddress, trader, PNL_OPTION_ORACLE) | |
700 | 700 | vmax(spotMarginRatio, oracleMarginRatio) | |
701 | 701 | } | |
702 | 702 | else spotMarginRatio | |
703 | 703 | let maintMarginRatio = maintenanceMarginRatio(marketAddress) | |
704 | - | let allow = if (if (if ( | |
704 | + | let allow = if (if (if (requireMoreMarginRatio(liquidationMarginRatio, maintMarginRatio, false)) | |
705 | 705 | then requireOpenPosition(marketAddress, trader) | |
706 | 706 | else false) | |
707 | 707 | then initialized(marketAddress) | |
708 | 708 | else false) | |
709 | 709 | then !(paused(marketAddress)) | |
710 | - | else false) | |
711 | - | then !(isMarketClosed(marketAddress)) | |
712 | 710 | else false | |
713 | 711 | let res = if (allow) | |
714 | 712 | then 1 | |
715 | 713 | else 0 | |
716 | 714 | let remainingMarginRatio = (liquidationMarginRatio - maintMarginRatio) | |
717 | 715 | throw(((((((toString(res) + ";") + toString(liquidationMarginRatio)) + ";") + toString(maintMarginRatio)) + ";") + toString(remainingMarginRatio))) | |
718 | 716 | } | |
719 | 717 | else throw("Strict value is not equal to itself.") | |
720 | 718 | } | |
721 | 719 | ||
722 | 720 | ||
723 | 721 |
github/deemru/w8io/0e76f2f 78.39 ms ◑