tx · 25o3gzaMe49eZgUyoMEdqps81Pfptxej6NQZU6mHLDJc

3N9kbR6BQEQV7pwBfDFzprJtNofgi6fSJ6Y:  -0.03700000 Waves

2022.12.08 11:40 [2351138] smart account 3N9kbR6BQEQV7pwBfDFzprJtNofgi6fSJ6Y > SELF 0.00000000 Waves

{ "type": 13, "id": "25o3gzaMe49eZgUyoMEdqps81Pfptxej6NQZU6mHLDJc", "fee": 3700000, "feeAssetId": null, "timestamp": 1670488871676, "version": 2, "chainId": 84, "sender": "3N9kbR6BQEQV7pwBfDFzprJtNofgi6fSJ6Y", "senderPublicKey": "EajGg1J8duApPELWPw9gVkPwAKFC9hujhvCcne4FunUa", "proofs": [ "5qDEebTNKi6KErvXGectAoNdkuCr6tv3d2Q5ckyqvpNEgXASUgVQw8wDM28mX8CzwxLk4GHsNxfdUqbChc5J89Y1" ], "script": "base64:BgI4CAISAwoBCBIAEgMKAQgSCgoICAEBAQEBAQgSDQoLCAgBAQEBAQEICAESAwoBARIDCgEBEgMKAQE3ABRrX2Nvb3JkaW5hdG9yQWRkcmVzcwIUa19jb29yZGluYXRvckFkZHJlc3MAEmtfYWRtaW5fcHVibGljX2tleQISa19hZG1pbl9wdWJsaWNfa2V5AA1rX3F1b3RlX2Fzc2V0Ag1rX3F1b3RlX2Fzc2V0AAVrX2FtbQIFa19hbW0AEWtfbWFuYWdlcl9hZGRyZXNzAhFrX21hbmFnZXJfYWRkcmVzcwASa19wb3NpdGlvblNlcXVlbmNlAhJrX3Bvc2l0aW9uU2VxdWVuY2UADmtfcG9zaXRpb25TaXplAg5rX3Bvc2l0aW9uU2l6ZQAFa19mZWUCBWtfZmVlABBrX2V4ZWN1dGVkT3JkZXJzAhBrX2V4ZWN1dGVkT3JkZXJzABBrX2NhbmNlbGVkT3JkZXJzAhBrX2NhbmNlbGVkT3JkZXJzAAdrX29yZGVyAgdrX29yZGVyAA1rX2xhc3RPcmRlcklkAg1rX2xhc3RPcmRlcklkABBrX3RyYWRlck9yZGVyQ250AhBrX3RyYWRlck9yZGVyQ250AAhrX3NlbmRlcgIIa19zZW5kZXIADWtfaW5pdGlhbGl6ZWQCDWtfaW5pdGlhbGl6ZWQABFNUT1AAAQAEVEFLRQACAAVMSU1JVAADAARMT05HAAEABVNIT1JUAAIACElOQ1JFQVNFAAEACERFQ1JFQVNFAAIAGU1BWF9UUkFERVJfT1JERVJTX1BFUl9BTU0ABQAEVElNRQgFCWxhc3RCbG9jawl0aW1lc3RhbXAADERFQ0lNQUxfVU5JVAkAaAIAAQkAaAIJAGgCCQBoAgkAaAIJAGgCAAoACgAKAAoACgAKAAxTUFJFQURfTElNSVQJAGkCBQxERUNJTUFMX1VOSVQAyAEBA2FicwECX3gDCQBmAgUCX3gAAAUCX3gJAQEtAQUCX3gBBGRpdmQCAl94Al95CQBuBAUCX3gFDERFQ0lNQUxfVU5JVAUCX3kFCEhBTEZFVkVOAQRtdWxkAgJfeAJfeQkAbgQFAl94BQJfeQUMREVDSU1BTF9VTklUBQhIQUxGRVZFTgEEbWludgICX3gCX3kDCQBmAgUCX3gFAl95BQJfeQUCX3gBDnRvQ29tcG9zaXRlS2V5AgRfa2V5CF9hZGRyZXNzCQCsAgIJAKwCAgUEX2tleQIBXwUIX2FkZHJlc3MBEGV4ZWN1dGVkT3JkZXJLZXkBCF9vcmRlcklkCQCsAgIJAKwCAgUQa19leGVjdXRlZE9yZGVycwIBXwkApAMBBQhfb3JkZXJJZAEQY2FuY2VsZWRPcmRlcktleQEIX29yZGVySWQJAKwCAgkArAICBRBrX2NhbmNlbGVkT3JkZXJzAgFfCQCkAwEFCF9vcmRlcklkAQhvcmRlcktleQEIX29yZGVySWQJAQ50b0NvbXBvc2l0ZUtleQIFB2tfb3JkZXIJAKQDAQUIX29yZGVySWQBE3RyYWRlck9yZGVyQ291bnRLZXkCBF9hbW0HX3RyYWRlcgkArAICCQCsAgIJAKwCAgkArAICBRBrX3RyYWRlck9yZGVyQ250AgFfBQRfYW1tAgFfBQdfdHJhZGVyAQtjb29yZGluYXRvcgAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCBQR0aGlzBRRrX2Nvb3JkaW5hdG9yQWRkcmVzcwITQ29vcmRpbmF0b3Igbm90IHNldAEKcXVvdGVBc3NldAAJANkEAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUNa19xdW90ZV9hc3NldAEObWFuYWdlckFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAURa19tYW5hZ2VyX2FkZHJlc3MCD01hbmFnZXIgbm90IHNldAELaXNXaGl0ZWxpc3QBCF9hZGRyZXNzCQELdmFsdWVPckVsc2UCCQCbCAIJAQtjb29yZGluYXRvcgAJAQ50b0NvbXBvc2l0ZUtleQIFBWtfYW1tBQhfYWRkcmVzcwcBDmFkbWluUHVibGljS2V5AAkA2QQBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABRJrX2FkbWluX3B1YmxpY19rZXkBC2luaXRpYWxpemVkAAkBC3ZhbHVlT3JFbHNlAgkAmwgCBQR0aGlzBQ1rX2luaXRpYWxpemVkBwEHaXNWYWxpZAEIX29yZGVySWQDCQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMJARBleGVjdXRlZE9yZGVyS2V5AQUIX29yZGVySWQHCQACAQkArAICAhhPcmRlciBhbHJlYWR5IGV4ZWN1dGVkOiAJAKQDAQUIX29yZGVySWQDCQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMJARBjYW5jZWxlZE9yZGVyS2V5AQUIX29yZGVySWQHCQACAQkArAICAhlPcmRlciBhbHJlYWR5IGNhbmNlbGxlZDogCQCkAwEFCF9vcmRlcklkBgEOY3VycmVudE9yZGVySWQACQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFDWtfbGFzdE9yZGVySWQAAAETZ2V0VHJhZGVyT3JkZXJDb3VudAIEX2FtbQdfdHJhZGVyBANrZXkJARN0cmFkZXJPcmRlckNvdW50S2V5AgUEX2FtbQUHX3RyYWRlcgkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQNrZXkAAAEIZ2V0T3JkZXIBCF9vcmRlcklkBAhvcmRlclN0cgkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFBHRoaXMJAQhvcmRlcktleQEFCF9vcmRlcklkCQCsAgICEkludmFsaWQgb3JkZXIgaWQ6IAkApAMBBQhfb3JkZXJJZAQNb3JkZXJQYXJ0TGlzdAkAtQkCBQhvcmRlclN0cgIBLAQDYW1tCQCRAwIFDW9yZGVyUGFydExpc3QAAAQGdHJhZGVyCQCRAwIFDW9yZGVyUGFydExpc3QAAQQIYW1vdW50SW4JARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAtgkBCQCRAwIFDW9yZGVyUGFydExpc3QAAgIQSW52YWxpZCBhbW91bnRJbgQIbGV2ZXJhZ2UJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAtgkBCQCRAwIFDW9yZGVyUGFydExpc3QAAwIQSW52YWxpZCBsZXZlcmFnZQQEdHlwZQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEJAJEDAgUNb3JkZXJQYXJ0TGlzdAAEAgxJbnZhbGlkIHR5cGUEDHRyaWdnZXJQcmljZQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEJAJEDAgUNb3JkZXJQYXJ0TGlzdAAFAhRJbnZhbGlkIHRyaWdnZXJQcmljZQQLcGF5bWVudFVzZG4JARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAtgkBCQCRAwIFDW9yZGVyUGFydExpc3QABgITSW52YWxpZCBwYXltZW50VXNkbgQEc2lkZQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEJAJEDAgUNb3JkZXJQYXJ0TGlzdAAHAgxJbnZhbGlkIHNpZGUEB3JlZkxpbmsJAJEDAgUNb3JkZXJQYXJ0TGlzdAAIBApwb3NpdGlvbklkCQETdmFsdWVPckVycm9yTWVzc2FnZQIJALYJAQkAkQMCBQ1vcmRlclBhcnRMaXN0AAkCEkludmFsaWQgcG9zaXRpb25JZAQKbGltaXRQcmljZQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEJAJEDAgUNb3JkZXJQYXJ0TGlzdAAKAhJJbnZhbGlkIGxpbWl0UHJpY2UJAJ0KCwUDYW1tBQZ0cmFkZXIFCGFtb3VudEluBQhsZXZlcmFnZQUEdHlwZQUMdHJpZ2dlclByaWNlBQtwYXltZW50VXNkbgUEc2lkZQUHcmVmTGluawUKcG9zaXRpb25JZAUKbGltaXRQcmljZQEOZ2V0TWFya2V0UHJpY2UBBF9hbW0EAXMJAPwHBAkBEUBleHRyTmF0aXZlKDEwNjIpAQUEX2FtbQIQY29tcHV0ZVNwb3RQcmljZQUDbmlsBQNuaWwDCQAAAgUBcwUBcwQDcmVzBAckbWF0Y2gwBQFzAwkAAQIFByRtYXRjaDACA0ludAQBdAUHJG1hdGNoMAUBdAkAAgECH0ludmFsaWQgY29tcHV0ZVNwb3RQcmljZSByZXN1bHQJAQV2YWx1ZQEFA3JlcwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgEGZ2V0RmVlAgRfYW1tB190cmFkZXIEAXMJAPwHBAkBEUBleHRyTmF0aXZlKDEwNjIpAQUEX2FtbQIfY29tcHV0ZUZlZUZvclRyYWRlcldpdGhBcnRpZmFjdAkAzAgCBQdfdHJhZGVyCQDMCAICAAUDbmlsBQNuaWwDCQAAAgUBcwUBcwQDcmVzBAckbWF0Y2gwBQFzAwkAAQIFByRtYXRjaDACDihJbnQsIEJvb2xlYW4pBAF0BQckbWF0Y2gwCAUBdAJfMQkAAgECLkludmFsaWQgY29tcHV0ZUZlZUZvclRyYWRlcldpdGhBcnRpZmFjdCByZXN1bHQJAQV2YWx1ZQEFA3JlcwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgEPZ2V0UG9zaXRpb25TaXplAgRfYW1tB190cmFkZXIEA2FtbQkBEUBleHRyTmF0aXZlKDEwNjIpAQUEX2FtbQQHc2l6ZUtleQkBDnRvQ29tcG9zaXRlS2V5AgUOa19wb3NpdGlvblNpemUFB190cmFkZXIJAQt2YWx1ZU9yRWxzZQIJAJoIAgUDYW1tBQdzaXplS2V5AAABDWdldFBvc2l0aW9uSWQCBF9hbW0HX3RyYWRlcgQDYW1tCQERQGV4dHJOYXRpdmUoMTA2MikBBQRfYW1tBAZzZXFLZXkJAQ50b0NvbXBvc2l0ZUtleQIFEmtfcG9zaXRpb25TZXF1ZW5jZQUHX3RyYWRlcgkBC3ZhbHVlT3JFbHNlAgkAmggCBQNhbW0FBnNlcUtleQAAAQlnZXRTcHJlYWQBBl9wcmljZQkBBG11bGQCBQZfcHJpY2UFDFNQUkVBRF9MSU1JVAEJc2F2ZU9yZGVyDAhfb3JkZXJJZARfYW1tB190cmFkZXIJX2Ftb3VudEluCV9sZXZlcmFnZQVfdHlwZQ1fdHJpZ2dlclByaWNlDF9wYXltZW50VXNkbgVfc2lkZQhfcmVmTGluawtfcG9zaXRpb25JZAtfbGltaXRQcmljZQQIb3JkZXJTdHIJALkJAgkAzAgCBQRfYW1tCQDMCAIFB190cmFkZXIJAMwIAgkApAMBBQlfYW1vdW50SW4JAMwIAgkApAMBBQlfbGV2ZXJhZ2UJAMwIAgkApAMBBQVfdHlwZQkAzAgCCQCkAwEFDV90cmlnZ2VyUHJpY2UJAMwIAgkApAMBBQxfcGF5bWVudFVzZG4JAMwIAgkApAMBBQVfc2lkZQkAzAgCBQhfcmVmTGluawkAzAgCCQCkAwEFC19wb3NpdGlvbklkCQDMCAIJAKQDAQULX2xpbWl0UHJpY2UFA25pbAIBLAkAzAgCCQELU3RyaW5nRW50cnkCCQEIb3JkZXJLZXkBBQhfb3JkZXJJZAUIb3JkZXJTdHIFA25pbAEWdXBkYXRlVHJhZGVyT3JkZXJDb3VudAMEX2FtbQdfdHJhZGVyBl9jb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBE3RyYWRlck9yZGVyQ291bnRLZXkCBQRfYW1tBQdfdHJhZGVyBQZfY291bnQFA25pbAERdXBkYXRlTGFzdE9yZGVySWQBDF9sYXN0T3JkZXJJZAkAzAgCCQEMSW50ZWdlckVudHJ5AgUNa19sYXN0T3JkZXJJZAUMX2xhc3RPcmRlcklkBQNuaWwBEG1hcmtFeGVjdXRlT3JkZXIBCF9vcmRlcklkCQDMCAIJAQxCb29sZWFuRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBRBrX2V4ZWN1dGVkT3JkZXJzCQCkAwEFCF9vcmRlcklkBgUDbmlsAQ9tYXJrQ2FuY2VsT3JkZXIBCF9vcmRlcklkCQDMCAIJAQxCb29sZWFuRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBRBrX2NhbmNlbGVkT3JkZXJzCQCkAwEFCF9vcmRlcklkBgUDbmlsCAFpAQpzZXRDb250ZXh0AQdfc2VuZGVyAwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIOT25seSBzZWxmLWNhbGwJAMwIAgkBC1N0cmluZ0VudHJ5AgUIa19zZW5kZXIFB19zZW5kZXIFA25pbAFpAQxyZXNldENvbnRleHQAAwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIOT25seSBzZWxmLWNhbGwJAMwIAgkBC0RlbGV0ZUVudHJ5AQUIa19zZW5kZXIFA25pbAFpAQppbml0aWFsaXplAQxfY29vcmRpbmF0b3IDCQELaW5pdGlhbGl6ZWQACQACAQITQWxyZWFkeSBpbml0aWFsaXplZAkAzAgCCQELU3RyaW5nRW50cnkCBRRrX2Nvb3JkaW5hdG9yQWRkcmVzcwUMX2Nvb3JkaW5hdG9yCQDMCAIJAQxCb29sZWFuRW50cnkCBQ1rX2luaXRpYWxpemVkBgUDbmlsAWkBC2NyZWF0ZU9yZGVyCARfYW1tBV90eXBlDV90cmlnZ2VyUHJpY2ULX2xpbWl0UHJpY2UJX2Ftb3VudEluCV9sZXZlcmFnZQVfc2lkZQhfcmVmTGluawMJAGYCCQCQAwEIBQFpCHBheW1lbnRzAAEJAAIBAjVJbnZhbGlkIGNyZWF0ZU9yZGVyIHBhcmFtZXRlcnM6IGludmFsaWQgcGF5bWVudCBjb3VudAQLJHQwODAyMzgyNzUDCQAAAgkAkAMBCAUBaQhwYXltZW50cwABCQCUCgIJANgEAQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCAkAkQMCCAUBaQhwYXltZW50cwAAB2Fzc2V0SWQCEEludmFsaWQgYXNzZXQgaWQICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50CQCUCgICAAAABA5wYXltZW50QXNzZXRJZAgFCyR0MDgwMjM4Mjc1Al8xBA1wYXltZW50QW1vdW50CAULJHQwODAyMzgyNzUCXzIEBmRvQ2FsbAkA/AcEBQR0aGlzAhNpbnRlcm5hbENyZWF0ZU9yZGVyCQDMCAIJAKUIAQgFAWkGY2FsbGVyCQDMCAIFBF9hbW0JAMwIAgUFX3R5cGUJAMwIAgUNX3RyaWdnZXJQcmljZQkAzAgCBQtfbGltaXRQcmljZQkAzAgCBQlfYW1vdW50SW4JAMwIAgUJX2xldmVyYWdlCQDMCAIFBV9zaWRlCQDMCAIFCF9yZWZMaW5rCQDMCAIFDnBheW1lbnRBc3NldElkCQDMCAIFDXBheW1lbnRBbW91bnQFA25pbAUDbmlsAwkAAAIFBmRvQ2FsbAUGZG9DYWxsBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQETaW50ZXJuYWxDcmVhdGVPcmRlcgsHX3RyYWRlcgRfYW1tBV90eXBlDV90cmlnZ2VyUHJpY2ULX2xpbWl0UHJpY2UJX2Ftb3VudEluCV9sZXZlcmFnZQVfc2lkZQhfcmVmTGluaw9fcGF5bWVudEFzc2V0SWQOX3BheW1lbnRBbW91bnQDAwMDAwMDAwMJAQEhAQkBC2luaXRpYWxpemVkAAYJAQEhAQkBC2lzV2hpdGVsaXN0AQUEX2FtbQYJAGcCAAAFDV90cmlnZ2VyUHJpY2UGCQBmAgAABQtfbGltaXRQcmljZQYJAGcCAAAFCV9hbW91bnRJbgYJAGYCAAAFCV9sZXZlcmFnZQYJAQEhAQMJAAACBQVfc2lkZQUETE9ORwYJAAACBQVfc2lkZQUFU0hPUlQGCQEBIQEDAwkAAAIFBV90eXBlBQRTVE9QBgkAAAIFBV90eXBlBQRUQUtFBgkAAAIFBV90eXBlBQVMSU1JVAYJAQEhAQkAAAIIBQFpBmNhbGxlcgUEdGhpcwkAAgECHkludmFsaWQgY3JlYXRlT3JkZXIgcGFyYW1ldGVycwQHb3JkZXJJZAkAZAIJAQ5jdXJyZW50T3JkZXJJZAAAAQQTbmV3VHJhZGVyT3JkZXJDb3VudAkAZAIJARNnZXRUcmFkZXJPcmRlckNvdW50AgUEX2FtbQUHX3RyYWRlcgABBAxwb3NpdGlvblNpemUJAQ9nZXRQb3NpdGlvblNpemUCBQRfYW1tBQdfdHJhZGVyBApfZGlyZWN0aW9uAwMDCQAAAgUMcG9zaXRpb25TaXplAAAGAwkAZgIFDHBvc2l0aW9uU2l6ZQAACQAAAgUFX3NpZGUFBExPTkcHBgMJAGYCAAAFDHBvc2l0aW9uU2l6ZQkAAAIFBV9zaWRlBQVTSE9SVAcFCElOQ1JFQVNFBQhERUNSRUFTRQMDCQAAAgUMcG9zaXRpb25TaXplAAADCQAAAgUFX3R5cGUFBFNUT1AGCQAAAgUFX3R5cGUFBFRBS0UHCQACAQIrQ2FuIG5vdCBjcmVhdGUgU1RPUC9UQUtFIG9yZGVyOiBubyBwb3NpdGlvbgQLdXNkblBheW1lbnQDCQAAAgUKX2RpcmVjdGlvbgUISU5DUkVBU0UDAwkBAiE9AgUPX3BheW1lbnRBc3NldElkCQDYBAEJAQpxdW90ZUFzc2V0AAYJAQIhPQIFDl9wYXltZW50QW1vdW50BQlfYW1vdW50SW4JAAIBAjRJbnZhbGlkIGNyZWF0ZUxpbWl0T3JkZXIgcGFyYW1ldGVyczogaW52YWxpZCBwYXltZW50BAVzdGFrZQkA/AcECQEObWFuYWdlckFkZHJlc3MAAgdkZXBvc2l0BQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUOX3BheW1lbnRBbW91bnQFA25pbAMJAAACBQVzdGFrZQUFc3Rha2UFDl9wYXltZW50QW1vdW50CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAAADCQAAAgULdXNkblBheW1lbnQFC3VzZG5QYXltZW50BApwb3NpdGlvbklkAwkBAiE9AgUMcG9zaXRpb25TaXplAAAJAQ1nZXRQb3NpdGlvbklkAgUEX2FtbQUHX3RyYWRlcgAAAwkAZgIFE25ld1RyYWRlck9yZGVyQ291bnQFGU1BWF9UUkFERVJfT1JERVJTX1BFUl9BTU0JAAIBAjBJbnZhbGlkIGNyZWF0ZUxpbWl0T3JkZXIgcGFyYW1ldGVyczogb3JkZXIgY291bnQJAM4IAgkAzggCCQEJc2F2ZU9yZGVyDAUHb3JkZXJJZAUEX2FtbQUHX3RyYWRlcgUJX2Ftb3VudEluBQlfbGV2ZXJhZ2UFBV90eXBlBQ1fdHJpZ2dlclByaWNlBQt1c2RuUGF5bWVudAUFX3NpZGUFCF9yZWZMaW5rBQpwb3NpdGlvbklkBQtfbGltaXRQcmljZQkBFnVwZGF0ZVRyYWRlck9yZGVyQ291bnQDBQRfYW1tBQdfdHJhZGVyBRNuZXdUcmFkZXJPcmRlckNvdW50CQERdXBkYXRlTGFzdE9yZGVySWQBBQdvcmRlcklkCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBC2NhbmNlbE9yZGVyAQhfb3JkZXJJZAQNJHQwMTEyMDUxMTQyNAkBCGdldE9yZGVyAQUIX29yZGVySWQEBF9hbW0IBQ0kdDAxMTIwNTExNDI0Al8xBAdfdHJhZGVyCAUNJHQwMTEyMDUxMTQyNAJfMgQJX2Ftb3VudEluCAUNJHQwMTEyMDUxMTQyNAJfMwQJX2xldmVyYWdlCAUNJHQwMTEyMDUxMTQyNAJfNAQFX3R5cGUIBQ0kdDAxMTIwNTExNDI0Al81BA1fdHJpZ2dlclByaWNlCAUNJHQwMTEyMDUxMTQyNAJfNgQLX2Ftb3VudFVzZG4IBQ0kdDAxMTIwNTExNDI0Al83BAVfc2lkZQgFDSR0MDExMjA1MTE0MjQCXzgECF9yZWZMaW5rCAUNJHQwMTEyMDUxMTQyNAJfOQQLX3Bvc2l0aW9uSWQIBQ0kdDAxMTIwNTExNDI0A18xMAQLX2xpbWl0UHJpY2UIBQ0kdDAxMTIwNTExNDI0A18xMQMDAwkBASEBCQELaW5pdGlhbGl6ZWQABgkBASEBCQEHaXNWYWxpZAEFCF9vcmRlcklkBgkBASEBCQAAAgkApQgBCAUBaQZjYWxsZXIFB190cmFkZXIJAAIBAh5JbnZhbGlkIGNhbmNlbE9yZGVyIHBhcmFtZXRlcnMEE25ld1RyYWRlck9yZGVyQ291bnQJAGUCCQETZ2V0VHJhZGVyT3JkZXJDb3VudAIFBF9hbW0FB190cmFkZXIAAQQId2l0aGRyYXcDCQBmAgULX2Ftb3VudFVzZG4AAAQHdW5zdGFrZQkA/AcECQEObWFuYWdlckFkZHJlc3MAAgh3aXRoZHJhdwkAzAgCCQDYBAEJAQpxdW90ZUFzc2V0AAkAzAgCBQtfYW1vdW50VXNkbgUDbmlsBQNuaWwDCQAAAgUHdW5zdGFrZQUHdW5zdGFrZQUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUId2l0aGRyYXcFCHdpdGhkcmF3CQDOCAIJAM4IAgkBD21hcmtDYW5jZWxPcmRlcgEFCF9vcmRlcklkCQEWdXBkYXRlVHJhZGVyT3JkZXJDb3VudAMFBF9hbW0FB190cmFkZXIFE25ld1RyYWRlck9yZGVyQ291bnQDCQBmAgULX2Ftb3VudFVzZG4AAAkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCAUBaQZjYWxsZXIFC19hbW91bnRVc2RuCQEKcXVvdGVBc3NldAAFA25pbAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDGV4ZWN1dGVPcmRlcgEIX29yZGVySWQEDSR0MDEyMjU3MTI0NzYJAQhnZXRPcmRlcgEFCF9vcmRlcklkBARfYW1tCAUNJHQwMTIyNTcxMjQ3NgJfMQQHX3RyYWRlcggFDSR0MDEyMjU3MTI0NzYCXzIECV9hbW91bnRJbggFDSR0MDEyMjU3MTI0NzYCXzMECV9sZXZlcmFnZQgFDSR0MDEyMjU3MTI0NzYCXzQEBV90eXBlCAUNJHQwMTIyNTcxMjQ3NgJfNQQNX3RyaWdnZXJQcmljZQgFDSR0MDEyMjU3MTI0NzYCXzYEC19hbW91bnRVc2RuCAUNJHQwMTIyNTcxMjQ3NgJfNwQFX3NpZGUIBQ0kdDAxMjI1NzEyNDc2Al84BAhfcmVmTGluawgFDSR0MDEyMjU3MTI0NzYCXzkEC19wb3NpdGlvbklkCAUNJHQwMTIyNTcxMjQ3NgNfMTAEC19saW1pdFByaWNlCAUNJHQwMTIyNTcxMjQ3NgNfMTEDAwkBASEBCQELaW5pdGlhbGl6ZWQABgkBASEBCQEHaXNWYWxpZAEFCF9vcmRlcklkCQACAQIfSW52YWxpZCBleGVjdXRlT3JkZXIgcGFyYW1ldGVycwQMcG9zaXRpb25TaXplCQEPZ2V0UG9zaXRpb25TaXplAgUEX2FtbQUHX3RyYWRlcgQRY3VycmVudFBvc2l0aW9uSWQDCQECIT0CBQxwb3NpdGlvblNpemUAAAkBDWdldFBvc2l0aW9uSWQCBQRfYW1tBQdfdHJhZGVyAAAEDSR0MDEyODAyMTY2MjMDCQAAAgUFX3R5cGUFBFNUT1AEEl9wb3NpdGlvbkRpcmVjdGlvbgMJAGYCBQxwb3NpdGlvblNpemUAAAUETE9ORwMJAGYCAAAFDHBvc2l0aW9uU2l6ZQUFU0hPUlQJAAIBAixDYW4gbm90IGV4ZWN1dGUgU1RPUCBvcmRlcjogbm8gb3BlbiBwb3NpdGlvbgQLbWFya2V0UHJpY2UJAQ5nZXRNYXJrZXRQcmljZQEFBF9hbW0EDGlzRXhlY3V0YWJsZQMJAAACBQVfc2lkZQUSX3Bvc2l0aW9uRGlyZWN0aW9uCQACAQInQ2FuIG5vdCBleGVjdXRlIFNUT1Agb3JkZXI6IHJlZHVjZSBvbmx5AwkBAiE9AgURY3VycmVudFBvc2l0aW9uSWQFC19wb3NpdGlvbklkCQACAQIrQ2FuIG5vdCBleGVjdXRlIFNUT1Agb3JkZXI6IHBvc2l0aW9uIGNsb3NlZAMJAAACBRJfcG9zaXRpb25EaXJlY3Rpb24FBExPTkcJAGcCBQ1fdHJpZ2dlclByaWNlBQttYXJrZXRQcmljZQkAZwIFC21hcmtldFByaWNlBQ1fdHJpZ2dlclByaWNlAwUMaXNFeGVjdXRhYmxlCQCVCgMCDWNsb3NlUG9zaXRpb24JAMwIAgkBBG1pbnYCBQlfYW1vdW50SW4JAQNhYnMBBQxwb3NpdGlvblNpemUJAMwIAgkBBG11bGQCBQtfbGltaXRQcmljZQkBA2FicwEFDHBvc2l0aW9uU2l6ZQUDbmlsBQNuaWwJAAIBAjFDYW4gbm90IGV4ZWN1dGUgU1RPUCBvcmRlcjogdHJpZ2dlclByaWNlIG1pc21hdGNoAwkAAAIFBV90eXBlBQRUQUtFBBJfcG9zaXRpb25EaXJlY3Rpb24DCQBmAgUMcG9zaXRpb25TaXplAAAFBExPTkcDCQBmAgAABQxwb3NpdGlvblNpemUFBVNIT1JUCQACAQIsQ2FuIG5vdCBleGVjdXRlIFNUT1Agb3JkZXI6IG5vIG9wZW4gcG9zaXRpb24EC21hcmtldFByaWNlCQEOZ2V0TWFya2V0UHJpY2UBBQRfYW1tBAxpc0V4ZWN1dGFibGUDCQAAAgUFX3NpZGUFEl9wb3NpdGlvbkRpcmVjdGlvbgkAAgECJ0NhbiBub3QgZXhlY3V0ZSBUQUtFIG9yZGVyOiByZWR1Y2Ugb25seQMJAQIhPQIFEWN1cnJlbnRQb3NpdGlvbklkBQtfcG9zaXRpb25JZAkAAgEJAKwCAgkArAICCQCsAgICLENhbiBub3QgZXhlY3V0ZSBUQUtFIG9yZGVyOiBwb3NpdGlvbiBjbG9zZWQgCQCkAwEFEWN1cnJlbnRQb3NpdGlvbklkAgIhPQkApAMBBQtfcG9zaXRpb25JZAMJAAACBRJfcG9zaXRpb25EaXJlY3Rpb24FBExPTkcJAGcCBQttYXJrZXRQcmljZQUNX3RyaWdnZXJQcmljZQkAZwIFDV90cmlnZ2VyUHJpY2UFC21hcmtldFByaWNlAwUMaXNFeGVjdXRhYmxlCQCVCgMCDWNsb3NlUG9zaXRpb24JAMwIAgkBBG1pbnYCBQlfYW1vdW50SW4JAQNhYnMBBQxwb3NpdGlvblNpemUJAMwIAgkBBG11bGQCBQtfbGltaXRQcmljZQkBA2FicwEFDHBvc2l0aW9uU2l6ZQUDbmlsBQNuaWwJAAIBAjFDYW4gbm90IGV4ZWN1dGUgVEFLRSBvcmRlcjogdHJpZ2dlclByaWNlIG1pc21hdGNoAwkAAAIFBV90eXBlBQVMSU1JVAQLbWFya2V0UHJpY2UJAQ5nZXRNYXJrZXRQcmljZQEFBF9hbW0EBnNwcmVhZAMJAAACBQtfbGltaXRQcmljZQAACQEJZ2V0U3ByZWFkAQUNX3RyaWdnZXJQcmljZQkBA2FicwEJAGUCBQ1fdHJpZ2dlclByaWNlBQtfbGltaXRQcmljZQQMaXNFeGVjdXRhYmxlAwkAZwIFC21hcmtldFByaWNlCQBlAgUNX3RyaWdnZXJQcmljZQUGc3ByZWFkCQBnAgkAZAIFDV90cmlnZ2VyUHJpY2UFBnNwcmVhZAULbWFya2V0UHJpY2UHAwUMaXNFeGVjdXRhYmxlBBJfcG9zaXRpb25EaXJlY3Rpb24DCQBmAgUMcG9zaXRpb25TaXplAAAFBExPTkcDCQBmAgAABQxwb3NpdGlvblNpemUFBVNIT1JUAP///////////wEECWRpcmVjdGlvbgMJAAACBQxwb3NpdGlvblNpemUAAAUISU5DUkVBU0UDCQAAAgUSX3Bvc2l0aW9uRGlyZWN0aW9uBQVfc2lkZQUISU5DUkVBU0UFCERFQ1JFQVNFAwkAAAIFCWRpcmVjdGlvbgUISU5DUkVBU0UED2Ftb3VudEluV2l0aEZlZQkAZQIFC19hbW91bnRVc2RuCQEEbXVsZAIFC19hbW91bnRVc2RuCQEGZ2V0RmVlAgUEX2FtbQUHX3RyYWRlcgkAlQoDAhBpbmNyZWFzZVBvc2l0aW9uCQDMCAIFBV9zaWRlCQDMCAIFCV9sZXZlcmFnZQkAzAgCAwkAAAIFC19saW1pdFByaWNlAAAAAAkBBGRpdmQCBQ9hbW91bnRJbldpdGhGZWUFC19saW1pdFByaWNlCQDMCAIFCF9yZWZMaW5rBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAULX2Ftb3VudFVzZG4FA25pbAkAlQoDAg1jbG9zZVBvc2l0aW9uCQDMCAIFCV9hbW91bnRJbgkAzAgCCQEEbXVsZAIFCV9hbW91bnRJbgULX2xpbWl0UHJpY2UFA25pbAUDbmlsCQACAQIyQ2FuIG5vdCBleGVjdXRlIExJTUlUIG9yZGVyOiB0cmlnZ2VyUHJpY2UgbWlzbWF0Y2gJAAIBCQCsAgICFEludmFsaWQgb3JkZXIgdHlwZTogCQCkAwEFBV90eXBlBAZtZXRob2QIBQ0kdDAxMjgwMjE2NjIzAl8xBARhcmdzCAUNJHQwMTI4MDIxNjYyMwJfMgQIcGF5bWVudHMIBQ0kdDAxMjgwMjE2NjIzAl8zBAh3aXRoZHJhdwMJAAACCQCQAwEFCHBheW1lbnRzAAEEB3Vuc3Rha2UJAPwHBAkBDm1hbmFnZXJBZGRyZXNzAAIId2l0aGRyYXcJAMwIAgkA2AQBCQEKcXVvdGVBc3NldAAJAMwIAggJAJEDAgUIcGF5bWVudHMAAAZhbW91bnQFA25pbAUDbmlsAwkAAAIFB3Vuc3Rha2UFB3Vuc3Rha2UFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFCHdpdGhkcmF3BQh3aXRoZHJhdwQMZG9TZXRDb250ZXh0CQD8BwQFBHRoaXMCCnNldENvbnRleHQJAMwIAgUHX3RyYWRlcgUDbmlsBQNuaWwDCQAAAgUMZG9TZXRDb250ZXh0BQxkb1NldENvbnRleHQED2RvQ2xvc2VQb3NpdGlvbgkA/AcECQERQGV4dHJOYXRpdmUoMTA2MikBBQRfYW1tBQZtZXRob2QFBGFyZ3MFCHBheW1lbnRzAwkAAAIFD2RvQ2xvc2VQb3NpdGlvbgUPZG9DbG9zZVBvc2l0aW9uBA5kb1Jlc2V0Q29udGV4dAkA/AcEBQR0aGlzAgxyZXNldENvbnRleHQFA25pbAUDbmlsAwkAAAIFDmRvUmVzZXRDb250ZXh0BQ5kb1Jlc2V0Q29udGV4dAkBEG1hcmtFeGVjdXRlT3JkZXIBBQhfb3JkZXJJZAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARR2aWV3X2NhbkV4ZWN1dGVPcmRlcgEIX29yZGVySWQEAXMJAPwHBAUEdGhpcwIMZXhlY3V0ZU9yZGVyCQDMCAIFCF9vcmRlcklkBQNuaWwFA25pbAMJAAACBQFzBQFzCQACAQIHU3VjY2VzcwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgECdHgBBnZlcmlmeQAJAPQDAwgFAnR4CWJvZHlCeXRlcwkAkQMCCAUCdHgGcHJvb2ZzAAAJAQ5hZG1pblB1YmxpY0tleQBIBtW6", "height": 2351138, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: DD4LroFKgFy71LTCYJrKN6ddxqGh7kHL7cVv4NZHNDVt Next: 9HEMv6NzTacEfbxV2S5MSzaPbbvk6qzzx3MmD4UrEe71 Diff:
OldNewDifferences
55
66 let k_admin_public_key = "k_admin_public_key"
77
8-let k_quoteAssetReserve = "k_qtAstR"
8+let k_quote_asset = "k_quote_asset"
99
10-let k_baseAssetReserve = "k_bsAstR"
10+let k_amm = "k_amm"
1111
12-let k_positionClosedDate = "k_positionClosedDate"
12+let k_manager_address = "k_manager_address"
13+
14+let k_positionSequence = "k_positionSequence"
15+
16+let k_positionSize = "k_positionSize"
17+
18+let k_fee = "k_fee"
1319
1420 let k_executedOrders = "k_executedOrders"
21+
22+let k_canceledOrders = "k_canceledOrders"
23+
24+let k_order = "k_order"
25+
26+let k_lastOrderId = "k_lastOrderId"
27+
28+let k_traderOrderCnt = "k_traderOrderCnt"
1529
1630 let k_sender = "k_sender"
1731
1832 let k_initialized = "k_initialized"
1933
20-let TAKE_PROFIT = 1
34+let STOP = 1
2135
22-let STOP_LOSS = 2
36+let TAKE = 2
37+
38+let LIMIT = 3
39+
40+let LONG = 1
41+
42+let SHORT = 2
43+
44+let INCREASE = 1
45+
46+let DECREASE = 2
47+
48+let MAX_TRADER_ORDERS_PER_AMM = 5
2349
2450 let TIME = lastBlock.timestamp
2551
2652 let DECIMAL_UNIT = (1 * (((((10 * 10) * 10) * 10) * 10) * 10))
53+
54+let SPREAD_LIMIT = (DECIMAL_UNIT / 200)
55+
56+func abs (_x) = if ((_x > 0))
57+ then _x
58+ else -(_x)
59+
2760
2861 func divd (_x,_y) = fraction(_x, DECIMAL_UNIT, _y, HALFEVEN)
2962
3164 func muld (_x,_y) = fraction(_x, _y, DECIMAL_UNIT, HALFEVEN)
3265
3366
34-func executedOrderKey (_orderId) = ((k_executedOrders + "_") + _orderId)
67+func minv (_x,_y) = if ((_x > _y))
68+ then _y
69+ else _x
70+
71+
72+func toCompositeKey (_key,_address) = ((_key + "_") + _address)
73+
74+
75+func executedOrderKey (_orderId) = ((k_executedOrders + "_") + toString(_orderId))
76+
77+
78+func canceledOrderKey (_orderId) = ((k_canceledOrders + "_") + toString(_orderId))
79+
80+
81+func orderKey (_orderId) = toCompositeKey(k_order, toString(_orderId))
82+
83+
84+func traderOrderCountKey (_amm,_trader) = ((((k_traderOrderCnt + "_") + _amm) + "_") + _trader)
3585
3686
3787 func coordinator () = valueOrErrorMessage(addressFromString(getStringValue(this, k_coordinatorAddress)), "Coordinator not set")
88+
89+
90+func quoteAsset () = fromBase58String(getStringValue(coordinator(), k_quote_asset))
91+
92+
93+func managerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_manager_address)), "Manager not set")
94+
95+
96+func isWhitelist (_address) = valueOrElse(getBoolean(coordinator(), toCompositeKey(k_amm, _address)), false)
3897
3998
4099 func adminPublicKey () = fromBase58String(getStringValue(coordinator(), k_admin_public_key))
43102 func initialized () = valueOrElse(getBoolean(this, k_initialized), false)
44103
45104
46-func requireValidOrderSignature (_prefix,_order,_signature,_senderPublicKey) = {
47- let message = toBytes((_prefix + _order))
48- let sig = fromBase58String(_signature)
49- let pub = fromBase58String(_senderPublicKey)
50- if (sigVerify(message, sig, pub))
51- then unit
52- else throw("Invalid order signature")
105+func isValid (_orderId) = if (valueOrElse(getBoolean(this, executedOrderKey(_orderId)), false))
106+ then throw(("Order already executed: " + toString(_orderId)))
107+ else if (valueOrElse(getBoolean(this, canceledOrderKey(_orderId)), false))
108+ then throw(("Order already cancelled: " + toString(_orderId)))
109+ else true
110+
111+
112+func currentOrderId () = valueOrElse(getInteger(this, k_lastOrderId), 0)
113+
114+
115+func getTraderOrderCount (_amm,_trader) = {
116+ let key = traderOrderCountKey(_amm, _trader)
117+ valueOrElse(getInteger(this, key), 0)
53118 }
54119
55120
56-func requireNotExecuted (_orderId) = if (valueOrElse(getBoolean(this, executedOrderKey(_orderId)), false))
57- then throw(("Order already executed: " + _orderId))
58- else unit
121+func getOrder (_orderId) = {
122+ let orderStr = valueOrErrorMessage(getString(this, orderKey(_orderId)), ("Invalid order id: " + toString(_orderId)))
123+ let orderPartList = split(orderStr, ",")
124+ let amm = orderPartList[0]
125+ let trader = orderPartList[1]
126+ let amountIn = valueOrErrorMessage(parseInt(orderPartList[2]), "Invalid amountIn")
127+ let leverage = valueOrErrorMessage(parseInt(orderPartList[3]), "Invalid leverage")
128+ let type = valueOrErrorMessage(parseInt(orderPartList[4]), "Invalid type")
129+ let triggerPrice = valueOrErrorMessage(parseInt(orderPartList[5]), "Invalid triggerPrice")
130+ let paymentUsdn = valueOrErrorMessage(parseInt(orderPartList[6]), "Invalid paymentUsdn")
131+ let side = valueOrErrorMessage(parseInt(orderPartList[7]), "Invalid side")
132+ let refLink = orderPartList[8]
133+ let positionId = valueOrErrorMessage(parseInt(orderPartList[9]), "Invalid positionId")
134+ let limitPrice = valueOrErrorMessage(parseInt(orderPartList[10]), "Invalid limitPrice")
135+ $Tuple11(amm, trader, amountIn, leverage, type, triggerPrice, paymentUsdn, side, refLink, positionId, limitPrice)
136+ }
137+
138+
139+func getMarketPrice (_amm) = {
140+ let s = invoke(addressFromStringValue(_amm), "computeSpotPrice", nil, nil)
141+ if ((s == s))
142+ then {
143+ let res = match s {
144+ case t: Int =>
145+ t
146+ case _ =>
147+ throw("Invalid computeSpotPrice result")
148+ }
149+ value(res)
150+ }
151+ else throw("Strict value is not equal to itself.")
152+ }
153+
154+
155+func getFee (_amm,_trader) = {
156+ let s = invoke(addressFromStringValue(_amm), "computeFeeForTraderWithArtifact", [_trader, ""], nil)
157+ if ((s == s))
158+ then {
159+ let res = match s {
160+ case t: (Int, Boolean) =>
161+ t._1
162+ case _ =>
163+ throw("Invalid computeFeeForTraderWithArtifact result")
164+ }
165+ value(res)
166+ }
167+ else throw("Strict value is not equal to itself.")
168+ }
169+
170+
171+func getPositionSize (_amm,_trader) = {
172+ let amm = addressFromStringValue(_amm)
173+ let sizeKey = toCompositeKey(k_positionSize, _trader)
174+ valueOrElse(getInteger(amm, sizeKey), 0)
175+ }
176+
177+
178+func getPositionId (_amm,_trader) = {
179+ let amm = addressFromStringValue(_amm)
180+ let seqKey = toCompositeKey(k_positionSequence, _trader)
181+ valueOrElse(getInteger(amm, seqKey), 0)
182+ }
183+
184+
185+func getSpread (_price) = muld(_price, SPREAD_LIMIT)
186+
187+
188+func saveOrder (_orderId,_amm,_trader,_amountIn,_leverage,_type,_triggerPrice,_paymentUsdn,_side,_refLink,_positionId,_limitPrice) = {
189+ let orderStr = makeString([_amm, _trader, toString(_amountIn), toString(_leverage), toString(_type), toString(_triggerPrice), toString(_paymentUsdn), toString(_side), _refLink, toString(_positionId), toString(_limitPrice)], ",")
190+[StringEntry(orderKey(_orderId), orderStr)]
191+ }
192+
193+
194+func updateTraderOrderCount (_amm,_trader,_count) = [IntegerEntry(traderOrderCountKey(_amm, _trader), _count)]
195+
196+
197+func updateLastOrderId (_lastOrderId) = [IntegerEntry(k_lastOrderId, _lastOrderId)]
198+
199+
200+func markExecuteOrder (_orderId) = [BooleanEntry(toCompositeKey(k_executedOrders, toString(_orderId)), true)]
201+
202+
203+func markCancelOrder (_orderId) = [BooleanEntry(toCompositeKey(k_canceledOrders, toString(_orderId)), true)]
59204
60205
61206 @Callable(i)
80225
81226
82227 @Callable(i)
83-func executeOrder (_prefix,_order,_signature) = {
84- let orderParts = split(_order, ",")
85- let orderType = valueOrErrorMessage(parseInt(orderParts[0]), "Invalid order data [type]")
86- let orderId = toBase58String(sha256(toBytes(_order)))
87- let validateNotExecuted = requireNotExecuted(orderId)
88- if ((validateNotExecuted == validateNotExecuted))
89- then if (if ((orderType == TAKE_PROFIT))
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+ }
241+
242+
243+
244+@Callable(i)
245+func internalCreateOrder (_trader,_amm,_type,_triggerPrice,_limitPrice,_amountIn,_leverage,_side,_refLink,_paymentAssetId,_paymentAmount) = if (if (if (if (if (if (if (if (if (!(initialized()))
246+ then true
247+ else !(isWhitelist(_amm)))
248+ then true
249+ else (0 >= _triggerPrice))
250+ then true
251+ else (0 > _limitPrice))
252+ then true
253+ else (0 >= _amountIn))
254+ then true
255+ else (0 > _leverage))
256+ then true
257+ else !(if ((_side == LONG))
258+ then true
259+ else (_side == SHORT)))
260+ then true
261+ else !(if (if ((_type == STOP))
262+ then true
263+ else (_type == TAKE))
264+ then true
265+ else (_type == LIMIT)))
266+ then true
267+ else !((i.caller == this)))
268+ then throw("Invalid createOrder parameters")
269+ else {
270+ let orderId = (currentOrderId() + 1)
271+ let newTraderOrderCount = (getTraderOrderCount(_amm, _trader) + 1)
272+ let positionSize = getPositionSize(_amm, _trader)
273+ let _direction = if (if (if ((positionSize == 0))
90274 then true
91- else (orderType == STOP_LOSS))
92- then {
93- let amm = orderParts[1]
94- let senderPublicKey = orderParts[2]
95- let price = valueOrErrorMessage(parseInt(orderParts[3]), "Invalid order data [price]")
96- let timestamp = valueOrErrorMessage(parseInt(orderParts[4]), "Invalid order data [timestamp]")
97- let validDue = valueOrErrorMessage(parseInt(orderParts[5]), "Invalid order data [validDue]")
98- let validateSignature = requireValidOrderSignature(_prefix, _order, _signature, senderPublicKey)
99- if ((validateSignature == validateSignature))
275+ else if ((positionSize > 0))
276+ then (_side == LONG)
277+ else false)
278+ then true
279+ else if ((0 > positionSize))
280+ then (_side == SHORT)
281+ else false)
282+ then INCREASE
283+ else DECREASE
284+ if (if ((positionSize == 0))
285+ then if ((_type == STOP))
286+ then true
287+ else (_type == TAKE)
288+ else false)
289+ then throw("Can not create STOP/TAKE order: no position")
290+ else {
291+ let usdnPayment = if ((_direction == INCREASE))
292+ then if (if ((_paymentAssetId != toBase58String(quoteAsset())))
293+ then true
294+ else (_paymentAmount != _amountIn))
295+ then throw("Invalid createLimitOrder parameters: invalid payment")
296+ else {
297+ let stake = invoke(managerAddress(), "deposit", nil, [AttachedPayment(quoteAsset(), _paymentAmount)])
298+ if ((stake == stake))
299+ then _paymentAmount
300+ else throw("Strict value is not equal to itself.")
301+ }
302+ else 0
303+ if ((usdnPayment == usdnPayment))
100304 then {
101- let ammAddress = valueOrErrorMessage(addressFromString(amm), "Invalid order data [amm]")
102- let quoteAssetReserve = getIntegerValue(ammAddress, k_quoteAssetReserve)
103- let baseAssetReserve = getIntegerValue(ammAddress, k_baseAssetReserve)
104- let ammPrice = divd(quoteAssetReserve, baseAssetReserve)
105- let priceMatch = if ((orderType == TAKE_PROFIT))
106- then (ammPrice >= price)
107- else (price >= ammPrice)
108- let validatePrice = if (!(priceMatch))
109- then throw(((("Can not execute order [price]: AMM Price=" + toString(ammPrice)) + " Order Price=") + toString(price)))
110- else unit
111- if ((validatePrice == validatePrice))
112- then {
113- let dueMatch = if ((validDue == 0))
114- then true
115- else (validDue >= TIME)
116- let validateDue = if (!(dueMatch))
117- then throw(((("Can not execute order [due]: Due=" + toString(validDue)) + " Time=") + toString(TIME)))
118- else unit
119- if ((validateDue == validateDue))
120- then {
121- let traderAddress = toString(addressFromPublicKey(fromBase58String(senderPublicKey)))
122- let positionWasClosed = valueOrElse(getInteger(ammAddress, ((k_positionClosedDate + "_") + traderAddress)), 0)
123- let positionMatch = (timestamp >= positionWasClosed)
124- let validatePosition = if (!(positionMatch))
125- then throw(((("Can not execute order [position closed]: Order Created=" + toString(timestamp)) + " Position Closed=") + toString(positionWasClosed)))
126- else unit
127- if ((validatePosition == validatePosition))
128- then if (if (if (priceMatch)
129- then dueMatch
130- else false)
131- then positionMatch
132- else false)
133- then {
134- let doSetContext = invoke(this, "setContext", [traderAddress], nil)
135- if ((doSetContext == doSetContext))
136- then {
137- let doClosePosition = invoke(ammAddress, "closePosition", nil, nil)
138- if ((doClosePosition == doClosePosition))
139- then {
140- let doResetContext = invoke(this, "resetContext", nil, nil)
141- if ((doResetContext == doResetContext))
142- then [BooleanEntry(executedOrderKey(orderId), true)]
143- else throw("Strict value is not equal to itself.")
144- }
145- else throw("Strict value is not equal to itself.")
146- }
147- else throw("Strict value is not equal to itself.")
148- }
149- else throw("Invalid order execution timing")
150- else throw("Strict value is not equal to itself.")
151- }
152- else throw("Strict value is not equal to itself.")
153- }
154- else throw("Strict value is not equal to itself.")
305+ let positionId = if ((positionSize != 0))
306+ then getPositionId(_amm, _trader)
307+ else 0
308+ if ((newTraderOrderCount > MAX_TRADER_ORDERS_PER_AMM))
309+ then throw("Invalid createLimitOrder parameters: order count")
310+ else ((saveOrder(orderId, _amm, _trader, _amountIn, _leverage, _type, _triggerPrice, usdnPayment, _side, _refLink, positionId, _limitPrice) ++ updateTraderOrderCount(_amm, _trader, newTraderOrderCount)) ++ updateLastOrderId(orderId))
155311 }
156312 else throw("Strict value is not equal to itself.")
157313 }
158- else throw(("Invalid order type: " + toString(orderType)))
314+ }
315+
316+
317+
318+@Callable(i)
319+func cancelOrder (_orderId) = {
320+ let $t01120511424 = getOrder(_orderId)
321+ let _amm = $t01120511424._1
322+ let _trader = $t01120511424._2
323+ let _amountIn = $t01120511424._3
324+ let _leverage = $t01120511424._4
325+ let _type = $t01120511424._5
326+ let _triggerPrice = $t01120511424._6
327+ let _amountUsdn = $t01120511424._7
328+ let _side = $t01120511424._8
329+ let _refLink = $t01120511424._9
330+ let _positionId = $t01120511424._10
331+ let _limitPrice = $t01120511424._11
332+ if (if (if (!(initialized()))
333+ then true
334+ else !(isValid(_orderId)))
335+ then true
336+ else !((toString(i.caller) == _trader)))
337+ then throw("Invalid cancelOrder parameters")
338+ else {
339+ let newTraderOrderCount = (getTraderOrderCount(_amm, _trader) - 1)
340+ let withdraw = if ((_amountUsdn > 0))
341+ then {
342+ let unstake = invoke(managerAddress(), "withdraw", [toBase58String(quoteAsset()), _amountUsdn], nil)
343+ if ((unstake == unstake))
344+ then nil
345+ else throw("Strict value is not equal to itself.")
346+ }
347+ else nil
348+ if ((withdraw == withdraw))
349+ then ((markCancelOrder(_orderId) ++ updateTraderOrderCount(_amm, _trader, newTraderOrderCount)) ++ (if ((_amountUsdn > 0))
350+ then [ScriptTransfer(i.caller, _amountUsdn, quoteAsset())]
351+ else nil))
352+ else throw("Strict value is not equal to itself.")
353+ }
354+ }
355+
356+
357+
358+@Callable(i)
359+func executeOrder (_orderId) = {
360+ let $t01225712476 = getOrder(_orderId)
361+ let _amm = $t01225712476._1
362+ let _trader = $t01225712476._2
363+ let _amountIn = $t01225712476._3
364+ let _leverage = $t01225712476._4
365+ let _type = $t01225712476._5
366+ let _triggerPrice = $t01225712476._6
367+ let _amountUsdn = $t01225712476._7
368+ let _side = $t01225712476._8
369+ let _refLink = $t01225712476._9
370+ let _positionId = $t01225712476._10
371+ let _limitPrice = $t01225712476._11
372+ if (if (!(initialized()))
373+ then true
374+ else !(isValid(_orderId)))
375+ then throw("Invalid executeOrder parameters")
376+ else {
377+ let positionSize = getPositionSize(_amm, _trader)
378+ let currentPositionId = if ((positionSize != 0))
379+ then getPositionId(_amm, _trader)
380+ else 0
381+ let $t01280216623 = if ((_type == STOP))
382+ then {
383+ let _positionDirection = if ((positionSize > 0))
384+ then LONG
385+ else if ((0 > positionSize))
386+ then SHORT
387+ else throw("Can not execute STOP order: no open position")
388+ let marketPrice = getMarketPrice(_amm)
389+ let isExecutable = if ((_side == _positionDirection))
390+ then throw("Can not execute STOP order: reduce only")
391+ else if ((currentPositionId != _positionId))
392+ then throw("Can not execute STOP order: position closed")
393+ else if ((_positionDirection == LONG))
394+ then (_triggerPrice >= marketPrice)
395+ else (marketPrice >= _triggerPrice)
396+ if (isExecutable)
397+ then $Tuple3("closePosition", [minv(_amountIn, abs(positionSize)), muld(_limitPrice, abs(positionSize))], nil)
398+ else throw("Can not execute STOP order: triggerPrice mismatch")
399+ }
400+ else if ((_type == TAKE))
401+ then {
402+ let _positionDirection = if ((positionSize > 0))
403+ then LONG
404+ else if ((0 > positionSize))
405+ then SHORT
406+ else throw("Can not execute STOP order: no open position")
407+ let marketPrice = getMarketPrice(_amm)
408+ let isExecutable = if ((_side == _positionDirection))
409+ then throw("Can not execute TAKE order: reduce only")
410+ else if ((currentPositionId != _positionId))
411+ then throw(((("Can not execute TAKE order: position closed " + toString(currentPositionId)) + "!=") + toString(_positionId)))
412+ else if ((_positionDirection == LONG))
413+ then (marketPrice >= _triggerPrice)
414+ else (_triggerPrice >= marketPrice)
415+ if (isExecutable)
416+ then $Tuple3("closePosition", [minv(_amountIn, abs(positionSize)), muld(_limitPrice, abs(positionSize))], nil)
417+ else throw("Can not execute TAKE order: triggerPrice mismatch")
418+ }
419+ else if ((_type == LIMIT))
420+ then {
421+ let marketPrice = getMarketPrice(_amm)
422+ let spread = if ((_limitPrice == 0))
423+ then getSpread(_triggerPrice)
424+ else abs((_triggerPrice - _limitPrice))
425+ let isExecutable = if ((marketPrice >= (_triggerPrice - spread)))
426+ then ((_triggerPrice + spread) >= marketPrice)
427+ else false
428+ if (isExecutable)
429+ then {
430+ let _positionDirection = if ((positionSize > 0))
431+ then LONG
432+ else if ((0 > positionSize))
433+ then SHORT
434+ else -1
435+ let direction = if ((positionSize == 0))
436+ then INCREASE
437+ else if ((_positionDirection == _side))
438+ then INCREASE
439+ else DECREASE
440+ if ((direction == INCREASE))
441+ then {
442+ let amountInWithFee = (_amountUsdn - muld(_amountUsdn, getFee(_amm, _trader)))
443+ $Tuple3("increasePosition", [_side, _leverage, if ((_limitPrice == 0))
444+ then 0
445+ else divd(amountInWithFee, _limitPrice), _refLink], [AttachedPayment(quoteAsset(), _amountUsdn)])
446+ }
447+ else $Tuple3("closePosition", [_amountIn, muld(_amountIn, _limitPrice)], nil)
448+ }
449+ else throw("Can not execute LIMIT order: triggerPrice mismatch")
450+ }
451+ else throw(("Invalid order type: " + toString(_type)))
452+ let method = $t01280216623._1
453+ let args = $t01280216623._2
454+ let payments = $t01280216623._3
455+ let withdraw = if ((size(payments) == 1))
456+ then {
457+ let unstake = invoke(managerAddress(), "withdraw", [toBase58String(quoteAsset()), payments[0].amount], nil)
458+ if ((unstake == unstake))
459+ then nil
460+ else throw("Strict value is not equal to itself.")
461+ }
462+ else nil
463+ if ((withdraw == withdraw))
464+ then {
465+ let doSetContext = invoke(this, "setContext", [_trader], nil)
466+ if ((doSetContext == doSetContext))
467+ then {
468+ let doClosePosition = invoke(addressFromStringValue(_amm), method, args, payments)
469+ if ((doClosePosition == doClosePosition))
470+ then {
471+ let doResetContext = invoke(this, "resetContext", nil, nil)
472+ if ((doResetContext == doResetContext))
473+ then markExecuteOrder(_orderId)
474+ else throw("Strict value is not equal to itself.")
475+ }
476+ else throw("Strict value is not equal to itself.")
477+ }
478+ else throw("Strict value is not equal to itself.")
479+ }
480+ else throw("Strict value is not equal to itself.")
481+ }
482+ }
483+
484+
485+
486+@Callable(i)
487+func view_canExecuteOrder (_orderId) = {
488+ let s = invoke(this, "executeOrder", [_orderId], nil)
489+ if ((s == s))
490+ then throw("Success")
159491 else throw("Strict value is not equal to itself.")
160492 }
161493
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
8-let k_quoteAssetReserve = "k_qtAstR"
8+let k_quote_asset = "k_quote_asset"
99
10-let k_baseAssetReserve = "k_bsAstR"
10+let k_amm = "k_amm"
1111
12-let k_positionClosedDate = "k_positionClosedDate"
12+let k_manager_address = "k_manager_address"
13+
14+let k_positionSequence = "k_positionSequence"
15+
16+let k_positionSize = "k_positionSize"
17+
18+let k_fee = "k_fee"
1319
1420 let k_executedOrders = "k_executedOrders"
21+
22+let k_canceledOrders = "k_canceledOrders"
23+
24+let k_order = "k_order"
25+
26+let k_lastOrderId = "k_lastOrderId"
27+
28+let k_traderOrderCnt = "k_traderOrderCnt"
1529
1630 let k_sender = "k_sender"
1731
1832 let k_initialized = "k_initialized"
1933
20-let TAKE_PROFIT = 1
34+let STOP = 1
2135
22-let STOP_LOSS = 2
36+let TAKE = 2
37+
38+let LIMIT = 3
39+
40+let LONG = 1
41+
42+let SHORT = 2
43+
44+let INCREASE = 1
45+
46+let DECREASE = 2
47+
48+let MAX_TRADER_ORDERS_PER_AMM = 5
2349
2450 let TIME = lastBlock.timestamp
2551
2652 let DECIMAL_UNIT = (1 * (((((10 * 10) * 10) * 10) * 10) * 10))
53+
54+let SPREAD_LIMIT = (DECIMAL_UNIT / 200)
55+
56+func abs (_x) = if ((_x > 0))
57+ then _x
58+ else -(_x)
59+
2760
2861 func divd (_x,_y) = fraction(_x, DECIMAL_UNIT, _y, HALFEVEN)
2962
3063
3164 func muld (_x,_y) = fraction(_x, _y, DECIMAL_UNIT, HALFEVEN)
3265
3366
34-func executedOrderKey (_orderId) = ((k_executedOrders + "_") + _orderId)
67+func minv (_x,_y) = if ((_x > _y))
68+ then _y
69+ else _x
70+
71+
72+func toCompositeKey (_key,_address) = ((_key + "_") + _address)
73+
74+
75+func executedOrderKey (_orderId) = ((k_executedOrders + "_") + toString(_orderId))
76+
77+
78+func canceledOrderKey (_orderId) = ((k_canceledOrders + "_") + toString(_orderId))
79+
80+
81+func orderKey (_orderId) = toCompositeKey(k_order, toString(_orderId))
82+
83+
84+func traderOrderCountKey (_amm,_trader) = ((((k_traderOrderCnt + "_") + _amm) + "_") + _trader)
3585
3686
3787 func coordinator () = valueOrErrorMessage(addressFromString(getStringValue(this, k_coordinatorAddress)), "Coordinator not set")
88+
89+
90+func quoteAsset () = fromBase58String(getStringValue(coordinator(), k_quote_asset))
91+
92+
93+func managerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_manager_address)), "Manager not set")
94+
95+
96+func isWhitelist (_address) = valueOrElse(getBoolean(coordinator(), toCompositeKey(k_amm, _address)), false)
3897
3998
4099 func adminPublicKey () = fromBase58String(getStringValue(coordinator(), k_admin_public_key))
41100
42101
43102 func initialized () = valueOrElse(getBoolean(this, k_initialized), false)
44103
45104
46-func requireValidOrderSignature (_prefix,_order,_signature,_senderPublicKey) = {
47- let message = toBytes((_prefix + _order))
48- let sig = fromBase58String(_signature)
49- let pub = fromBase58String(_senderPublicKey)
50- if (sigVerify(message, sig, pub))
51- then unit
52- else throw("Invalid order signature")
105+func isValid (_orderId) = if (valueOrElse(getBoolean(this, executedOrderKey(_orderId)), false))
106+ then throw(("Order already executed: " + toString(_orderId)))
107+ else if (valueOrElse(getBoolean(this, canceledOrderKey(_orderId)), false))
108+ then throw(("Order already cancelled: " + toString(_orderId)))
109+ else true
110+
111+
112+func currentOrderId () = valueOrElse(getInteger(this, k_lastOrderId), 0)
113+
114+
115+func getTraderOrderCount (_amm,_trader) = {
116+ let key = traderOrderCountKey(_amm, _trader)
117+ valueOrElse(getInteger(this, key), 0)
53118 }
54119
55120
56-func requireNotExecuted (_orderId) = if (valueOrElse(getBoolean(this, executedOrderKey(_orderId)), false))
57- then throw(("Order already executed: " + _orderId))
58- else unit
121+func getOrder (_orderId) = {
122+ let orderStr = valueOrErrorMessage(getString(this, orderKey(_orderId)), ("Invalid order id: " + toString(_orderId)))
123+ let orderPartList = split(orderStr, ",")
124+ let amm = orderPartList[0]
125+ let trader = orderPartList[1]
126+ let amountIn = valueOrErrorMessage(parseInt(orderPartList[2]), "Invalid amountIn")
127+ let leverage = valueOrErrorMessage(parseInt(orderPartList[3]), "Invalid leverage")
128+ let type = valueOrErrorMessage(parseInt(orderPartList[4]), "Invalid type")
129+ let triggerPrice = valueOrErrorMessage(parseInt(orderPartList[5]), "Invalid triggerPrice")
130+ let paymentUsdn = valueOrErrorMessage(parseInt(orderPartList[6]), "Invalid paymentUsdn")
131+ let side = valueOrErrorMessage(parseInt(orderPartList[7]), "Invalid side")
132+ let refLink = orderPartList[8]
133+ let positionId = valueOrErrorMessage(parseInt(orderPartList[9]), "Invalid positionId")
134+ let limitPrice = valueOrErrorMessage(parseInt(orderPartList[10]), "Invalid limitPrice")
135+ $Tuple11(amm, trader, amountIn, leverage, type, triggerPrice, paymentUsdn, side, refLink, positionId, limitPrice)
136+ }
137+
138+
139+func getMarketPrice (_amm) = {
140+ let s = invoke(addressFromStringValue(_amm), "computeSpotPrice", nil, nil)
141+ if ((s == s))
142+ then {
143+ let res = match s {
144+ case t: Int =>
145+ t
146+ case _ =>
147+ throw("Invalid computeSpotPrice result")
148+ }
149+ value(res)
150+ }
151+ else throw("Strict value is not equal to itself.")
152+ }
153+
154+
155+func getFee (_amm,_trader) = {
156+ let s = invoke(addressFromStringValue(_amm), "computeFeeForTraderWithArtifact", [_trader, ""], nil)
157+ if ((s == s))
158+ then {
159+ let res = match s {
160+ case t: (Int, Boolean) =>
161+ t._1
162+ case _ =>
163+ throw("Invalid computeFeeForTraderWithArtifact result")
164+ }
165+ value(res)
166+ }
167+ else throw("Strict value is not equal to itself.")
168+ }
169+
170+
171+func getPositionSize (_amm,_trader) = {
172+ let amm = addressFromStringValue(_amm)
173+ let sizeKey = toCompositeKey(k_positionSize, _trader)
174+ valueOrElse(getInteger(amm, sizeKey), 0)
175+ }
176+
177+
178+func getPositionId (_amm,_trader) = {
179+ let amm = addressFromStringValue(_amm)
180+ let seqKey = toCompositeKey(k_positionSequence, _trader)
181+ valueOrElse(getInteger(amm, seqKey), 0)
182+ }
183+
184+
185+func getSpread (_price) = muld(_price, SPREAD_LIMIT)
186+
187+
188+func saveOrder (_orderId,_amm,_trader,_amountIn,_leverage,_type,_triggerPrice,_paymentUsdn,_side,_refLink,_positionId,_limitPrice) = {
189+ let orderStr = makeString([_amm, _trader, toString(_amountIn), toString(_leverage), toString(_type), toString(_triggerPrice), toString(_paymentUsdn), toString(_side), _refLink, toString(_positionId), toString(_limitPrice)], ",")
190+[StringEntry(orderKey(_orderId), orderStr)]
191+ }
192+
193+
194+func updateTraderOrderCount (_amm,_trader,_count) = [IntegerEntry(traderOrderCountKey(_amm, _trader), _count)]
195+
196+
197+func updateLastOrderId (_lastOrderId) = [IntegerEntry(k_lastOrderId, _lastOrderId)]
198+
199+
200+func markExecuteOrder (_orderId) = [BooleanEntry(toCompositeKey(k_executedOrders, toString(_orderId)), true)]
201+
202+
203+func markCancelOrder (_orderId) = [BooleanEntry(toCompositeKey(k_canceledOrders, toString(_orderId)), true)]
59204
60205
61206 @Callable(i)
62207 func setContext (_sender) = if ((i.caller != this))
63208 then throw("Only self-call")
64209 else [StringEntry(k_sender, _sender)]
65210
66211
67212
68213 @Callable(i)
69214 func resetContext () = if ((i.caller != this))
70215 then throw("Only self-call")
71216 else [DeleteEntry(k_sender)]
72217
73218
74219
75220 @Callable(i)
76221 func initialize (_coordinator) = if (initialized())
77222 then throw("Already initialized")
78223 else [StringEntry(k_coordinatorAddress, _coordinator), BooleanEntry(k_initialized, true)]
79224
80225
81226
82227 @Callable(i)
83-func executeOrder (_prefix,_order,_signature) = {
84- let orderParts = split(_order, ",")
85- let orderType = valueOrErrorMessage(parseInt(orderParts[0]), "Invalid order data [type]")
86- let orderId = toBase58String(sha256(toBytes(_order)))
87- let validateNotExecuted = requireNotExecuted(orderId)
88- if ((validateNotExecuted == validateNotExecuted))
89- then if (if ((orderType == TAKE_PROFIT))
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+ }
241+
242+
243+
244+@Callable(i)
245+func internalCreateOrder (_trader,_amm,_type,_triggerPrice,_limitPrice,_amountIn,_leverage,_side,_refLink,_paymentAssetId,_paymentAmount) = if (if (if (if (if (if (if (if (if (!(initialized()))
246+ then true
247+ else !(isWhitelist(_amm)))
248+ then true
249+ else (0 >= _triggerPrice))
250+ then true
251+ else (0 > _limitPrice))
252+ then true
253+ else (0 >= _amountIn))
254+ then true
255+ else (0 > _leverage))
256+ then true
257+ else !(if ((_side == LONG))
258+ then true
259+ else (_side == SHORT)))
260+ then true
261+ else !(if (if ((_type == STOP))
262+ then true
263+ else (_type == TAKE))
264+ then true
265+ else (_type == LIMIT)))
266+ then true
267+ else !((i.caller == this)))
268+ then throw("Invalid createOrder parameters")
269+ else {
270+ let orderId = (currentOrderId() + 1)
271+ let newTraderOrderCount = (getTraderOrderCount(_amm, _trader) + 1)
272+ let positionSize = getPositionSize(_amm, _trader)
273+ let _direction = if (if (if ((positionSize == 0))
90274 then true
91- else (orderType == STOP_LOSS))
92- then {
93- let amm = orderParts[1]
94- let senderPublicKey = orderParts[2]
95- let price = valueOrErrorMessage(parseInt(orderParts[3]), "Invalid order data [price]")
96- let timestamp = valueOrErrorMessage(parseInt(orderParts[4]), "Invalid order data [timestamp]")
97- let validDue = valueOrErrorMessage(parseInt(orderParts[5]), "Invalid order data [validDue]")
98- let validateSignature = requireValidOrderSignature(_prefix, _order, _signature, senderPublicKey)
99- if ((validateSignature == validateSignature))
275+ else if ((positionSize > 0))
276+ then (_side == LONG)
277+ else false)
278+ then true
279+ else if ((0 > positionSize))
280+ then (_side == SHORT)
281+ else false)
282+ then INCREASE
283+ else DECREASE
284+ if (if ((positionSize == 0))
285+ then if ((_type == STOP))
286+ then true
287+ else (_type == TAKE)
288+ else false)
289+ then throw("Can not create STOP/TAKE order: no position")
290+ else {
291+ let usdnPayment = if ((_direction == INCREASE))
292+ then if (if ((_paymentAssetId != toBase58String(quoteAsset())))
293+ then true
294+ else (_paymentAmount != _amountIn))
295+ then throw("Invalid createLimitOrder parameters: invalid payment")
296+ else {
297+ let stake = invoke(managerAddress(), "deposit", nil, [AttachedPayment(quoteAsset(), _paymentAmount)])
298+ if ((stake == stake))
299+ then _paymentAmount
300+ else throw("Strict value is not equal to itself.")
301+ }
302+ else 0
303+ if ((usdnPayment == usdnPayment))
100304 then {
101- let ammAddress = valueOrErrorMessage(addressFromString(amm), "Invalid order data [amm]")
102- let quoteAssetReserve = getIntegerValue(ammAddress, k_quoteAssetReserve)
103- let baseAssetReserve = getIntegerValue(ammAddress, k_baseAssetReserve)
104- let ammPrice = divd(quoteAssetReserve, baseAssetReserve)
105- let priceMatch = if ((orderType == TAKE_PROFIT))
106- then (ammPrice >= price)
107- else (price >= ammPrice)
108- let validatePrice = if (!(priceMatch))
109- then throw(((("Can not execute order [price]: AMM Price=" + toString(ammPrice)) + " Order Price=") + toString(price)))
110- else unit
111- if ((validatePrice == validatePrice))
112- then {
113- let dueMatch = if ((validDue == 0))
114- then true
115- else (validDue >= TIME)
116- let validateDue = if (!(dueMatch))
117- then throw(((("Can not execute order [due]: Due=" + toString(validDue)) + " Time=") + toString(TIME)))
118- else unit
119- if ((validateDue == validateDue))
120- then {
121- let traderAddress = toString(addressFromPublicKey(fromBase58String(senderPublicKey)))
122- let positionWasClosed = valueOrElse(getInteger(ammAddress, ((k_positionClosedDate + "_") + traderAddress)), 0)
123- let positionMatch = (timestamp >= positionWasClosed)
124- let validatePosition = if (!(positionMatch))
125- then throw(((("Can not execute order [position closed]: Order Created=" + toString(timestamp)) + " Position Closed=") + toString(positionWasClosed)))
126- else unit
127- if ((validatePosition == validatePosition))
128- then if (if (if (priceMatch)
129- then dueMatch
130- else false)
131- then positionMatch
132- else false)
133- then {
134- let doSetContext = invoke(this, "setContext", [traderAddress], nil)
135- if ((doSetContext == doSetContext))
136- then {
137- let doClosePosition = invoke(ammAddress, "closePosition", nil, nil)
138- if ((doClosePosition == doClosePosition))
139- then {
140- let doResetContext = invoke(this, "resetContext", nil, nil)
141- if ((doResetContext == doResetContext))
142- then [BooleanEntry(executedOrderKey(orderId), true)]
143- else throw("Strict value is not equal to itself.")
144- }
145- else throw("Strict value is not equal to itself.")
146- }
147- else throw("Strict value is not equal to itself.")
148- }
149- else throw("Invalid order execution timing")
150- else throw("Strict value is not equal to itself.")
151- }
152- else throw("Strict value is not equal to itself.")
153- }
154- else throw("Strict value is not equal to itself.")
305+ let positionId = if ((positionSize != 0))
306+ then getPositionId(_amm, _trader)
307+ else 0
308+ if ((newTraderOrderCount > MAX_TRADER_ORDERS_PER_AMM))
309+ then throw("Invalid createLimitOrder parameters: order count")
310+ else ((saveOrder(orderId, _amm, _trader, _amountIn, _leverage, _type, _triggerPrice, usdnPayment, _side, _refLink, positionId, _limitPrice) ++ updateTraderOrderCount(_amm, _trader, newTraderOrderCount)) ++ updateLastOrderId(orderId))
155311 }
156312 else throw("Strict value is not equal to itself.")
157313 }
158- else throw(("Invalid order type: " + toString(orderType)))
314+ }
315+
316+
317+
318+@Callable(i)
319+func cancelOrder (_orderId) = {
320+ let $t01120511424 = getOrder(_orderId)
321+ let _amm = $t01120511424._1
322+ let _trader = $t01120511424._2
323+ let _amountIn = $t01120511424._3
324+ let _leverage = $t01120511424._4
325+ let _type = $t01120511424._5
326+ let _triggerPrice = $t01120511424._6
327+ let _amountUsdn = $t01120511424._7
328+ let _side = $t01120511424._8
329+ let _refLink = $t01120511424._9
330+ let _positionId = $t01120511424._10
331+ let _limitPrice = $t01120511424._11
332+ if (if (if (!(initialized()))
333+ then true
334+ else !(isValid(_orderId)))
335+ then true
336+ else !((toString(i.caller) == _trader)))
337+ then throw("Invalid cancelOrder parameters")
338+ else {
339+ let newTraderOrderCount = (getTraderOrderCount(_amm, _trader) - 1)
340+ let withdraw = if ((_amountUsdn > 0))
341+ then {
342+ let unstake = invoke(managerAddress(), "withdraw", [toBase58String(quoteAsset()), _amountUsdn], nil)
343+ if ((unstake == unstake))
344+ then nil
345+ else throw("Strict value is not equal to itself.")
346+ }
347+ else nil
348+ if ((withdraw == withdraw))
349+ then ((markCancelOrder(_orderId) ++ updateTraderOrderCount(_amm, _trader, newTraderOrderCount)) ++ (if ((_amountUsdn > 0))
350+ then [ScriptTransfer(i.caller, _amountUsdn, quoteAsset())]
351+ else nil))
352+ else throw("Strict value is not equal to itself.")
353+ }
354+ }
355+
356+
357+
358+@Callable(i)
359+func executeOrder (_orderId) = {
360+ let $t01225712476 = getOrder(_orderId)
361+ let _amm = $t01225712476._1
362+ let _trader = $t01225712476._2
363+ let _amountIn = $t01225712476._3
364+ let _leverage = $t01225712476._4
365+ let _type = $t01225712476._5
366+ let _triggerPrice = $t01225712476._6
367+ let _amountUsdn = $t01225712476._7
368+ let _side = $t01225712476._8
369+ let _refLink = $t01225712476._9
370+ let _positionId = $t01225712476._10
371+ let _limitPrice = $t01225712476._11
372+ if (if (!(initialized()))
373+ then true
374+ else !(isValid(_orderId)))
375+ then throw("Invalid executeOrder parameters")
376+ else {
377+ let positionSize = getPositionSize(_amm, _trader)
378+ let currentPositionId = if ((positionSize != 0))
379+ then getPositionId(_amm, _trader)
380+ else 0
381+ let $t01280216623 = if ((_type == STOP))
382+ then {
383+ let _positionDirection = if ((positionSize > 0))
384+ then LONG
385+ else if ((0 > positionSize))
386+ then SHORT
387+ else throw("Can not execute STOP order: no open position")
388+ let marketPrice = getMarketPrice(_amm)
389+ let isExecutable = if ((_side == _positionDirection))
390+ then throw("Can not execute STOP order: reduce only")
391+ else if ((currentPositionId != _positionId))
392+ then throw("Can not execute STOP order: position closed")
393+ else if ((_positionDirection == LONG))
394+ then (_triggerPrice >= marketPrice)
395+ else (marketPrice >= _triggerPrice)
396+ if (isExecutable)
397+ then $Tuple3("closePosition", [minv(_amountIn, abs(positionSize)), muld(_limitPrice, abs(positionSize))], nil)
398+ else throw("Can not execute STOP order: triggerPrice mismatch")
399+ }
400+ else if ((_type == TAKE))
401+ then {
402+ let _positionDirection = if ((positionSize > 0))
403+ then LONG
404+ else if ((0 > positionSize))
405+ then SHORT
406+ else throw("Can not execute STOP order: no open position")
407+ let marketPrice = getMarketPrice(_amm)
408+ let isExecutable = if ((_side == _positionDirection))
409+ then throw("Can not execute TAKE order: reduce only")
410+ else if ((currentPositionId != _positionId))
411+ then throw(((("Can not execute TAKE order: position closed " + toString(currentPositionId)) + "!=") + toString(_positionId)))
412+ else if ((_positionDirection == LONG))
413+ then (marketPrice >= _triggerPrice)
414+ else (_triggerPrice >= marketPrice)
415+ if (isExecutable)
416+ then $Tuple3("closePosition", [minv(_amountIn, abs(positionSize)), muld(_limitPrice, abs(positionSize))], nil)
417+ else throw("Can not execute TAKE order: triggerPrice mismatch")
418+ }
419+ else if ((_type == LIMIT))
420+ then {
421+ let marketPrice = getMarketPrice(_amm)
422+ let spread = if ((_limitPrice == 0))
423+ then getSpread(_triggerPrice)
424+ else abs((_triggerPrice - _limitPrice))
425+ let isExecutable = if ((marketPrice >= (_triggerPrice - spread)))
426+ then ((_triggerPrice + spread) >= marketPrice)
427+ else false
428+ if (isExecutable)
429+ then {
430+ let _positionDirection = if ((positionSize > 0))
431+ then LONG
432+ else if ((0 > positionSize))
433+ then SHORT
434+ else -1
435+ let direction = if ((positionSize == 0))
436+ then INCREASE
437+ else if ((_positionDirection == _side))
438+ then INCREASE
439+ else DECREASE
440+ if ((direction == INCREASE))
441+ then {
442+ let amountInWithFee = (_amountUsdn - muld(_amountUsdn, getFee(_amm, _trader)))
443+ $Tuple3("increasePosition", [_side, _leverage, if ((_limitPrice == 0))
444+ then 0
445+ else divd(amountInWithFee, _limitPrice), _refLink], [AttachedPayment(quoteAsset(), _amountUsdn)])
446+ }
447+ else $Tuple3("closePosition", [_amountIn, muld(_amountIn, _limitPrice)], nil)
448+ }
449+ else throw("Can not execute LIMIT order: triggerPrice mismatch")
450+ }
451+ else throw(("Invalid order type: " + toString(_type)))
452+ let method = $t01280216623._1
453+ let args = $t01280216623._2
454+ let payments = $t01280216623._3
455+ let withdraw = if ((size(payments) == 1))
456+ then {
457+ let unstake = invoke(managerAddress(), "withdraw", [toBase58String(quoteAsset()), payments[0].amount], nil)
458+ if ((unstake == unstake))
459+ then nil
460+ else throw("Strict value is not equal to itself.")
461+ }
462+ else nil
463+ if ((withdraw == withdraw))
464+ then {
465+ let doSetContext = invoke(this, "setContext", [_trader], nil)
466+ if ((doSetContext == doSetContext))
467+ then {
468+ let doClosePosition = invoke(addressFromStringValue(_amm), method, args, payments)
469+ if ((doClosePosition == doClosePosition))
470+ then {
471+ let doResetContext = invoke(this, "resetContext", nil, nil)
472+ if ((doResetContext == doResetContext))
473+ then markExecuteOrder(_orderId)
474+ else throw("Strict value is not equal to itself.")
475+ }
476+ else throw("Strict value is not equal to itself.")
477+ }
478+ else throw("Strict value is not equal to itself.")
479+ }
480+ else throw("Strict value is not equal to itself.")
481+ }
482+ }
483+
484+
485+
486+@Callable(i)
487+func view_canExecuteOrder (_orderId) = {
488+ let s = invoke(this, "executeOrder", [_orderId], nil)
489+ if ((s == s))
490+ then throw("Success")
159491 else throw("Strict value is not equal to itself.")
160492 }
161493
162494
163495 @Verifier(tx)
164496 func verify () = sigVerify(tx.bodyBytes, tx.proofs[0], adminPublicKey())
165497

github/deemru/w8io/026f985 
49.53 ms