tx · 38uueL58LQ3CAXPXJbX7wEcHzX2EZgUbgo41CgqVgUYN

3MzGPAZokuNfqjMuP7yDXFATZjhjtEP5UCa:  -0.03700000 Waves

2023.03.10 19:36 [2484221] smart account 3MzGPAZokuNfqjMuP7yDXFATZjhjtEP5UCa > SELF 0.00000000 Waves

{ "type": 13, "id": "38uueL58LQ3CAXPXJbX7wEcHzX2EZgUbgo41CgqVgUYN", "fee": 3700000, "feeAssetId": null, "timestamp": 1678466215781, "version": 2, "chainId": 84, "sender": "3MzGPAZokuNfqjMuP7yDXFATZjhjtEP5UCa", "senderPublicKey": "4EBKd2zSCvpiSLeyovT5FUuMvGpi6oxdBAbvQybSYi6p", "proofs": [ "2ZjwmRv9eLqWoPxQaiDrd5Rw23n6jmcPmiFB2sBYkV1skwHZmcWga5nxf5okr8e1p9CXkne6nhbjFeicmhkwgdzp" ], "script": "base64:BgJLCAISBAoCCAgSAwoBCBIAEgMKAQgSCgoICAEBAQEBAQgSCwoJCAEBAQgBAQEBEg0KCwgIAQEBAQEBCAgBEgMKAQESAwoBARIDCgEBPQAUa19jb29yZGluYXRvckFkZHJlc3MCFGtfY29vcmRpbmF0b3JBZGRyZXNzAA9rX2FkbWluX2FkZHJlc3MCD2tfYWRtaW5fYWRkcmVzcwANa19xdW90ZV9hc3NldAINa19xdW90ZV9hc3NldAAFa19hbW0CBWtfYW1tABFrX21hbmFnZXJfYWRkcmVzcwIRa19tYW5hZ2VyX2FkZHJlc3MAEmtfcG9zaXRpb25TZXF1ZW5jZQISa19wb3NpdGlvblNlcXVlbmNlAA5rX3Bvc2l0aW9uU2l6ZQIOa19wb3NpdGlvblNpemUAEGtfZXhlY3V0ZWRPcmRlcnMCEGtfZXhlY3V0ZWRPcmRlcnMAEGtfY2FuY2VsZWRPcmRlcnMCEGtfY2FuY2VsZWRPcmRlcnMAB2tfb3JkZXICB2tfb3JkZXIADWtfbGFzdE9yZGVySWQCDWtfbGFzdE9yZGVySWQAEGtfdHJhZGVyT3JkZXJDbnQCEGtfdHJhZGVyT3JkZXJDbnQAEGtfdHJhZGVyT3JkZXJJZHMCEGtfdHJhZGVyT3JkZXJJZHMACGtfc2VuZGVyAghrX3NlbmRlcgANa19pbml0aWFsaXplZAINa19pbml0aWFsaXplZAAEU1RPUAABAARUQUtFAAIABUxJTUlUAAMABExPTkcAAQAFU0hPUlQAAgAISU5DUkVBU0UAAQAIREVDUkVBU0UAAgAZTUFYX1RSQURFUl9PUkRFUlNfUEVSX0FNTQAFAARUSU1FCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAAMREVDSU1BTF9VTklUCQBoAgABCQBoAgkAaAIJAGgCCQBoAgkAaAIACgAKAAoACgAKAAoADFNQUkVBRF9MSU1JVAkAaQIFDERFQ0lNQUxfVU5JVADIAQEDYWJzAQJfeAMJAGYCBQJfeAAABQJfeAkBAS0BBQJfeAEEZGl2ZAICX3gCX3kJAG4EBQJfeAUMREVDSU1BTF9VTklUBQJfeQUISEFMRkVWRU4BBG11bGQCAl94Al95CQBuBAUCX3gFAl95BQxERUNJTUFMX1VOSVQFCEhBTEZFVkVOAQRtaW52AgJfeAJfeQMJAGYCBQJfeAUCX3kFAl95BQJfeAEOdG9Db21wb3NpdGVLZXkCBF9rZXkIX2FkZHJlc3MJAKwCAgkArAICBQRfa2V5AgFfBQhfYWRkcmVzcwEQZXhlY3V0ZWRPcmRlcktleQEIX29yZGVySWQJAKwCAgkArAICBRBrX2V4ZWN1dGVkT3JkZXJzAgFfCQCkAwEFCF9vcmRlcklkARBjYW5jZWxlZE9yZGVyS2V5AQhfb3JkZXJJZAkArAICCQCsAgIFEGtfY2FuY2VsZWRPcmRlcnMCAV8JAKQDAQUIX29yZGVySWQBCG9yZGVyS2V5AQhfb3JkZXJJZAkBDnRvQ29tcG9zaXRlS2V5AgUHa19vcmRlcgkApAMBBQhfb3JkZXJJZAETdHJhZGVyT3JkZXJDb3VudEtleQIEX2FtbQdfdHJhZGVyCQCsAgIJAKwCAgkArAICCQCsAgIFEGtfdHJhZGVyT3JkZXJDbnQCAV8FBF9hbW0CAV8FB190cmFkZXIBEXRyYWRlck9yZGVySWRzS2V5AgRfYW1tB190cmFkZXIJAKwCAgkArAICCQCsAgIJAKwCAgUQa190cmFkZXJPcmRlcklkcwIBXwUEX2FtbQIBXwUHX3RyYWRlcgELY29vcmRpbmF0b3IACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgUEdGhpcwUUa19jb29yZGluYXRvckFkZHJlc3MCE0Nvb3JkaW5hdG9yIG5vdCBzZXQBCnF1b3RlQXNzZXQACQDZBAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFDWtfcXVvdGVfYXNzZXQBDm1hbmFnZXJBZGRyZXNzAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFEWtfbWFuYWdlcl9hZGRyZXNzAg9NYW5hZ2VyIG5vdCBzZXQBC2lzV2hpdGVsaXN0AQhfYWRkcmVzcwkBC3ZhbHVlT3JFbHNlAgkAmwgCCQELY29vcmRpbmF0b3IACQEOdG9Db21wb3NpdGVLZXkCBQVrX2FtbQUIX2FkZHJlc3MHAQtpbml0aWFsaXplZAAJAQt2YWx1ZU9yRWxzZQIJAJsIAgUEdGhpcwUNa19pbml0aWFsaXplZAcBB2lzVmFsaWQBCF9vcmRlcklkAwkBC3ZhbHVlT3JFbHNlAgkAmwgCBQR0aGlzCQEQZXhlY3V0ZWRPcmRlcktleQEFCF9vcmRlcklkBwkAAgEJAKwCAgIYT3JkZXIgYWxyZWFkeSBleGVjdXRlZDogCQCkAwEFCF9vcmRlcklkAwkBC3ZhbHVlT3JFbHNlAgkAmwgCBQR0aGlzCQEQY2FuY2VsZWRPcmRlcktleQEFCF9vcmRlcklkBwkAAgEJAKwCAgIZT3JkZXIgYWxyZWFkeSBjYW5jZWxsZWQ6IAkApAMBBQhfb3JkZXJJZAYBDmN1cnJlbnRPcmRlcklkAAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQ1rX2xhc3RPcmRlcklkAAABE2dldFRyYWRlck9yZGVyQ291bnQCBF9hbW0HX3RyYWRlcgQDa2V5CQETdHJhZGVyT3JkZXJDb3VudEtleQIFBF9hbW0FB190cmFkZXIJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwUDa2V5AAABEnRyYWRlckFtbU9yZGVyc0lkcwIEX2FtbQdfdHJhZGVyBANrZXkJARF0cmFkZXJPcmRlcklkc0tleQIFBF9hbW0FB190cmFkZXIEA3ZhbAkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzBQNrZXkCAAMJAAACBQN2YWwCAAUDbmlsCQC1CQIFA3ZhbAIBLAEIZ2V0T3JkZXIBCF9vcmRlcklkBAhvcmRlclN0cgkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFBHRoaXMJAQhvcmRlcktleQEFCF9vcmRlcklkCQCsAgICEkludmFsaWQgb3JkZXIgaWQ6IAkApAMBBQhfb3JkZXJJZAQNb3JkZXJQYXJ0TGlzdAkAtQkCBQhvcmRlclN0cgIBLAQDYW1tCQCRAwIFDW9yZGVyUGFydExpc3QAAAQGdHJhZGVyCQCRAwIFDW9yZGVyUGFydExpc3QAAQQIYW1vdW50SW4JARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAtgkBCQCRAwIFDW9yZGVyUGFydExpc3QAAgIQSW52YWxpZCBhbW91bnRJbgQIbGV2ZXJhZ2UJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAtgkBCQCRAwIFDW9yZGVyUGFydExpc3QAAwIQSW52YWxpZCBsZXZlcmFnZQQEdHlwZQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEJAJEDAgUNb3JkZXJQYXJ0TGlzdAAEAgxJbnZhbGlkIHR5cGUEDHRyaWdnZXJQcmljZQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEJAJEDAgUNb3JkZXJQYXJ0TGlzdAAFAhRJbnZhbGlkIHRyaWdnZXJQcmljZQQLcGF5bWVudFVzZG4JARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAtgkBCQCRAwIFDW9yZGVyUGFydExpc3QABgITSW52YWxpZCBwYXltZW50VXNkbgQEc2lkZQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEJAJEDAgUNb3JkZXJQYXJ0TGlzdAAHAgxJbnZhbGlkIHNpZGUEB3JlZkxpbmsJAJEDAgUNb3JkZXJQYXJ0TGlzdAAIBApwb3NpdGlvbklkCQETdmFsdWVPckVycm9yTWVzc2FnZQIJALYJAQkAkQMCBQ1vcmRlclBhcnRMaXN0AAkCEkludmFsaWQgcG9zaXRpb25JZAQKbGltaXRQcmljZQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEJAJEDAgUNb3JkZXJQYXJ0TGlzdAAKAhJJbnZhbGlkIGxpbWl0UHJpY2UJAJ0KCwUDYW1tBQZ0cmFkZXIFCGFtb3VudEluBQhsZXZlcmFnZQUEdHlwZQUMdHJpZ2dlclByaWNlBQtwYXltZW50VXNkbgUEc2lkZQUHcmVmTGluawUKcG9zaXRpb25JZAUKbGltaXRQcmljZQEOZ2V0TWFya2V0UHJpY2UBBF9hbW0EAXMJAPwHBAkBEUBleHRyTmF0aXZlKDEwNjIpAQUEX2FtbQIQY29tcHV0ZVNwb3RQcmljZQUDbmlsBQNuaWwDCQAAAgUBcwUBcwQDcmVzBAckbWF0Y2gwBQFzAwkAAQIFByRtYXRjaDACA0ludAQBdAUHJG1hdGNoMAUBdAkAAgECH0ludmFsaWQgY29tcHV0ZVNwb3RQcmljZSByZXN1bHQJAQV2YWx1ZQEFA3JlcwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgEGZ2V0RmVlAgRfYW1tB190cmFkZXIEAXMJAPwHBAkBEUBleHRyTmF0aXZlKDEwNjIpAQUEX2FtbQIfY29tcHV0ZUZlZUZvclRyYWRlcldpdGhBcnRpZmFjdAkAzAgCBQdfdHJhZGVyCQDMCAICAAUDbmlsBQNuaWwDCQAAAgUBcwUBcwQDcmVzBAckbWF0Y2gwBQFzAwkAAQIFByRtYXRjaDACDihJbnQsIEJvb2xlYW4pBAF0BQckbWF0Y2gwCAUBdAJfMQkAAgECLkludmFsaWQgY29tcHV0ZUZlZUZvclRyYWRlcldpdGhBcnRpZmFjdCByZXN1bHQJAQV2YWx1ZQEFA3JlcwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgEUZ2V0UG9zaXRpb25EaXJlY3Rpb24CCl9vcmRlclNpZGUKX29yZGVyVHlwZQMDCQAAAgUKX29yZGVyVHlwZQUEVEFLRQYJAAACBQpfb3JkZXJUeXBlBQRTVE9QAwkAAAIFCl9vcmRlclNpZGUFBExPTkcFBVNIT1JUBQRMT05HBQpfb3JkZXJTaWRlAQ9nZXRQb3NpdGlvblNpemUDBF9hbW0HX3RyYWRlcgpfZGlyZWN0aW9uBANhbW0JARFAZXh0ck5hdGl2ZSgxMDYyKQEFBF9hbW0EC3Bvc2l0aW9uS2V5CQCsAgIJAKwCAgUHX3RyYWRlcgIBXwkApAMBBQpfZGlyZWN0aW9uBAdzaXplS2V5CQEOdG9Db21wb3NpdGVLZXkCBQ5rX3Bvc2l0aW9uU2l6ZQULcG9zaXRpb25LZXkJAQt2YWx1ZU9yRWxzZQIJAJoIAgUDYW1tBQdzaXplS2V5AAABDWdldFBvc2l0aW9uSWQDBF9hbW0HX3RyYWRlcgpfZGlyZWN0aW9uBANhbW0JARFAZXh0ck5hdGl2ZSgxMDYyKQEFBF9hbW0EC3Bvc2l0aW9uS2V5CQCsAgIJAKwCAgUHX3RyYWRlcgIBXwkApAMBBQpfZGlyZWN0aW9uBAZzZXFLZXkJAQ50b0NvbXBvc2l0ZUtleQIFEmtfcG9zaXRpb25TZXF1ZW5jZQULcG9zaXRpb25LZXkJAQt2YWx1ZU9yRWxzZQIJAJoIAgUDYW1tBQZzZXFLZXkAAAEJZ2V0U3ByZWFkAQZfcHJpY2UJAQRtdWxkAgUGX3ByaWNlBQxTUFJFQURfTElNSVQBCXNhdmVPcmRlcgwIX29yZGVySWQEX2FtbQdfdHJhZGVyCV9hbW91bnRJbglfbGV2ZXJhZ2UFX3R5cGUNX3RyaWdnZXJQcmljZQxfcGF5bWVudFVzZG4FX3NpZGUIX3JlZkxpbmsLX3Bvc2l0aW9uSWQLX2xpbWl0UHJpY2UECG9yZGVyU3RyCQC5CQIJAMwIAgUEX2FtbQkAzAgCBQdfdHJhZGVyCQDMCAIJAKQDAQUJX2Ftb3VudEluCQDMCAIJAKQDAQUJX2xldmVyYWdlCQDMCAIJAKQDAQUFX3R5cGUJAMwIAgkApAMBBQ1fdHJpZ2dlclByaWNlCQDMCAIJAKQDAQUMX3BheW1lbnRVc2RuCQDMCAIJAKQDAQUFX3NpZGUJAMwIAgUIX3JlZkxpbmsJAMwIAgkApAMBBQtfcG9zaXRpb25JZAkAzAgCCQCkAwEFC19saW1pdFByaWNlBQNuaWwCASwJAMwIAgkBC1N0cmluZ0VudHJ5AgkBCG9yZGVyS2V5AQUIX29yZGVySWQFCG9yZGVyU3RyBQNuaWwBEHVwZGF0ZU9yZGVySWRTdHIDD19vcmRlcklkc05ld1N0cgRfYW1tB190cmFkZXIJAMwIAgkBC1N0cmluZ0VudHJ5AgkBEXRyYWRlck9yZGVySWRzS2V5AgUEX2FtbQUHX3RyYWRlcgUPX29yZGVySWRzTmV3U3RyBQNuaWwBFGFkZFJlbW92ZU9yZGVySWRMaXN0BQlfb3JkZXJJZHMIX29yZGVySWQEX2FtbQdfdHJhZGVyBF9hZGQEC29yZGVySWRzTmV3AwUEX2FkZAkAzQgCBQlfb3JkZXJJZHMJAKQDAQUIX29yZGVySWQJANEIAgUJX29yZGVySWRzCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAM8IAgUJX29yZGVySWRzCQCkAwEFCF9vcmRlcklkCQCsAgICEk5vIG9yZGVyIHdpdGggaWQ6IAkApAMBBQhfb3JkZXJJZAULb3JkZXJJZHNOZXcBEGFkZFJlbW92ZU9yZGVySWQECF9vcmRlcklkBF9hbW0HX3RyYWRlcgRfYWRkBAhvcmRlcklkcwkBEnRyYWRlckFtbU9yZGVyc0lkcwIFBF9hbW0FB190cmFkZXIEC29yZGVySWRzTmV3CQEUYWRkUmVtb3ZlT3JkZXJJZExpc3QFBQhvcmRlcklkcwUIX29yZGVySWQFBF9hbW0FB190cmFkZXIFBF9hZGQEDm9yZGVySWRzTmV3U3RyCQC5CQIFC29yZGVySWRzTmV3AgEsCQEQdXBkYXRlT3JkZXJJZFN0cgMFDm9yZGVySWRzTmV3U3RyBQRfYW1tBQdfdHJhZGVyARZ1cGRhdGVUcmFkZXJPcmRlckNvdW50AwRfYW1tB190cmFkZXIGX2NvdW50AwkAZgIAAAUGX2NvdW50CQACAQkArAICAhVJbnZhbGlkIG9yZGVyIGNvdW50OiAJAKQDAQUGX2NvdW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQETdHJhZGVyT3JkZXJDb3VudEtleQIFBF9hbW0FB190cmFkZXIFBl9jb3VudAUDbmlsARF1cGRhdGVMYXN0T3JkZXJJZAEMX2xhc3RPcmRlcklkCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ1rX2xhc3RPcmRlcklkBQxfbGFzdE9yZGVySWQFA25pbAEQbWFya0V4ZWN1dGVPcmRlcgEIX29yZGVySWQJAMwIAgkBDEJvb2xlYW5FbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFEGtfZXhlY3V0ZWRPcmRlcnMJAKQDAQUIX29yZGVySWQGBQNuaWwBD21hcmtDYW5jZWxPcmRlcgEIX29yZGVySWQJAMwIAgkBDEJvb2xlYW5FbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFEGtfY2FuY2VsZWRPcmRlcnMJAKQDAQUIX29yZGVySWQGBQNuaWwBDmdldFBvc2l0aW9uSWRzAgRfYW1tB190cmFkZXIEEGxvbmdQb3NpdGlvblNpemUJAQ9nZXRQb3NpdGlvblNpemUDBQRfYW1tBQdfdHJhZGVyBQRMT05HBBVjdXJyZW50TG9uZ1Bvc2l0aW9uSWQDCQECIT0CBRBsb25nUG9zaXRpb25TaXplAAAJAQ1nZXRQb3NpdGlvbklkAwUEX2FtbQUHX3RyYWRlcgUETE9ORwAABBFzaG9ydFBvc2l0aW9uU2l6ZQkBD2dldFBvc2l0aW9uU2l6ZQMFBF9hbW0FB190cmFkZXIFBVNIT1JUBBZjdXJyZW50U2hvcnRQb3NpdGlvbklkAwkBAiE9AgURc2hvcnRQb3NpdGlvblNpemUAAAkBDWdldFBvc2l0aW9uSWQDBQRfYW1tBQdfdHJhZGVyBQVTSE9SVAAACQDMCAIFFWN1cnJlbnRMb25nUG9zaXRpb25JZAkAzAgCBRZjdXJyZW50U2hvcnRQb3NpdGlvbklkBQNuaWwKAWkBEmNsZWFuVXBTdGFsZU9yZGVycwIEX2FtbQdfdHJhZGVyBAZvcmRlcnMJARJ0cmFkZXJBbW1PcmRlcnNJZHMCBQRfYW1tBQdfdHJhZGVyBAtwb3NpdGlvbklkcwkBDmdldFBvc2l0aW9uSWRzAgUEX2FtbQUHX3RyYWRlcgoBCmNsZWFuVXBPbmUCBF9hY2MIX29yZGVySWQECm9yZGVySWRJbnQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAtgkBBQhfb3JkZXJJZAIQSW52YWxpZCBvcmRlciBpZAQLJHQwOTYxNTk4MTAJAQhnZXRPcmRlcgEFCm9yZGVySWRJbnQEA194MQgFCyR0MDk2MTU5ODEwAl8xBANfeDIIBQskdDA5NjE1OTgxMAJfMgQDX3gzCAULJHQwOTYxNTk4MTACXzMEA194NAgFCyR0MDk2MTU5ODEwAl80BAVfdHlwZQgFCyR0MDk2MTU5ODEwAl81BANfeDUIBQskdDA5NjE1OTgxMAJfNgQDX3g2CAULJHQwOTYxNTk4MTACXzcEA194NwgFCyR0MDk2MTU5ODEwAl84BANfeDgIBQskdDA5NjE1OTgxMAJfOQQLX3Bvc2l0aW9uSWQIBQskdDA5NjE1OTgxMANfMTAEA194OQgFCyR0MDk2MTU5ODEwA18xMQMDAwMJAAACBQVfdHlwZQUEU1RPUAYJAAACBQVfdHlwZQUEVEFLRQkBAiE9AgkAkQMCBQtwb3NpdGlvbklkcwAABQtfcG9zaXRpb25JZAcJAQIhPQIJAJEDAgULcG9zaXRpb25JZHMAAQULX3Bvc2l0aW9uSWQHBAZjaGFuZ2UJAQ9tYXJrQ2FuY2VsT3JkZXIBBQpvcmRlcklkSW50BAxuZXdPcmRlckxpc3QJARRhZGRSZW1vdmVPcmRlcklkTGlzdAUIBQRfYWNjAl8xBQpvcmRlcklkSW50BQRfYW1tBQdfdHJhZGVyBwkAlAoCBQxuZXdPcmRlckxpc3QJAM4IAggFBF9hY2MCXzIFBmNoYW5nZQUEX2FjYwQNJHQwMTAxNjMxMDIzNwoAAiRsBQZvcmRlcnMKAAIkcwkAkAMBBQIkbAoABSRhY2MwCQCUCgIFBm9yZGVycwUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQpjbGVhblVwT25lAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhNMaXN0IHNpemUgZXhjZWVkcyA3CQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcECW5ld09yZGVycwgFDSR0MDEwMTYzMTAyMzcCXzEEDWNhbmNlbEFjdGlvbnMIBQ0kdDAxMDE2MzEwMjM3Al8yCQDOCAIJAM4IAgUNY2FuY2VsQWN0aW9ucwkBFnVwZGF0ZVRyYWRlck9yZGVyQ291bnQDBQRfYW1tBQdfdHJhZGVyCQCQAwEFCW5ld09yZGVycwkBEHVwZGF0ZU9yZGVySWRTdHIDCQC5CQIFCW5ld09yZGVycwIBLAUEX2FtbQUHX3RyYWRlcgFpAQpzZXRDb250ZXh0AQdfc2VuZGVyAwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIOT25seSBzZWxmLWNhbGwJAMwIAgkBC1N0cmluZ0VudHJ5AgUIa19zZW5kZXIFB19zZW5kZXIFA25pbAFpAQxyZXNldENvbnRleHQAAwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIOT25seSBzZWxmLWNhbGwJAMwIAgkBC0RlbGV0ZUVudHJ5AQUIa19zZW5kZXIFA25pbAFpAQppbml0aWFsaXplAQxfY29vcmRpbmF0b3IDAwkBC2luaXRpYWxpemVkAAYJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECFFVuYWJsZSB0byBpbml0aWFsaXplCQDMCAIJAQtTdHJpbmdFbnRyeQIFFGtfY29vcmRpbmF0b3JBZGRyZXNzCQClCAEJARFAZXh0ck5hdGl2ZSgxMDYyKQEFDF9jb29yZGluYXRvcgkAzAgCCQEMQm9vbGVhbkVudHJ5AgUNa19pbml0aWFsaXplZAYFA25pbAFpAQtjcmVhdGVPcmRlcggEX2FtbQVfdHlwZQ1fdHJpZ2dlclByaWNlC19saW1pdFByaWNlCV9hbW91bnRJbglfbGV2ZXJhZ2UFX3NpZGUIX3JlZkxpbmsEB190cmFkZXIJAKUIAQgFAWkGY2FsbGVyBAdjbGVhblVwCQD8BwQFBHRoaXMCEmNsZWFuVXBTdGFsZU9yZGVycwkAzAgCBQRfYW1tCQDMCAIFB190cmFkZXIFA25pbAUDbmlsAwkAAAIFB2NsZWFuVXAFB2NsZWFuVXADCQBmAgkAkAMBCAUBaQhwYXltZW50cwABCQACAQI1SW52YWxpZCBjcmVhdGVPcmRlciBwYXJhbWV0ZXJzOiBpbnZhbGlkIHBheW1lbnQgY291bnQEDSR0MDEyMjQ2MTI0OTgDCQAAAgkAkAMBCAUBaQhwYXltZW50cwABCQCUCgIJANgEAQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCAkAkQMCCAUBaQhwYXltZW50cwAAB2Fzc2V0SWQCEEludmFsaWQgYXNzZXQgaWQICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50CQCUCgICAAAABA5wYXltZW50QXNzZXRJZAgFDSR0MDEyMjQ2MTI0OTgCXzEEDXBheW1lbnRBbW91bnQIBQ0kdDAxMjI0NjEyNDk4Al8yBAZkb0NhbGwJAPwHBAUEdGhpcwITaW50ZXJuYWxDcmVhdGVPcmRlcgkAzAgCBQdfdHJhZGVyCQDMCAIFBF9hbW0JAMwIAgUFX3R5cGUJAMwIAgUNX3RyaWdnZXJQcmljZQkAzAgCBQtfbGltaXRQcmljZQkAzAgCBQlfYW1vdW50SW4JAMwIAgUJX2xldmVyYWdlCQDMCAIFBV9zaWRlCQDMCAIFCF9yZWZMaW5rCQDMCAIFDnBheW1lbnRBc3NldElkCQDMCAIFDXBheW1lbnRBbW91bnQFA25pbAUDbmlsAwkAAAIFBmRvQ2FsbAUGZG9DYWxsBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEcaW5jcmVhc2VQb3NpdGlvbldpdGhTdG9wTG9zcwkEX2FtbQpfZGlyZWN0aW9uCV9sZXZlcmFnZRNfbWluQmFzZUFzc2V0QW1vdW50CF9yZWZMaW5rEV9zdG9wVHJpZ2dlclByaWNlD19zdG9wTGltaXRQcmljZRFfdGFrZVRyaWdnZXJQcmljZQ9fdGFrZUxpbWl0UHJpY2UEB190cmFkZXIJAKUIAQgFAWkGY2FsbGVyBAdjbGVhblVwCQD8BwQFBHRoaXMCEmNsZWFuVXBTdGFsZU9yZGVycwkAzAgCBQRfYW1tCQDMCAIFB190cmFkZXIFA25pbAUDbmlsAwkAAAIFB2NsZWFuVXAFB2NsZWFuVXADAwkBASEBCQELaW5pdGlhbGl6ZWQABgkBASEBCQELaXNXaGl0ZWxpc3QBBQRfYW1tCQACAQIvSW52YWxpZCBpbmNyZWFzZVBvc2l0aW9uV2l0aFN0b3BMb3NzIHBhcmFtZXRlcnMEDHBvc2l0aW9uU2l6ZQkBD2dldFBvc2l0aW9uU2l6ZQMFBF9hbW0FB190cmFkZXIFCl9kaXJlY3Rpb24DCQECIT0CBQxwb3NpdGlvblNpemUAAAkAAgECQkludmFsaWQgaW5jcmVhc2VQb3NpdGlvbldpdGhTdG9wTG9zcyBwYXJhbWV0ZXJzOiBvbmx5IG5ldyBwb3NpdGlvbgQMZG9TZXRDb250ZXh0CQD8BwQFBHRoaXMCCnNldENvbnRleHQJAMwIAgUHX3RyYWRlcgUDbmlsBQNuaWwDCQAAAgUMZG9TZXRDb250ZXh0BQxkb1NldENvbnRleHQED2RvQ2xvc2VQb3NpdGlvbgkA/AcECQERQGV4dHJOYXRpdmUoMTA2MikBBQRfYW1tAhBpbmNyZWFzZVBvc2l0aW9uCQDMCAIFCl9kaXJlY3Rpb24JAMwIAgUJX2xldmVyYWdlCQDMCAIFE19taW5CYXNlQXNzZXRBbW91bnQJAMwIAgUIX3JlZkxpbmsFA25pbAgFAWkIcGF5bWVudHMDCQAAAgUPZG9DbG9zZVBvc2l0aW9uBQ9kb0Nsb3NlUG9zaXRpb24EDmRvUmVzZXRDb250ZXh0CQD8BwQFBHRoaXMCDHJlc2V0Q29udGV4dAUDbmlsBQNuaWwDCQAAAgUOZG9SZXNldENvbnRleHQFDmRvUmVzZXRDb250ZXh0BBJvcGVuZWRQb3NpdGlvblNpemUJAQ9nZXRQb3NpdGlvblNpemUDBQRfYW1tBQdfdHJhZGVyBQpfZGlyZWN0aW9uAwkAAAIFEm9wZW5lZFBvc2l0aW9uU2l6ZQUSb3BlbmVkUG9zaXRpb25TaXplBAhhbW91bnRJbgkBA2FicwEFEm9wZW5lZFBvc2l0aW9uU2l6ZQQMc3RvcExvc3NTaWRlAwkAZgIAAAUSb3BlbmVkUG9zaXRpb25TaXplBQRMT05HBQVTSE9SVAQRZG9DcmVhdGVTdG9wT3JkZXIDCQBmAgURX3N0b3BUcmlnZ2VyUHJpY2UAAAQRZG9DcmVhdGVTdG9wT3JkZXIJAPwHBAUEdGhpcwITaW50ZXJuYWxDcmVhdGVPcmRlcgkAzAgCBQdfdHJhZGVyCQDMCAIFBF9hbW0JAMwIAgUEU1RPUAkAzAgCBRFfc3RvcFRyaWdnZXJQcmljZQkAzAgCBQ9fc3RvcExpbWl0UHJpY2UJAMwIAgUIYW1vdW50SW4JAMwIAgAACQDMCAIFDHN0b3BMb3NzU2lkZQkAzAgCBQhfcmVmTGluawkAzAgCAgAJAMwIAgAABQNuaWwFA25pbAMJAAACBRFkb0NyZWF0ZVN0b3BPcmRlcgURZG9DcmVhdGVTdG9wT3JkZXIFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFEWRvQ3JlYXRlU3RvcE9yZGVyBRFkb0NyZWF0ZVN0b3BPcmRlcgQRZG9DcmVhdGVUYWtlT3JkZXIDCQBmAgURX3Rha2VUcmlnZ2VyUHJpY2UAAAQRZG9DcmVhdGVUYWtlT3JkZXIJAPwHBAUEdGhpcwITaW50ZXJuYWxDcmVhdGVPcmRlcgkAzAgCBQdfdHJhZGVyCQDMCAIFBF9hbW0JAMwIAgUEVEFLRQkAzAgCBRFfdGFrZVRyaWdnZXJQcmljZQkAzAgCBQ9fdGFrZUxpbWl0UHJpY2UJAMwIAgUIYW1vdW50SW4JAMwIAgAACQDMCAIFDHN0b3BMb3NzU2lkZQkAzAgCBQhfcmVmTGluawkAzAgCAgAJAMwIAgAABQNuaWwFA25pbAMJAAACBRFkb0NyZWF0ZVRha2VPcmRlcgURZG9DcmVhdGVUYWtlT3JkZXIFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFEWRvQ3JlYXRlVGFrZU9yZGVyBRFkb0NyZWF0ZVRha2VPcmRlcgUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBE2ludGVybmFsQ3JlYXRlT3JkZXILB190cmFkZXIEX2FtbQVfdHlwZQ1fdHJpZ2dlclByaWNlC19saW1pdFByaWNlCV9hbW91bnRJbglfbGV2ZXJhZ2UFX3NpZGUIX3JlZkxpbmsPX3BheW1lbnRBc3NldElkDl9wYXltZW50QW1vdW50AwMDAwMDAwMDCQEBIQEJAQtpbml0aWFsaXplZAAGCQEBIQEJAQtpc1doaXRlbGlzdAEFBF9hbW0GCQBnAgAABQ1fdHJpZ2dlclByaWNlBgkAZgIAAAULX2xpbWl0UHJpY2UGCQBnAgAABQlfYW1vdW50SW4GCQBmAgAABQlfbGV2ZXJhZ2UGCQEBIQEDCQAAAgUFX3NpZGUFBExPTkcGCQAAAgUFX3NpZGUFBVNIT1JUBgkBASEBAwMJAAACBQVfdHlwZQUEU1RPUAYJAAACBQVfdHlwZQUEVEFLRQYJAAACBQVfdHlwZQUFTElNSVQGCQEBIQEJAAACCAUBaQZjYWxsZXIFBHRoaXMJAAIBAh5JbnZhbGlkIGNyZWF0ZU9yZGVyIHBhcmFtZXRlcnMEB29yZGVySWQJAGQCCQEOY3VycmVudE9yZGVySWQAAAEEEXBvc2l0aW9uRGlyZWN0aW9uCQEUZ2V0UG9zaXRpb25EaXJlY3Rpb24CBQVfc2lkZQUFX3R5cGUEE25ld1RyYWRlck9yZGVyQ291bnQJAGQCCQETZ2V0VHJhZGVyT3JkZXJDb3VudAIFBF9hbW0FB190cmFkZXIAAQQMcG9zaXRpb25TaXplCQEPZ2V0UG9zaXRpb25TaXplAwUEX2FtbQUHX3RyYWRlcgURcG9zaXRpb25EaXJlY3Rpb24ECl9kaXJlY3Rpb24DAwMJAAACBQxwb3NpdGlvblNpemUAAAYDCQBmAgUMcG9zaXRpb25TaXplAAAJAAACBQVfc2lkZQUETE9ORwcGAwkAZgIAAAUMcG9zaXRpb25TaXplCQAAAgUFX3NpZGUFBVNIT1JUBwUISU5DUkVBU0UFCERFQ1JFQVNFAwMJAAACBQxwb3NpdGlvblNpemUAAAMJAAACBQVfdHlwZQUEU1RPUAYJAAACBQVfdHlwZQUEVEFLRQcJAAIBAitDYW4gbm90IGNyZWF0ZSBTVE9QL1RBS0Ugb3JkZXI6IG5vIHBvc2l0aW9uBAt1c2RuUGF5bWVudAMJAAACBQpfZGlyZWN0aW9uBQhJTkNSRUFTRQMDCQECIT0CBQ9fcGF5bWVudEFzc2V0SWQJANgEAQkBCnF1b3RlQXNzZXQABgkBAiE9AgUOX3BheW1lbnRBbW91bnQFCV9hbW91bnRJbgkAAgECNEludmFsaWQgY3JlYXRlTGltaXRPcmRlciBwYXJhbWV0ZXJzOiBpbnZhbGlkIHBheW1lbnQEBXN0YWtlCQD8BwQJAQ5tYW5hZ2VyQWRkcmVzcwACB2RlcG9zaXQFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQ5fcGF5bWVudEFtb3VudAUDbmlsAwkAAAIFBXN0YWtlBQVzdGFrZQUOX3BheW1lbnRBbW91bnQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4AAAMJAAACBQt1c2RuUGF5bWVudAULdXNkblBheW1lbnQECnBvc2l0aW9uSWQDCQECIT0CBQxwb3NpdGlvblNpemUAAAkBDWdldFBvc2l0aW9uSWQDBQRfYW1tBQdfdHJhZGVyBRFwb3NpdGlvbkRpcmVjdGlvbgAAAwMDCQAAAgUFX3R5cGUFBFNUT1AGCQAAAgUFX3R5cGUFBFRBS0UJAAACBQpwb3NpdGlvbklkAAAHCQACAQI/U1RPUCBhbmQgVEFLRSBvcmRlciBzaG91bGQgYmUgYXNzaWduZWQgdG8gcG9zaXRpb24gd2l0aCBpZCAhPSAwAwkAZgIFE25ld1RyYWRlck9yZGVyQ291bnQFGU1BWF9UUkFERVJfT1JERVJTX1BFUl9BTU0JAAIBAjBJbnZhbGlkIGNyZWF0ZUxpbWl0T3JkZXIgcGFyYW1ldGVyczogb3JkZXIgY291bnQJAM4IAgkAzggCCQDOCAIJAQlzYXZlT3JkZXIMBQdvcmRlcklkBQRfYW1tBQdfdHJhZGVyBQlfYW1vdW50SW4FCV9sZXZlcmFnZQUFX3R5cGUFDV90cmlnZ2VyUHJpY2UFC3VzZG5QYXltZW50BQVfc2lkZQUIX3JlZkxpbmsFCnBvc2l0aW9uSWQFC19saW1pdFByaWNlCQEQYWRkUmVtb3ZlT3JkZXJJZAQFB29yZGVySWQFBF9hbW0FB190cmFkZXIGCQEWdXBkYXRlVHJhZGVyT3JkZXJDb3VudAMFBF9hbW0FB190cmFkZXIFE25ld1RyYWRlck9yZGVyQ291bnQJARF1cGRhdGVMYXN0T3JkZXJJZAEFB29yZGVySWQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQELY2FuY2VsT3JkZXIBCF9vcmRlcklkBA0kdDAxOTA0MTE5MjYwCQEIZ2V0T3JkZXIBBQhfb3JkZXJJZAQEX2FtbQgFDSR0MDE5MDQxMTkyNjACXzEEB190cmFkZXIIBQ0kdDAxOTA0MTE5MjYwAl8yBAlfYW1vdW50SW4IBQ0kdDAxOTA0MTE5MjYwAl8zBAlfbGV2ZXJhZ2UIBQ0kdDAxOTA0MTE5MjYwAl80BAVfdHlwZQgFDSR0MDE5MDQxMTkyNjACXzUEDV90cmlnZ2VyUHJpY2UIBQ0kdDAxOTA0MTE5MjYwAl82BAtfYW1vdW50VXNkbggFDSR0MDE5MDQxMTkyNjACXzcEBV9zaWRlCAUNJHQwMTkwNDExOTI2MAJfOAQIX3JlZkxpbmsIBQ0kdDAxOTA0MTE5MjYwAl85BAtfcG9zaXRpb25JZAgFDSR0MDE5MDQxMTkyNjADXzEwBAtfbGltaXRQcmljZQgFDSR0MDE5MDQxMTkyNjADXzExAwMDCQEBIQEJAQtpbml0aWFsaXplZAAGCQEBIQEJAQdpc1ZhbGlkAQUIX29yZGVySWQGCQEBIQEJAAACCQClCAEIBQFpBmNhbGxlcgUHX3RyYWRlcgkAAgECHkludmFsaWQgY2FuY2VsT3JkZXIgcGFyYW1ldGVycwQHY2xlYW5VcAkA/AcEBQR0aGlzAhJjbGVhblVwU3RhbGVPcmRlcnMJAMwIAgUEX2FtbQkAzAgCBQdfdHJhZGVyBQNuaWwFA25pbAMJAAACBQdjbGVhblVwBQdjbGVhblVwBBNuZXdUcmFkZXJPcmRlckNvdW50CQBlAgkBE2dldFRyYWRlck9yZGVyQ291bnQCBQRfYW1tBQdfdHJhZGVyAAEECHdpdGhkcmF3AwkAZgIFC19hbW91bnRVc2RuAAAEB3Vuc3Rha2UJAPwHBAkBDm1hbmFnZXJBZGRyZXNzAAIId2l0aGRyYXcJAMwIAgkA2AQBCQEKcXVvdGVBc3NldAAJAMwIAgULX2Ftb3VudFVzZG4FA25pbAUDbmlsAwkAAAIFB3Vuc3Rha2UFB3Vuc3Rha2UFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFCHdpdGhkcmF3BQh3aXRoZHJhdwkAzggCCQDOCAIJAM4IAgkBD21hcmtDYW5jZWxPcmRlcgEFCF9vcmRlcklkCQEQYWRkUmVtb3ZlT3JkZXJJZAQFCF9vcmRlcklkBQRfYW1tBQdfdHJhZGVyBwkBFnVwZGF0ZVRyYWRlck9yZGVyQ291bnQDBQRfYW1tBQdfdHJhZGVyBRNuZXdUcmFkZXJPcmRlckNvdW50AwkAZgIFC19hbW91bnRVc2RuAAAJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwgFAWkGY2FsbGVyBQtfYW1vdW50VXNkbgkBCnF1b3RlQXNzZXQABQNuaWwFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQxleGVjdXRlT3JkZXIBCF9vcmRlcklkBA0kdDAyMDQ1NzIwNjc2CQEIZ2V0T3JkZXIBBQhfb3JkZXJJZAQEX2FtbQgFDSR0MDIwNDU3MjA2NzYCXzEEB190cmFkZXIIBQ0kdDAyMDQ1NzIwNjc2Al8yBAlfYW1vdW50SW4IBQ0kdDAyMDQ1NzIwNjc2Al8zBAlfbGV2ZXJhZ2UIBQ0kdDAyMDQ1NzIwNjc2Al80BAVfdHlwZQgFDSR0MDIwNDU3MjA2NzYCXzUEDV90cmlnZ2VyUHJpY2UIBQ0kdDAyMDQ1NzIwNjc2Al82BAtfYW1vdW50VXNkbggFDSR0MDIwNDU3MjA2NzYCXzcEBV9zaWRlCAUNJHQwMjA0NTcyMDY3NgJfOAQIX3JlZkxpbmsIBQ0kdDAyMDQ1NzIwNjc2Al85BAtfcG9zaXRpb25JZAgFDSR0MDIwNDU3MjA2NzYDXzEwBAtfbGltaXRQcmljZQgFDSR0MDIwNDU3MjA2NzYDXzExBAdjbGVhblVwCQD8BwQFBHRoaXMCEmNsZWFuVXBTdGFsZU9yZGVycwkAzAgCBQRfYW1tCQDMCAIFB190cmFkZXIFA25pbAUDbmlsAwkAAAIFB2NsZWFuVXAFB2NsZWFuVXAEEXBvc2l0aW9uRGlyZWN0aW9uCQEUZ2V0UG9zaXRpb25EaXJlY3Rpb24CBQVfc2lkZQUFX3R5cGUDAwkBASEBCQELaW5pdGlhbGl6ZWQABgkBASEBCQEHaXNWYWxpZAEFCF9vcmRlcklkCQACAQIfSW52YWxpZCBleGVjdXRlT3JkZXIgcGFyYW1ldGVycwQMcG9zaXRpb25TaXplCQEPZ2V0UG9zaXRpb25TaXplAwUEX2FtbQUHX3RyYWRlcgURcG9zaXRpb25EaXJlY3Rpb24EEWN1cnJlbnRQb3NpdGlvbklkAwkBAiE9AgUMcG9zaXRpb25TaXplAAAJAQ1nZXRQb3NpdGlvbklkAwUEX2FtbQUHX3RyYWRlcgURcG9zaXRpb25EaXJlY3Rpb24AAAQNJHQwMjExODAyNDU1OAMJAAACBQVfdHlwZQUEU1RPUAQSX3Bvc2l0aW9uRGlyZWN0aW9uAwkAZgIFDHBvc2l0aW9uU2l6ZQAABQRMT05HAwkAZgIAAAUMcG9zaXRpb25TaXplBQVTSE9SVAkAAgECLENhbiBub3QgZXhlY3V0ZSBTVE9QIG9yZGVyOiBubyBvcGVuIHBvc2l0aW9uBAttYXJrZXRQcmljZQkBDmdldE1hcmtldFByaWNlAQUEX2FtbQQMaXNFeGVjdXRhYmxlAwkAAAIFBV9zaWRlBRJfcG9zaXRpb25EaXJlY3Rpb24JAAIBAidDYW4gbm90IGV4ZWN1dGUgU1RPUCBvcmRlcjogcmVkdWNlIG9ubHkDCQECIT0CBRFjdXJyZW50UG9zaXRpb25JZAULX3Bvc2l0aW9uSWQJAAIBAitDYW4gbm90IGV4ZWN1dGUgU1RPUCBvcmRlcjogcG9zaXRpb24gY2xvc2VkAwkAAAIFEl9wb3NpdGlvbkRpcmVjdGlvbgUETE9ORwkAZwIFDV90cmlnZ2VyUHJpY2UFC21hcmtldFByaWNlCQBnAgULbWFya2V0UHJpY2UFDV90cmlnZ2VyUHJpY2UDBQxpc0V4ZWN1dGFibGUJAJUKAwINY2xvc2VQb3NpdGlvbgkAzAgCCQEEbWludgIFCV9hbW91bnRJbgkBA2FicwEFDHBvc2l0aW9uU2l6ZQkAzAgCBRFwb3NpdGlvbkRpcmVjdGlvbgkAzAgCCQEEbXVsZAIFC19saW1pdFByaWNlCQEDYWJzAQUMcG9zaXRpb25TaXplCQDMCAIHBQNuaWwFA25pbAkAAgECMUNhbiBub3QgZXhlY3V0ZSBTVE9QIG9yZGVyOiB0cmlnZ2VyUHJpY2UgbWlzbWF0Y2gDCQAAAgUFX3R5cGUFBFRBS0UEEl9wb3NpdGlvbkRpcmVjdGlvbgMJAGYCBQxwb3NpdGlvblNpemUAAAUETE9ORwMJAGYCAAAFDHBvc2l0aW9uU2l6ZQUFU0hPUlQJAAIBAixDYW4gbm90IGV4ZWN1dGUgU1RPUCBvcmRlcjogbm8gb3BlbiBwb3NpdGlvbgQLbWFya2V0UHJpY2UJAQ5nZXRNYXJrZXRQcmljZQEFBF9hbW0EDGlzRXhlY3V0YWJsZQMJAAACBQVfc2lkZQUSX3Bvc2l0aW9uRGlyZWN0aW9uCQACAQInQ2FuIG5vdCBleGVjdXRlIFRBS0Ugb3JkZXI6IHJlZHVjZSBvbmx5AwkBAiE9AgURY3VycmVudFBvc2l0aW9uSWQFC19wb3NpdGlvbklkCQACAQkArAICCQCsAgIJAKwCAgIsQ2FuIG5vdCBleGVjdXRlIFRBS0Ugb3JkZXI6IHBvc2l0aW9uIGNsb3NlZCAJAKQDAQURY3VycmVudFBvc2l0aW9uSWQCAiE9CQCkAwEFC19wb3NpdGlvbklkAwkAAAIFEl9wb3NpdGlvbkRpcmVjdGlvbgUETE9ORwkAZwIFC21hcmtldFByaWNlBQ1fdHJpZ2dlclByaWNlCQBnAgUNX3RyaWdnZXJQcmljZQULbWFya2V0UHJpY2UDBQxpc0V4ZWN1dGFibGUJAJUKAwINY2xvc2VQb3NpdGlvbgkAzAgCCQEEbWludgIFCV9hbW91bnRJbgkBA2FicwEFDHBvc2l0aW9uU2l6ZQkAzAgCBRFwb3NpdGlvbkRpcmVjdGlvbgkAzAgCCQEEbXVsZAIFC19saW1pdFByaWNlCQEDYWJzAQUMcG9zaXRpb25TaXplCQDMCAIHBQNuaWwFA25pbAkAAgECMUNhbiBub3QgZXhlY3V0ZSBUQUtFIG9yZGVyOiB0cmlnZ2VyUHJpY2UgbWlzbWF0Y2gDCQAAAgUFX3R5cGUFBUxJTUlUBAttYXJrZXRQcmljZQkBDmdldE1hcmtldFByaWNlAQUEX2FtbQQGc3ByZWFkAwkAAAIFC19saW1pdFByaWNlAAAJAQlnZXRTcHJlYWQBBQ1fdHJpZ2dlclByaWNlCQEDYWJzAQkAZQIFDV90cmlnZ2VyUHJpY2UFC19saW1pdFByaWNlBAxpc0V4ZWN1dGFibGUDCQBnAgULbWFya2V0UHJpY2UJAGUCBQ1fdHJpZ2dlclByaWNlBQZzcHJlYWQJAGcCCQBkAgUNX3RyaWdnZXJQcmljZQUGc3ByZWFkBQttYXJrZXRQcmljZQcDBQxpc0V4ZWN1dGFibGUED2Ftb3VudEluV2l0aEZlZQkAZQIFC19hbW91bnRVc2RuCQEEbXVsZAIFC19hbW91bnRVc2RuCQEGZ2V0RmVlAgUEX2FtbQUHX3RyYWRlcgkAlQoDAhBpbmNyZWFzZVBvc2l0aW9uCQDMCAIFBV9zaWRlCQDMCAIFCV9sZXZlcmFnZQkAzAgCAwkAAAIFC19saW1pdFByaWNlAAAAAAkBBGRpdmQCBQ9hbW91bnRJbldpdGhGZWUFC19saW1pdFByaWNlCQDMCAIFCF9yZWZMaW5rBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAULX2Ftb3VudFVzZG4FA25pbAkAAgECMkNhbiBub3QgZXhlY3V0ZSBMSU1JVCBvcmRlcjogdHJpZ2dlclByaWNlIG1pc21hdGNoCQACAQkArAICAhRJbnZhbGlkIG9yZGVyIHR5cGU6IAkApAMBBQVfdHlwZQQGbWV0aG9kCAUNJHQwMjExODAyNDU1OAJfMQQEYXJncwgFDSR0MDIxMTgwMjQ1NTgCXzIECHBheW1lbnRzCAUNJHQwMjExODAyNDU1OAJfMwQId2l0aGRyYXcDCQAAAgkAkAMBBQhwYXltZW50cwABBAd1bnN0YWtlCQD8BwQJAQ5tYW5hZ2VyQWRkcmVzcwACCHdpdGhkcmF3CQDMCAIJANgEAQkBCnF1b3RlQXNzZXQACQDMCAIICQCRAwIFCHBheW1lbnRzAAAGYW1vdW50BQNuaWwFA25pbAMJAAACBQd1bnN0YWtlBQd1bnN0YWtlBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBQh3aXRoZHJhdwUId2l0aGRyYXcEDGRvU2V0Q29udGV4dAkA/AcEBQR0aGlzAgpzZXRDb250ZXh0CQDMCAIFB190cmFkZXIFA25pbAUDbmlsAwkAAAIFDGRvU2V0Q29udGV4dAUMZG9TZXRDb250ZXh0BA9kb0Nsb3NlUG9zaXRpb24JAPwHBAkBEUBleHRyTmF0aXZlKDEwNjIpAQUEX2FtbQUGbWV0aG9kBQRhcmdzBQhwYXltZW50cwMJAAACBQ9kb0Nsb3NlUG9zaXRpb24FD2RvQ2xvc2VQb3NpdGlvbgQOZG9SZXNldENvbnRleHQJAPwHBAUEdGhpcwIMcmVzZXRDb250ZXh0BQNuaWwFA25pbAMJAAACBQ5kb1Jlc2V0Q29udGV4dAUOZG9SZXNldENvbnRleHQEE25ld1RyYWRlck9yZGVyQ291bnQJAGUCCQETZ2V0VHJhZGVyT3JkZXJDb3VudAIFBF9hbW0FB190cmFkZXIAAQkAzggCCQDOCAIJARZ1cGRhdGVUcmFkZXJPcmRlckNvdW50AwUEX2FtbQUHX3RyYWRlcgUTbmV3VHJhZGVyT3JkZXJDb3VudAkBEGFkZFJlbW92ZU9yZGVySWQEBQhfb3JkZXJJZAUEX2FtbQUHX3RyYWRlcgcJARBtYXJrRXhlY3V0ZU9yZGVyAQUIX29yZGVySWQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEUdmlld19jYW5FeGVjdXRlT3JkZXIBCF9vcmRlcklkBAFzCQD8BwQFBHRoaXMCDGV4ZWN1dGVPcmRlcgkAzAgCBQhfb3JkZXJJZAUDbmlsBQNuaWwDCQAAAgUBcwUBcwkAAgECB1N1Y2Nlc3MJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BAnR4AQZ2ZXJpZnkABA5jb29yZGluYXRvclN0cgkAnQgCBQR0aGlzBRRrX2Nvb3JkaW5hdG9yQWRkcmVzcwMJAQlpc0RlZmluZWQBBQ5jb29yZGluYXRvclN0cgQFYWRtaW4JAJ0IAgkBEUBleHRyTmF0aXZlKDEwNjIpAQkBBXZhbHVlAQUOY29vcmRpbmF0b3JTdHIFD2tfYWRtaW5fYWRkcmVzcwMJAQlpc0RlZmluZWQBBQVhZG1pbgkBC3ZhbHVlT3JFbHNlAgkAmwgCCQERQGV4dHJOYXRpdmUoMTA2MikBCQEFdmFsdWUBBQVhZG1pbgkArAICCQCsAgIJAKwCAgIHc3RhdHVzXwkApQgBBQR0aGlzAgFfCQDYBAEIBQJ0eAJpZAcJAAIBAi51bmFibGUgdG8gdmVyaWZ5OiBhZG1pbiBub3Qgc2V0IGluIGNvb3JkaW5hdG9yCQD0AwMIBQJ0eAlib2R5Qnl0ZXMJAJEDAggFAnR4BnByb29mcwAACAUCdHgPc2VuZGVyUHVibGljS2V5r8Zeyg==", "height": 2484221, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: GeNcE4sbrT2XvrJngU5vHRqGqxsomEWQKGHwHCVuNL5P Next: ED8H92iHUuNVXbc1JqPsV7FJVe87wKAUMxhtLrbD1XXU Diff:
OldNewDifferences
1414 let k_positionSequence = "k_positionSequence"
1515
1616 let k_positionSize = "k_positionSize"
17-
18-let k_fee = "k_fee"
1917
2018 let k_executedOrders = "k_executedOrders"
2119
179177 }
180178
181179
182-func getPositionSize (_amm,_trader) = {
180+func getPositionDirection (_orderSide,_orderType) = if (if ((_orderType == TAKE))
181+ then true
182+ else (_orderType == STOP))
183+ then if ((_orderSide == LONG))
184+ then SHORT
185+ else LONG
186+ else _orderSide
187+
188+
189+func getPositionSize (_amm,_trader,_direction) = {
183190 let amm = addressFromStringValue(_amm)
184- let sizeKey = toCompositeKey(k_positionSize, _trader)
191+ let positionKey = ((_trader + "_") + toString(_direction))
192+ let sizeKey = toCompositeKey(k_positionSize, positionKey)
185193 valueOrElse(getInteger(amm, sizeKey), 0)
186194 }
187195
188196
189-func getPositionId (_amm,_trader) = {
197+func getPositionId (_amm,_trader,_direction) = {
190198 let amm = addressFromStringValue(_amm)
191- let seqKey = toCompositeKey(k_positionSequence, _trader)
199+ let positionKey = ((_trader + "_") + toString(_direction))
200+ let seqKey = toCompositeKey(k_positionSequence, positionKey)
192201 valueOrElse(getInteger(amm, seqKey), 0)
193202 }
194203
202211 }
203212
204213
205-func addRemoveOrderId (_orderId,_amm,_trader,_add) = {
206- let orderIds = traderAmmOrdersIds(_amm, _trader)
214+func updateOrderIdStr (_orderIdsNewStr,_amm,_trader) = [StringEntry(traderOrderIdsKey(_amm, _trader), _orderIdsNewStr)]
215+
216+
217+func addRemoveOrderIdList (_orderIds,_orderId,_amm,_trader,_add) = {
207218 let orderIdsNew = if (_add)
208- then (orderIds :+ toString(_orderId))
209- else removeByIndex(orderIds, valueOrErrorMessage(indexOf(orderIds, toString(_orderId)), ("No order with id: " + toString(_orderId))))
210- let orderIdsNewStr = makeString(orderIdsNew, ",")
211-[StringEntry(traderOrderIdsKey(_amm, _trader), orderIdsNewStr)]
219+ then (_orderIds :+ toString(_orderId))
220+ else removeByIndex(_orderIds, valueOrErrorMessage(indexOf(_orderIds, toString(_orderId)), ("No order with id: " + toString(_orderId))))
221+ orderIdsNew
212222 }
213223
214224
215-func updateTraderOrderCount (_amm,_trader,_count) = [IntegerEntry(traderOrderCountKey(_amm, _trader), _count)]
225+func addRemoveOrderId (_orderId,_amm,_trader,_add) = {
226+ let orderIds = traderAmmOrdersIds(_amm, _trader)
227+ let orderIdsNew = addRemoveOrderIdList(orderIds, _orderId, _amm, _trader, _add)
228+ let orderIdsNewStr = makeString(orderIdsNew, ",")
229+ updateOrderIdStr(orderIdsNewStr, _amm, _trader)
230+ }
231+
232+
233+func updateTraderOrderCount (_amm,_trader,_count) = if ((0 > _count))
234+ then throw(("Invalid order count: " + toString(_count)))
235+ else [IntegerEntry(traderOrderCountKey(_amm, _trader), _count)]
216236
217237
218238 func updateLastOrderId (_lastOrderId) = [IntegerEntry(k_lastOrderId, _lastOrderId)]
224244 func markCancelOrder (_orderId) = [BooleanEntry(toCompositeKey(k_canceledOrders, toString(_orderId)), true)]
225245
226246
247+func getPositionIds (_amm,_trader) = {
248+ let longPositionSize = getPositionSize(_amm, _trader, LONG)
249+ let currentLongPositionId = if ((longPositionSize != 0))
250+ then getPositionId(_amm, _trader, LONG)
251+ else 0
252+ let shortPositionSize = getPositionSize(_amm, _trader, SHORT)
253+ let currentShortPositionId = if ((shortPositionSize != 0))
254+ then getPositionId(_amm, _trader, SHORT)
255+ else 0
256+[currentLongPositionId, currentShortPositionId]
257+ }
258+
259+
227260 @Callable(i)
228261 func cleanUpStaleOrders (_amm,_trader) = {
229262 let orders = traderAmmOrdersIds(_amm, _trader)
230- let orderCount = getTraderOrderCount(_amm, _trader)
263+ let positionIds = getPositionIds(_amm, _trader)
231264 func cleanUpOne (_acc,_orderId) = {
232265 let orderIdInt = valueOrErrorMessage(parseInt(_orderId), "Invalid order id")
233- let $t082878482 = getOrder(orderIdInt)
234- let _x1 = $t082878482._1
235- let _x2 = $t082878482._2
236- let _x3 = $t082878482._3
237- let _x4 = $t082878482._4
238- let _type = $t082878482._5
239- let _x5 = $t082878482._6
240- let _x6 = $t082878482._7
241- let _x7 = $t082878482._8
242- let _x8 = $t082878482._9
243- let _positionId = $t082878482._10
244- let _x9 = $t082878482._11
245- let positionSize = getPositionSize(_amm, _trader)
246- let currentPositionId = if ((positionSize != 0))
247- then getPositionId(_amm, _trader)
248- else 0
249- if (if (if ((_type == STOP))
266+ let $t096159810 = getOrder(orderIdInt)
267+ let _x1 = $t096159810._1
268+ let _x2 = $t096159810._2
269+ let _x3 = $t096159810._3
270+ let _x4 = $t096159810._4
271+ let _type = $t096159810._5
272+ let _x5 = $t096159810._6
273+ let _x6 = $t096159810._7
274+ let _x7 = $t096159810._8
275+ let _x8 = $t096159810._9
276+ let _positionId = $t096159810._10
277+ let _x9 = $t096159810._11
278+ if (if (if (if ((_type == STOP))
250279 then true
251280 else (_type == TAKE))
252- then (currentPositionId != _positionId)
281+ then (positionIds[0] != _positionId)
282+ else false)
283+ then (positionIds[1] != _positionId)
253284 else false)
254285 then {
255- let change = (markCancelOrder(orderIdInt) ++ addRemoveOrderId(orderIdInt, _amm, _trader, false))
256- $Tuple2((_acc._1 + 1), (_acc._2 ++ change))
286+ let change = markCancelOrder(orderIdInt)
287+ let newOrderList = addRemoveOrderIdList(_acc._1, orderIdInt, _amm, _trader, false)
288+ $Tuple2(newOrderList, (_acc._2 ++ change))
257289 }
258290 else _acc
259291 }
260292
261- let result = {
293+ let $t01016310237 = {
262294 let $l = orders
263295 let $s = size($l)
264- let $acc0 = $Tuple2(0, nil)
296+ let $acc0 = $Tuple2(orders, nil)
265297 func $f0_1 ($a,$i) = if (($i >= $s))
266298 then $a
267299 else cleanUpOne($a, $l[$i])
268300
269301 func $f0_2 ($a,$i) = if (($i >= $s))
270302 then $a
271- else throw("List size exceeds 5")
303+ else throw("List size exceeds 7")
272304
273- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5)
305+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7)
274306 }
275- (result._2 ++ updateTraderOrderCount(_amm, _trader, (orderCount - result._1)))
307+ let newOrders = $t01016310237._1
308+ let cancelActions = $t01016310237._2
309+ ((cancelActions ++ updateTraderOrderCount(_amm, _trader, size(newOrders))) ++ updateOrderIdStr(makeString(newOrders, ","), _amm, _trader))
276310 }
277311
278312
308342 then if ((size(i.payments) > 1))
309343 then throw("Invalid createOrder parameters: invalid payment count")
310344 else {
311- let $t01024710499 = if ((size(i.payments) == 1))
345+ let $t01224612498 = if ((size(i.payments) == 1))
312346 then $Tuple2(toBase58String(valueOrErrorMessage(i.payments[0].assetId, "Invalid asset id")), i.payments[0].amount)
313347 else $Tuple2("", 0)
314- let paymentAssetId = $t01024710499._1
315- let paymentAmount = $t01024710499._2
348+ let paymentAssetId = $t01224612498._1
349+ let paymentAmount = $t01224612498._2
316350 let doCall = invoke(this, "internalCreateOrder", [_trader, _amm, _type, _triggerPrice, _limitPrice, _amountIn, _leverage, _side, _refLink, paymentAssetId, paymentAmount], nil)
317351 if ((doCall == doCall))
318352 then nil
333367 else !(isWhitelist(_amm)))
334368 then throw("Invalid increasePositionWithStopLoss parameters")
335369 else {
336- let positionSize = getPositionSize(_amm, _trader)
370+ let positionSize = getPositionSize(_amm, _trader, _direction)
337371 if ((positionSize != 0))
338372 then throw("Invalid increasePositionWithStopLoss parameters: only new position")
339373 else {
346380 let doResetContext = invoke(this, "resetContext", nil, nil)
347381 if ((doResetContext == doResetContext))
348382 then {
349- let openedPositionSize = getPositionSize(_amm, _trader)
383+ let openedPositionSize = getPositionSize(_amm, _trader, _direction)
350384 if ((openedPositionSize == openedPositionSize))
351385 then {
352386 let amountIn = abs(openedPositionSize)
408442 then true
409443 else (_side == SHORT)))
410444 then true
411- else !(if ((_type == STOP))
445+ else !(if (if ((_type == STOP))
412446 then true
413- else (_type == TAKE)))
447+ else (_type == TAKE))
448+ then true
449+ else (_type == LIMIT)))
414450 then true
415451 else !((i.caller == this)))
416452 then throw("Invalid createOrder parameters")
417453 else {
418454 let orderId = (currentOrderId() + 1)
455+ let positionDirection = getPositionDirection(_side, _type)
419456 let newTraderOrderCount = (getTraderOrderCount(_amm, _trader) + 1)
420- let positionSize = getPositionSize(_amm, _trader)
457+ let positionSize = getPositionSize(_amm, _trader, positionDirection)
421458 let _direction = if (if (if ((positionSize == 0))
422459 then true
423460 else if ((positionSize > 0))
451488 if ((usdnPayment == usdnPayment))
452489 then {
453490 let positionId = if ((positionSize != 0))
454- then getPositionId(_amm, _trader)
491+ then getPositionId(_amm, _trader, positionDirection)
455492 else 0
456- if ((newTraderOrderCount > MAX_TRADER_ORDERS_PER_AMM))
457- then throw("Invalid createLimitOrder parameters: order count")
458- else (((saveOrder(orderId, _amm, _trader, _amountIn, _leverage, _type, _triggerPrice, usdnPayment, _side, _refLink, positionId, _limitPrice) ++ addRemoveOrderId(orderId, _amm, _trader, true)) ++ updateTraderOrderCount(_amm, _trader, newTraderOrderCount)) ++ updateLastOrderId(orderId))
493+ if (if (if ((_type == STOP))
494+ then true
495+ else (_type == TAKE))
496+ then (positionId == 0)
497+ else false)
498+ then throw("STOP and TAKE order should be assigned to position with id != 0")
499+ else if ((newTraderOrderCount > MAX_TRADER_ORDERS_PER_AMM))
500+ then throw("Invalid createLimitOrder parameters: order count")
501+ else (((saveOrder(orderId, _amm, _trader, _amountIn, _leverage, _type, _triggerPrice, usdnPayment, _side, _refLink, positionId, _limitPrice) ++ addRemoveOrderId(orderId, _amm, _trader, true)) ++ updateTraderOrderCount(_amm, _trader, newTraderOrderCount)) ++ updateLastOrderId(orderId))
459502 }
460503 else throw("Strict value is not equal to itself.")
461504 }
465508
466509 @Callable(i)
467510 func cancelOrder (_orderId) = {
468- let $t01585016069 = getOrder(_orderId)
469- let _amm = $t01585016069._1
470- let _trader = $t01585016069._2
471- let _amountIn = $t01585016069._3
472- let _leverage = $t01585016069._4
473- let _type = $t01585016069._5
474- let _triggerPrice = $t01585016069._6
475- let _amountUsdn = $t01585016069._7
476- let _side = $t01585016069._8
477- let _refLink = $t01585016069._9
478- let _positionId = $t01585016069._10
479- let _limitPrice = $t01585016069._11
511+ let $t01904119260 = getOrder(_orderId)
512+ let _amm = $t01904119260._1
513+ let _trader = $t01904119260._2
514+ let _amountIn = $t01904119260._3
515+ let _leverage = $t01904119260._4
516+ let _type = $t01904119260._5
517+ let _triggerPrice = $t01904119260._6
518+ let _amountUsdn = $t01904119260._7
519+ let _side = $t01904119260._8
520+ let _refLink = $t01904119260._9
521+ let _positionId = $t01904119260._10
522+ let _limitPrice = $t01904119260._11
480523 if (if (if (!(initialized()))
481524 then true
482525 else !(isValid(_orderId)))
510553
511554 @Callable(i)
512555 func executeOrder (_orderId) = {
513- let $t01704017259 = getOrder(_orderId)
514- let _amm = $t01704017259._1
515- let _trader = $t01704017259._2
516- let _amountIn = $t01704017259._3
517- let _leverage = $t01704017259._4
518- let _type = $t01704017259._5
519- let _triggerPrice = $t01704017259._6
520- let _amountUsdn = $t01704017259._7
521- let _side = $t01704017259._8
522- let _refLink = $t01704017259._9
523- let _positionId = $t01704017259._10
524- let _limitPrice = $t01704017259._11
556+ let $t02045720676 = getOrder(_orderId)
557+ let _amm = $t02045720676._1
558+ let _trader = $t02045720676._2
559+ let _amountIn = $t02045720676._3
560+ let _leverage = $t02045720676._4
561+ let _type = $t02045720676._5
562+ let _triggerPrice = $t02045720676._6
563+ let _amountUsdn = $t02045720676._7
564+ let _side = $t02045720676._8
565+ let _refLink = $t02045720676._9
566+ let _positionId = $t02045720676._10
567+ let _limitPrice = $t02045720676._11
525568 let cleanUp = invoke(this, "cleanUpStaleOrders", [_amm, _trader], nil)
526569 if ((cleanUp == cleanUp))
527- then if (if (!(initialized()))
528- then true
529- else !(isValid(_orderId)))
530- then throw("Invalid executeOrder parameters")
531- else {
532- let positionSize = getPositionSize(_amm, _trader)
533- let currentPositionId = if ((positionSize != 0))
534- then getPositionId(_amm, _trader)
535- else 0
536- let $t01766321505 = if ((_type == STOP))
537- then {
538- let _positionDirection = if ((positionSize > 0))
539- then LONG
540- else if ((0 > positionSize))
541- then SHORT
542- else throw("Can not execute STOP order: no open position")
543- let marketPrice = getMarketPrice(_amm)
544- let isExecutable = if ((_side == _positionDirection))
545- then throw("Can not execute STOP order: reduce only")
546- else if ((currentPositionId != _positionId))
547- then throw("Can not execute STOP order: position closed")
548- else if ((_positionDirection == LONG))
549- then (_triggerPrice >= marketPrice)
550- else (marketPrice >= _triggerPrice)
551- if (isExecutable)
552- then $Tuple3("closePosition", [minv(_amountIn, abs(positionSize)), muld(_limitPrice, abs(positionSize)), false], nil)
553- else throw("Can not execute STOP order: triggerPrice mismatch")
554- }
555- else if ((_type == TAKE))
570+ then {
571+ let positionDirection = getPositionDirection(_side, _type)
572+ if (if (!(initialized()))
573+ then true
574+ else !(isValid(_orderId)))
575+ then throw("Invalid executeOrder parameters")
576+ else {
577+ let positionSize = getPositionSize(_amm, _trader, positionDirection)
578+ let currentPositionId = if ((positionSize != 0))
579+ then getPositionId(_amm, _trader, positionDirection)
580+ else 0
581+ let $t02118024558 = if ((_type == STOP))
556582 then {
557583 let _positionDirection = if ((positionSize > 0))
558584 then LONG
561587 else throw("Can not execute STOP order: no open position")
562588 let marketPrice = getMarketPrice(_amm)
563589 let isExecutable = if ((_side == _positionDirection))
564- then throw("Can not execute TAKE order: reduce only")
590+ then throw("Can not execute STOP order: reduce only")
565591 else if ((currentPositionId != _positionId))
566- then throw(((("Can not execute TAKE order: position closed " + toString(currentPositionId)) + "!=") + toString(_positionId)))
592+ then throw("Can not execute STOP order: position closed")
567593 else if ((_positionDirection == LONG))
568- then (marketPrice >= _triggerPrice)
569- else (_triggerPrice >= marketPrice)
594+ then (_triggerPrice >= marketPrice)
595+ else (marketPrice >= _triggerPrice)
570596 if (isExecutable)
571- then $Tuple3("closePosition", [minv(_amountIn, abs(positionSize)), muld(_limitPrice, abs(positionSize)), false], nil)
572- else throw("Can not execute TAKE order: triggerPrice mismatch")
597+ then $Tuple3("closePosition", [minv(_amountIn, abs(positionSize)), positionDirection, muld(_limitPrice, abs(positionSize)), false], nil)
598+ else throw("Can not execute STOP order: triggerPrice mismatch")
573599 }
574- else if ((_type == LIMIT))
600+ else if ((_type == TAKE))
575601 then {
602+ let _positionDirection = if ((positionSize > 0))
603+ then LONG
604+ else if ((0 > positionSize))
605+ then SHORT
606+ else throw("Can not execute STOP order: no open position")
576607 let marketPrice = getMarketPrice(_amm)
577- let spread = if ((_limitPrice == 0))
578- then getSpread(_triggerPrice)
579- else abs((_triggerPrice - _limitPrice))
580- let isExecutable = if ((marketPrice >= (_triggerPrice - spread)))
581- then ((_triggerPrice + spread) >= marketPrice)
582- else false
608+ let isExecutable = if ((_side == _positionDirection))
609+ then throw("Can not execute TAKE order: reduce only")
610+ else if ((currentPositionId != _positionId))
611+ then throw(((("Can not execute TAKE order: position closed " + toString(currentPositionId)) + "!=") + toString(_positionId)))
612+ else if ((_positionDirection == LONG))
613+ then (marketPrice >= _triggerPrice)
614+ else (_triggerPrice >= marketPrice)
583615 if (isExecutable)
584- then {
585- let _positionDirection = if ((positionSize > 0))
586- then LONG
587- else if ((0 > positionSize))
588- then SHORT
589- else -1
590- let direction = if ((positionSize == 0))
591- then INCREASE
592- else if ((_positionDirection == _side))
593- then INCREASE
594- else DECREASE
595- if ((direction == INCREASE))
596- then {
597- let amountInWithFee = (_amountUsdn - muld(_amountUsdn, getFee(_amm, _trader)))
598- $Tuple3("increasePosition", [_side, _leverage, if ((_limitPrice == 0))
599- then 0
600- else divd(amountInWithFee, _limitPrice), _refLink], [AttachedPayment(quoteAsset(), _amountUsdn)])
601- }
602- else $Tuple3("closePosition", [_amountIn, muld(_amountIn, _limitPrice), false], nil)
603- }
604- else throw("Can not execute LIMIT order: triggerPrice mismatch")
616+ then $Tuple3("closePosition", [minv(_amountIn, abs(positionSize)), positionDirection, muld(_limitPrice, abs(positionSize)), false], nil)
617+ else throw("Can not execute TAKE order: triggerPrice mismatch")
605618 }
606- else throw(("Invalid order type: " + toString(_type)))
607- let method = $t01766321505._1
608- let args = $t01766321505._2
609- let payments = $t01766321505._3
610- let withdraw = if ((size(payments) == 1))
611- then {
612- let unstake = invoke(managerAddress(), "withdraw", [toBase58String(quoteAsset()), payments[0].amount], nil)
613- if ((unstake == unstake))
614- then nil
615- else throw("Strict value is not equal to itself.")
616- }
617- else nil
618- if ((withdraw == withdraw))
619- then {
620- let doSetContext = invoke(this, "setContext", [_trader], nil)
621- if ((doSetContext == doSetContext))
622- then {
623- let doClosePosition = invoke(addressFromStringValue(_amm), method, args, payments)
624- if ((doClosePosition == doClosePosition))
625- then {
626- let doResetContext = invoke(this, "resetContext", nil, nil)
627- if ((doResetContext == doResetContext))
628- then {
629- let newTraderOrderCount = (getTraderOrderCount(_amm, _trader) - 1)
630- ((updateTraderOrderCount(_amm, _trader, newTraderOrderCount) ++ addRemoveOrderId(_orderId, _amm, _trader, false)) ++ markExecuteOrder(_orderId))
631- }
632- else throw("Strict value is not equal to itself.")
633- }
634- else throw("Strict value is not equal to itself.")
635- }
636- else throw("Strict value is not equal to itself.")
637- }
638- else throw("Strict value is not equal to itself.")
639- }
619+ else if ((_type == LIMIT))
620+ then {
621+ let marketPrice = getMarketPrice(_amm)
622+ let spread = if ((_limitPrice == 0))
623+ then getSpread(_triggerPrice)
624+ else abs((_triggerPrice - _limitPrice))
625+ let isExecutable = if ((marketPrice >= (_triggerPrice - spread)))
626+ then ((_triggerPrice + spread) >= marketPrice)
627+ else false
628+ if (isExecutable)
629+ then {
630+ let amountInWithFee = (_amountUsdn - muld(_amountUsdn, getFee(_amm, _trader)))
631+ $Tuple3("increasePosition", [_side, _leverage, if ((_limitPrice == 0))
632+ then 0
633+ else divd(amountInWithFee, _limitPrice), _refLink], [AttachedPayment(quoteAsset(), _amountUsdn)])
634+ }
635+ else throw("Can not execute LIMIT order: triggerPrice mismatch")
636+ }
637+ else throw(("Invalid order type: " + toString(_type)))
638+ let method = $t02118024558._1
639+ let args = $t02118024558._2
640+ let payments = $t02118024558._3
641+ let withdraw = if ((size(payments) == 1))
642+ then {
643+ let unstake = invoke(managerAddress(), "withdraw", [toBase58String(quoteAsset()), payments[0].amount], nil)
644+ if ((unstake == unstake))
645+ then nil
646+ else throw("Strict value is not equal to itself.")
647+ }
648+ else nil
649+ if ((withdraw == withdraw))
650+ then {
651+ let doSetContext = invoke(this, "setContext", [_trader], nil)
652+ if ((doSetContext == doSetContext))
653+ then {
654+ let doClosePosition = invoke(addressFromStringValue(_amm), method, args, payments)
655+ if ((doClosePosition == doClosePosition))
656+ then {
657+ let doResetContext = invoke(this, "resetContext", nil, nil)
658+ if ((doResetContext == doResetContext))
659+ then {
660+ let newTraderOrderCount = (getTraderOrderCount(_amm, _trader) - 1)
661+ ((updateTraderOrderCount(_amm, _trader, newTraderOrderCount) ++ addRemoveOrderId(_orderId, _amm, _trader, false)) ++ markExecuteOrder(_orderId))
662+ }
663+ else throw("Strict value is not equal to itself.")
664+ }
665+ else throw("Strict value is not equal to itself.")
666+ }
667+ else throw("Strict value is not equal to itself.")
668+ }
669+ else throw("Strict value is not equal to itself.")
670+ }
671+ }
640672 else throw("Strict value is not equal to itself.")
641673 }
642674
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let k_coordinatorAddress = "k_coordinatorAddress"
55
66 let k_admin_address = "k_admin_address"
77
88 let k_quote_asset = "k_quote_asset"
99
1010 let k_amm = "k_amm"
1111
1212 let k_manager_address = "k_manager_address"
1313
1414 let k_positionSequence = "k_positionSequence"
1515
1616 let k_positionSize = "k_positionSize"
17-
18-let k_fee = "k_fee"
1917
2018 let k_executedOrders = "k_executedOrders"
2119
2220 let k_canceledOrders = "k_canceledOrders"
2321
2422 let k_order = "k_order"
2523
2624 let k_lastOrderId = "k_lastOrderId"
2725
2826 let k_traderOrderCnt = "k_traderOrderCnt"
2927
3028 let k_traderOrderIds = "k_traderOrderIds"
3129
3230 let k_sender = "k_sender"
3331
3432 let k_initialized = "k_initialized"
3533
3634 let STOP = 1
3735
3836 let TAKE = 2
3937
4038 let LIMIT = 3
4139
4240 let LONG = 1
4341
4442 let SHORT = 2
4543
4644 let INCREASE = 1
4745
4846 let DECREASE = 2
4947
5048 let MAX_TRADER_ORDERS_PER_AMM = 5
5149
5250 let TIME = lastBlock.timestamp
5351
5452 let DECIMAL_UNIT = (1 * (((((10 * 10) * 10) * 10) * 10) * 10))
5553
5654 let SPREAD_LIMIT = (DECIMAL_UNIT / 200)
5755
5856 func abs (_x) = if ((_x > 0))
5957 then _x
6058 else -(_x)
6159
6260
6361 func divd (_x,_y) = fraction(_x, DECIMAL_UNIT, _y, HALFEVEN)
6462
6563
6664 func muld (_x,_y) = fraction(_x, _y, DECIMAL_UNIT, HALFEVEN)
6765
6866
6967 func minv (_x,_y) = if ((_x > _y))
7068 then _y
7169 else _x
7270
7371
7472 func toCompositeKey (_key,_address) = ((_key + "_") + _address)
7573
7674
7775 func executedOrderKey (_orderId) = ((k_executedOrders + "_") + toString(_orderId))
7876
7977
8078 func canceledOrderKey (_orderId) = ((k_canceledOrders + "_") + toString(_orderId))
8179
8280
8381 func orderKey (_orderId) = toCompositeKey(k_order, toString(_orderId))
8482
8583
8684 func traderOrderCountKey (_amm,_trader) = ((((k_traderOrderCnt + "_") + _amm) + "_") + _trader)
8785
8886
8987 func traderOrderIdsKey (_amm,_trader) = ((((k_traderOrderIds + "_") + _amm) + "_") + _trader)
9088
9189
9290 func coordinator () = valueOrErrorMessage(addressFromString(getStringValue(this, k_coordinatorAddress)), "Coordinator not set")
9391
9492
9593 func quoteAsset () = fromBase58String(getStringValue(coordinator(), k_quote_asset))
9694
9795
9896 func managerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_manager_address)), "Manager not set")
9997
10098
10199 func isWhitelist (_address) = valueOrElse(getBoolean(coordinator(), toCompositeKey(k_amm, _address)), false)
102100
103101
104102 func initialized () = valueOrElse(getBoolean(this, k_initialized), false)
105103
106104
107105 func isValid (_orderId) = if (valueOrElse(getBoolean(this, executedOrderKey(_orderId)), false))
108106 then throw(("Order already executed: " + toString(_orderId)))
109107 else if (valueOrElse(getBoolean(this, canceledOrderKey(_orderId)), false))
110108 then throw(("Order already cancelled: " + toString(_orderId)))
111109 else true
112110
113111
114112 func currentOrderId () = valueOrElse(getInteger(this, k_lastOrderId), 0)
115113
116114
117115 func getTraderOrderCount (_amm,_trader) = {
118116 let key = traderOrderCountKey(_amm, _trader)
119117 valueOrElse(getInteger(this, key), 0)
120118 }
121119
122120
123121 func traderAmmOrdersIds (_amm,_trader) = {
124122 let key = traderOrderIdsKey(_amm, _trader)
125123 let val = valueOrElse(getString(this, key), "")
126124 if ((val == ""))
127125 then nil
128126 else split(val, ",")
129127 }
130128
131129
132130 func getOrder (_orderId) = {
133131 let orderStr = valueOrErrorMessage(getString(this, orderKey(_orderId)), ("Invalid order id: " + toString(_orderId)))
134132 let orderPartList = split(orderStr, ",")
135133 let amm = orderPartList[0]
136134 let trader = orderPartList[1]
137135 let amountIn = valueOrErrorMessage(parseInt(orderPartList[2]), "Invalid amountIn")
138136 let leverage = valueOrErrorMessage(parseInt(orderPartList[3]), "Invalid leverage")
139137 let type = valueOrErrorMessage(parseInt(orderPartList[4]), "Invalid type")
140138 let triggerPrice = valueOrErrorMessage(parseInt(orderPartList[5]), "Invalid triggerPrice")
141139 let paymentUsdn = valueOrErrorMessage(parseInt(orderPartList[6]), "Invalid paymentUsdn")
142140 let side = valueOrErrorMessage(parseInt(orderPartList[7]), "Invalid side")
143141 let refLink = orderPartList[8]
144142 let positionId = valueOrErrorMessage(parseInt(orderPartList[9]), "Invalid positionId")
145143 let limitPrice = valueOrErrorMessage(parseInt(orderPartList[10]), "Invalid limitPrice")
146144 $Tuple11(amm, trader, amountIn, leverage, type, triggerPrice, paymentUsdn, side, refLink, positionId, limitPrice)
147145 }
148146
149147
150148 func getMarketPrice (_amm) = {
151149 let s = invoke(addressFromStringValue(_amm), "computeSpotPrice", nil, nil)
152150 if ((s == s))
153151 then {
154152 let res = match s {
155153 case t: Int =>
156154 t
157155 case _ =>
158156 throw("Invalid computeSpotPrice result")
159157 }
160158 value(res)
161159 }
162160 else throw("Strict value is not equal to itself.")
163161 }
164162
165163
166164 func getFee (_amm,_trader) = {
167165 let s = invoke(addressFromStringValue(_amm), "computeFeeForTraderWithArtifact", [_trader, ""], nil)
168166 if ((s == s))
169167 then {
170168 let res = match s {
171169 case t: (Int, Boolean) =>
172170 t._1
173171 case _ =>
174172 throw("Invalid computeFeeForTraderWithArtifact result")
175173 }
176174 value(res)
177175 }
178176 else throw("Strict value is not equal to itself.")
179177 }
180178
181179
182-func getPositionSize (_amm,_trader) = {
180+func getPositionDirection (_orderSide,_orderType) = if (if ((_orderType == TAKE))
181+ then true
182+ else (_orderType == STOP))
183+ then if ((_orderSide == LONG))
184+ then SHORT
185+ else LONG
186+ else _orderSide
187+
188+
189+func getPositionSize (_amm,_trader,_direction) = {
183190 let amm = addressFromStringValue(_amm)
184- let sizeKey = toCompositeKey(k_positionSize, _trader)
191+ let positionKey = ((_trader + "_") + toString(_direction))
192+ let sizeKey = toCompositeKey(k_positionSize, positionKey)
185193 valueOrElse(getInteger(amm, sizeKey), 0)
186194 }
187195
188196
189-func getPositionId (_amm,_trader) = {
197+func getPositionId (_amm,_trader,_direction) = {
190198 let amm = addressFromStringValue(_amm)
191- let seqKey = toCompositeKey(k_positionSequence, _trader)
199+ let positionKey = ((_trader + "_") + toString(_direction))
200+ let seqKey = toCompositeKey(k_positionSequence, positionKey)
192201 valueOrElse(getInteger(amm, seqKey), 0)
193202 }
194203
195204
196205 func getSpread (_price) = muld(_price, SPREAD_LIMIT)
197206
198207
199208 func saveOrder (_orderId,_amm,_trader,_amountIn,_leverage,_type,_triggerPrice,_paymentUsdn,_side,_refLink,_positionId,_limitPrice) = {
200209 let orderStr = makeString([_amm, _trader, toString(_amountIn), toString(_leverage), toString(_type), toString(_triggerPrice), toString(_paymentUsdn), toString(_side), _refLink, toString(_positionId), toString(_limitPrice)], ",")
201210 [StringEntry(orderKey(_orderId), orderStr)]
202211 }
203212
204213
205-func addRemoveOrderId (_orderId,_amm,_trader,_add) = {
206- let orderIds = traderAmmOrdersIds(_amm, _trader)
214+func updateOrderIdStr (_orderIdsNewStr,_amm,_trader) = [StringEntry(traderOrderIdsKey(_amm, _trader), _orderIdsNewStr)]
215+
216+
217+func addRemoveOrderIdList (_orderIds,_orderId,_amm,_trader,_add) = {
207218 let orderIdsNew = if (_add)
208- then (orderIds :+ toString(_orderId))
209- else removeByIndex(orderIds, valueOrErrorMessage(indexOf(orderIds, toString(_orderId)), ("No order with id: " + toString(_orderId))))
210- let orderIdsNewStr = makeString(orderIdsNew, ",")
211-[StringEntry(traderOrderIdsKey(_amm, _trader), orderIdsNewStr)]
219+ then (_orderIds :+ toString(_orderId))
220+ else removeByIndex(_orderIds, valueOrErrorMessage(indexOf(_orderIds, toString(_orderId)), ("No order with id: " + toString(_orderId))))
221+ orderIdsNew
212222 }
213223
214224
215-func updateTraderOrderCount (_amm,_trader,_count) = [IntegerEntry(traderOrderCountKey(_amm, _trader), _count)]
225+func addRemoveOrderId (_orderId,_amm,_trader,_add) = {
226+ let orderIds = traderAmmOrdersIds(_amm, _trader)
227+ let orderIdsNew = addRemoveOrderIdList(orderIds, _orderId, _amm, _trader, _add)
228+ let orderIdsNewStr = makeString(orderIdsNew, ",")
229+ updateOrderIdStr(orderIdsNewStr, _amm, _trader)
230+ }
231+
232+
233+func updateTraderOrderCount (_amm,_trader,_count) = if ((0 > _count))
234+ then throw(("Invalid order count: " + toString(_count)))
235+ else [IntegerEntry(traderOrderCountKey(_amm, _trader), _count)]
216236
217237
218238 func updateLastOrderId (_lastOrderId) = [IntegerEntry(k_lastOrderId, _lastOrderId)]
219239
220240
221241 func markExecuteOrder (_orderId) = [BooleanEntry(toCompositeKey(k_executedOrders, toString(_orderId)), true)]
222242
223243
224244 func markCancelOrder (_orderId) = [BooleanEntry(toCompositeKey(k_canceledOrders, toString(_orderId)), true)]
225245
226246
247+func getPositionIds (_amm,_trader) = {
248+ let longPositionSize = getPositionSize(_amm, _trader, LONG)
249+ let currentLongPositionId = if ((longPositionSize != 0))
250+ then getPositionId(_amm, _trader, LONG)
251+ else 0
252+ let shortPositionSize = getPositionSize(_amm, _trader, SHORT)
253+ let currentShortPositionId = if ((shortPositionSize != 0))
254+ then getPositionId(_amm, _trader, SHORT)
255+ else 0
256+[currentLongPositionId, currentShortPositionId]
257+ }
258+
259+
227260 @Callable(i)
228261 func cleanUpStaleOrders (_amm,_trader) = {
229262 let orders = traderAmmOrdersIds(_amm, _trader)
230- let orderCount = getTraderOrderCount(_amm, _trader)
263+ let positionIds = getPositionIds(_amm, _trader)
231264 func cleanUpOne (_acc,_orderId) = {
232265 let orderIdInt = valueOrErrorMessage(parseInt(_orderId), "Invalid order id")
233- let $t082878482 = getOrder(orderIdInt)
234- let _x1 = $t082878482._1
235- let _x2 = $t082878482._2
236- let _x3 = $t082878482._3
237- let _x4 = $t082878482._4
238- let _type = $t082878482._5
239- let _x5 = $t082878482._6
240- let _x6 = $t082878482._7
241- let _x7 = $t082878482._8
242- let _x8 = $t082878482._9
243- let _positionId = $t082878482._10
244- let _x9 = $t082878482._11
245- let positionSize = getPositionSize(_amm, _trader)
246- let currentPositionId = if ((positionSize != 0))
247- then getPositionId(_amm, _trader)
248- else 0
249- if (if (if ((_type == STOP))
266+ let $t096159810 = getOrder(orderIdInt)
267+ let _x1 = $t096159810._1
268+ let _x2 = $t096159810._2
269+ let _x3 = $t096159810._3
270+ let _x4 = $t096159810._4
271+ let _type = $t096159810._5
272+ let _x5 = $t096159810._6
273+ let _x6 = $t096159810._7
274+ let _x7 = $t096159810._8
275+ let _x8 = $t096159810._9
276+ let _positionId = $t096159810._10
277+ let _x9 = $t096159810._11
278+ if (if (if (if ((_type == STOP))
250279 then true
251280 else (_type == TAKE))
252- then (currentPositionId != _positionId)
281+ then (positionIds[0] != _positionId)
282+ else false)
283+ then (positionIds[1] != _positionId)
253284 else false)
254285 then {
255- let change = (markCancelOrder(orderIdInt) ++ addRemoveOrderId(orderIdInt, _amm, _trader, false))
256- $Tuple2((_acc._1 + 1), (_acc._2 ++ change))
286+ let change = markCancelOrder(orderIdInt)
287+ let newOrderList = addRemoveOrderIdList(_acc._1, orderIdInt, _amm, _trader, false)
288+ $Tuple2(newOrderList, (_acc._2 ++ change))
257289 }
258290 else _acc
259291 }
260292
261- let result = {
293+ let $t01016310237 = {
262294 let $l = orders
263295 let $s = size($l)
264- let $acc0 = $Tuple2(0, nil)
296+ let $acc0 = $Tuple2(orders, nil)
265297 func $f0_1 ($a,$i) = if (($i >= $s))
266298 then $a
267299 else cleanUpOne($a, $l[$i])
268300
269301 func $f0_2 ($a,$i) = if (($i >= $s))
270302 then $a
271- else throw("List size exceeds 5")
303+ else throw("List size exceeds 7")
272304
273- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5)
305+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7)
274306 }
275- (result._2 ++ updateTraderOrderCount(_amm, _trader, (orderCount - result._1)))
307+ let newOrders = $t01016310237._1
308+ let cancelActions = $t01016310237._2
309+ ((cancelActions ++ updateTraderOrderCount(_amm, _trader, size(newOrders))) ++ updateOrderIdStr(makeString(newOrders, ","), _amm, _trader))
276310 }
277311
278312
279313
280314 @Callable(i)
281315 func setContext (_sender) = if ((i.caller != this))
282316 then throw("Only self-call")
283317 else [StringEntry(k_sender, _sender)]
284318
285319
286320
287321 @Callable(i)
288322 func resetContext () = if ((i.caller != this))
289323 then throw("Only self-call")
290324 else [DeleteEntry(k_sender)]
291325
292326
293327
294328 @Callable(i)
295329 func initialize (_coordinator) = if (if (initialized())
296330 then true
297331 else (i.caller != this))
298332 then throw("Unable to initialize")
299333 else [StringEntry(k_coordinatorAddress, toString(addressFromStringValue(_coordinator))), BooleanEntry(k_initialized, true)]
300334
301335
302336
303337 @Callable(i)
304338 func createOrder (_amm,_type,_triggerPrice,_limitPrice,_amountIn,_leverage,_side,_refLink) = {
305339 let _trader = toString(i.caller)
306340 let cleanUp = invoke(this, "cleanUpStaleOrders", [_amm, _trader], nil)
307341 if ((cleanUp == cleanUp))
308342 then if ((size(i.payments) > 1))
309343 then throw("Invalid createOrder parameters: invalid payment count")
310344 else {
311- let $t01024710499 = if ((size(i.payments) == 1))
345+ let $t01224612498 = if ((size(i.payments) == 1))
312346 then $Tuple2(toBase58String(valueOrErrorMessage(i.payments[0].assetId, "Invalid asset id")), i.payments[0].amount)
313347 else $Tuple2("", 0)
314- let paymentAssetId = $t01024710499._1
315- let paymentAmount = $t01024710499._2
348+ let paymentAssetId = $t01224612498._1
349+ let paymentAmount = $t01224612498._2
316350 let doCall = invoke(this, "internalCreateOrder", [_trader, _amm, _type, _triggerPrice, _limitPrice, _amountIn, _leverage, _side, _refLink, paymentAssetId, paymentAmount], nil)
317351 if ((doCall == doCall))
318352 then nil
319353 else throw("Strict value is not equal to itself.")
320354 }
321355 else throw("Strict value is not equal to itself.")
322356 }
323357
324358
325359
326360 @Callable(i)
327361 func increasePositionWithStopLoss (_amm,_direction,_leverage,_minBaseAssetAmount,_refLink,_stopTriggerPrice,_stopLimitPrice,_takeTriggerPrice,_takeLimitPrice) = {
328362 let _trader = toString(i.caller)
329363 let cleanUp = invoke(this, "cleanUpStaleOrders", [_amm, _trader], nil)
330364 if ((cleanUp == cleanUp))
331365 then if (if (!(initialized()))
332366 then true
333367 else !(isWhitelist(_amm)))
334368 then throw("Invalid increasePositionWithStopLoss parameters")
335369 else {
336- let positionSize = getPositionSize(_amm, _trader)
370+ let positionSize = getPositionSize(_amm, _trader, _direction)
337371 if ((positionSize != 0))
338372 then throw("Invalid increasePositionWithStopLoss parameters: only new position")
339373 else {
340374 let doSetContext = invoke(this, "setContext", [_trader], nil)
341375 if ((doSetContext == doSetContext))
342376 then {
343377 let doClosePosition = invoke(addressFromStringValue(_amm), "increasePosition", [_direction, _leverage, _minBaseAssetAmount, _refLink], i.payments)
344378 if ((doClosePosition == doClosePosition))
345379 then {
346380 let doResetContext = invoke(this, "resetContext", nil, nil)
347381 if ((doResetContext == doResetContext))
348382 then {
349- let openedPositionSize = getPositionSize(_amm, _trader)
383+ let openedPositionSize = getPositionSize(_amm, _trader, _direction)
350384 if ((openedPositionSize == openedPositionSize))
351385 then {
352386 let amountIn = abs(openedPositionSize)
353387 let stopLossSide = if ((0 > openedPositionSize))
354388 then LONG
355389 else SHORT
356390 let doCreateStopOrder = if ((_stopTriggerPrice > 0))
357391 then {
358392 let doCreateStopOrder = invoke(this, "internalCreateOrder", [_trader, _amm, STOP, _stopTriggerPrice, _stopLimitPrice, amountIn, 0, stopLossSide, _refLink, "", 0], nil)
359393 if ((doCreateStopOrder == doCreateStopOrder))
360394 then nil
361395 else throw("Strict value is not equal to itself.")
362396 }
363397 else nil
364398 if ((doCreateStopOrder == doCreateStopOrder))
365399 then {
366400 let doCreateTakeOrder = if ((_takeTriggerPrice > 0))
367401 then {
368402 let doCreateTakeOrder = invoke(this, "internalCreateOrder", [_trader, _amm, TAKE, _takeTriggerPrice, _takeLimitPrice, amountIn, 0, stopLossSide, _refLink, "", 0], nil)
369403 if ((doCreateTakeOrder == doCreateTakeOrder))
370404 then nil
371405 else throw("Strict value is not equal to itself.")
372406 }
373407 else nil
374408 if ((doCreateTakeOrder == doCreateTakeOrder))
375409 then nil
376410 else throw("Strict value is not equal to itself.")
377411 }
378412 else throw("Strict value is not equal to itself.")
379413 }
380414 else throw("Strict value is not equal to itself.")
381415 }
382416 else throw("Strict value is not equal to itself.")
383417 }
384418 else throw("Strict value is not equal to itself.")
385419 }
386420 else throw("Strict value is not equal to itself.")
387421 }
388422 }
389423 else throw("Strict value is not equal to itself.")
390424 }
391425
392426
393427
394428 @Callable(i)
395429 func internalCreateOrder (_trader,_amm,_type,_triggerPrice,_limitPrice,_amountIn,_leverage,_side,_refLink,_paymentAssetId,_paymentAmount) = if (if (if (if (if (if (if (if (if (!(initialized()))
396430 then true
397431 else !(isWhitelist(_amm)))
398432 then true
399433 else (0 >= _triggerPrice))
400434 then true
401435 else (0 > _limitPrice))
402436 then true
403437 else (0 >= _amountIn))
404438 then true
405439 else (0 > _leverage))
406440 then true
407441 else !(if ((_side == LONG))
408442 then true
409443 else (_side == SHORT)))
410444 then true
411- else !(if ((_type == STOP))
445+ else !(if (if ((_type == STOP))
412446 then true
413- else (_type == TAKE)))
447+ else (_type == TAKE))
448+ then true
449+ else (_type == LIMIT)))
414450 then true
415451 else !((i.caller == this)))
416452 then throw("Invalid createOrder parameters")
417453 else {
418454 let orderId = (currentOrderId() + 1)
455+ let positionDirection = getPositionDirection(_side, _type)
419456 let newTraderOrderCount = (getTraderOrderCount(_amm, _trader) + 1)
420- let positionSize = getPositionSize(_amm, _trader)
457+ let positionSize = getPositionSize(_amm, _trader, positionDirection)
421458 let _direction = if (if (if ((positionSize == 0))
422459 then true
423460 else if ((positionSize > 0))
424461 then (_side == LONG)
425462 else false)
426463 then true
427464 else if ((0 > positionSize))
428465 then (_side == SHORT)
429466 else false)
430467 then INCREASE
431468 else DECREASE
432469 if (if ((positionSize == 0))
433470 then if ((_type == STOP))
434471 then true
435472 else (_type == TAKE)
436473 else false)
437474 then throw("Can not create STOP/TAKE order: no position")
438475 else {
439476 let usdnPayment = if ((_direction == INCREASE))
440477 then if (if ((_paymentAssetId != toBase58String(quoteAsset())))
441478 then true
442479 else (_paymentAmount != _amountIn))
443480 then throw("Invalid createLimitOrder parameters: invalid payment")
444481 else {
445482 let stake = invoke(managerAddress(), "deposit", nil, [AttachedPayment(quoteAsset(), _paymentAmount)])
446483 if ((stake == stake))
447484 then _paymentAmount
448485 else throw("Strict value is not equal to itself.")
449486 }
450487 else 0
451488 if ((usdnPayment == usdnPayment))
452489 then {
453490 let positionId = if ((positionSize != 0))
454- then getPositionId(_amm, _trader)
491+ then getPositionId(_amm, _trader, positionDirection)
455492 else 0
456- if ((newTraderOrderCount > MAX_TRADER_ORDERS_PER_AMM))
457- then throw("Invalid createLimitOrder parameters: order count")
458- else (((saveOrder(orderId, _amm, _trader, _amountIn, _leverage, _type, _triggerPrice, usdnPayment, _side, _refLink, positionId, _limitPrice) ++ addRemoveOrderId(orderId, _amm, _trader, true)) ++ updateTraderOrderCount(_amm, _trader, newTraderOrderCount)) ++ updateLastOrderId(orderId))
493+ if (if (if ((_type == STOP))
494+ then true
495+ else (_type == TAKE))
496+ then (positionId == 0)
497+ else false)
498+ then throw("STOP and TAKE order should be assigned to position with id != 0")
499+ else if ((newTraderOrderCount > MAX_TRADER_ORDERS_PER_AMM))
500+ then throw("Invalid createLimitOrder parameters: order count")
501+ else (((saveOrder(orderId, _amm, _trader, _amountIn, _leverage, _type, _triggerPrice, usdnPayment, _side, _refLink, positionId, _limitPrice) ++ addRemoveOrderId(orderId, _amm, _trader, true)) ++ updateTraderOrderCount(_amm, _trader, newTraderOrderCount)) ++ updateLastOrderId(orderId))
459502 }
460503 else throw("Strict value is not equal to itself.")
461504 }
462505 }
463506
464507
465508
466509 @Callable(i)
467510 func cancelOrder (_orderId) = {
468- let $t01585016069 = getOrder(_orderId)
469- let _amm = $t01585016069._1
470- let _trader = $t01585016069._2
471- let _amountIn = $t01585016069._3
472- let _leverage = $t01585016069._4
473- let _type = $t01585016069._5
474- let _triggerPrice = $t01585016069._6
475- let _amountUsdn = $t01585016069._7
476- let _side = $t01585016069._8
477- let _refLink = $t01585016069._9
478- let _positionId = $t01585016069._10
479- let _limitPrice = $t01585016069._11
511+ let $t01904119260 = getOrder(_orderId)
512+ let _amm = $t01904119260._1
513+ let _trader = $t01904119260._2
514+ let _amountIn = $t01904119260._3
515+ let _leverage = $t01904119260._4
516+ let _type = $t01904119260._5
517+ let _triggerPrice = $t01904119260._6
518+ let _amountUsdn = $t01904119260._7
519+ let _side = $t01904119260._8
520+ let _refLink = $t01904119260._9
521+ let _positionId = $t01904119260._10
522+ let _limitPrice = $t01904119260._11
480523 if (if (if (!(initialized()))
481524 then true
482525 else !(isValid(_orderId)))
483526 then true
484527 else !((toString(i.caller) == _trader)))
485528 then throw("Invalid cancelOrder parameters")
486529 else {
487530 let cleanUp = invoke(this, "cleanUpStaleOrders", [_amm, _trader], nil)
488531 if ((cleanUp == cleanUp))
489532 then {
490533 let newTraderOrderCount = (getTraderOrderCount(_amm, _trader) - 1)
491534 let withdraw = if ((_amountUsdn > 0))
492535 then {
493536 let unstake = invoke(managerAddress(), "withdraw", [toBase58String(quoteAsset()), _amountUsdn], nil)
494537 if ((unstake == unstake))
495538 then nil
496539 else throw("Strict value is not equal to itself.")
497540 }
498541 else nil
499542 if ((withdraw == withdraw))
500543 then (((markCancelOrder(_orderId) ++ addRemoveOrderId(_orderId, _amm, _trader, false)) ++ updateTraderOrderCount(_amm, _trader, newTraderOrderCount)) ++ (if ((_amountUsdn > 0))
501544 then [ScriptTransfer(i.caller, _amountUsdn, quoteAsset())]
502545 else nil))
503546 else throw("Strict value is not equal to itself.")
504547 }
505548 else throw("Strict value is not equal to itself.")
506549 }
507550 }
508551
509552
510553
511554 @Callable(i)
512555 func executeOrder (_orderId) = {
513- let $t01704017259 = getOrder(_orderId)
514- let _amm = $t01704017259._1
515- let _trader = $t01704017259._2
516- let _amountIn = $t01704017259._3
517- let _leverage = $t01704017259._4
518- let _type = $t01704017259._5
519- let _triggerPrice = $t01704017259._6
520- let _amountUsdn = $t01704017259._7
521- let _side = $t01704017259._8
522- let _refLink = $t01704017259._9
523- let _positionId = $t01704017259._10
524- let _limitPrice = $t01704017259._11
556+ let $t02045720676 = getOrder(_orderId)
557+ let _amm = $t02045720676._1
558+ let _trader = $t02045720676._2
559+ let _amountIn = $t02045720676._3
560+ let _leverage = $t02045720676._4
561+ let _type = $t02045720676._5
562+ let _triggerPrice = $t02045720676._6
563+ let _amountUsdn = $t02045720676._7
564+ let _side = $t02045720676._8
565+ let _refLink = $t02045720676._9
566+ let _positionId = $t02045720676._10
567+ let _limitPrice = $t02045720676._11
525568 let cleanUp = invoke(this, "cleanUpStaleOrders", [_amm, _trader], nil)
526569 if ((cleanUp == cleanUp))
527- then if (if (!(initialized()))
528- then true
529- else !(isValid(_orderId)))
530- then throw("Invalid executeOrder parameters")
531- else {
532- let positionSize = getPositionSize(_amm, _trader)
533- let currentPositionId = if ((positionSize != 0))
534- then getPositionId(_amm, _trader)
535- else 0
536- let $t01766321505 = if ((_type == STOP))
537- then {
538- let _positionDirection = if ((positionSize > 0))
539- then LONG
540- else if ((0 > positionSize))
541- then SHORT
542- else throw("Can not execute STOP order: no open position")
543- let marketPrice = getMarketPrice(_amm)
544- let isExecutable = if ((_side == _positionDirection))
545- then throw("Can not execute STOP order: reduce only")
546- else if ((currentPositionId != _positionId))
547- then throw("Can not execute STOP order: position closed")
548- else if ((_positionDirection == LONG))
549- then (_triggerPrice >= marketPrice)
550- else (marketPrice >= _triggerPrice)
551- if (isExecutable)
552- then $Tuple3("closePosition", [minv(_amountIn, abs(positionSize)), muld(_limitPrice, abs(positionSize)), false], nil)
553- else throw("Can not execute STOP order: triggerPrice mismatch")
554- }
555- else if ((_type == TAKE))
570+ then {
571+ let positionDirection = getPositionDirection(_side, _type)
572+ if (if (!(initialized()))
573+ then true
574+ else !(isValid(_orderId)))
575+ then throw("Invalid executeOrder parameters")
576+ else {
577+ let positionSize = getPositionSize(_amm, _trader, positionDirection)
578+ let currentPositionId = if ((positionSize != 0))
579+ then getPositionId(_amm, _trader, positionDirection)
580+ else 0
581+ let $t02118024558 = if ((_type == STOP))
556582 then {
557583 let _positionDirection = if ((positionSize > 0))
558584 then LONG
559585 else if ((0 > positionSize))
560586 then SHORT
561587 else throw("Can not execute STOP order: no open position")
562588 let marketPrice = getMarketPrice(_amm)
563589 let isExecutable = if ((_side == _positionDirection))
564- then throw("Can not execute TAKE order: reduce only")
590+ then throw("Can not execute STOP order: reduce only")
565591 else if ((currentPositionId != _positionId))
566- then throw(((("Can not execute TAKE order: position closed " + toString(currentPositionId)) + "!=") + toString(_positionId)))
592+ then throw("Can not execute STOP order: position closed")
567593 else if ((_positionDirection == LONG))
568- then (marketPrice >= _triggerPrice)
569- else (_triggerPrice >= marketPrice)
594+ then (_triggerPrice >= marketPrice)
595+ else (marketPrice >= _triggerPrice)
570596 if (isExecutable)
571- then $Tuple3("closePosition", [minv(_amountIn, abs(positionSize)), muld(_limitPrice, abs(positionSize)), false], nil)
572- else throw("Can not execute TAKE order: triggerPrice mismatch")
597+ then $Tuple3("closePosition", [minv(_amountIn, abs(positionSize)), positionDirection, muld(_limitPrice, abs(positionSize)), false], nil)
598+ else throw("Can not execute STOP order: triggerPrice mismatch")
573599 }
574- else if ((_type == LIMIT))
600+ else if ((_type == TAKE))
575601 then {
602+ let _positionDirection = if ((positionSize > 0))
603+ then LONG
604+ else if ((0 > positionSize))
605+ then SHORT
606+ else throw("Can not execute STOP order: no open position")
576607 let marketPrice = getMarketPrice(_amm)
577- let spread = if ((_limitPrice == 0))
578- then getSpread(_triggerPrice)
579- else abs((_triggerPrice - _limitPrice))
580- let isExecutable = if ((marketPrice >= (_triggerPrice - spread)))
581- then ((_triggerPrice + spread) >= marketPrice)
582- else false
608+ let isExecutable = if ((_side == _positionDirection))
609+ then throw("Can not execute TAKE order: reduce only")
610+ else if ((currentPositionId != _positionId))
611+ then throw(((("Can not execute TAKE order: position closed " + toString(currentPositionId)) + "!=") + toString(_positionId)))
612+ else if ((_positionDirection == LONG))
613+ then (marketPrice >= _triggerPrice)
614+ else (_triggerPrice >= marketPrice)
583615 if (isExecutable)
584- then {
585- let _positionDirection = if ((positionSize > 0))
586- then LONG
587- else if ((0 > positionSize))
588- then SHORT
589- else -1
590- let direction = if ((positionSize == 0))
591- then INCREASE
592- else if ((_positionDirection == _side))
593- then INCREASE
594- else DECREASE
595- if ((direction == INCREASE))
596- then {
597- let amountInWithFee = (_amountUsdn - muld(_amountUsdn, getFee(_amm, _trader)))
598- $Tuple3("increasePosition", [_side, _leverage, if ((_limitPrice == 0))
599- then 0
600- else divd(amountInWithFee, _limitPrice), _refLink], [AttachedPayment(quoteAsset(), _amountUsdn)])
601- }
602- else $Tuple3("closePosition", [_amountIn, muld(_amountIn, _limitPrice), false], nil)
603- }
604- else throw("Can not execute LIMIT order: triggerPrice mismatch")
616+ then $Tuple3("closePosition", [minv(_amountIn, abs(positionSize)), positionDirection, muld(_limitPrice, abs(positionSize)), false], nil)
617+ else throw("Can not execute TAKE order: triggerPrice mismatch")
605618 }
606- else throw(("Invalid order type: " + toString(_type)))
607- let method = $t01766321505._1
608- let args = $t01766321505._2
609- let payments = $t01766321505._3
610- let withdraw = if ((size(payments) == 1))
611- then {
612- let unstake = invoke(managerAddress(), "withdraw", [toBase58String(quoteAsset()), payments[0].amount], nil)
613- if ((unstake == unstake))
614- then nil
615- else throw("Strict value is not equal to itself.")
616- }
617- else nil
618- if ((withdraw == withdraw))
619- then {
620- let doSetContext = invoke(this, "setContext", [_trader], nil)
621- if ((doSetContext == doSetContext))
622- then {
623- let doClosePosition = invoke(addressFromStringValue(_amm), method, args, payments)
624- if ((doClosePosition == doClosePosition))
625- then {
626- let doResetContext = invoke(this, "resetContext", nil, nil)
627- if ((doResetContext == doResetContext))
628- then {
629- let newTraderOrderCount = (getTraderOrderCount(_amm, _trader) - 1)
630- ((updateTraderOrderCount(_amm, _trader, newTraderOrderCount) ++ addRemoveOrderId(_orderId, _amm, _trader, false)) ++ markExecuteOrder(_orderId))
631- }
632- else throw("Strict value is not equal to itself.")
633- }
634- else throw("Strict value is not equal to itself.")
635- }
636- else throw("Strict value is not equal to itself.")
637- }
638- else throw("Strict value is not equal to itself.")
639- }
619+ else if ((_type == LIMIT))
620+ then {
621+ let marketPrice = getMarketPrice(_amm)
622+ let spread = if ((_limitPrice == 0))
623+ then getSpread(_triggerPrice)
624+ else abs((_triggerPrice - _limitPrice))
625+ let isExecutable = if ((marketPrice >= (_triggerPrice - spread)))
626+ then ((_triggerPrice + spread) >= marketPrice)
627+ else false
628+ if (isExecutable)
629+ then {
630+ let amountInWithFee = (_amountUsdn - muld(_amountUsdn, getFee(_amm, _trader)))
631+ $Tuple3("increasePosition", [_side, _leverage, if ((_limitPrice == 0))
632+ then 0
633+ else divd(amountInWithFee, _limitPrice), _refLink], [AttachedPayment(quoteAsset(), _amountUsdn)])
634+ }
635+ else throw("Can not execute LIMIT order: triggerPrice mismatch")
636+ }
637+ else throw(("Invalid order type: " + toString(_type)))
638+ let method = $t02118024558._1
639+ let args = $t02118024558._2
640+ let payments = $t02118024558._3
641+ let withdraw = if ((size(payments) == 1))
642+ then {
643+ let unstake = invoke(managerAddress(), "withdraw", [toBase58String(quoteAsset()), payments[0].amount], nil)
644+ if ((unstake == unstake))
645+ then nil
646+ else throw("Strict value is not equal to itself.")
647+ }
648+ else nil
649+ if ((withdraw == withdraw))
650+ then {
651+ let doSetContext = invoke(this, "setContext", [_trader], nil)
652+ if ((doSetContext == doSetContext))
653+ then {
654+ let doClosePosition = invoke(addressFromStringValue(_amm), method, args, payments)
655+ if ((doClosePosition == doClosePosition))
656+ then {
657+ let doResetContext = invoke(this, "resetContext", nil, nil)
658+ if ((doResetContext == doResetContext))
659+ then {
660+ let newTraderOrderCount = (getTraderOrderCount(_amm, _trader) - 1)
661+ ((updateTraderOrderCount(_amm, _trader, newTraderOrderCount) ++ addRemoveOrderId(_orderId, _amm, _trader, false)) ++ markExecuteOrder(_orderId))
662+ }
663+ else throw("Strict value is not equal to itself.")
664+ }
665+ else throw("Strict value is not equal to itself.")
666+ }
667+ else throw("Strict value is not equal to itself.")
668+ }
669+ else throw("Strict value is not equal to itself.")
670+ }
671+ }
640672 else throw("Strict value is not equal to itself.")
641673 }
642674
643675
644676
645677 @Callable(i)
646678 func view_canExecuteOrder (_orderId) = {
647679 let s = invoke(this, "executeOrder", [_orderId], nil)
648680 if ((s == s))
649681 then throw("Success")
650682 else throw("Strict value is not equal to itself.")
651683 }
652684
653685
654686 @Verifier(tx)
655687 func verify () = {
656688 let coordinatorStr = getString(this, k_coordinatorAddress)
657689 if (isDefined(coordinatorStr))
658690 then {
659691 let admin = getString(addressFromStringValue(value(coordinatorStr)), k_admin_address)
660692 if (isDefined(admin))
661693 then valueOrElse(getBoolean(addressFromStringValue(value(admin)), ((("status_" + toString(this)) + "_") + toBase58String(tx.id))), false)
662694 else throw("unable to verify: admin not set in coordinator")
663695 }
664696 else sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
665697 }
666698

github/deemru/w8io/873ac7e 
339.55 ms