tx · Fj8LyeAxMh3HyxXSCJcfdzuxbkP34QExpoCxpuGYvYrU

3N9kbR6BQEQV7pwBfDFzprJtNofgi6fSJ6Y:  -0.03700000 Waves

2022.12.21 20:40 [2370372] smart account 3N9kbR6BQEQV7pwBfDFzprJtNofgi6fSJ6Y > SELF 0.00000000 Waves

{ "type": 13, "id": "Fj8LyeAxMh3HyxXSCJcfdzuxbkP34QExpoCxpuGYvYrU", "fee": 3700000, "feeAssetId": null, "timestamp": 1671644440005, "version": 2, "chainId": 84, "sender": "3N9kbR6BQEQV7pwBfDFzprJtNofgi6fSJ6Y", "senderPublicKey": "EajGg1J8duApPELWPw9gVkPwAKFC9hujhvCcne4FunUa", "proofs": [ "2b1ioECWLgjEpbDacsYGNQMb1VGcPKqNumL1NbfzChW8bP7NYMHrfzYp5GKAyB566iZTV6PWV9PYHjxoVNwkjDog" ], "script": "base64:BgJLCAISBAoCCAgSAwoBCBIAEgMKAQgSCgoICAEBAQEBAQgSCwoJCAEBAQgBAQEBEg0KCwgIAQEBAQEBCAgBEgMKAQESAwoBARIDCgEBOwAUa19jb29yZGluYXRvckFkZHJlc3MCFGtfY29vcmRpbmF0b3JBZGRyZXNzABJrX2FkbWluX3B1YmxpY19rZXkCEmtfYWRtaW5fcHVibGljX2tleQANa19xdW90ZV9hc3NldAINa19xdW90ZV9hc3NldAAFa19hbW0CBWtfYW1tABFrX21hbmFnZXJfYWRkcmVzcwIRa19tYW5hZ2VyX2FkZHJlc3MAEmtfcG9zaXRpb25TZXF1ZW5jZQISa19wb3NpdGlvblNlcXVlbmNlAA5rX3Bvc2l0aW9uU2l6ZQIOa19wb3NpdGlvblNpemUABWtfZmVlAgVrX2ZlZQAQa19leGVjdXRlZE9yZGVycwIQa19leGVjdXRlZE9yZGVycwAQa19jYW5jZWxlZE9yZGVycwIQa19jYW5jZWxlZE9yZGVycwAHa19vcmRlcgIHa19vcmRlcgANa19sYXN0T3JkZXJJZAINa19sYXN0T3JkZXJJZAAQa190cmFkZXJPcmRlckNudAIQa190cmFkZXJPcmRlckNudAAQa190cmFkZXJPcmRlcklkcwIQa190cmFkZXJPcmRlcklkcwAIa19zZW5kZXICCGtfc2VuZGVyAA1rX2luaXRpYWxpemVkAg1rX2luaXRpYWxpemVkAARTVE9QAAEABFRBS0UAAgAFTElNSVQAAwAETE9ORwABAAVTSE9SVAACAAhJTkNSRUFTRQABAAhERUNSRUFTRQACABlNQVhfVFJBREVSX09SREVSU19QRVJfQU1NAAUABFRJTUUIBQlsYXN0QmxvY2sJdGltZXN0YW1wAAxERUNJTUFMX1VOSVQJAGgCAAEJAGgCCQBoAgkAaAIJAGgCCQBoAgAKAAoACgAKAAoACgAMU1BSRUFEX0xJTUlUCQBpAgUMREVDSU1BTF9VTklUAMgBAQNhYnMBAl94AwkAZgIFAl94AAAFAl94CQEBLQEFAl94AQRkaXZkAgJfeAJfeQkAbgQFAl94BQxERUNJTUFMX1VOSVQFAl95BQhIQUxGRVZFTgEEbXVsZAICX3gCX3kJAG4EBQJfeAUCX3kFDERFQ0lNQUxfVU5JVAUISEFMRkVWRU4BBG1pbnYCAl94Al95AwkAZgIFAl94BQJfeQUCX3kFAl94AQ50b0NvbXBvc2l0ZUtleQIEX2tleQhfYWRkcmVzcwkArAICCQCsAgIFBF9rZXkCAV8FCF9hZGRyZXNzARBleGVjdXRlZE9yZGVyS2V5AQhfb3JkZXJJZAkArAICCQCsAgIFEGtfZXhlY3V0ZWRPcmRlcnMCAV8JAKQDAQUIX29yZGVySWQBEGNhbmNlbGVkT3JkZXJLZXkBCF9vcmRlcklkCQCsAgIJAKwCAgUQa19jYW5jZWxlZE9yZGVycwIBXwkApAMBBQhfb3JkZXJJZAEIb3JkZXJLZXkBCF9vcmRlcklkCQEOdG9Db21wb3NpdGVLZXkCBQdrX29yZGVyCQCkAwEFCF9vcmRlcklkARN0cmFkZXJPcmRlckNvdW50S2V5AgRfYW1tB190cmFkZXIJAKwCAgkArAICCQCsAgIJAKwCAgUQa190cmFkZXJPcmRlckNudAIBXwUEX2FtbQIBXwUHX3RyYWRlcgERdHJhZGVyT3JkZXJJZHNLZXkCBF9hbW0HX3RyYWRlcgkArAICCQCsAgIJAKwCAgkArAICBRBrX3RyYWRlck9yZGVySWRzAgFfBQRfYW1tAgFfBQdfdHJhZGVyAQtjb29yZGluYXRvcgAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCBQR0aGlzBRRrX2Nvb3JkaW5hdG9yQWRkcmVzcwITQ29vcmRpbmF0b3Igbm90IHNldAEKcXVvdGVBc3NldAAJANkEAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUNa19xdW90ZV9hc3NldAEObWFuYWdlckFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAURa19tYW5hZ2VyX2FkZHJlc3MCD01hbmFnZXIgbm90IHNldAELaXNXaGl0ZWxpc3QBCF9hZGRyZXNzCQELdmFsdWVPckVsc2UCCQCbCAIJAQtjb29yZGluYXRvcgAJAQ50b0NvbXBvc2l0ZUtleQIFBWtfYW1tBQhfYWRkcmVzcwcBDmFkbWluUHVibGljS2V5AAkA2QQBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABRJrX2FkbWluX3B1YmxpY19rZXkBC2luaXRpYWxpemVkAAkBC3ZhbHVlT3JFbHNlAgkAmwgCBQR0aGlzBQ1rX2luaXRpYWxpemVkBwEHaXNWYWxpZAEIX29yZGVySWQDCQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMJARBleGVjdXRlZE9yZGVyS2V5AQUIX29yZGVySWQHCQACAQkArAICAhhPcmRlciBhbHJlYWR5IGV4ZWN1dGVkOiAJAKQDAQUIX29yZGVySWQDCQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMJARBjYW5jZWxlZE9yZGVyS2V5AQUIX29yZGVySWQHCQACAQkArAICAhlPcmRlciBhbHJlYWR5IGNhbmNlbGxlZDogCQCkAwEFCF9vcmRlcklkBgEOY3VycmVudE9yZGVySWQACQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFDWtfbGFzdE9yZGVySWQAAAETZ2V0VHJhZGVyT3JkZXJDb3VudAIEX2FtbQdfdHJhZGVyBANrZXkJARN0cmFkZXJPcmRlckNvdW50S2V5AgUEX2FtbQUHX3RyYWRlcgkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQNrZXkAAAESdHJhZGVyQW1tT3JkZXJzSWRzAgRfYW1tB190cmFkZXIEA2tleQkBEXRyYWRlck9yZGVySWRzS2V5AgUEX2FtbQUHX3RyYWRlcgQDdmFsCQELdmFsdWVPckVsc2UCCQCdCAIFBHRoaXMFA2tleQIAAwkAAAIFA3ZhbAIABQNuaWwJALUJAgUDdmFsAgEsAQhnZXRPcmRlcgEIX29yZGVySWQECG9yZGVyU3RyCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ0IAgUEdGhpcwkBCG9yZGVyS2V5AQUIX29yZGVySWQJAKwCAgISSW52YWxpZCBvcmRlciBpZDogCQCkAwEFCF9vcmRlcklkBA1vcmRlclBhcnRMaXN0CQC1CQIFCG9yZGVyU3RyAgEsBANhbW0JAJEDAgUNb3JkZXJQYXJ0TGlzdAAABAZ0cmFkZXIJAJEDAgUNb3JkZXJQYXJ0TGlzdAABBAhhbW91bnRJbgkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEJAJEDAgUNb3JkZXJQYXJ0TGlzdAACAhBJbnZhbGlkIGFtb3VudEluBAhsZXZlcmFnZQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEJAJEDAgUNb3JkZXJQYXJ0TGlzdAADAhBJbnZhbGlkIGxldmVyYWdlBAR0eXBlCQETdmFsdWVPckVycm9yTWVzc2FnZQIJALYJAQkAkQMCBQ1vcmRlclBhcnRMaXN0AAQCDEludmFsaWQgdHlwZQQMdHJpZ2dlclByaWNlCQETdmFsdWVPckVycm9yTWVzc2FnZQIJALYJAQkAkQMCBQ1vcmRlclBhcnRMaXN0AAUCFEludmFsaWQgdHJpZ2dlclByaWNlBAtwYXltZW50VXNkbgkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEJAJEDAgUNb3JkZXJQYXJ0TGlzdAAGAhNJbnZhbGlkIHBheW1lbnRVc2RuBARzaWRlCQETdmFsdWVPckVycm9yTWVzc2FnZQIJALYJAQkAkQMCBQ1vcmRlclBhcnRMaXN0AAcCDEludmFsaWQgc2lkZQQHcmVmTGluawkAkQMCBQ1vcmRlclBhcnRMaXN0AAgECnBvc2l0aW9uSWQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAtgkBCQCRAwIFDW9yZGVyUGFydExpc3QACQISSW52YWxpZCBwb3NpdGlvbklkBApsaW1pdFByaWNlCQETdmFsdWVPckVycm9yTWVzc2FnZQIJALYJAQkAkQMCBQ1vcmRlclBhcnRMaXN0AAoCEkludmFsaWQgbGltaXRQcmljZQkAnQoLBQNhbW0FBnRyYWRlcgUIYW1vdW50SW4FCGxldmVyYWdlBQR0eXBlBQx0cmlnZ2VyUHJpY2UFC3BheW1lbnRVc2RuBQRzaWRlBQdyZWZMaW5rBQpwb3NpdGlvbklkBQpsaW1pdFByaWNlAQ5nZXRNYXJrZXRQcmljZQEEX2FtbQQBcwkA/AcECQERQGV4dHJOYXRpdmUoMTA2MikBBQRfYW1tAhBjb21wdXRlU3BvdFByaWNlBQNuaWwFA25pbAMJAAACBQFzBQFzBANyZXMEByRtYXRjaDAFAXMDCQABAgUHJG1hdGNoMAIDSW50BAF0BQckbWF0Y2gwBQF0CQACAQIfSW52YWxpZCBjb21wdXRlU3BvdFByaWNlIHJlc3VsdAkBBXZhbHVlAQUDcmVzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAQZnZXRGZWUCBF9hbW0HX3RyYWRlcgQBcwkA/AcECQERQGV4dHJOYXRpdmUoMTA2MikBBQRfYW1tAh9jb21wdXRlRmVlRm9yVHJhZGVyV2l0aEFydGlmYWN0CQDMCAIFB190cmFkZXIJAMwIAgIABQNuaWwFA25pbAMJAAACBQFzBQFzBANyZXMEByRtYXRjaDAFAXMDCQABAgUHJG1hdGNoMAIOKEludCwgQm9vbGVhbikEAXQFByRtYXRjaDAIBQF0Al8xCQACAQIuSW52YWxpZCBjb21wdXRlRmVlRm9yVHJhZGVyV2l0aEFydGlmYWN0IHJlc3VsdAkBBXZhbHVlAQUDcmVzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAQ9nZXRQb3NpdGlvblNpemUCBF9hbW0HX3RyYWRlcgQDYW1tCQERQGV4dHJOYXRpdmUoMTA2MikBBQRfYW1tBAdzaXplS2V5CQEOdG9Db21wb3NpdGVLZXkCBQ5rX3Bvc2l0aW9uU2l6ZQUHX3RyYWRlcgkBC3ZhbHVlT3JFbHNlAgkAmggCBQNhbW0FB3NpemVLZXkAAAENZ2V0UG9zaXRpb25JZAIEX2FtbQdfdHJhZGVyBANhbW0JARFAZXh0ck5hdGl2ZSgxMDYyKQEFBF9hbW0EBnNlcUtleQkBDnRvQ29tcG9zaXRlS2V5AgUSa19wb3NpdGlvblNlcXVlbmNlBQdfdHJhZGVyCQELdmFsdWVPckVsc2UCCQCaCAIFA2FtbQUGc2VxS2V5AAABCWdldFNwcmVhZAEGX3ByaWNlCQEEbXVsZAIFBl9wcmljZQUMU1BSRUFEX0xJTUlUAQlzYXZlT3JkZXIMCF9vcmRlcklkBF9hbW0HX3RyYWRlcglfYW1vdW50SW4JX2xldmVyYWdlBV90eXBlDV90cmlnZ2VyUHJpY2UMX3BheW1lbnRVc2RuBV9zaWRlCF9yZWZMaW5rC19wb3NpdGlvbklkC19saW1pdFByaWNlBAhvcmRlclN0cgkAuQkCCQDMCAIFBF9hbW0JAMwIAgUHX3RyYWRlcgkAzAgCCQCkAwEFCV9hbW91bnRJbgkAzAgCCQCkAwEFCV9sZXZlcmFnZQkAzAgCCQCkAwEFBV90eXBlCQDMCAIJAKQDAQUNX3RyaWdnZXJQcmljZQkAzAgCCQCkAwEFDF9wYXltZW50VXNkbgkAzAgCCQCkAwEFBV9zaWRlCQDMCAIFCF9yZWZMaW5rCQDMCAIJAKQDAQULX3Bvc2l0aW9uSWQJAMwIAgkApAMBBQtfbGltaXRQcmljZQUDbmlsAgEsCQDMCAIJAQtTdHJpbmdFbnRyeQIJAQhvcmRlcktleQEFCF9vcmRlcklkBQhvcmRlclN0cgUDbmlsARBhZGRSZW1vdmVPcmRlcklkBAhfb3JkZXJJZARfYW1tB190cmFkZXIEX2FkZAQIb3JkZXJJZHMJARJ0cmFkZXJBbW1PcmRlcnNJZHMCBQRfYW1tBQdfdHJhZGVyBAtvcmRlcklkc05ldwMFBF9hZGQJAM0IAgUIb3JkZXJJZHMJAKQDAQUIX29yZGVySWQJANEIAgUIb3JkZXJJZHMJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAzwgCBQhvcmRlcklkcwkApAMBBQhfb3JkZXJJZAkArAICAhJObyBvcmRlciB3aXRoIGlkOiAJAKQDAQUIX29yZGVySWQEDm9yZGVySWRzTmV3U3RyCQC5CQIFC29yZGVySWRzTmV3AgEsCQDMCAIJAQtTdHJpbmdFbnRyeQIJARF0cmFkZXJPcmRlcklkc0tleQIFBF9hbW0FB190cmFkZXIFDm9yZGVySWRzTmV3U3RyBQNuaWwBFnVwZGF0ZVRyYWRlck9yZGVyQ291bnQDBF9hbW0HX3RyYWRlcgZfY291bnQJAMwIAgkBDEludGVnZXJFbnRyeQIJARN0cmFkZXJPcmRlckNvdW50S2V5AgUEX2FtbQUHX3RyYWRlcgUGX2NvdW50BQNuaWwBEXVwZGF0ZUxhc3RPcmRlcklkAQxfbGFzdE9yZGVySWQJAMwIAgkBDEludGVnZXJFbnRyeQIFDWtfbGFzdE9yZGVySWQFDF9sYXN0T3JkZXJJZAUDbmlsARBtYXJrRXhlY3V0ZU9yZGVyAQhfb3JkZXJJZAkAzAgCCQEMQm9vbGVhbkVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUQa19leGVjdXRlZE9yZGVycwkApAMBBQhfb3JkZXJJZAYFA25pbAEPbWFya0NhbmNlbE9yZGVyAQhfb3JkZXJJZAkAzAgCCQEMQm9vbGVhbkVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUQa19jYW5jZWxlZE9yZGVycwkApAMBBQhfb3JkZXJJZAYFA25pbAoBaQESY2xlYW5VcFN0YWxlT3JkZXJzAgRfYW1tB190cmFkZXIEBm9yZGVycwkBEnRyYWRlckFtbU9yZGVyc0lkcwIFBF9hbW0FB190cmFkZXIKAQpjbGVhblVwT25lAgRfYWNjCF9vcmRlcklkBApvcmRlcklkSW50CQETdmFsdWVPckVycm9yTWVzc2FnZQIJALYJAQUIX29yZGVySWQCEEludmFsaWQgb3JkZXIgaWQECyR0MDgzMjA4NTE1CQEIZ2V0T3JkZXIBBQpvcmRlcklkSW50BANfeDEIBQskdDA4MzIwODUxNQJfMQQDX3gyCAULJHQwODMyMDg1MTUCXzIEA194MwgFCyR0MDgzMjA4NTE1Al8zBANfeDQIBQskdDA4MzIwODUxNQJfNAQFX3R5cGUIBQskdDA4MzIwODUxNQJfNQQDX3g1CAULJHQwODMyMDg1MTUCXzYEA194NggFCyR0MDgzMjA4NTE1Al83BANfeDcIBQskdDA4MzIwODUxNQJfOAQDX3g4CAULJHQwODMyMDg1MTUCXzkEC19wb3NpdGlvbklkCAULJHQwODMyMDg1MTUDXzEwBANfeDkIBQskdDA4MzIwODUxNQNfMTEEDHBvc2l0aW9uU2l6ZQkBD2dldFBvc2l0aW9uU2l6ZQIFBF9hbW0FB190cmFkZXIEEWN1cnJlbnRQb3NpdGlvbklkAwkBAiE9AgUMcG9zaXRpb25TaXplAAAJAQ1nZXRQb3NpdGlvbklkAgUEX2FtbQUHX3RyYWRlcgAAAwMDCQAAAgUFX3R5cGUFBFNUT1AGCQAAAgUFX3R5cGUFBFRBS0UJAQIhPQIFEWN1cnJlbnRQb3NpdGlvbklkBQtfcG9zaXRpb25JZAcEBmNoYW5nZQkAzggCCQEPbWFya0NhbmNlbE9yZGVyAQUKb3JkZXJJZEludAkBEGFkZFJlbW92ZU9yZGVySWQEBQpvcmRlcklkSW50BQRfYW1tBQdfdHJhZGVyBwkAzggCBQRfYWNjBQZjaGFuZ2UFBF9hY2MKAAIkbAUGb3JkZXJzCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQpjbGVhblVwT25lAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhNMaXN0IHNpemUgZXhjZWVkcyA1CQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQFpAQpzZXRDb250ZXh0AQdfc2VuZGVyAwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIOT25seSBzZWxmLWNhbGwJAMwIAgkBC1N0cmluZ0VudHJ5AgUIa19zZW5kZXIFB19zZW5kZXIFA25pbAFpAQxyZXNldENvbnRleHQAAwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIOT25seSBzZWxmLWNhbGwJAMwIAgkBC0RlbGV0ZUVudHJ5AQUIa19zZW5kZXIFA25pbAFpAQppbml0aWFsaXplAQxfY29vcmRpbmF0b3IDCQELaW5pdGlhbGl6ZWQACQACAQITQWxyZWFkeSBpbml0aWFsaXplZAkAzAgCCQELU3RyaW5nRW50cnkCBRRrX2Nvb3JkaW5hdG9yQWRkcmVzcwUMX2Nvb3JkaW5hdG9yCQDMCAIJAQxCb29sZWFuRW50cnkCBQ1rX2luaXRpYWxpemVkBgUDbmlsAWkBC2NyZWF0ZU9yZGVyCARfYW1tBV90eXBlDV90cmlnZ2VyUHJpY2ULX2xpbWl0UHJpY2UJX2Ftb3VudEluCV9sZXZlcmFnZQVfc2lkZQhfcmVmTGluawQHX3RyYWRlcgkApQgBCAUBaQZjYWxsZXIEB2NsZWFuVXAJAPwHBAUEdGhpcwISY2xlYW5VcFN0YWxlT3JkZXJzCQDMCAIFBF9hbW0JAMwIAgUHX3RyYWRlcgUDbmlsBQNuaWwDCQAAAgUHY2xlYW5VcAUHY2xlYW5VcAMJAGYCCQCQAwEIBQFpCHBheW1lbnRzAAEJAAIBAjVJbnZhbGlkIGNyZWF0ZU9yZGVyIHBhcmFtZXRlcnM6IGludmFsaWQgcGF5bWVudCBjb3VudAQNJHQwMTAxMDAxMDM1MgMJAAACCQCQAwEIBQFpCHBheW1lbnRzAAEJAJQKAgkA2AQBCQETdmFsdWVPckVycm9yTWVzc2FnZQIICQCRAwIIBQFpCHBheW1lbnRzAAAHYXNzZXRJZAIQSW52YWxpZCBhc3NldCBpZAgJAJEDAggFAWkIcGF5bWVudHMAAAZhbW91bnQJAJQKAgIAAAAEDnBheW1lbnRBc3NldElkCAUNJHQwMTAxMDAxMDM1MgJfMQQNcGF5bWVudEFtb3VudAgFDSR0MDEwMTAwMTAzNTICXzIEBmRvQ2FsbAkA/AcEBQR0aGlzAhNpbnRlcm5hbENyZWF0ZU9yZGVyCQDMCAIFB190cmFkZXIJAMwIAgUEX2FtbQkAzAgCBQVfdHlwZQkAzAgCBQ1fdHJpZ2dlclByaWNlCQDMCAIFC19saW1pdFByaWNlCQDMCAIFCV9hbW91bnRJbgkAzAgCBQlfbGV2ZXJhZ2UJAMwIAgUFX3NpZGUJAMwIAgUIX3JlZkxpbmsJAMwIAgUOcGF5bWVudEFzc2V0SWQJAMwIAgUNcGF5bWVudEFtb3VudAUDbmlsBQNuaWwDCQAAAgUGZG9DYWxsBQZkb0NhbGwFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARxpbmNyZWFzZVBvc2l0aW9uV2l0aFN0b3BMb3NzCQRfYW1tCl9kaXJlY3Rpb24JX2xldmVyYWdlE19taW5CYXNlQXNzZXRBbW91bnQIX3JlZkxpbmsRX3N0b3BUcmlnZ2VyUHJpY2UPX3N0b3BMaW1pdFByaWNlEV90YWtlVHJpZ2dlclByaWNlD190YWtlTGltaXRQcmljZQQHX3RyYWRlcgkApQgBCAUBaQZjYWxsZXIEB2NsZWFuVXAJAPwHBAUEdGhpcwISY2xlYW5VcFN0YWxlT3JkZXJzCQDMCAIFBF9hbW0JAMwIAgUHX3RyYWRlcgUDbmlsBQNuaWwDCQAAAgUHY2xlYW5VcAUHY2xlYW5VcAMDCQEBIQEJAQtpbml0aWFsaXplZAAGCQEBIQEJAQtpc1doaXRlbGlzdAEFBF9hbW0JAAIBAi9JbnZhbGlkIGluY3JlYXNlUG9zaXRpb25XaXRoU3RvcExvc3MgcGFyYW1ldGVycwQMcG9zaXRpb25TaXplCQEPZ2V0UG9zaXRpb25TaXplAgUEX2FtbQUHX3RyYWRlcgMJAQIhPQIFDHBvc2l0aW9uU2l6ZQAACQACAQJCSW52YWxpZCBpbmNyZWFzZVBvc2l0aW9uV2l0aFN0b3BMb3NzIHBhcmFtZXRlcnM6IG9ubHkgbmV3IHBvc2l0aW9uBAxkb1NldENvbnRleHQJAPwHBAUEdGhpcwIKc2V0Q29udGV4dAkAzAgCBQdfdHJhZGVyBQNuaWwFA25pbAMJAAACBQxkb1NldENvbnRleHQFDGRvU2V0Q29udGV4dAQPZG9DbG9zZVBvc2l0aW9uCQD8BwQJARFAZXh0ck5hdGl2ZSgxMDYyKQEFBF9hbW0CEGluY3JlYXNlUG9zaXRpb24JAMwIAgUKX2RpcmVjdGlvbgkAzAgCBQlfbGV2ZXJhZ2UJAMwIAgUTX21pbkJhc2VBc3NldEFtb3VudAkAzAgCBQhfcmVmTGluawUDbmlsCAUBaQhwYXltZW50cwMJAAACBQ9kb0Nsb3NlUG9zaXRpb24FD2RvQ2xvc2VQb3NpdGlvbgQOZG9SZXNldENvbnRleHQJAPwHBAUEdGhpcwIMcmVzZXRDb250ZXh0BQNuaWwFA25pbAMJAAACBQ5kb1Jlc2V0Q29udGV4dAUOZG9SZXNldENvbnRleHQEEm9wZW5lZFBvc2l0aW9uU2l6ZQkBD2dldFBvc2l0aW9uU2l6ZQIFBF9hbW0FB190cmFkZXIDCQAAAgUSb3BlbmVkUG9zaXRpb25TaXplBRJvcGVuZWRQb3NpdGlvblNpemUECGFtb3VudEluCQEDYWJzAQUSb3BlbmVkUG9zaXRpb25TaXplBAxzdG9wTG9zc1NpZGUDCQBmAgAABRJvcGVuZWRQb3NpdGlvblNpemUFBExPTkcFBVNIT1JUBBFkb0NyZWF0ZVN0b3BPcmRlcgMJAGYCBRFfc3RvcFRyaWdnZXJQcmljZQAABBFkb0NyZWF0ZVN0b3BPcmRlcgkA/AcEBQR0aGlzAhNpbnRlcm5hbENyZWF0ZU9yZGVyCQDMCAIFB190cmFkZXIJAMwIAgUEX2FtbQkAzAgCBQRTVE9QCQDMCAIFEV9zdG9wVHJpZ2dlclByaWNlCQDMCAIFD19zdG9wTGltaXRQcmljZQkAzAgCBQhhbW91bnRJbgkAzAgCAAAJAMwIAgUMc3RvcExvc3NTaWRlCQDMCAIFCF9yZWZMaW5rCQDMCAICAAkAzAgCAAAFA25pbAUDbmlsAwkAAAIFEWRvQ3JlYXRlU3RvcE9yZGVyBRFkb0NyZWF0ZVN0b3BPcmRlcgUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgURZG9DcmVhdGVTdG9wT3JkZXIFEWRvQ3JlYXRlU3RvcE9yZGVyBBFkb0NyZWF0ZVRha2VPcmRlcgMJAGYCBRFfdGFrZVRyaWdnZXJQcmljZQAABBFkb0NyZWF0ZVRha2VPcmRlcgkA/AcEBQR0aGlzAhNpbnRlcm5hbENyZWF0ZU9yZGVyCQDMCAIFB190cmFkZXIJAMwIAgUEX2FtbQkAzAgCBQRUQUtFCQDMCAIFEV90YWtlVHJpZ2dlclByaWNlCQDMCAIFD190YWtlTGltaXRQcmljZQkAzAgCBQhhbW91bnRJbgkAzAgCAAAJAMwIAgUMc3RvcExvc3NTaWRlCQDMCAIFCF9yZWZMaW5rCQDMCAICAAkAzAgCAAAFA25pbAUDbmlsAwkAAAIFEWRvQ3JlYXRlVGFrZU9yZGVyBRFkb0NyZWF0ZVRha2VPcmRlcgUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgURZG9DcmVhdGVUYWtlT3JkZXIFEWRvQ3JlYXRlVGFrZU9yZGVyBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQETaW50ZXJuYWxDcmVhdGVPcmRlcgsHX3RyYWRlcgRfYW1tBV90eXBlDV90cmlnZ2VyUHJpY2ULX2xpbWl0UHJpY2UJX2Ftb3VudEluCV9sZXZlcmFnZQVfc2lkZQhfcmVmTGluaw9fcGF5bWVudEFzc2V0SWQOX3BheW1lbnRBbW91bnQDAwMDAwMDAwMJAQEhAQkBC2luaXRpYWxpemVkAAYJAQEhAQkBC2lzV2hpdGVsaXN0AQUEX2FtbQYJAGcCAAAFDV90cmlnZ2VyUHJpY2UGCQBmAgAABQtfbGltaXRQcmljZQYJAGcCAAAFCV9hbW91bnRJbgYJAGYCAAAFCV9sZXZlcmFnZQYJAQEhAQMJAAACBQVfc2lkZQUETE9ORwYJAAACBQVfc2lkZQUFU0hPUlQGCQEBIQEDAwkAAAIFBV90eXBlBQRTVE9QBgkAAAIFBV90eXBlBQRUQUtFBgkAAAIFBV90eXBlBQVMSU1JVAYJAQEhAQkAAAIIBQFpBmNhbGxlcgUEdGhpcwkAAgECHkludmFsaWQgY3JlYXRlT3JkZXIgcGFyYW1ldGVycwQHb3JkZXJJZAkAZAIJAQ5jdXJyZW50T3JkZXJJZAAAAQQTbmV3VHJhZGVyT3JkZXJDb3VudAkAZAIJARNnZXRUcmFkZXJPcmRlckNvdW50AgUEX2FtbQUHX3RyYWRlcgABBAxwb3NpdGlvblNpemUJAQ9nZXRQb3NpdGlvblNpemUCBQRfYW1tBQdfdHJhZGVyBApfZGlyZWN0aW9uAwMDCQAAAgUMcG9zaXRpb25TaXplAAAGAwkAZgIFDHBvc2l0aW9uU2l6ZQAACQAAAgUFX3NpZGUFBExPTkcHBgMJAGYCAAAFDHBvc2l0aW9uU2l6ZQkAAAIFBV9zaWRlBQVTSE9SVAcFCElOQ1JFQVNFBQhERUNSRUFTRQMDCQAAAgUMcG9zaXRpb25TaXplAAADCQAAAgUFX3R5cGUFBFNUT1AGCQAAAgUFX3R5cGUFBFRBS0UHCQACAQIrQ2FuIG5vdCBjcmVhdGUgU1RPUC9UQUtFIG9yZGVyOiBubyBwb3NpdGlvbgQLdXNkblBheW1lbnQDCQAAAgUKX2RpcmVjdGlvbgUISU5DUkVBU0UDAwkBAiE9AgUPX3BheW1lbnRBc3NldElkCQDYBAEJAQpxdW90ZUFzc2V0AAYJAQIhPQIFDl9wYXltZW50QW1vdW50BQlfYW1vdW50SW4JAAIBAjRJbnZhbGlkIGNyZWF0ZUxpbWl0T3JkZXIgcGFyYW1ldGVyczogaW52YWxpZCBwYXltZW50BAVzdGFrZQkA/AcECQEObWFuYWdlckFkZHJlc3MAAgdkZXBvc2l0BQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUOX3BheW1lbnRBbW91bnQFA25pbAMJAAACBQVzdGFrZQUFc3Rha2UFDl9wYXltZW50QW1vdW50CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAAADCQAAAgULdXNkblBheW1lbnQFC3VzZG5QYXltZW50BApwb3NpdGlvbklkAwkBAiE9AgUMcG9zaXRpb25TaXplAAAJAQ1nZXRQb3NpdGlvbklkAgUEX2FtbQUHX3RyYWRlcgAAAwkAZgIFE25ld1RyYWRlck9yZGVyQ291bnQFGU1BWF9UUkFERVJfT1JERVJTX1BFUl9BTU0JAAIBAjBJbnZhbGlkIGNyZWF0ZUxpbWl0T3JkZXIgcGFyYW1ldGVyczogb3JkZXIgY291bnQJAM4IAgkAzggCCQDOCAIJAQlzYXZlT3JkZXIMBQdvcmRlcklkBQRfYW1tBQdfdHJhZGVyBQlfYW1vdW50SW4FCV9sZXZlcmFnZQUFX3R5cGUFDV90cmlnZ2VyUHJpY2UFC3VzZG5QYXltZW50BQVfc2lkZQUIX3JlZkxpbmsFCnBvc2l0aW9uSWQFC19saW1pdFByaWNlCQEQYWRkUmVtb3ZlT3JkZXJJZAQFB29yZGVySWQFBF9hbW0FB190cmFkZXIGCQEWdXBkYXRlVHJhZGVyT3JkZXJDb3VudAMFBF9hbW0FB190cmFkZXIFE25ld1RyYWRlck9yZGVyQ291bnQJARF1cGRhdGVMYXN0T3JkZXJJZAEFB29yZGVySWQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQELY2FuY2VsT3JkZXIBCF9vcmRlcklkBA0kdDAxNTcyMTE1OTQwCQEIZ2V0T3JkZXIBBQhfb3JkZXJJZAQEX2FtbQgFDSR0MDE1NzIxMTU5NDACXzEEB190cmFkZXIIBQ0kdDAxNTcyMTE1OTQwAl8yBAlfYW1vdW50SW4IBQ0kdDAxNTcyMTE1OTQwAl8zBAlfbGV2ZXJhZ2UIBQ0kdDAxNTcyMTE1OTQwAl80BAVfdHlwZQgFDSR0MDE1NzIxMTU5NDACXzUEDV90cmlnZ2VyUHJpY2UIBQ0kdDAxNTcyMTE1OTQwAl82BAtfYW1vdW50VXNkbggFDSR0MDE1NzIxMTU5NDACXzcEBV9zaWRlCAUNJHQwMTU3MjExNTk0MAJfOAQIX3JlZkxpbmsIBQ0kdDAxNTcyMTE1OTQwAl85BAtfcG9zaXRpb25JZAgFDSR0MDE1NzIxMTU5NDADXzEwBAtfbGltaXRQcmljZQgFDSR0MDE1NzIxMTU5NDADXzExAwMDCQEBIQEJAQtpbml0aWFsaXplZAAGCQEBIQEJAQdpc1ZhbGlkAQUIX29yZGVySWQGCQEBIQEJAAACCQClCAEIBQFpBmNhbGxlcgUHX3RyYWRlcgkAAgECHkludmFsaWQgY2FuY2VsT3JkZXIgcGFyYW1ldGVycwQHY2xlYW5VcAkA/AcEBQR0aGlzAhJjbGVhblVwU3RhbGVPcmRlcnMJAMwIAgUEX2FtbQkAzAgCBQdfdHJhZGVyBQNuaWwFA25pbAMJAAACBQdjbGVhblVwBQdjbGVhblVwBBNuZXdUcmFkZXJPcmRlckNvdW50CQBlAgkBE2dldFRyYWRlck9yZGVyQ291bnQCBQRfYW1tBQdfdHJhZGVyAAEECHdpdGhkcmF3AwkAZgIFC19hbW91bnRVc2RuAAAEB3Vuc3Rha2UJAPwHBAkBDm1hbmFnZXJBZGRyZXNzAAIId2l0aGRyYXcJAMwIAgkA2AQBCQEKcXVvdGVBc3NldAAJAMwIAgULX2Ftb3VudFVzZG4FA25pbAUDbmlsAwkAAAIFB3Vuc3Rha2UFB3Vuc3Rha2UFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFCHdpdGhkcmF3BQh3aXRoZHJhdwkAzggCCQDOCAIJAM4IAgkBD21hcmtDYW5jZWxPcmRlcgEFCF9vcmRlcklkCQEQYWRkUmVtb3ZlT3JkZXJJZAQFCF9vcmRlcklkBQRfYW1tBQdfdHJhZGVyBwkBFnVwZGF0ZVRyYWRlck9yZGVyQ291bnQDBQRfYW1tBQdfdHJhZGVyBRNuZXdUcmFkZXJPcmRlckNvdW50AwkAZgIFC19hbW91bnRVc2RuAAAJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwgFAWkGY2FsbGVyBQtfYW1vdW50VXNkbgkBCnF1b3RlQXNzZXQABQNuaWwFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQxleGVjdXRlT3JkZXIBCF9vcmRlcklkBA0kdDAxNjkxMTE3MTMwCQEIZ2V0T3JkZXIBBQhfb3JkZXJJZAQEX2FtbQgFDSR0MDE2OTExMTcxMzACXzEEB190cmFkZXIIBQ0kdDAxNjkxMTE3MTMwAl8yBAlfYW1vdW50SW4IBQ0kdDAxNjkxMTE3MTMwAl8zBAlfbGV2ZXJhZ2UIBQ0kdDAxNjkxMTE3MTMwAl80BAVfdHlwZQgFDSR0MDE2OTExMTcxMzACXzUEDV90cmlnZ2VyUHJpY2UIBQ0kdDAxNjkxMTE3MTMwAl82BAtfYW1vdW50VXNkbggFDSR0MDE2OTExMTcxMzACXzcEBV9zaWRlCAUNJHQwMTY5MTExNzEzMAJfOAQIX3JlZkxpbmsIBQ0kdDAxNjkxMTE3MTMwAl85BAtfcG9zaXRpb25JZAgFDSR0MDE2OTExMTcxMzADXzEwBAtfbGltaXRQcmljZQgFDSR0MDE2OTExMTcxMzADXzExBAdjbGVhblVwCQD8BwQFBHRoaXMCEmNsZWFuVXBTdGFsZU9yZGVycwkAzAgCBQRfYW1tCQDMCAIFB190cmFkZXIFA25pbAUDbmlsAwkAAAIFB2NsZWFuVXAFB2NsZWFuVXADAwkBASEBCQELaW5pdGlhbGl6ZWQABgkBASEBCQEHaXNWYWxpZAEFCF9vcmRlcklkCQACAQIfSW52YWxpZCBleGVjdXRlT3JkZXIgcGFyYW1ldGVycwQMcG9zaXRpb25TaXplCQEPZ2V0UG9zaXRpb25TaXplAgUEX2FtbQUHX3RyYWRlcgQRY3VycmVudFBvc2l0aW9uSWQDCQECIT0CBQxwb3NpdGlvblNpemUAAAkBDWdldFBvc2l0aW9uSWQCBQRfYW1tBQdfdHJhZGVyAAAEDSR0MDE3NTM4MjEzNTkDCQAAAgUFX3R5cGUFBFNUT1AEEl9wb3NpdGlvbkRpcmVjdGlvbgMJAGYCBQxwb3NpdGlvblNpemUAAAUETE9ORwMJAGYCAAAFDHBvc2l0aW9uU2l6ZQUFU0hPUlQJAAIBAixDYW4gbm90IGV4ZWN1dGUgU1RPUCBvcmRlcjogbm8gb3BlbiBwb3NpdGlvbgQLbWFya2V0UHJpY2UJAQ5nZXRNYXJrZXRQcmljZQEFBF9hbW0EDGlzRXhlY3V0YWJsZQMJAAACBQVfc2lkZQUSX3Bvc2l0aW9uRGlyZWN0aW9uCQACAQInQ2FuIG5vdCBleGVjdXRlIFNUT1Agb3JkZXI6IHJlZHVjZSBvbmx5AwkBAiE9AgURY3VycmVudFBvc2l0aW9uSWQFC19wb3NpdGlvbklkCQACAQIrQ2FuIG5vdCBleGVjdXRlIFNUT1Agb3JkZXI6IHBvc2l0aW9uIGNsb3NlZAMJAAACBRJfcG9zaXRpb25EaXJlY3Rpb24FBExPTkcJAGcCBQ1fdHJpZ2dlclByaWNlBQttYXJrZXRQcmljZQkAZwIFC21hcmtldFByaWNlBQ1fdHJpZ2dlclByaWNlAwUMaXNFeGVjdXRhYmxlCQCVCgMCDWNsb3NlUG9zaXRpb24JAMwIAgkBBG1pbnYCBQlfYW1vdW50SW4JAQNhYnMBBQxwb3NpdGlvblNpemUJAMwIAgkBBG11bGQCBQtfbGltaXRQcmljZQkBA2FicwEFDHBvc2l0aW9uU2l6ZQUDbmlsBQNuaWwJAAIBAjFDYW4gbm90IGV4ZWN1dGUgU1RPUCBvcmRlcjogdHJpZ2dlclByaWNlIG1pc21hdGNoAwkAAAIFBV90eXBlBQRUQUtFBBJfcG9zaXRpb25EaXJlY3Rpb24DCQBmAgUMcG9zaXRpb25TaXplAAAFBExPTkcDCQBmAgAABQxwb3NpdGlvblNpemUFBVNIT1JUCQACAQIsQ2FuIG5vdCBleGVjdXRlIFNUT1Agb3JkZXI6IG5vIG9wZW4gcG9zaXRpb24EC21hcmtldFByaWNlCQEOZ2V0TWFya2V0UHJpY2UBBQRfYW1tBAxpc0V4ZWN1dGFibGUDCQAAAgUFX3NpZGUFEl9wb3NpdGlvbkRpcmVjdGlvbgkAAgECJ0NhbiBub3QgZXhlY3V0ZSBUQUtFIG9yZGVyOiByZWR1Y2Ugb25seQMJAQIhPQIFEWN1cnJlbnRQb3NpdGlvbklkBQtfcG9zaXRpb25JZAkAAgEJAKwCAgkArAICCQCsAgICLENhbiBub3QgZXhlY3V0ZSBUQUtFIG9yZGVyOiBwb3NpdGlvbiBjbG9zZWQgCQCkAwEFEWN1cnJlbnRQb3NpdGlvbklkAgIhPQkApAMBBQtfcG9zaXRpb25JZAMJAAACBRJfcG9zaXRpb25EaXJlY3Rpb24FBExPTkcJAGcCBQttYXJrZXRQcmljZQUNX3RyaWdnZXJQcmljZQkAZwIFDV90cmlnZ2VyUHJpY2UFC21hcmtldFByaWNlAwUMaXNFeGVjdXRhYmxlCQCVCgMCDWNsb3NlUG9zaXRpb24JAMwIAgkBBG1pbnYCBQlfYW1vdW50SW4JAQNhYnMBBQxwb3NpdGlvblNpemUJAMwIAgkBBG11bGQCBQtfbGltaXRQcmljZQkBA2FicwEFDHBvc2l0aW9uU2l6ZQUDbmlsBQNuaWwJAAIBAjFDYW4gbm90IGV4ZWN1dGUgVEFLRSBvcmRlcjogdHJpZ2dlclByaWNlIG1pc21hdGNoAwkAAAIFBV90eXBlBQVMSU1JVAQLbWFya2V0UHJpY2UJAQ5nZXRNYXJrZXRQcmljZQEFBF9hbW0EBnNwcmVhZAMJAAACBQtfbGltaXRQcmljZQAACQEJZ2V0U3ByZWFkAQUNX3RyaWdnZXJQcmljZQkBA2FicwEJAGUCBQ1fdHJpZ2dlclByaWNlBQtfbGltaXRQcmljZQQMaXNFeGVjdXRhYmxlAwkAZwIFC21hcmtldFByaWNlCQBlAgUNX3RyaWdnZXJQcmljZQUGc3ByZWFkCQBnAgkAZAIFDV90cmlnZ2VyUHJpY2UFBnNwcmVhZAULbWFya2V0UHJpY2UHAwUMaXNFeGVjdXRhYmxlBBJfcG9zaXRpb25EaXJlY3Rpb24DCQBmAgUMcG9zaXRpb25TaXplAAAFBExPTkcDCQBmAgAABQxwb3NpdGlvblNpemUFBVNIT1JUAP///////////wEECWRpcmVjdGlvbgMJAAACBQxwb3NpdGlvblNpemUAAAUISU5DUkVBU0UDCQAAAgUSX3Bvc2l0aW9uRGlyZWN0aW9uBQVfc2lkZQUISU5DUkVBU0UFCERFQ1JFQVNFAwkAAAIFCWRpcmVjdGlvbgUISU5DUkVBU0UED2Ftb3VudEluV2l0aEZlZQkAZQIFC19hbW91bnRVc2RuCQEEbXVsZAIFC19hbW91bnRVc2RuCQEGZ2V0RmVlAgUEX2FtbQUHX3RyYWRlcgkAlQoDAhBpbmNyZWFzZVBvc2l0aW9uCQDMCAIFBV9zaWRlCQDMCAIFCV9sZXZlcmFnZQkAzAgCAwkAAAIFC19saW1pdFByaWNlAAAAAAkBBGRpdmQCBQ9hbW91bnRJbldpdGhGZWUFC19saW1pdFByaWNlCQDMCAIFCF9yZWZMaW5rBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAULX2Ftb3VudFVzZG4FA25pbAkAlQoDAg1jbG9zZVBvc2l0aW9uCQDMCAIFCV9hbW91bnRJbgkAzAgCCQEEbXVsZAIFCV9hbW91bnRJbgULX2xpbWl0UHJpY2UFA25pbAUDbmlsCQACAQIyQ2FuIG5vdCBleGVjdXRlIExJTUlUIG9yZGVyOiB0cmlnZ2VyUHJpY2UgbWlzbWF0Y2gJAAIBCQCsAgICFEludmFsaWQgb3JkZXIgdHlwZTogCQCkAwEFBV90eXBlBAZtZXRob2QIBQ0kdDAxNzUzODIxMzU5Al8xBARhcmdzCAUNJHQwMTc1MzgyMTM1OQJfMgQIcGF5bWVudHMIBQ0kdDAxNzUzODIxMzU5Al8zBAh3aXRoZHJhdwMJAAACCQCQAwEFCHBheW1lbnRzAAEEB3Vuc3Rha2UJAPwHBAkBDm1hbmFnZXJBZGRyZXNzAAIId2l0aGRyYXcJAMwIAgkA2AQBCQEKcXVvdGVBc3NldAAJAMwIAggJAJEDAgUIcGF5bWVudHMAAAZhbW91bnQFA25pbAUDbmlsAwkAAAIFB3Vuc3Rha2UFB3Vuc3Rha2UFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFCHdpdGhkcmF3BQh3aXRoZHJhdwQMZG9TZXRDb250ZXh0CQD8BwQFBHRoaXMCCnNldENvbnRleHQJAMwIAgUHX3RyYWRlcgUDbmlsBQNuaWwDCQAAAgUMZG9TZXRDb250ZXh0BQxkb1NldENvbnRleHQED2RvQ2xvc2VQb3NpdGlvbgkA/AcECQERQGV4dHJOYXRpdmUoMTA2MikBBQRfYW1tBQZtZXRob2QFBGFyZ3MFCHBheW1lbnRzAwkAAAIFD2RvQ2xvc2VQb3NpdGlvbgUPZG9DbG9zZVBvc2l0aW9uBA5kb1Jlc2V0Q29udGV4dAkA/AcEBQR0aGlzAgxyZXNldENvbnRleHQFA25pbAUDbmlsAwkAAAIFDmRvUmVzZXRDb250ZXh0BQ5kb1Jlc2V0Q29udGV4dAQTbmV3VHJhZGVyT3JkZXJDb3VudAkAZQIJARNnZXRUcmFkZXJPcmRlckNvdW50AgUEX2FtbQUHX3RyYWRlcgABCQDOCAIJAM4IAgkBFnVwZGF0ZVRyYWRlck9yZGVyQ291bnQDBQRfYW1tBQdfdHJhZGVyBRNuZXdUcmFkZXJPcmRlckNvdW50CQEQYWRkUmVtb3ZlT3JkZXJJZAQFCF9vcmRlcklkBQRfYW1tBQdfdHJhZGVyBwkBEG1hcmtFeGVjdXRlT3JkZXIBBQhfb3JkZXJJZAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARR2aWV3X2NhbkV4ZWN1dGVPcmRlcgEIX29yZGVySWQEAXMJAPwHBAUEdGhpcwIMZXhlY3V0ZU9yZGVyCQDMCAIFCF9vcmRlcklkBQNuaWwFA25pbAMJAAACBQFzBQFzCQACAQIHU3VjY2VzcwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgECdHgBBnZlcmlmeQAJAPQDAwgFAnR4CWJvZHlCeXRlcwkAkQMCCAUCdHgGcHJvb2ZzAAAJAQ5hZG1pblB1YmxpY0tleQC8ceGo", "height": 2370372, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 9HEMv6NzTacEfbxV2S5MSzaPbbvk6qzzx3MmD4UrEe71 Next: G7FXZm7SAJJt3w4FYMYKa97zdrFBQqRBG961NkLTHbhM Diff:
OldNewDifferences
2626 let k_lastOrderId = "k_lastOrderId"
2727
2828 let k_traderOrderCnt = "k_traderOrderCnt"
29+
30+let k_traderOrderIds = "k_traderOrderIds"
2931
3032 let k_sender = "k_sender"
3133
8486 func traderOrderCountKey (_amm,_trader) = ((((k_traderOrderCnt + "_") + _amm) + "_") + _trader)
8587
8688
89+func traderOrderIdsKey (_amm,_trader) = ((((k_traderOrderIds + "_") + _amm) + "_") + _trader)
90+
91+
8792 func coordinator () = valueOrErrorMessage(addressFromString(getStringValue(this, k_coordinatorAddress)), "Coordinator not set")
8893
8994
115120 func getTraderOrderCount (_amm,_trader) = {
116121 let key = traderOrderCountKey(_amm, _trader)
117122 valueOrElse(getInteger(this, key), 0)
123+ }
124+
125+
126+func traderAmmOrdersIds (_amm,_trader) = {
127+ let key = traderOrderIdsKey(_amm, _trader)
128+ let val = valueOrElse(getString(this, key), "")
129+ if ((val == ""))
130+ then nil
131+ else split(val, ",")
118132 }
119133
120134
191205 }
192206
193207
208+func addRemoveOrderId (_orderId,_amm,_trader,_add) = {
209+ let orderIds = traderAmmOrdersIds(_amm, _trader)
210+ let orderIdsNew = if (_add)
211+ then (orderIds :+ toString(_orderId))
212+ else removeByIndex(orderIds, valueOrErrorMessage(indexOf(orderIds, toString(_orderId)), ("No order with id: " + toString(_orderId))))
213+ let orderIdsNewStr = makeString(orderIdsNew, ",")
214+[StringEntry(traderOrderIdsKey(_amm, _trader), orderIdsNewStr)]
215+ }
216+
217+
194218 func updateTraderOrderCount (_amm,_trader,_count) = [IntegerEntry(traderOrderCountKey(_amm, _trader), _count)]
195219
196220
201225
202226
203227 func markCancelOrder (_orderId) = [BooleanEntry(toCompositeKey(k_canceledOrders, toString(_orderId)), true)]
228+
229+
230+@Callable(i)
231+func cleanUpStaleOrders (_amm,_trader) = {
232+ let orders = traderAmmOrdersIds(_amm, _trader)
233+ func cleanUpOne (_acc,_orderId) = {
234+ let orderIdInt = valueOrErrorMessage(parseInt(_orderId), "Invalid order id")
235+ let $t083208515 = getOrder(orderIdInt)
236+ let _x1 = $t083208515._1
237+ let _x2 = $t083208515._2
238+ let _x3 = $t083208515._3
239+ let _x4 = $t083208515._4
240+ let _type = $t083208515._5
241+ let _x5 = $t083208515._6
242+ let _x6 = $t083208515._7
243+ let _x7 = $t083208515._8
244+ let _x8 = $t083208515._9
245+ let _positionId = $t083208515._10
246+ let _x9 = $t083208515._11
247+ let positionSize = getPositionSize(_amm, _trader)
248+ let currentPositionId = if ((positionSize != 0))
249+ then getPositionId(_amm, _trader)
250+ else 0
251+ if (if (if ((_type == STOP))
252+ then true
253+ else (_type == TAKE))
254+ then (currentPositionId != _positionId)
255+ else false)
256+ then {
257+ let change = (markCancelOrder(orderIdInt) ++ addRemoveOrderId(orderIdInt, _amm, _trader, false))
258+ (_acc ++ change)
259+ }
260+ else _acc
261+ }
262+
263+ let $l = orders
264+ let $s = size($l)
265+ let $acc0 = nil
266+ func $f0_1 ($a,$i) = if (($i >= $s))
267+ then $a
268+ else cleanUpOne($a, $l[$i])
269+
270+ func $f0_2 ($a,$i) = if (($i >= $s))
271+ then $a
272+ else throw("List size exceeds 5")
273+
274+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5)
275+ }
276+
204277
205278
206279 @Callable(i)
225298
226299
227300 @Callable(i)
228-func createOrder (_amm,_type,_triggerPrice,_limitPrice,_amountIn,_leverage,_side,_refLink) = if ((size(i.payments) > 1))
229- then throw("Invalid createOrder parameters: invalid payment count")
230- else {
231- let $t080238275 = if ((size(i.payments) == 1))
232- then $Tuple2(toBase58String(valueOrErrorMessage(i.payments[0].assetId, "Invalid asset id")), i.payments[0].amount)
233- else $Tuple2("", 0)
234- let paymentAssetId = $t080238275._1
235- let paymentAmount = $t080238275._2
236- let doCall = invoke(this, "internalCreateOrder", [toString(i.caller), _amm, _type, _triggerPrice, _limitPrice, _amountIn, _leverage, _side, _refLink, paymentAssetId, paymentAmount], nil)
237- if ((doCall == doCall))
238- then nil
239- else throw("Strict value is not equal to itself.")
240- }
301+func createOrder (_amm,_type,_triggerPrice,_limitPrice,_amountIn,_leverage,_side,_refLink) = {
302+ let _trader = toString(i.caller)
303+ let cleanUp = invoke(this, "cleanUpStaleOrders", [_amm, _trader], nil)
304+ if ((cleanUp == cleanUp))
305+ then if ((size(i.payments) > 1))
306+ then throw("Invalid createOrder parameters: invalid payment count")
307+ else {
308+ let $t01010010352 = if ((size(i.payments) == 1))
309+ then $Tuple2(toBase58String(valueOrErrorMessage(i.payments[0].assetId, "Invalid asset id")), i.payments[0].amount)
310+ else $Tuple2("", 0)
311+ let paymentAssetId = $t01010010352._1
312+ let paymentAmount = $t01010010352._2
313+ let doCall = invoke(this, "internalCreateOrder", [_trader, _amm, _type, _triggerPrice, _limitPrice, _amountIn, _leverage, _side, _refLink, paymentAssetId, paymentAmount], nil)
314+ if ((doCall == doCall))
315+ then nil
316+ else throw("Strict value is not equal to itself.")
317+ }
318+ else throw("Strict value is not equal to itself.")
319+ }
241320
242321
243322
244323 @Callable(i)
245324 func increasePositionWithStopLoss (_amm,_direction,_leverage,_minBaseAssetAmount,_refLink,_stopTriggerPrice,_stopLimitPrice,_takeTriggerPrice,_takeLimitPrice) = {
246325 let _trader = toString(i.caller)
247- if (if (!(initialized()))
248- then true
249- else !(isWhitelist(_amm)))
250- then throw("Invalid increasePositionWithStopLoss parameters")
251- else {
252- let positionSize = getPositionSize(_amm, _trader)
253- if ((positionSize != 0))
254- then throw("Invalid increasePositionWithStopLoss parameters: only new position")
255- else {
256- let doSetContext = invoke(this, "setContext", [_trader], nil)
257- if ((doSetContext == doSetContext))
258- then {
259- let doClosePosition = invoke(addressFromStringValue(_amm), "increasePosition", [_direction, _leverage, _minBaseAssetAmount, _refLink], i.payments)
260- if ((doClosePosition == doClosePosition))
261- then {
262- let doResetContext = invoke(this, "resetContext", nil, nil)
263- if ((doResetContext == doResetContext))
264- then {
265- let openedPositionSize = getPositionSize(_amm, _trader)
266- if ((openedPositionSize == openedPositionSize))
267- then {
268- let amountIn = abs(openedPositionSize)
269- let stopLossSide = if ((0 > openedPositionSize))
270- then LONG
271- else SHORT
272- let doCreateStopOrder = if ((_stopTriggerPrice > 0))
273- then {
274- let doCreateStopOrder = invoke(this, "internalCreateOrder", [_trader, _amm, STOP, _stopTriggerPrice, _stopLimitPrice, amountIn, 0, stopLossSide, _refLink, "", 0], nil)
275- if ((doCreateStopOrder == doCreateStopOrder))
276- then nil
277- else throw("Strict value is not equal to itself.")
278- }
279- else nil
280- if ((doCreateStopOrder == doCreateStopOrder))
281- then {
282- let doCreateTakeOrder = if ((_takeTriggerPrice > 0))
283- then {
284- let doCreateTakeOrder = invoke(this, "internalCreateOrder", [_trader, _amm, TAKE, _takeTriggerPrice, _takeLimitPrice, amountIn, 0, stopLossSide, _refLink, "", 0], nil)
285- if ((doCreateTakeOrder == doCreateTakeOrder))
286- then nil
287- else throw("Strict value is not equal to itself.")
288- }
289- else nil
290- if ((doCreateTakeOrder == doCreateTakeOrder))
291- then nil
292- else throw("Strict value is not equal to itself.")
293- }
294- else throw("Strict value is not equal to itself.")
295- }
296- else throw("Strict value is not equal to itself.")
297- }
298- else throw("Strict value is not equal to itself.")
299- }
300- else throw("Strict value is not equal to itself.")
301- }
302- else throw("Strict value is not equal to itself.")
303- }
304- }
326+ let cleanUp = invoke(this, "cleanUpStaleOrders", [_amm, _trader], nil)
327+ if ((cleanUp == cleanUp))
328+ then if (if (!(initialized()))
329+ then true
330+ else !(isWhitelist(_amm)))
331+ then throw("Invalid increasePositionWithStopLoss parameters")
332+ else {
333+ let positionSize = getPositionSize(_amm, _trader)
334+ if ((positionSize != 0))
335+ then throw("Invalid increasePositionWithStopLoss parameters: only new position")
336+ else {
337+ let doSetContext = invoke(this, "setContext", [_trader], nil)
338+ if ((doSetContext == doSetContext))
339+ then {
340+ let doClosePosition = invoke(addressFromStringValue(_amm), "increasePosition", [_direction, _leverage, _minBaseAssetAmount, _refLink], i.payments)
341+ if ((doClosePosition == doClosePosition))
342+ then {
343+ let doResetContext = invoke(this, "resetContext", nil, nil)
344+ if ((doResetContext == doResetContext))
345+ then {
346+ let openedPositionSize = getPositionSize(_amm, _trader)
347+ if ((openedPositionSize == openedPositionSize))
348+ then {
349+ let amountIn = abs(openedPositionSize)
350+ let stopLossSide = if ((0 > openedPositionSize))
351+ then LONG
352+ else SHORT
353+ let doCreateStopOrder = if ((_stopTriggerPrice > 0))
354+ then {
355+ let doCreateStopOrder = invoke(this, "internalCreateOrder", [_trader, _amm, STOP, _stopTriggerPrice, _stopLimitPrice, amountIn, 0, stopLossSide, _refLink, "", 0], nil)
356+ if ((doCreateStopOrder == doCreateStopOrder))
357+ then nil
358+ else throw("Strict value is not equal to itself.")
359+ }
360+ else nil
361+ if ((doCreateStopOrder == doCreateStopOrder))
362+ then {
363+ let doCreateTakeOrder = if ((_takeTriggerPrice > 0))
364+ then {
365+ let doCreateTakeOrder = invoke(this, "internalCreateOrder", [_trader, _amm, TAKE, _takeTriggerPrice, _takeLimitPrice, amountIn, 0, stopLossSide, _refLink, "", 0], nil)
366+ if ((doCreateTakeOrder == doCreateTakeOrder))
367+ then nil
368+ else throw("Strict value is not equal to itself.")
369+ }
370+ else nil
371+ if ((doCreateTakeOrder == doCreateTakeOrder))
372+ then nil
373+ else throw("Strict value is not equal to itself.")
374+ }
375+ else throw("Strict value is not equal to itself.")
376+ }
377+ else throw("Strict value is not equal to itself.")
378+ }
379+ else throw("Strict value is not equal to itself.")
380+ }
381+ else throw("Strict value is not equal to itself.")
382+ }
383+ else throw("Strict value is not equal to itself.")
384+ }
385+ }
386+ else throw("Strict value is not equal to itself.")
305387 }
306388
307389
372454 else 0
373455 if ((newTraderOrderCount > MAX_TRADER_ORDERS_PER_AMM))
374456 then throw("Invalid createLimitOrder parameters: order count")
375- else ((saveOrder(orderId, _amm, _trader, _amountIn, _leverage, _type, _triggerPrice, usdnPayment, _side, _refLink, positionId, _limitPrice) ++ updateTraderOrderCount(_amm, _trader, newTraderOrderCount)) ++ updateLastOrderId(orderId))
457+ 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))
376458 }
377459 else throw("Strict value is not equal to itself.")
378460 }
382464
383465 @Callable(i)
384466 func cancelOrder (_orderId) = {
385- let $t01350813727 = getOrder(_orderId)
386- let _amm = $t01350813727._1
387- let _trader = $t01350813727._2
388- let _amountIn = $t01350813727._3
389- let _leverage = $t01350813727._4
390- let _type = $t01350813727._5
391- let _triggerPrice = $t01350813727._6
392- let _amountUsdn = $t01350813727._7
393- let _side = $t01350813727._8
394- let _refLink = $t01350813727._9
395- let _positionId = $t01350813727._10
396- let _limitPrice = $t01350813727._11
467+ let $t01572115940 = getOrder(_orderId)
468+ let _amm = $t01572115940._1
469+ let _trader = $t01572115940._2
470+ let _amountIn = $t01572115940._3
471+ let _leverage = $t01572115940._4
472+ let _type = $t01572115940._5
473+ let _triggerPrice = $t01572115940._6
474+ let _amountUsdn = $t01572115940._7
475+ let _side = $t01572115940._8
476+ let _refLink = $t01572115940._9
477+ let _positionId = $t01572115940._10
478+ let _limitPrice = $t01572115940._11
397479 if (if (if (!(initialized()))
398480 then true
399481 else !(isValid(_orderId)))
401483 else !((toString(i.caller) == _trader)))
402484 then throw("Invalid cancelOrder parameters")
403485 else {
404- let newTraderOrderCount = (getTraderOrderCount(_amm, _trader) - 1)
405- let withdraw = if ((_amountUsdn > 0))
486+ let cleanUp = invoke(this, "cleanUpStaleOrders", [_amm, _trader], nil)
487+ if ((cleanUp == cleanUp))
406488 then {
407- let unstake = invoke(managerAddress(), "withdraw", [toBase58String(quoteAsset()), _amountUsdn], nil)
408- if ((unstake == unstake))
409- then nil
489+ let newTraderOrderCount = (getTraderOrderCount(_amm, _trader) - 1)
490+ let withdraw = if ((_amountUsdn > 0))
491+ then {
492+ let unstake = invoke(managerAddress(), "withdraw", [toBase58String(quoteAsset()), _amountUsdn], nil)
493+ if ((unstake == unstake))
494+ then nil
495+ else throw("Strict value is not equal to itself.")
496+ }
497+ else nil
498+ if ((withdraw == withdraw))
499+ then (((markCancelOrder(_orderId) ++ addRemoveOrderId(_orderId, _amm, _trader, false)) ++ updateTraderOrderCount(_amm, _trader, newTraderOrderCount)) ++ (if ((_amountUsdn > 0))
500+ then [ScriptTransfer(i.caller, _amountUsdn, quoteAsset())]
501+ else nil))
410502 else throw("Strict value is not equal to itself.")
411503 }
412- else nil
413- if ((withdraw == withdraw))
414- then ((markCancelOrder(_orderId) ++ updateTraderOrderCount(_amm, _trader, newTraderOrderCount)) ++ (if ((_amountUsdn > 0))
415- then [ScriptTransfer(i.caller, _amountUsdn, quoteAsset())]
416- else nil))
417504 else throw("Strict value is not equal to itself.")
418505 }
419506 }
422509
423510 @Callable(i)
424511 func executeOrder (_orderId) = {
425- let $t01456014779 = getOrder(_orderId)
426- let _amm = $t01456014779._1
427- let _trader = $t01456014779._2
428- let _amountIn = $t01456014779._3
429- let _leverage = $t01456014779._4
430- let _type = $t01456014779._5
431- let _triggerPrice = $t01456014779._6
432- let _amountUsdn = $t01456014779._7
433- let _side = $t01456014779._8
434- let _refLink = $t01456014779._9
435- let _positionId = $t01456014779._10
436- let _limitPrice = $t01456014779._11
437- if (if (!(initialized()))
438- then true
439- else !(isValid(_orderId)))
440- then throw("Invalid executeOrder parameters")
441- else {
442- let positionSize = getPositionSize(_amm, _trader)
443- let currentPositionId = if ((positionSize != 0))
444- then getPositionId(_amm, _trader)
445- else 0
446- let $t01510518926 = if ((_type == STOP))
447- then {
448- let _positionDirection = if ((positionSize > 0))
449- then LONG
450- else if ((0 > positionSize))
451- then SHORT
452- else throw("Can not execute STOP order: no open position")
453- let marketPrice = getMarketPrice(_amm)
454- let isExecutable = if ((_side == _positionDirection))
455- then throw("Can not execute STOP order: reduce only")
456- else if ((currentPositionId != _positionId))
457- then throw("Can not execute STOP order: position closed")
458- else if ((_positionDirection == LONG))
459- then (_triggerPrice >= marketPrice)
460- else (marketPrice >= _triggerPrice)
461- if (isExecutable)
462- then $Tuple3("closePosition", [minv(_amountIn, abs(positionSize)), muld(_limitPrice, abs(positionSize))], nil)
463- else throw("Can not execute STOP order: triggerPrice mismatch")
464- }
465- else if ((_type == TAKE))
512+ let $t01691117130 = getOrder(_orderId)
513+ let _amm = $t01691117130._1
514+ let _trader = $t01691117130._2
515+ let _amountIn = $t01691117130._3
516+ let _leverage = $t01691117130._4
517+ let _type = $t01691117130._5
518+ let _triggerPrice = $t01691117130._6
519+ let _amountUsdn = $t01691117130._7
520+ let _side = $t01691117130._8
521+ let _refLink = $t01691117130._9
522+ let _positionId = $t01691117130._10
523+ let _limitPrice = $t01691117130._11
524+ let cleanUp = invoke(this, "cleanUpStaleOrders", [_amm, _trader], nil)
525+ if ((cleanUp == cleanUp))
526+ then if (if (!(initialized()))
527+ then true
528+ else !(isValid(_orderId)))
529+ then throw("Invalid executeOrder parameters")
530+ else {
531+ let positionSize = getPositionSize(_amm, _trader)
532+ let currentPositionId = if ((positionSize != 0))
533+ then getPositionId(_amm, _trader)
534+ else 0
535+ let $t01753821359 = if ((_type == STOP))
466536 then {
467537 let _positionDirection = if ((positionSize > 0))
468538 then LONG
471541 else throw("Can not execute STOP order: no open position")
472542 let marketPrice = getMarketPrice(_amm)
473543 let isExecutable = if ((_side == _positionDirection))
474- then throw("Can not execute TAKE order: reduce only")
544+ then throw("Can not execute STOP order: reduce only")
475545 else if ((currentPositionId != _positionId))
476- then throw(((("Can not execute TAKE order: position closed " + toString(currentPositionId)) + "!=") + toString(_positionId)))
546+ then throw("Can not execute STOP order: position closed")
477547 else if ((_positionDirection == LONG))
478- then (marketPrice >= _triggerPrice)
479- else (_triggerPrice >= marketPrice)
548+ then (_triggerPrice >= marketPrice)
549+ else (marketPrice >= _triggerPrice)
480550 if (isExecutable)
481551 then $Tuple3("closePosition", [minv(_amountIn, abs(positionSize)), muld(_limitPrice, abs(positionSize))], nil)
482- else throw("Can not execute TAKE order: triggerPrice mismatch")
552+ else throw("Can not execute STOP order: triggerPrice mismatch")
483553 }
484- else if ((_type == LIMIT))
554+ else if ((_type == TAKE))
485555 then {
556+ let _positionDirection = if ((positionSize > 0))
557+ then LONG
558+ else if ((0 > positionSize))
559+ then SHORT
560+ else throw("Can not execute STOP order: no open position")
486561 let marketPrice = getMarketPrice(_amm)
487- let spread = if ((_limitPrice == 0))
488- then getSpread(_triggerPrice)
489- else abs((_triggerPrice - _limitPrice))
490- let isExecutable = if ((marketPrice >= (_triggerPrice - spread)))
491- then ((_triggerPrice + spread) >= marketPrice)
492- else false
562+ let isExecutable = if ((_side == _positionDirection))
563+ then throw("Can not execute TAKE order: reduce only")
564+ else if ((currentPositionId != _positionId))
565+ then throw(((("Can not execute TAKE order: position closed " + toString(currentPositionId)) + "!=") + toString(_positionId)))
566+ else if ((_positionDirection == LONG))
567+ then (marketPrice >= _triggerPrice)
568+ else (_triggerPrice >= marketPrice)
493569 if (isExecutable)
494- then {
495- let _positionDirection = if ((positionSize > 0))
496- then LONG
497- else if ((0 > positionSize))
498- then SHORT
499- else -1
500- let direction = if ((positionSize == 0))
501- then INCREASE
502- else if ((_positionDirection == _side))
570+ then $Tuple3("closePosition", [minv(_amountIn, abs(positionSize)), muld(_limitPrice, abs(positionSize))], nil)
571+ else throw("Can not execute TAKE order: triggerPrice mismatch")
572+ }
573+ else if ((_type == LIMIT))
574+ then {
575+ let marketPrice = getMarketPrice(_amm)
576+ let spread = if ((_limitPrice == 0))
577+ then getSpread(_triggerPrice)
578+ else abs((_triggerPrice - _limitPrice))
579+ let isExecutable = if ((marketPrice >= (_triggerPrice - spread)))
580+ then ((_triggerPrice + spread) >= marketPrice)
581+ else false
582+ if (isExecutable)
583+ then {
584+ let _positionDirection = if ((positionSize > 0))
585+ then LONG
586+ else if ((0 > positionSize))
587+ then SHORT
588+ else -1
589+ let direction = if ((positionSize == 0))
503590 then INCREASE
504- else DECREASE
505- if ((direction == INCREASE))
506- then {
507- let amountInWithFee = (_amountUsdn - muld(_amountUsdn, getFee(_amm, _trader)))
508- $Tuple3("increasePosition", [_side, _leverage, if ((_limitPrice == 0))
509- then 0
510- else divd(amountInWithFee, _limitPrice), _refLink], [AttachedPayment(quoteAsset(), _amountUsdn)])
511- }
512- else $Tuple3("closePosition", [_amountIn, muld(_amountIn, _limitPrice)], nil)
513- }
514- else throw("Can not execute LIMIT order: triggerPrice mismatch")
515- }
516- else throw(("Invalid order type: " + toString(_type)))
517- let method = $t01510518926._1
518- let args = $t01510518926._2
519- let payments = $t01510518926._3
520- let withdraw = if ((size(payments) == 1))
521- then {
522- let unstake = invoke(managerAddress(), "withdraw", [toBase58String(quoteAsset()), payments[0].amount], nil)
523- if ((unstake == unstake))
524- then nil
525- else throw("Strict value is not equal to itself.")
526- }
527- else nil
528- if ((withdraw == withdraw))
529- then {
530- let doSetContext = invoke(this, "setContext", [_trader], nil)
531- if ((doSetContext == doSetContext))
532- then {
533- let doClosePosition = invoke(addressFromStringValue(_amm), method, args, payments)
534- if ((doClosePosition == doClosePosition))
535- then {
536- let doResetContext = invoke(this, "resetContext", nil, nil)
537- if ((doResetContext == doResetContext))
538- then markExecuteOrder(_orderId)
539- else throw("Strict value is not equal to itself.")
540- }
541- else throw("Strict value is not equal to itself.")
542- }
543- else throw("Strict value is not equal to itself.")
544- }
545- else throw("Strict value is not equal to itself.")
546- }
591+ else if ((_positionDirection == _side))
592+ then INCREASE
593+ else DECREASE
594+ if ((direction == INCREASE))
595+ then {
596+ let amountInWithFee = (_amountUsdn - muld(_amountUsdn, getFee(_amm, _trader)))
597+ $Tuple3("increasePosition", [_side, _leverage, if ((_limitPrice == 0))
598+ then 0
599+ else divd(amountInWithFee, _limitPrice), _refLink], [AttachedPayment(quoteAsset(), _amountUsdn)])
600+ }
601+ else $Tuple3("closePosition", [_amountIn, muld(_amountIn, _limitPrice)], nil)
602+ }
603+ else throw("Can not execute LIMIT order: triggerPrice mismatch")
604+ }
605+ else throw(("Invalid order type: " + toString(_type)))
606+ let method = $t01753821359._1
607+ let args = $t01753821359._2
608+ let payments = $t01753821359._3
609+ let withdraw = if ((size(payments) == 1))
610+ then {
611+ let unstake = invoke(managerAddress(), "withdraw", [toBase58String(quoteAsset()), payments[0].amount], nil)
612+ if ((unstake == unstake))
613+ then nil
614+ else throw("Strict value is not equal to itself.")
615+ }
616+ else nil
617+ if ((withdraw == withdraw))
618+ then {
619+ let doSetContext = invoke(this, "setContext", [_trader], nil)
620+ if ((doSetContext == doSetContext))
621+ then {
622+ let doClosePosition = invoke(addressFromStringValue(_amm), method, args, payments)
623+ if ((doClosePosition == doClosePosition))
624+ then {
625+ let doResetContext = invoke(this, "resetContext", nil, nil)
626+ if ((doResetContext == doResetContext))
627+ then {
628+ let newTraderOrderCount = (getTraderOrderCount(_amm, _trader) - 1)
629+ ((updateTraderOrderCount(_amm, _trader, newTraderOrderCount) ++ addRemoveOrderId(_orderId, _amm, _trader, false)) ++ markExecuteOrder(_orderId))
630+ }
631+ else throw("Strict value is not equal to itself.")
632+ }
633+ else throw("Strict value is not equal to itself.")
634+ }
635+ else throw("Strict value is not equal to itself.")
636+ }
637+ else throw("Strict value is not equal to itself.")
638+ }
639+ else throw("Strict value is not equal to itself.")
547640 }
548641
549642
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_public_key = "k_admin_public_key"
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"
1717
1818 let k_fee = "k_fee"
1919
2020 let k_executedOrders = "k_executedOrders"
2121
2222 let k_canceledOrders = "k_canceledOrders"
2323
2424 let k_order = "k_order"
2525
2626 let k_lastOrderId = "k_lastOrderId"
2727
2828 let k_traderOrderCnt = "k_traderOrderCnt"
29+
30+let k_traderOrderIds = "k_traderOrderIds"
2931
3032 let k_sender = "k_sender"
3133
3234 let k_initialized = "k_initialized"
3335
3436 let STOP = 1
3537
3638 let TAKE = 2
3739
3840 let LIMIT = 3
3941
4042 let LONG = 1
4143
4244 let SHORT = 2
4345
4446 let INCREASE = 1
4547
4648 let DECREASE = 2
4749
4850 let MAX_TRADER_ORDERS_PER_AMM = 5
4951
5052 let TIME = lastBlock.timestamp
5153
5254 let DECIMAL_UNIT = (1 * (((((10 * 10) * 10) * 10) * 10) * 10))
5355
5456 let SPREAD_LIMIT = (DECIMAL_UNIT / 200)
5557
5658 func abs (_x) = if ((_x > 0))
5759 then _x
5860 else -(_x)
5961
6062
6163 func divd (_x,_y) = fraction(_x, DECIMAL_UNIT, _y, HALFEVEN)
6264
6365
6466 func muld (_x,_y) = fraction(_x, _y, DECIMAL_UNIT, HALFEVEN)
6567
6668
6769 func minv (_x,_y) = if ((_x > _y))
6870 then _y
6971 else _x
7072
7173
7274 func toCompositeKey (_key,_address) = ((_key + "_") + _address)
7375
7476
7577 func executedOrderKey (_orderId) = ((k_executedOrders + "_") + toString(_orderId))
7678
7779
7880 func canceledOrderKey (_orderId) = ((k_canceledOrders + "_") + toString(_orderId))
7981
8082
8183 func orderKey (_orderId) = toCompositeKey(k_order, toString(_orderId))
8284
8385
8486 func traderOrderCountKey (_amm,_trader) = ((((k_traderOrderCnt + "_") + _amm) + "_") + _trader)
8587
8688
89+func traderOrderIdsKey (_amm,_trader) = ((((k_traderOrderIds + "_") + _amm) + "_") + _trader)
90+
91+
8792 func coordinator () = valueOrErrorMessage(addressFromString(getStringValue(this, k_coordinatorAddress)), "Coordinator not set")
8893
8994
9095 func quoteAsset () = fromBase58String(getStringValue(coordinator(), k_quote_asset))
9196
9297
9398 func managerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_manager_address)), "Manager not set")
9499
95100
96101 func isWhitelist (_address) = valueOrElse(getBoolean(coordinator(), toCompositeKey(k_amm, _address)), false)
97102
98103
99104 func adminPublicKey () = fromBase58String(getStringValue(coordinator(), k_admin_public_key))
100105
101106
102107 func initialized () = valueOrElse(getBoolean(this, k_initialized), false)
103108
104109
105110 func isValid (_orderId) = if (valueOrElse(getBoolean(this, executedOrderKey(_orderId)), false))
106111 then throw(("Order already executed: " + toString(_orderId)))
107112 else if (valueOrElse(getBoolean(this, canceledOrderKey(_orderId)), false))
108113 then throw(("Order already cancelled: " + toString(_orderId)))
109114 else true
110115
111116
112117 func currentOrderId () = valueOrElse(getInteger(this, k_lastOrderId), 0)
113118
114119
115120 func getTraderOrderCount (_amm,_trader) = {
116121 let key = traderOrderCountKey(_amm, _trader)
117122 valueOrElse(getInteger(this, key), 0)
123+ }
124+
125+
126+func traderAmmOrdersIds (_amm,_trader) = {
127+ let key = traderOrderIdsKey(_amm, _trader)
128+ let val = valueOrElse(getString(this, key), "")
129+ if ((val == ""))
130+ then nil
131+ else split(val, ",")
118132 }
119133
120134
121135 func getOrder (_orderId) = {
122136 let orderStr = valueOrErrorMessage(getString(this, orderKey(_orderId)), ("Invalid order id: " + toString(_orderId)))
123137 let orderPartList = split(orderStr, ",")
124138 let amm = orderPartList[0]
125139 let trader = orderPartList[1]
126140 let amountIn = valueOrErrorMessage(parseInt(orderPartList[2]), "Invalid amountIn")
127141 let leverage = valueOrErrorMessage(parseInt(orderPartList[3]), "Invalid leverage")
128142 let type = valueOrErrorMessage(parseInt(orderPartList[4]), "Invalid type")
129143 let triggerPrice = valueOrErrorMessage(parseInt(orderPartList[5]), "Invalid triggerPrice")
130144 let paymentUsdn = valueOrErrorMessage(parseInt(orderPartList[6]), "Invalid paymentUsdn")
131145 let side = valueOrErrorMessage(parseInt(orderPartList[7]), "Invalid side")
132146 let refLink = orderPartList[8]
133147 let positionId = valueOrErrorMessage(parseInt(orderPartList[9]), "Invalid positionId")
134148 let limitPrice = valueOrErrorMessage(parseInt(orderPartList[10]), "Invalid limitPrice")
135149 $Tuple11(amm, trader, amountIn, leverage, type, triggerPrice, paymentUsdn, side, refLink, positionId, limitPrice)
136150 }
137151
138152
139153 func getMarketPrice (_amm) = {
140154 let s = invoke(addressFromStringValue(_amm), "computeSpotPrice", nil, nil)
141155 if ((s == s))
142156 then {
143157 let res = match s {
144158 case t: Int =>
145159 t
146160 case _ =>
147161 throw("Invalid computeSpotPrice result")
148162 }
149163 value(res)
150164 }
151165 else throw("Strict value is not equal to itself.")
152166 }
153167
154168
155169 func getFee (_amm,_trader) = {
156170 let s = invoke(addressFromStringValue(_amm), "computeFeeForTraderWithArtifact", [_trader, ""], nil)
157171 if ((s == s))
158172 then {
159173 let res = match s {
160174 case t: (Int, Boolean) =>
161175 t._1
162176 case _ =>
163177 throw("Invalid computeFeeForTraderWithArtifact result")
164178 }
165179 value(res)
166180 }
167181 else throw("Strict value is not equal to itself.")
168182 }
169183
170184
171185 func getPositionSize (_amm,_trader) = {
172186 let amm = addressFromStringValue(_amm)
173187 let sizeKey = toCompositeKey(k_positionSize, _trader)
174188 valueOrElse(getInteger(amm, sizeKey), 0)
175189 }
176190
177191
178192 func getPositionId (_amm,_trader) = {
179193 let amm = addressFromStringValue(_amm)
180194 let seqKey = toCompositeKey(k_positionSequence, _trader)
181195 valueOrElse(getInteger(amm, seqKey), 0)
182196 }
183197
184198
185199 func getSpread (_price) = muld(_price, SPREAD_LIMIT)
186200
187201
188202 func saveOrder (_orderId,_amm,_trader,_amountIn,_leverage,_type,_triggerPrice,_paymentUsdn,_side,_refLink,_positionId,_limitPrice) = {
189203 let orderStr = makeString([_amm, _trader, toString(_amountIn), toString(_leverage), toString(_type), toString(_triggerPrice), toString(_paymentUsdn), toString(_side), _refLink, toString(_positionId), toString(_limitPrice)], ",")
190204 [StringEntry(orderKey(_orderId), orderStr)]
191205 }
192206
193207
208+func addRemoveOrderId (_orderId,_amm,_trader,_add) = {
209+ let orderIds = traderAmmOrdersIds(_amm, _trader)
210+ let orderIdsNew = if (_add)
211+ then (orderIds :+ toString(_orderId))
212+ else removeByIndex(orderIds, valueOrErrorMessage(indexOf(orderIds, toString(_orderId)), ("No order with id: " + toString(_orderId))))
213+ let orderIdsNewStr = makeString(orderIdsNew, ",")
214+[StringEntry(traderOrderIdsKey(_amm, _trader), orderIdsNewStr)]
215+ }
216+
217+
194218 func updateTraderOrderCount (_amm,_trader,_count) = [IntegerEntry(traderOrderCountKey(_amm, _trader), _count)]
195219
196220
197221 func updateLastOrderId (_lastOrderId) = [IntegerEntry(k_lastOrderId, _lastOrderId)]
198222
199223
200224 func markExecuteOrder (_orderId) = [BooleanEntry(toCompositeKey(k_executedOrders, toString(_orderId)), true)]
201225
202226
203227 func markCancelOrder (_orderId) = [BooleanEntry(toCompositeKey(k_canceledOrders, toString(_orderId)), true)]
228+
229+
230+@Callable(i)
231+func cleanUpStaleOrders (_amm,_trader) = {
232+ let orders = traderAmmOrdersIds(_amm, _trader)
233+ func cleanUpOne (_acc,_orderId) = {
234+ let orderIdInt = valueOrErrorMessage(parseInt(_orderId), "Invalid order id")
235+ let $t083208515 = getOrder(orderIdInt)
236+ let _x1 = $t083208515._1
237+ let _x2 = $t083208515._2
238+ let _x3 = $t083208515._3
239+ let _x4 = $t083208515._4
240+ let _type = $t083208515._5
241+ let _x5 = $t083208515._6
242+ let _x6 = $t083208515._7
243+ let _x7 = $t083208515._8
244+ let _x8 = $t083208515._9
245+ let _positionId = $t083208515._10
246+ let _x9 = $t083208515._11
247+ let positionSize = getPositionSize(_amm, _trader)
248+ let currentPositionId = if ((positionSize != 0))
249+ then getPositionId(_amm, _trader)
250+ else 0
251+ if (if (if ((_type == STOP))
252+ then true
253+ else (_type == TAKE))
254+ then (currentPositionId != _positionId)
255+ else false)
256+ then {
257+ let change = (markCancelOrder(orderIdInt) ++ addRemoveOrderId(orderIdInt, _amm, _trader, false))
258+ (_acc ++ change)
259+ }
260+ else _acc
261+ }
262+
263+ let $l = orders
264+ let $s = size($l)
265+ let $acc0 = nil
266+ func $f0_1 ($a,$i) = if (($i >= $s))
267+ then $a
268+ else cleanUpOne($a, $l[$i])
269+
270+ func $f0_2 ($a,$i) = if (($i >= $s))
271+ then $a
272+ else throw("List size exceeds 5")
273+
274+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5)
275+ }
276+
204277
205278
206279 @Callable(i)
207280 func setContext (_sender) = if ((i.caller != this))
208281 then throw("Only self-call")
209282 else [StringEntry(k_sender, _sender)]
210283
211284
212285
213286 @Callable(i)
214287 func resetContext () = if ((i.caller != this))
215288 then throw("Only self-call")
216289 else [DeleteEntry(k_sender)]
217290
218291
219292
220293 @Callable(i)
221294 func initialize (_coordinator) = if (initialized())
222295 then throw("Already initialized")
223296 else [StringEntry(k_coordinatorAddress, _coordinator), BooleanEntry(k_initialized, true)]
224297
225298
226299
227300 @Callable(i)
228-func createOrder (_amm,_type,_triggerPrice,_limitPrice,_amountIn,_leverage,_side,_refLink) = if ((size(i.payments) > 1))
229- then throw("Invalid createOrder parameters: invalid payment count")
230- else {
231- let $t080238275 = if ((size(i.payments) == 1))
232- then $Tuple2(toBase58String(valueOrErrorMessage(i.payments[0].assetId, "Invalid asset id")), i.payments[0].amount)
233- else $Tuple2("", 0)
234- let paymentAssetId = $t080238275._1
235- let paymentAmount = $t080238275._2
236- let doCall = invoke(this, "internalCreateOrder", [toString(i.caller), _amm, _type, _triggerPrice, _limitPrice, _amountIn, _leverage, _side, _refLink, paymentAssetId, paymentAmount], nil)
237- if ((doCall == doCall))
238- then nil
239- else throw("Strict value is not equal to itself.")
240- }
301+func createOrder (_amm,_type,_triggerPrice,_limitPrice,_amountIn,_leverage,_side,_refLink) = {
302+ let _trader = toString(i.caller)
303+ let cleanUp = invoke(this, "cleanUpStaleOrders", [_amm, _trader], nil)
304+ if ((cleanUp == cleanUp))
305+ then if ((size(i.payments) > 1))
306+ then throw("Invalid createOrder parameters: invalid payment count")
307+ else {
308+ let $t01010010352 = if ((size(i.payments) == 1))
309+ then $Tuple2(toBase58String(valueOrErrorMessage(i.payments[0].assetId, "Invalid asset id")), i.payments[0].amount)
310+ else $Tuple2("", 0)
311+ let paymentAssetId = $t01010010352._1
312+ let paymentAmount = $t01010010352._2
313+ let doCall = invoke(this, "internalCreateOrder", [_trader, _amm, _type, _triggerPrice, _limitPrice, _amountIn, _leverage, _side, _refLink, paymentAssetId, paymentAmount], nil)
314+ if ((doCall == doCall))
315+ then nil
316+ else throw("Strict value is not equal to itself.")
317+ }
318+ else throw("Strict value is not equal to itself.")
319+ }
241320
242321
243322
244323 @Callable(i)
245324 func increasePositionWithStopLoss (_amm,_direction,_leverage,_minBaseAssetAmount,_refLink,_stopTriggerPrice,_stopLimitPrice,_takeTriggerPrice,_takeLimitPrice) = {
246325 let _trader = toString(i.caller)
247- if (if (!(initialized()))
248- then true
249- else !(isWhitelist(_amm)))
250- then throw("Invalid increasePositionWithStopLoss parameters")
251- else {
252- let positionSize = getPositionSize(_amm, _trader)
253- if ((positionSize != 0))
254- then throw("Invalid increasePositionWithStopLoss parameters: only new position")
255- else {
256- let doSetContext = invoke(this, "setContext", [_trader], nil)
257- if ((doSetContext == doSetContext))
258- then {
259- let doClosePosition = invoke(addressFromStringValue(_amm), "increasePosition", [_direction, _leverage, _minBaseAssetAmount, _refLink], i.payments)
260- if ((doClosePosition == doClosePosition))
261- then {
262- let doResetContext = invoke(this, "resetContext", nil, nil)
263- if ((doResetContext == doResetContext))
264- then {
265- let openedPositionSize = getPositionSize(_amm, _trader)
266- if ((openedPositionSize == openedPositionSize))
267- then {
268- let amountIn = abs(openedPositionSize)
269- let stopLossSide = if ((0 > openedPositionSize))
270- then LONG
271- else SHORT
272- let doCreateStopOrder = if ((_stopTriggerPrice > 0))
273- then {
274- let doCreateStopOrder = invoke(this, "internalCreateOrder", [_trader, _amm, STOP, _stopTriggerPrice, _stopLimitPrice, amountIn, 0, stopLossSide, _refLink, "", 0], nil)
275- if ((doCreateStopOrder == doCreateStopOrder))
276- then nil
277- else throw("Strict value is not equal to itself.")
278- }
279- else nil
280- if ((doCreateStopOrder == doCreateStopOrder))
281- then {
282- let doCreateTakeOrder = if ((_takeTriggerPrice > 0))
283- then {
284- let doCreateTakeOrder = invoke(this, "internalCreateOrder", [_trader, _amm, TAKE, _takeTriggerPrice, _takeLimitPrice, amountIn, 0, stopLossSide, _refLink, "", 0], nil)
285- if ((doCreateTakeOrder == doCreateTakeOrder))
286- then nil
287- else throw("Strict value is not equal to itself.")
288- }
289- else nil
290- if ((doCreateTakeOrder == doCreateTakeOrder))
291- then nil
292- else throw("Strict value is not equal to itself.")
293- }
294- else throw("Strict value is not equal to itself.")
295- }
296- else throw("Strict value is not equal to itself.")
297- }
298- else throw("Strict value is not equal to itself.")
299- }
300- else throw("Strict value is not equal to itself.")
301- }
302- else throw("Strict value is not equal to itself.")
303- }
304- }
326+ let cleanUp = invoke(this, "cleanUpStaleOrders", [_amm, _trader], nil)
327+ if ((cleanUp == cleanUp))
328+ then if (if (!(initialized()))
329+ then true
330+ else !(isWhitelist(_amm)))
331+ then throw("Invalid increasePositionWithStopLoss parameters")
332+ else {
333+ let positionSize = getPositionSize(_amm, _trader)
334+ if ((positionSize != 0))
335+ then throw("Invalid increasePositionWithStopLoss parameters: only new position")
336+ else {
337+ let doSetContext = invoke(this, "setContext", [_trader], nil)
338+ if ((doSetContext == doSetContext))
339+ then {
340+ let doClosePosition = invoke(addressFromStringValue(_amm), "increasePosition", [_direction, _leverage, _minBaseAssetAmount, _refLink], i.payments)
341+ if ((doClosePosition == doClosePosition))
342+ then {
343+ let doResetContext = invoke(this, "resetContext", nil, nil)
344+ if ((doResetContext == doResetContext))
345+ then {
346+ let openedPositionSize = getPositionSize(_amm, _trader)
347+ if ((openedPositionSize == openedPositionSize))
348+ then {
349+ let amountIn = abs(openedPositionSize)
350+ let stopLossSide = if ((0 > openedPositionSize))
351+ then LONG
352+ else SHORT
353+ let doCreateStopOrder = if ((_stopTriggerPrice > 0))
354+ then {
355+ let doCreateStopOrder = invoke(this, "internalCreateOrder", [_trader, _amm, STOP, _stopTriggerPrice, _stopLimitPrice, amountIn, 0, stopLossSide, _refLink, "", 0], nil)
356+ if ((doCreateStopOrder == doCreateStopOrder))
357+ then nil
358+ else throw("Strict value is not equal to itself.")
359+ }
360+ else nil
361+ if ((doCreateStopOrder == doCreateStopOrder))
362+ then {
363+ let doCreateTakeOrder = if ((_takeTriggerPrice > 0))
364+ then {
365+ let doCreateTakeOrder = invoke(this, "internalCreateOrder", [_trader, _amm, TAKE, _takeTriggerPrice, _takeLimitPrice, amountIn, 0, stopLossSide, _refLink, "", 0], nil)
366+ if ((doCreateTakeOrder == doCreateTakeOrder))
367+ then nil
368+ else throw("Strict value is not equal to itself.")
369+ }
370+ else nil
371+ if ((doCreateTakeOrder == doCreateTakeOrder))
372+ then nil
373+ else throw("Strict value is not equal to itself.")
374+ }
375+ else throw("Strict value is not equal to itself.")
376+ }
377+ else throw("Strict value is not equal to itself.")
378+ }
379+ else throw("Strict value is not equal to itself.")
380+ }
381+ else throw("Strict value is not equal to itself.")
382+ }
383+ else throw("Strict value is not equal to itself.")
384+ }
385+ }
386+ else throw("Strict value is not equal to itself.")
305387 }
306388
307389
308390
309391 @Callable(i)
310392 func internalCreateOrder (_trader,_amm,_type,_triggerPrice,_limitPrice,_amountIn,_leverage,_side,_refLink,_paymentAssetId,_paymentAmount) = if (if (if (if (if (if (if (if (if (!(initialized()))
311393 then true
312394 else !(isWhitelist(_amm)))
313395 then true
314396 else (0 >= _triggerPrice))
315397 then true
316398 else (0 > _limitPrice))
317399 then true
318400 else (0 >= _amountIn))
319401 then true
320402 else (0 > _leverage))
321403 then true
322404 else !(if ((_side == LONG))
323405 then true
324406 else (_side == SHORT)))
325407 then true
326408 else !(if (if ((_type == STOP))
327409 then true
328410 else (_type == TAKE))
329411 then true
330412 else (_type == LIMIT)))
331413 then true
332414 else !((i.caller == this)))
333415 then throw("Invalid createOrder parameters")
334416 else {
335417 let orderId = (currentOrderId() + 1)
336418 let newTraderOrderCount = (getTraderOrderCount(_amm, _trader) + 1)
337419 let positionSize = getPositionSize(_amm, _trader)
338420 let _direction = if (if (if ((positionSize == 0))
339421 then true
340422 else if ((positionSize > 0))
341423 then (_side == LONG)
342424 else false)
343425 then true
344426 else if ((0 > positionSize))
345427 then (_side == SHORT)
346428 else false)
347429 then INCREASE
348430 else DECREASE
349431 if (if ((positionSize == 0))
350432 then if ((_type == STOP))
351433 then true
352434 else (_type == TAKE)
353435 else false)
354436 then throw("Can not create STOP/TAKE order: no position")
355437 else {
356438 let usdnPayment = if ((_direction == INCREASE))
357439 then if (if ((_paymentAssetId != toBase58String(quoteAsset())))
358440 then true
359441 else (_paymentAmount != _amountIn))
360442 then throw("Invalid createLimitOrder parameters: invalid payment")
361443 else {
362444 let stake = invoke(managerAddress(), "deposit", nil, [AttachedPayment(quoteAsset(), _paymentAmount)])
363445 if ((stake == stake))
364446 then _paymentAmount
365447 else throw("Strict value is not equal to itself.")
366448 }
367449 else 0
368450 if ((usdnPayment == usdnPayment))
369451 then {
370452 let positionId = if ((positionSize != 0))
371453 then getPositionId(_amm, _trader)
372454 else 0
373455 if ((newTraderOrderCount > MAX_TRADER_ORDERS_PER_AMM))
374456 then throw("Invalid createLimitOrder parameters: order count")
375- else ((saveOrder(orderId, _amm, _trader, _amountIn, _leverage, _type, _triggerPrice, usdnPayment, _side, _refLink, positionId, _limitPrice) ++ updateTraderOrderCount(_amm, _trader, newTraderOrderCount)) ++ updateLastOrderId(orderId))
457+ 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))
376458 }
377459 else throw("Strict value is not equal to itself.")
378460 }
379461 }
380462
381463
382464
383465 @Callable(i)
384466 func cancelOrder (_orderId) = {
385- let $t01350813727 = getOrder(_orderId)
386- let _amm = $t01350813727._1
387- let _trader = $t01350813727._2
388- let _amountIn = $t01350813727._3
389- let _leverage = $t01350813727._4
390- let _type = $t01350813727._5
391- let _triggerPrice = $t01350813727._6
392- let _amountUsdn = $t01350813727._7
393- let _side = $t01350813727._8
394- let _refLink = $t01350813727._9
395- let _positionId = $t01350813727._10
396- let _limitPrice = $t01350813727._11
467+ let $t01572115940 = getOrder(_orderId)
468+ let _amm = $t01572115940._1
469+ let _trader = $t01572115940._2
470+ let _amountIn = $t01572115940._3
471+ let _leverage = $t01572115940._4
472+ let _type = $t01572115940._5
473+ let _triggerPrice = $t01572115940._6
474+ let _amountUsdn = $t01572115940._7
475+ let _side = $t01572115940._8
476+ let _refLink = $t01572115940._9
477+ let _positionId = $t01572115940._10
478+ let _limitPrice = $t01572115940._11
397479 if (if (if (!(initialized()))
398480 then true
399481 else !(isValid(_orderId)))
400482 then true
401483 else !((toString(i.caller) == _trader)))
402484 then throw("Invalid cancelOrder parameters")
403485 else {
404- let newTraderOrderCount = (getTraderOrderCount(_amm, _trader) - 1)
405- let withdraw = if ((_amountUsdn > 0))
486+ let cleanUp = invoke(this, "cleanUpStaleOrders", [_amm, _trader], nil)
487+ if ((cleanUp == cleanUp))
406488 then {
407- let unstake = invoke(managerAddress(), "withdraw", [toBase58String(quoteAsset()), _amountUsdn], nil)
408- if ((unstake == unstake))
409- then nil
489+ let newTraderOrderCount = (getTraderOrderCount(_amm, _trader) - 1)
490+ let withdraw = if ((_amountUsdn > 0))
491+ then {
492+ let unstake = invoke(managerAddress(), "withdraw", [toBase58String(quoteAsset()), _amountUsdn], nil)
493+ if ((unstake == unstake))
494+ then nil
495+ else throw("Strict value is not equal to itself.")
496+ }
497+ else nil
498+ if ((withdraw == withdraw))
499+ then (((markCancelOrder(_orderId) ++ addRemoveOrderId(_orderId, _amm, _trader, false)) ++ updateTraderOrderCount(_amm, _trader, newTraderOrderCount)) ++ (if ((_amountUsdn > 0))
500+ then [ScriptTransfer(i.caller, _amountUsdn, quoteAsset())]
501+ else nil))
410502 else throw("Strict value is not equal to itself.")
411503 }
412- else nil
413- if ((withdraw == withdraw))
414- then ((markCancelOrder(_orderId) ++ updateTraderOrderCount(_amm, _trader, newTraderOrderCount)) ++ (if ((_amountUsdn > 0))
415- then [ScriptTransfer(i.caller, _amountUsdn, quoteAsset())]
416- else nil))
417504 else throw("Strict value is not equal to itself.")
418505 }
419506 }
420507
421508
422509
423510 @Callable(i)
424511 func executeOrder (_orderId) = {
425- let $t01456014779 = getOrder(_orderId)
426- let _amm = $t01456014779._1
427- let _trader = $t01456014779._2
428- let _amountIn = $t01456014779._3
429- let _leverage = $t01456014779._4
430- let _type = $t01456014779._5
431- let _triggerPrice = $t01456014779._6
432- let _amountUsdn = $t01456014779._7
433- let _side = $t01456014779._8
434- let _refLink = $t01456014779._9
435- let _positionId = $t01456014779._10
436- let _limitPrice = $t01456014779._11
437- if (if (!(initialized()))
438- then true
439- else !(isValid(_orderId)))
440- then throw("Invalid executeOrder parameters")
441- else {
442- let positionSize = getPositionSize(_amm, _trader)
443- let currentPositionId = if ((positionSize != 0))
444- then getPositionId(_amm, _trader)
445- else 0
446- let $t01510518926 = if ((_type == STOP))
447- then {
448- let _positionDirection = if ((positionSize > 0))
449- then LONG
450- else if ((0 > positionSize))
451- then SHORT
452- else throw("Can not execute STOP order: no open position")
453- let marketPrice = getMarketPrice(_amm)
454- let isExecutable = if ((_side == _positionDirection))
455- then throw("Can not execute STOP order: reduce only")
456- else if ((currentPositionId != _positionId))
457- then throw("Can not execute STOP order: position closed")
458- else if ((_positionDirection == LONG))
459- then (_triggerPrice >= marketPrice)
460- else (marketPrice >= _triggerPrice)
461- if (isExecutable)
462- then $Tuple3("closePosition", [minv(_amountIn, abs(positionSize)), muld(_limitPrice, abs(positionSize))], nil)
463- else throw("Can not execute STOP order: triggerPrice mismatch")
464- }
465- else if ((_type == TAKE))
512+ let $t01691117130 = getOrder(_orderId)
513+ let _amm = $t01691117130._1
514+ let _trader = $t01691117130._2
515+ let _amountIn = $t01691117130._3
516+ let _leverage = $t01691117130._4
517+ let _type = $t01691117130._5
518+ let _triggerPrice = $t01691117130._6
519+ let _amountUsdn = $t01691117130._7
520+ let _side = $t01691117130._8
521+ let _refLink = $t01691117130._9
522+ let _positionId = $t01691117130._10
523+ let _limitPrice = $t01691117130._11
524+ let cleanUp = invoke(this, "cleanUpStaleOrders", [_amm, _trader], nil)
525+ if ((cleanUp == cleanUp))
526+ then if (if (!(initialized()))
527+ then true
528+ else !(isValid(_orderId)))
529+ then throw("Invalid executeOrder parameters")
530+ else {
531+ let positionSize = getPositionSize(_amm, _trader)
532+ let currentPositionId = if ((positionSize != 0))
533+ then getPositionId(_amm, _trader)
534+ else 0
535+ let $t01753821359 = if ((_type == STOP))
466536 then {
467537 let _positionDirection = if ((positionSize > 0))
468538 then LONG
469539 else if ((0 > positionSize))
470540 then SHORT
471541 else throw("Can not execute STOP order: no open position")
472542 let marketPrice = getMarketPrice(_amm)
473543 let isExecutable = if ((_side == _positionDirection))
474- then throw("Can not execute TAKE order: reduce only")
544+ then throw("Can not execute STOP order: reduce only")
475545 else if ((currentPositionId != _positionId))
476- then throw(((("Can not execute TAKE order: position closed " + toString(currentPositionId)) + "!=") + toString(_positionId)))
546+ then throw("Can not execute STOP order: position closed")
477547 else if ((_positionDirection == LONG))
478- then (marketPrice >= _triggerPrice)
479- else (_triggerPrice >= marketPrice)
548+ then (_triggerPrice >= marketPrice)
549+ else (marketPrice >= _triggerPrice)
480550 if (isExecutable)
481551 then $Tuple3("closePosition", [minv(_amountIn, abs(positionSize)), muld(_limitPrice, abs(positionSize))], nil)
482- else throw("Can not execute TAKE order: triggerPrice mismatch")
552+ else throw("Can not execute STOP order: triggerPrice mismatch")
483553 }
484- else if ((_type == LIMIT))
554+ else if ((_type == TAKE))
485555 then {
556+ let _positionDirection = if ((positionSize > 0))
557+ then LONG
558+ else if ((0 > positionSize))
559+ then SHORT
560+ else throw("Can not execute STOP order: no open position")
486561 let marketPrice = getMarketPrice(_amm)
487- let spread = if ((_limitPrice == 0))
488- then getSpread(_triggerPrice)
489- else abs((_triggerPrice - _limitPrice))
490- let isExecutable = if ((marketPrice >= (_triggerPrice - spread)))
491- then ((_triggerPrice + spread) >= marketPrice)
492- else false
562+ let isExecutable = if ((_side == _positionDirection))
563+ then throw("Can not execute TAKE order: reduce only")
564+ else if ((currentPositionId != _positionId))
565+ then throw(((("Can not execute TAKE order: position closed " + toString(currentPositionId)) + "!=") + toString(_positionId)))
566+ else if ((_positionDirection == LONG))
567+ then (marketPrice >= _triggerPrice)
568+ else (_triggerPrice >= marketPrice)
493569 if (isExecutable)
494- then {
495- let _positionDirection = if ((positionSize > 0))
496- then LONG
497- else if ((0 > positionSize))
498- then SHORT
499- else -1
500- let direction = if ((positionSize == 0))
501- then INCREASE
502- else if ((_positionDirection == _side))
570+ then $Tuple3("closePosition", [minv(_amountIn, abs(positionSize)), muld(_limitPrice, abs(positionSize))], nil)
571+ else throw("Can not execute TAKE order: triggerPrice mismatch")
572+ }
573+ else if ((_type == LIMIT))
574+ then {
575+ let marketPrice = getMarketPrice(_amm)
576+ let spread = if ((_limitPrice == 0))
577+ then getSpread(_triggerPrice)
578+ else abs((_triggerPrice - _limitPrice))
579+ let isExecutable = if ((marketPrice >= (_triggerPrice - spread)))
580+ then ((_triggerPrice + spread) >= marketPrice)
581+ else false
582+ if (isExecutable)
583+ then {
584+ let _positionDirection = if ((positionSize > 0))
585+ then LONG
586+ else if ((0 > positionSize))
587+ then SHORT
588+ else -1
589+ let direction = if ((positionSize == 0))
503590 then INCREASE
504- else DECREASE
505- if ((direction == INCREASE))
506- then {
507- let amountInWithFee = (_amountUsdn - muld(_amountUsdn, getFee(_amm, _trader)))
508- $Tuple3("increasePosition", [_side, _leverage, if ((_limitPrice == 0))
509- then 0
510- else divd(amountInWithFee, _limitPrice), _refLink], [AttachedPayment(quoteAsset(), _amountUsdn)])
511- }
512- else $Tuple3("closePosition", [_amountIn, muld(_amountIn, _limitPrice)], nil)
513- }
514- else throw("Can not execute LIMIT order: triggerPrice mismatch")
515- }
516- else throw(("Invalid order type: " + toString(_type)))
517- let method = $t01510518926._1
518- let args = $t01510518926._2
519- let payments = $t01510518926._3
520- let withdraw = if ((size(payments) == 1))
521- then {
522- let unstake = invoke(managerAddress(), "withdraw", [toBase58String(quoteAsset()), payments[0].amount], nil)
523- if ((unstake == unstake))
524- then nil
525- else throw("Strict value is not equal to itself.")
526- }
527- else nil
528- if ((withdraw == withdraw))
529- then {
530- let doSetContext = invoke(this, "setContext", [_trader], nil)
531- if ((doSetContext == doSetContext))
532- then {
533- let doClosePosition = invoke(addressFromStringValue(_amm), method, args, payments)
534- if ((doClosePosition == doClosePosition))
535- then {
536- let doResetContext = invoke(this, "resetContext", nil, nil)
537- if ((doResetContext == doResetContext))
538- then markExecuteOrder(_orderId)
539- else throw("Strict value is not equal to itself.")
540- }
541- else throw("Strict value is not equal to itself.")
542- }
543- else throw("Strict value is not equal to itself.")
544- }
545- else throw("Strict value is not equal to itself.")
546- }
591+ else if ((_positionDirection == _side))
592+ then INCREASE
593+ else DECREASE
594+ if ((direction == INCREASE))
595+ then {
596+ let amountInWithFee = (_amountUsdn - muld(_amountUsdn, getFee(_amm, _trader)))
597+ $Tuple3("increasePosition", [_side, _leverage, if ((_limitPrice == 0))
598+ then 0
599+ else divd(amountInWithFee, _limitPrice), _refLink], [AttachedPayment(quoteAsset(), _amountUsdn)])
600+ }
601+ else $Tuple3("closePosition", [_amountIn, muld(_amountIn, _limitPrice)], nil)
602+ }
603+ else throw("Can not execute LIMIT order: triggerPrice mismatch")
604+ }
605+ else throw(("Invalid order type: " + toString(_type)))
606+ let method = $t01753821359._1
607+ let args = $t01753821359._2
608+ let payments = $t01753821359._3
609+ let withdraw = if ((size(payments) == 1))
610+ then {
611+ let unstake = invoke(managerAddress(), "withdraw", [toBase58String(quoteAsset()), payments[0].amount], nil)
612+ if ((unstake == unstake))
613+ then nil
614+ else throw("Strict value is not equal to itself.")
615+ }
616+ else nil
617+ if ((withdraw == withdraw))
618+ then {
619+ let doSetContext = invoke(this, "setContext", [_trader], nil)
620+ if ((doSetContext == doSetContext))
621+ then {
622+ let doClosePosition = invoke(addressFromStringValue(_amm), method, args, payments)
623+ if ((doClosePosition == doClosePosition))
624+ then {
625+ let doResetContext = invoke(this, "resetContext", nil, nil)
626+ if ((doResetContext == doResetContext))
627+ then {
628+ let newTraderOrderCount = (getTraderOrderCount(_amm, _trader) - 1)
629+ ((updateTraderOrderCount(_amm, _trader, newTraderOrderCount) ++ addRemoveOrderId(_orderId, _amm, _trader, false)) ++ markExecuteOrder(_orderId))
630+ }
631+ else throw("Strict value is not equal to itself.")
632+ }
633+ else throw("Strict value is not equal to itself.")
634+ }
635+ else throw("Strict value is not equal to itself.")
636+ }
637+ else throw("Strict value is not equal to itself.")
638+ }
639+ else throw("Strict value is not equal to itself.")
547640 }
548641
549642
550643
551644 @Callable(i)
552645 func view_canExecuteOrder (_orderId) = {
553646 let s = invoke(this, "executeOrder", [_orderId], nil)
554647 if ((s == s))
555648 then throw("Success")
556649 else throw("Strict value is not equal to itself.")
557650 }
558651
559652
560653 @Verifier(tx)
561654 func verify () = sigVerify(tx.bodyBytes, tx.proofs[0], adminPublicKey())
562655

github/deemru/w8io/026f985 
87.43 ms