tx · 3tpZgRYUYK6YJFLPSpadCRBRZ1zSAocVHPiuLzpJEDiV

3PG2vMhK5CPqsCDodvLGzQ84QkoHXCJ3oNP:  -0.02500000 Waves

2022.08.08 11:05 [3240724] smart account 3PG2vMhK5CPqsCDodvLGzQ84QkoHXCJ3oNP > SELF 0.00000000 Waves

{ "type": 13, "id": "3tpZgRYUYK6YJFLPSpadCRBRZ1zSAocVHPiuLzpJEDiV", "fee": 2500000, "feeAssetId": null, "timestamp": 1659947840872, "version": 1, "sender": "3PG2vMhK5CPqsCDodvLGzQ84QkoHXCJ3oNP", "senderPublicKey": "5RM3w4ysmDbtgfswnVNPx7DQkNwVAG3RoxNFHgt6ToNU", "proofs": [ "", "4kpjcFoV4M58smSPr1Qny9LZdMhTMSNa559Nina8a81qBbfndLMXNwtQRCSydtuGNffQ8Ytbnww4ngndCswBW9E7", "", "5Ee5JhBuJ51XBSpfvN1wVb7b2Jjhsvad1KWktzFkaTcn1kDGTAzpcvzVMhTuJchgtSv3oTJYNBxqg976JNj1KDzb" ], "script": "base64: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eQAAAAAAAAAACgAAAAAUbk1ldHJpY0lkeFN1cmZTdXBwbHkAAAAAAAAAAAsAAAAADGJGdW5jSWR4U3VyZgAAAAAAAAAAAAAAAAANYkZ1bmNJZHhXYXZlcwAAAAAAAAAAAQAAAAAMYkZ1bmNJZHhVc2RuAAAAAAAAAAACAAAAABRiRnVuY0lkeFJlc2VydmVTdGFydAAAAAAAAAAAAwAAAAATYkZ1bmNJZHhTdXBwbHlTdGFydAAAAAAAAAAABAAAAAAPYkZ1bmNJZHhCUlN0YXJ0AAAAAAAAAAAFAAAAABJiRnVuY0lkeFJlc2VydmVFbmQAAAAAAAAAAAYAAAAAEWJGdW5jSWR4U3VwcGx5RW5kAAAAAAAAAAAHAAAAAA1iRnVuY0lkeEJSRW5kAAAAAAAAAAAIAAAAAAxiRnVuY0lkeFJlc3QAAAAAAAAAAAkAAAAAEmJGdW5jSWR4V2F2ZXNQcmljZQAAAAAAAAAACgAAAAAZSWR4Q29udHJvbENmZ05ldXRyaW5vRGFwcAAAAAAAAAAAAQAAAAAYSWR4Q29udHJvbENmZ0F1Y3Rpb25EYXBwAAAAAAAAAAACAAAAABRJZHhDb250cm9sQ2ZnUnBkRGFwcAAAAAAAAAAAAwAAAAAVSWR4Q29udHJvbENmZ01hdGhEYXBwAAAAAAAAAAAEAAAAABxJZHhDb250cm9sQ2ZnTGlxdWlkYXRpb25EYXBwAAAAAAAAAAAFAAAAABVJZHhDb250cm9sQ2ZnUmVzdERhcHAAAAAAAAAAAAYAAAAAHUlkeENvbnRyb2xDZmdOb2RlUmVnaXN0cnlEYXBwAAAAAAAAAAAHAAAAABxJZHhDb250cm9sQ2ZnTnNidFN0YWtpbmdEYXBwAAAAAAAAAAAIAAAAABlJZHhDb250cm9sQ2ZnTWVkaWF0b3JEYXBwAAAAAAAAAAAJAAAAABxJZHhDb250cm9sQ2ZnU3VyZlN0YWtpbmdEYXBwAAAAAAAAAAAKAAAAACBJZHhDb250cm9sQ2ZnR25zYnRDb250cm9sbGVyRGFwcAAAAAAAAAAACwEAAAAPZ2V0U3RyaW5nT3JGYWlsAAAAAgAAAAdhZGRyZXNzAAAAA2tleQkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEHQAAAAIFAAAAB2FkZHJlc3MFAAAAA2tleQkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACAgAAAAptYW5kYXRvcnkgCQAEJQAAAAEFAAAAB2FkZHJlc3MCAAAAAS4FAAAAA2tleQIAAAAPIGlzIG5vdCBkZWZpbmVkAQAAABFrZXlDb250cm9sQWRkcmVzcwAAAAACAAAAHCVzJXNfX2NvbmZpZ19fY29udHJvbEFkZHJlc3MBAAAADWtleUNvbnRyb2xDZmcAAAAAAgAAABElc19fY29udHJvbENvbmZpZwEAAAAUcmVhZENvbnRyb2xDZmdPckZhaWwAAAABAAAAB2NvbnRyb2wJAAS1AAAAAgkBAAAAD2dldFN0cmluZ09yRmFpbAAAAAIFAAAAB2NvbnRyb2wJAQAAAA1rZXlDb250cm9sQ2ZnAAAAAAUAAAADU0VQAQAAABhnZXRDb250cmFjdEFkZHJlc3NPckZhaWwAAAACAAAACmNvbnRyb2xDZmcAAAADaWR4CQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQmAAAAAQkAAZEAAAACBQAAAApjb250cm9sQ2ZnBQAAAANpZHgJAAEsAAAAAgIAAAAtQ29udHJvbCBjZmcgZG9lc24ndCBjb250YWluIGFkZHJlc3MgYXQgaW5kZXggCQABpAAAAAEFAAAAA2lkeAAAAAAPY29udHJvbENvbnRyYWN0CQEAAAARQGV4dHJOYXRpdmUoMTA2MikAAAABCQEAAAALdmFsdWVPckVsc2UAAAACCQAEHQAAAAIFAAAABHRoaXMJAQAAABFrZXlDb250cm9sQWRkcmVzcwAAAAACAAAAIzNQNUJmZDU4UFBmTnZCTTJIeThRZmJjRHFNZU50emc3S2ZQAAAAAApjb250cm9sQ2ZnCQEAAAAUcmVhZENvbnRyb2xDZmdPckZhaWwAAAABBQAAAA9jb250cm9sQ29udHJhY3QAAAAADG1hdGhDb250cmFjdAkBAAAAGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAAAAAIFAAAACmNvbnRyb2xDZmcFAAAAFUlkeENvbnRyb2xDZmdNYXRoRGFwcAAAAAAQbmV1dHJpbm9Db250cmFjdAkBAAAAGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAAAAAIFAAAACmNvbnRyb2xDZmcFAAAAGUlkeENvbnRyb2xDZmdOZXV0cmlub0RhcHAAAAAAE3N1cmZTdGFraW5nQ29udHJhY3QJAQAAABhnZXRDb250cmFjdEFkZHJlc3NPckZhaWwAAAACBQAAAApjb250cm9sQ2ZnBQAAABxJZHhDb250cm9sQ2ZnU3VyZlN0YWtpbmdEYXBwAAAAAAhQcmljZUtleQIAAAAFcHJpY2UAAAAADk5zYnRBc3NldElkS2V5AgAAAA1ib25kX2Fzc2V0X2lkAAAAABJOZXV0cmlub0Fzc2V0SWRLZXkCAAAAEW5ldXRyaW5vX2Fzc2V0X2lkAAAAAA5TdXJmQXNzZXRJZEtleQIAAAANc3VyZl9hc3NldF9pZAAAAAARQmFsYW5jZUxvY2tlZGtLZXkCAAAADWJhbGFuY2VfbG9ja18AAAAAFVdhdmVzTG9ja2VkQmFsYW5jZUtleQkAASwAAAACBQAAABFCYWxhbmNlTG9ja2Vka0tleQIAAAAFd2F2ZXMAAAAAGE5ldXRyaW5vTG9ja2VkQmFsYW5jZUtleQkAASwAAAACBQAAABFCYWxhbmNlTG9ja2Vka0tleQIAAAAIbmV1dHJpbm8AAAAADUZpcnN0T3JkZXJLZXkCAAAAC29yZGVyX2ZpcnN0AAAAAA9NYXRoQ29udHJhY3RLZXkCAAAADW1hdGhfY29udHJhY3QAAAAAFU1pbldhdmVzRm9yTnNidEJ1eUtleQIAAAASbWluX3dhdmVzX25zYnRfYnV5AAAAAA5NaW5Oc2J0U2VsbEtleQIAAAANbWluX25zYnRfc2VsbAAAAAAVTWluV2F2ZXNGb3JTdXJmQnV5S2V5AgAAABJtaW5fd2F2ZXNfc3VyZl9idXkAAAAAFE1pblVzZG5Gb3JTdXJmQnV5S2V5AgAAABFtaW5fdXNkbl9zdXJmX2J1eQEAAAASZ2V0Um9pQnlPcmRlcklkS2V5AAAAAQAAAAdvcmRlcklkCQABLAAAAAICAAAAEGRlYnVnX29yZGVyX3JvaV8FAAAAB29yZGVySWQBAAAAEGdldE9yZGVyUHJpY2VLZXkAAAABAAAAB29yZGVySWQJAAEsAAAAAgIAAAAMb3JkZXJfcHJpY2VfBQAAAAdvcmRlcklkAQAAABBnZXRPcmRlclRvdGFsS2V5AAAAAQAAAAdvcmRlcklkCQABLAAAAAICAAAADG9yZGVyX3RvdGFsXwUAAAAHb3JkZXJJZAEAAAAQZ2V0T3JkZXJPd25lcktleQAAAAEAAAAHb3JkZXJJZAkAASwAAAACAgAAAAxvcmRlcl9vd25lcl8FAAAAB29yZGVySWQBAAAAEWdldE9yZGVySGVpZ2h0S2V5AAAAAQAAAAdvcmRlcklkCQABLAAAAAICAAAADW9yZGVyX2hlaWdodF8FAAAAB29yZGVySWQBAAAAEWdldE9yZGVyU3RhdHVzS2V5AAAAAQAAAAdvcmRlcklkCQABLAAAAAICAAAADW9yZGVyX3N0YXR1c18FAAAAB29yZGVySWQBAAAAFmdldE9yZGVyRmlsbGVkVG90YWxLZXkAAAABAAAAB29yZGVySWQJAAEsAAAAAgIAAAATb3JkZXJfZmlsbGVkX3RvdGFsXwUAAAAHb3JkZXJJZAEAAAAPZ2V0UHJldk9yZGVyS2V5AAAAAQAAAAdvcmRlcklkCQABLAAAAAICAAAAC29yZGVyX3ByZXZfBQAAAAdvcmRlcklkAQAAAA9nZXROZXh0T3JkZXJLZXkAAAABAAAAB29yZGVySWQJAAEsAAAAAgIAAAALb3JkZXJfbmV4dF8FAAAAB29yZGVySWQBAAAAFmNvbnZlcnROZXV0cmlub1RvV2F2ZXMAAAACAAAABmFtb3VudAAAAAVwcmljZQkAAGsAAAADBQAAAAZhbW91bnQFAAAABU1VTFQ4BQAAAAVwcmljZQEAAAAWY29udmVydFdhdmVzVG9OZXV0cmlubwAAAAIAAAAGYW1vdW50AAAABXByaWNlCQAAawAAAAMFAAAABmFtb3VudAUAAAAFcHJpY2UFAAAABU1VTFQ4AQAAAAV0b1gxNgAAAAIAAAAHb3JpZ1ZhbAAAAA1vcmlnU2NhbGVNdWx0CQABPAAAAAMJAAE2AAAAAQUAAAAHb3JpZ1ZhbAUAAAAHTVVMVFgxNgkAATYAAAABBQAAAA1vcmlnU2NhbGVNdWx0AQAAAAdmcm9tWDE2AAAAAgAAAAN2YWwAAAAPcmVzdWx0U2NhbGVNdWx0CQABoAAAAAEJAAE8AAAAAwUAAAADdmFsCQABNgAAAAEFAAAAD3Jlc3VsdFNjYWxlTXVsdAUAAAAHTVVMVFgxNgAAAAAPbmV1dHJpbm9Bc3NldElkAQAAACC2JinDBPXOU5GkDkt1JC9kjFGx+t+vVCm9SNIdKrKq0QAAAAALbnNidEFzc2V0SWQBAAAAIFXuw76qC/BQ6HHIG6pucJ6kscj+Si65wfHMxWsPeJdLAAAAAAlpc0Jsb2NrZWQJAQAAABZnZXRCb29sQnlBZGRyZXNzQW5kS2V5AAAAAgUAAAAPY29udHJvbENvbnRyYWN0AgAAAAppc19ibG9ja2VkAAAAABVtaW5XYXZlc0Ftb3VudE5zYnRCdXkJAQAAAAt2YWx1ZU9yRWxzZQAAAAIJAAQaAAAAAgUAAAAEdGhpcwUAAAAVTWluV2F2ZXNGb3JOc2J0QnV5S2V5AAAAAAA7msoAAAAAAAttaW5Oc2J0U2VsbAkBAAAAC3ZhbHVlT3JFbHNlAAAAAgkABBoAAAACBQAAAAR0aGlzBQAAAA5NaW5Oc2J0U2VsbEtleQAAAAAAAA9CQAAAAAAVbWluV2F2ZXNBbW91bnRTdXJmQnV5CQEAAAALdmFsdWVPckVsc2UAAAACCQAEGgAAAAIFAAAABHRoaXMFAAAAFU1pbldhdmVzRm9yU3VyZkJ1eUtleQAAAAAABfXhAAAAAAAUbWluVXNkbkFtb3VudFN1cmZCdXkJAQAAAAt2YWx1ZU9yRWxzZQAAAAIJAAQaAAAAAgUAAAAEdGhpcwUAAAAUTWluVXNkbkZvclN1cmZCdXlLZXkAAAAAAACYloAAAAAACmZpcnN0T3JkZXIJAQAAAA5nZXRTdHJpbmdCeUtleQAAAAEFAAAADUZpcnN0T3JkZXJLZXkBAAAADWdldE9yZGVyUHJpY2UAAAABAAAAAmlkCQEAAAAOZ2V0TnVtYmVyQnlLZXkAAAABCQEAAAAQZ2V0T3JkZXJQcmljZUtleQAAAAEFAAAAAmlkAQAAAA1nZXRPcmRlclRvdGFsAAAAAQAAAAJpZAkBAAAADmdldE51bWJlckJ5S2V5AAAAAQkBAAAAEGdldE9yZGVyVG90YWxLZXkAAAABBQAAAAJpZAEAAAANZ2V0T3JkZXJPd25lcgAAAAEAAAACaWQJAQAAAA5nZXRTdHJpbmdCeUtleQAAAAEJAQAAABBnZXRPcmRlck93bmVyS2V5AAAAAQUAAAACaWQBAAAADmdldE9yZGVyU3RhdHVzAAAAAQAAAAJpZAkBAAAADmdldFN0cmluZ0J5S2V5AAAAAQkBAAAAEWdldE9yZGVyU3RhdHVzS2V5AAAAAQUAAAACaWQBAAAAE2dldE9yZGVyRmlsbGVkVG90YWwAAAABAAAAAmlkCQEAAAAOZ2V0TnVtYmVyQnlLZXkAAAABCQEAAAAWZ2V0T3JkZXJGaWxsZWRUb3RhbEtleQAAAAEFAAAAAmlkAQAAAAxnZXRQcmV2T3JkZXIAAAABAAAAAmlkCQEAAAAOZ2V0U3RyaW5nQnlLZXkAAAABCQEAAAAPZ2V0UHJldk9yZGVyS2V5AAAAAQUAAAACaWQBAAAADGdldE5leHRPcmRlcgAAAAEAAAACaWQJAQAAAA5nZXRTdHJpbmdCeUtleQAAAAEJAQAAAA9nZXROZXh0T3JkZXJLZXkAAAABBQAAAAJpZAEAAAAPZ2V0UmV2ZXJzZVByaWNlAAAAAQAAAAVwcmljZQkAAGkAAAACCQAAaAAAAAIFAAAABU1VTFQ2BQAAAAVNVUxUNgUAAAAFcHJpY2UBAAAAFmNhbGNOc2J0MldhdmVzUHJpY2VSYXcAAAACAAAADXNwZW50V2F2ZXNSYXcAAAAPcmVjZWl2ZWROc2J0UmF3CQABPAAAAAMJAAE2AAAAAQUAAAANc3BlbnRXYXZlc1JhdwkAATYAAAABCQAAaAAAAAIFAAAABU1VTFQ2BQAAAAVNVUxUNgkAATYAAAABBQAAAA9yZWNlaXZlZE5zYnRSYXcBAAAACW9yZGVyRGF0YQAAAAgAAAAHb3JkZXJJZAAAAA10b3RhbFdhdmVsZXRzAAAADmZpbGxlZFdhdmVsZXRzAAAABW93bmVyAAAABnN0YXR1cwAAAANyb2kAAAAFcHJpY2UAAAAMY3VycmVudFByaWNlCQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIJAQAAABBnZXRPcmRlclByaWNlS2V5AAAAAQUAAAAHb3JkZXJJZAkAAaYAAAABBQAAAAVwcmljZQkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgkBAAAAEGdldE9yZGVyVG90YWxLZXkAAAABBQAAAAdvcmRlcklkBQAAAA10b3RhbFdhdmVsZXRzCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAAWZ2V0T3JkZXJGaWxsZWRUb3RhbEtleQAAAAEFAAAA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AQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAADlN1cmZBc3NldElkS2V5CQACWAAAAAEFAAAAB2Fzc2V0SWQJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAAFU1pbldhdmVzRm9yU3VyZkJ1eUtleQUAAAAVbWluV2F2ZXNGb3JTdXJmQnV5S2V5CQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAABRNaW5Vc2RuRm9yU3VyZkJ1eUtleQUAAAAUbWluVXNkbkZvclN1cmZCdXlLZXkFAAAAA25pbAAAAAFpAQAAAAdidXlOc2J0AAAAAAQAAAADcG10CQEAAAAFdmFsdWUAAAABCQABkQAAAAIIBQAAAAFpAAAACHBheW1lbnRzAAAAAAAAAAAABAAAAAlwbXRBbW91bnQIBQAAAANwbXQAAAAGYW1vdW50BAAAAAh3YXZlc1BheQUAAAAJcG10QW1vdW50AwUAAAAJaXNCbG9ja2VkCQAAAgAAAAECAAAAWWNvbnRyYWN0IGlzIGJsb2NrZWQgYnkgRU1FUkdFTkNZIFNIVVRET1dOIGFjdGlvbnMgdW50aWwgcmVhY3RpdmF0aW9uIGJ5IGVtZXJnZW5jeSBvcmFjbGVzAwkBAAAACWlzRGVmaW5lZAAAAAEIBQAAAANwbXQAAAAHYXNzZXRJZAkAAAIAAAABAgAAABJjYW4gdXNlIHdhdmVzIG9ubHkDCQAAZgAAAAIFAAAAFW1pbldhdmVzQW1vdW50TnNidEJ1eQUAAAAJcG10QW1vdW50CQAAAgAAAAEJAAEsAAAAAgkAASwAAAACAgAAAARtaW4gCQABpAAAAAEJAABpAAAAAgUAAAAVbWluV2F2ZXNBbW91bnROc2J0QnV5BQAAAAVNVUxUOAIAAAAPIHdhdmVzIGV4cGVjdGVkBAAAAAxvd25lckFkZHJlc3MIBQAAAAFpAAAABmNhbGxlcgQAAAAPbmV1dHJpbm9NZXRyaWNzCQEAAAAJYXNBbnlMaXN0AAAAAQkAA/wAAAAEBQAAAAxtYXRoQ29udHJhY3QCAAAAGmNhbGNOZXV0aW5vTWV0cmljc1JFQURPTkxZBQAAAANuaWwFAAAAA25pbAQAAAAMY3VycmVudFByaWNlCQEAAAAFYXNJbnQAAAABCQABkQAAAAIFAAAAD25ldXRyaW5vTWV0cmljcwAAAAAAAAAAAAQAAAALY3VydmVSZXN1bHQJAQAAAAlhc0FueUxpc3QAAAABCQAD/AAAAAQFAAAADG1hdGhDb250cmFjdAIAAAAVY3VydmVGdW5jdGlvblJFQURPTkxZCQAETAAAAAIFAAAACHdhdmVzUGF5BQAAAANuaWwFAAAAA25pbAQAAAAKbnNidEFtb3VudAkBAAAABWFzSW50AAAAAQkAAZEAAAACBQAAAAtjdXJ2ZVJlc3VsdAAAAAAAAAAAAAMJAABnAAAAAgAAAAAAAAAAAAUAAAAKbnNidEFtb3VudAkAAAIAAAABAgAAAA9uc2J0QW1vdW50IDw9IDAEAAAAEm5zYnQyV2F2ZXNQcmljZVJhdwkBAAAAFmNhbGNOc2J0MldhdmVzUHJpY2VSYXcAAAACBQAAAAh3YXZlc1BheQUAAAAKbnNidEFtb3VudAQAAAADcm9pAAAAAAAAAAAABAAAAAxhbW91bnRMZWFzZWQJAAP8AAAABAUAAAAQbmV1dHJpbm9Db250cmFjdAIAAAALYWNjZXB0V2F2ZXMFAAAAA25pbAgFAAAAAWkAAAAIcGF5bWVudHMDCQAAAAAAAAIFAAAADGFtb3VudExlYXNlZAUAAAAMYW1vdW50TGVhc2VkCQAFFAAAAAIJAAROAAAAAgkBAAAACW9yZGVyRGF0YQAAAAgJAAJYAAAAAQgFAAAAAWkAAAANdHJhbnNhY3Rpb25JZAUAAAAJcG10QW1vdW50BQAAAAlwbXRBbW91bnQJAAQlAAAAAQUAAAAMb3duZXJBZGRyZXNzBQAAAAZGSUxMRUQFAAAAA3JvaQUAAAASbnNidDJXYXZlc1ByaWNlUmF3BQAAAAxjdXJyZW50UHJpY2UJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwUAAAAMb3duZXJBZGRyZXNzBQAAAApuc2J0QW1vdW50BQAAAAtuc2J0QXNzZXRJZAkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACAgAAABFkZWJ1Z19jdXJ2ZVJlc3VsdAkBAAAABXRvU3RyAAAAAgIAAAALY3VydmVSZXN1bHQFAAAAC2N1cnZlUmVzdWx0BQAAAANuaWwFAAAACm5zYnRBbW91bnQJAAACAAAAAQIAAAAkU3Ry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bnNmZXIAAAADCAUAAAABaQAAAAZjYWxsZXIFAAAABmFtb3VudAUAAAAEdW5pdAUAAAADbmlsAAAAAWkBAAAAIG1pbldhdmVzQW1vdW50TnNidEJ1eVNZU1JFQURPTkxZAAAAAAkABRQAAAACBQAAAANuaWwFAAAAFW1pbldhdmVzQW1vdW50TnNidEJ1eQAAAAFpAQAAAB9taW5Oc2J0QW1vdW50Rm9yU2VsbFNZU1JFQURPTkxZAAAAAAkABRQAAAACBQAAAANuaWwFAAAAC21pbk5zYnRTZWxsAAAAAWkBAAAAIG1pbldhdmVzQW1vdW50U3VyZkJ1eVNZU1JFQURPTkxZAAAAAAkABRQAAAACBQAAAANuaWwFAAAAFW1pbldhdmVzQW1vdW50U3VyZkJ1eQAAAAFpAQAAAB9taW5Vc2RuQW1vdW50U3VyZkJ1eVNZU1JFQURPTkxZAAAAAAkABRQAAAACBQAAAANuaWwFAAAAFG1pblVzZG5BbW91bnRTdXJmQnV5AAAAAWkBAAAAB2J1eVN1cmYAAAADAAAAEmF2ZXJhZ2VQcmljZVdhbnRlZAAAABBtYXhUb2xlcmFuY2VQZXJjAAAACWF1dG9TdGFrZQQAAAAMdGVzdEFjY291bnRzCQEAAAALdmFsdWVPckVsc2UAAAACCQAEHQAAAAIFAAAABHRoaXMCAAAADHRlc3RBY2NvdW50cwIAAAAAAwMJAQAAAAIhPQAAAAIFAAAADHRlc3RBY2NvdW50cwIAAAAACQEAAAABIQAAAAEJAQAAAAhjb250YWlucwAAAAIFAAAADHRlc3RBY2NvdW50cwkABCUAAAABCAUAAAABaQAAAAZjYWxsZXIHCQAAAgAAAAECAAAAMkJlIHBhdGllbnQhIE5lZWQgdG8gdGVzdCBpbiBtYWlubmV0IGJlZm9yZSBsYXVuY2guAwkBAAAAAiE9AAAAAgkAAZAAAAABCAUAAAABaQAAAAhwYXltZW50cwAAAAAAAAAAAQkAAAIAAAABAgAAACJleGFjdGx5IDEgcGF5bWVudCBtdXN0IGJlIGF0dGFjaGVkAwkAAGcAAAACAAAAAAAAAAAABQAAABJhdmVyYWdlUHJpY2VXYW50ZWQJAAACAAAAAQIAAAAlYXZlcmFnZVByaWNlV2FudGVkIHNob3VsZCBiZSBwb3Np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cmZBc3NldElkBQAAAApzdXJmQW1vdW50BQAAAANuaWwDCQAAAAAAAAIFAAAACnN0YWtpbmdJbnYFAAAACnN0YWtpbmdJbnYFAAAAA25pbAkAAAIAAAABAgAAACRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwgFAAAAAWkAAAAGY2FsbGVyBQAAAApzdXJmQW1vdW50BQAAAAtzdXJmQXNzZXRJZAUAAAADbmlsCQAETgAAAAIJAAROAAAAAgUAAAAIdHJhbnNmZXIJAARMAAAAAgkBAAAACHN1cmZEYXRhAAAAAQUAAAAKc3VyZlJlc3VsdAUAAAADbmlsBQAAAApzdXJmQWN0aW9uAAAAAWkBAAAACWlzc3VlU3VyZgAAAAEAAAAKc3VyZkFtb3VudAQAAAALc3VyZkFzc2V0SWQJAAJZAAAAAQkBAAAAEUBleHRyTmF0aXZlKDEwNTgpAAAAAQUAAAAOU3VyZkFzc2V0SWRLZXkDCQEAAAACIT0AAAACCAUAAAABaQAAAAZjYWxsZXIFAAAABHRoaXMJAAACAAAAAQIAAAAdaXNzdWVTdXJmIC0gcGVybWlzc2lvbiBkZW5pZWQJAAUUAAAAAgkABEwAAAACCQEAAAAHUmVpc3N1ZQAAAAMFAAAAC3N1cmZBc3NldElkBQAAAApzdXJmQW1vdW50BgUAAAADbmlsBQAAAAtzdXJmQXNzZXRJZAAAAAEAAAACdHgBAAAABnZlcmlmeQAAAAAEAAAAE3B1YktleUFkbWluc0xpc3RTdHIJAAS5AAAAAgkABEwAAAACAgAAACxHSmRMU2FMaXY1Szd4dWVqYWM4bWNSY0hveW8zZFByRVNydmt0RzNhNk1BUgkABEwAAAACAgAAACxFWXdabVVSZDVLS2FRUkJqc1ZhNmc4RFBpc0ZvUzZTb3ZSSnRGaUw1Z01IVQkABEwAAAACAgAAACxEdG1BZnVEZENySEs4c3BkQWVBWXpxNk1zWmVnZUQ5Z25zcnB1VFJrQ2JWQQkABEwAAAACAgAAACw1V1JYRlNqd2NUYk5mS2NKczhacVhtU1NXWXNTVkpVdE12TXFaajVoSDROYwUAAAADbmlsBQAAAANTRVAEAAAAEHB1YktleUFkbWluc0xpc3QJAAS1AAAAAgkBAAAAC3ZhbHVlT3JFbHNlAAAAAgkABB0AAAACBQAAAA9jb250cm9sQ29udHJhY3QCAAAADCVzX19tdWx0aXNpZwUAAAATcHViS2V5QWRtaW5zTGlzdFN0cgUAAAADU0VQBAAAAAVjb3VudAkAAGQAAAACCQAAZAAAAAIJAABkAAAAAgMJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAAACQACWQAAAAEJAAGRAAAAAgUAAAAQcHViS2V5QWRtaW5zTGlzdAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAMJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAABCQACWQAAAAEJAAGRAAAAAgUAAAAQcHViS2V5QWRtaW5zTGlzdAAAAAAAAAAAAQAAAAAAAAAAAQAAAAAAAAAAAAMJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAACCQACWQAAAAEJAAGRAAAAAgUAAAAQcHViS2V5QWRtaW5zTGlzdAAAAAAAAAAAAgAAAAAAAAAAAQAAAAAAAAAAAAMJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAADCQACWQAAAAEJAAGRAAAAAgUAAAAQcHViS2V5QWRtaW5zTGlzdAAAAAAAAAAAAwAAAAAAAAAAAgAAAAAAAAAAAAkAAGcAAAACBQAAAAVjb3VudAAAAAAAAAAAAyhuRw8=", "chainId": 87, "height": 3240724, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: BLYHoENqBHjCtC5mPbPu9p2HdCCQNUtxjmhb2WCZTXhR Next: 7Wf7d6yzqwj2VXbcsNLcSWSzBd6XGKQxuV8ZgEFkbWHp Diff:
OldNewDifferences
11 {-# STDLIB_VERSION 5 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4+let revisionNum = "cbd0bdc8bbba91db64066b16a84913a4c965e23e"
5+
46 func getNumberByKey (key) = valueOrElse(getInteger(this, key), 0)
57
68
4042 }
4143
4244
45+func asBytes (val) = match val {
46+ case valByte: ByteVector =>
47+ valByte
48+ case _ =>
49+ throw("fail to cast into Int")
50+}
51+
52+
4353 let SEP = "__"
4454
45-let WAVELET = 100000000
55+let MULT6 = 1000000
4656
47-let PAULI = 1000000
57+let MULT8 = 100000000
4858
49-let BIGPAULI = toBigInt(1000000)
59+let MULTX10 = toBigInt(10000000000)
5060
51-let PRICELET = 1000000
61+let MULTX12 = toBigInt(1000000000000)
5262
53-let MULT = 100000000
54-
55-let BIGMULT16 = toBigInt(10000000000000000)
56-
57-let SCALE8 = 8
58-
59-let SCALE16 = 16
60-
61-let MINORDERTOTAL = (10 * WAVELET)
62-
63-let MAXROI = 95
63+let MULTX16 = toBigInt(10000000000000000)
6464
6565 let CANCELED = "canceled"
6666
6767 let NEW = "new"
6868
6969 let FILLED = "filled"
70+
71+let WAVESID = fromBase58String("WAVES")
72+
73+let nMetricIdxPrice = 0
74+
75+let nMetricIdxUsdnLockedBalance = 1
76+
77+let nMetricIdxWavesLockedBalance = 2
78+
79+let nMetricIdxReserve = 3
80+
81+let nMetricIdxReserveInUsdn = 4
82+
83+let nMetricIdxUsdnSupply = 5
84+
85+let nMetricIdxSurplus = 6
86+
87+let nMetricIdxSurplusPercent = 7
88+
89+let nMetricIdxBR = 8
90+
91+let nMetricIdxNsbtSupply = 9
92+
93+let nMetricIdxMaxNsbtSupply = 10
94+
95+let nMetricIdxSurfSupply = 11
96+
97+let bFuncIdxSurf = 0
98+
99+let bFuncIdxWaves = 1
100+
101+let bFuncIdxUsdn = 2
102+
103+let bFuncIdxReserveStart = 3
104+
105+let bFuncIdxSupplyStart = 4
106+
107+let bFuncIdxBRStart = 5
108+
109+let bFuncIdxReserveEnd = 6
110+
111+let bFuncIdxSupplyEnd = 7
112+
113+let bFuncIdxBREnd = 8
114+
115+let bFuncIdxRest = 9
116+
117+let bFuncIdxWavesPrice = 10
118+
119+let IdxControlCfgNeutrinoDapp = 1
120+
121+let IdxControlCfgAuctionDapp = 2
122+
123+let IdxControlCfgRpdDapp = 3
124+
125+let IdxControlCfgMathDapp = 4
126+
127+let IdxControlCfgLiquidationDapp = 5
128+
129+let IdxControlCfgRestDapp = 6
130+
131+let IdxControlCfgNodeRegistryDapp = 7
132+
133+let IdxControlCfgNsbtStakingDapp = 8
134+
135+let IdxControlCfgMediatorDapp = 9
136+
137+let IdxControlCfgSurfStakingDapp = 10
138+
139+let IdxControlCfgGnsbtControllerDapp = 11
140+
141+func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), (((("mandatory " + toString(address)) + ".") + key) + " is not defined"))
142+
143+
144+func keyControlAddress () = "%s%s__config__controlAddress"
145+
146+
147+func keyControlCfg () = "%s__controlConfig"
148+
149+
150+func readControlCfgOrFail (control) = split(getStringOrFail(control, keyControlCfg()), SEP)
151+
152+
153+func getContractAddressOrFail (controlCfg,idx) = valueOrErrorMessage(addressFromString(controlCfg[idx]), ("Control cfg doesn't contain address at index " + toString(idx)))
154+
155+
156+let controlContract = addressFromStringValue(valueOrElse(getString(this, keyControlAddress()), "3P5Bfd58PPfNvBM2Hy8QfbcDqMeNtzg7KfP"))
157+
158+let controlCfg = readControlCfgOrFail(controlContract)
159+
160+let mathContract = getContractAddressOrFail(controlCfg, IdxControlCfgMathDapp)
161+
162+let neutrinoContract = getContractAddressOrFail(controlCfg, IdxControlCfgNeutrinoDapp)
163+
164+let surfStakingContract = getContractAddressOrFail(controlCfg, IdxControlCfgSurfStakingDapp)
70165
71166 let PriceKey = "price"
72167
121216 func getNextOrderKey (orderId) = ("order_next_" + orderId)
122217
123218
124-func convertNeutrinoToWaves (amount,price) = fraction(fraction(amount, PRICELET, price), WAVELET, PAULI)
219+func convertNeutrinoToWaves (amount,price) = fraction(amount, MULT8, price)
125220
126221
127-func convertWavesToNeutrino (amount,price) = fraction(fraction(amount, price, PRICELET), PAULI, WAVELET)
222+func convertWavesToNeutrino (amount,price) = fraction(amount, price, MULT8)
128223
129224
130-func convertWavesToBond (amount,price) = convertWavesToNeutrino(amount, price)
225+func toX16 (origVal,origScaleMult) = fraction(toBigInt(origVal), MULTX16, toBigInt(origScaleMult))
131226
132227
133-func convertBondToWaves (amount,price) = convertNeutrinoToWaves(amount, price)
228+func fromX16 (val,resultScaleMult) = toInt(fraction(val, toBigInt(resultScaleMult), MULTX16))
134229
135-
136-func toX16 (origVal,origScaleMult) = fraction(toBigInt(origVal), BIGMULT16, toBigInt(origScaleMult))
137-
138-
139-func fromX16 (val,resultScaleMult) = toInt(fraction(val, toBigInt(resultScaleMult), BIGMULT16))
140-
141-
142-let neutrinoContract = Address(base58'3PC9BfRwJWWiw9AREE2B3eWzCks3CYtg4yo')
143-
144-let controlContract = Address(base58'3P5Bfd58PPfNvBM2Hy8QfbcDqMeNtzg7KfP')
145-
146-let liquidationContract = Address(base58'3P4PCxsJqMzQBALo8zANHtBDZRRquobHQp7')
147-
148-let mathContract = addressFromStringValue(getStringByKey(MathContractKey))
149230
150231 let neutrinoAssetId = base58'DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p'
151232
156237 let minWavesAmountNsbtBuy = valueOrElse(getInteger(this, MinWavesForNsbtBuyKey), 1000000000)
157238
158239 let minNsbtSell = valueOrElse(getInteger(this, MinNsbtSellKey), 1000000)
240+
241+let minWavesAmountSurfBuy = valueOrElse(getInteger(this, MinWavesForSurfBuyKey), 100000000)
242+
243+let minUsdnAmountSurfBuy = valueOrElse(getInteger(this, MinUsdnForSurfBuyKey), 10000000)
159244
160245 let firstOrder = getStringByKey(FirstOrderKey)
161246
180265 func getNextOrder (id) = getStringByKey(getNextOrderKey(id))
181266
182267
183-func getReversePrice (price) = ((PRICELET * PRICELET) / price)
268+func getReversePrice (price) = ((MULT6 * MULT6) / price)
184269
185270
186-func calcNsbt2WavesPriceRaw (spentWavesRaw,receivedNsbtRaw) = fraction(toBigInt(spentWavesRaw), toBigInt((PAULI * PRICELET)), toBigInt(receivedNsbtRaw))
271+func calcNsbt2WavesPriceRaw (spentWavesRaw,receivedNsbtRaw) = fraction(toBigInt(spentWavesRaw), toBigInt((MULT6 * MULT6)), toBigInt(receivedNsbtRaw))
187272
188273
189274 func orderData (orderId,totalWavelets,filledWavelets,owner,status,roi,price,currentPrice) = [StringEntry(getOrderPriceKey(orderId), toString(price)), IntegerEntry(getOrderTotalKey(orderId), totalWavelets), IntegerEntry(getOrderFilledTotalKey(orderId), filledWavelets), StringEntry(getOrderOwnerKey(orderId), owner), IntegerEntry(getOrderHeightKey(orderId), height), StringEntry(getOrderStatusKey(orderId), status), IntegerEntry(("debug_order_currentPrice_" + orderId), currentPrice), IntegerEntry(getRoiByOrderIdKey(orderId), roi)]
190275
191276
192277 func toStr (name,curveResult) = (((((((((((((((((((((((((((((((((((name + "[nsbtAmountRaw=") + toString(asInt(curveResult[0]))) + " usdnPayment=") + toString(asInt(curveResult[1]))) + " wRaw=") + toString(asInt(curveResult[2]))) + " uRaw=") + toString(asInt(curveResult[3]))) + " mRaw=") + toString(asInt(curveResult[4]))) + " sRaw=") + toString(asInt(curveResult[5]))) + " nsbtCurveParam_a=") + toString(asInt(curveResult[6]))) + " nsbtCurveParam_b=") + toString(asInt(curveResult[7]))) + " wReservesInUsdn=") + toString(asInt(curveResult[8]))) + " price=") + toString(asInt(curveResult[9]))) + " multBR=") + toString(asInt(curveResult[10]))) + " multPower=") + toString(asInt(curveResult[11]))) + " multExpInPower=") + asString(curveResult[12])) + " multK=") + asString(curveResult[13])) + " step1=") + asString(curveResult[14])) + " step2=") + asString(curveResult[15])) + " step3=") + toString(asInt(curveResult[16]))) + "]")
278+
279+
280+func surfData (surfResult) = StringEntry("debug_surfResult", makeString(["%d%d%d%d%d%d%d%d%d%d%d", toString(asInt(surfResult[bFuncIdxSurf])), toString(asInt(surfResult[bFuncIdxWaves])), toString(asInt(surfResult[bFuncIdxUsdn])), toString(asInt(surfResult[bFuncIdxReserveStart])), toString(asInt(surfResult[bFuncIdxSupplyStart])), toString(asInt(surfResult[bFuncIdxBRStart])), toString(asInt(surfResult[bFuncIdxReserveEnd])), toString(asInt(surfResult[bFuncIdxSupplyEnd])), toString(asInt(surfResult[bFuncIdxBREnd])), toString(asInt(surfResult[bFuncIdxRest])), toString(asInt(surfResult[bFuncIdxWavesPrice]))], SEP))
193281
194282
195283 @Callable(i)
220308 else if (isDefined(pmt.assetId))
221309 then throw("can use waves only")
222310 else if ((minWavesAmountNsbtBuy > pmtAmount))
223- then throw((("min " + toString((minWavesAmountNsbtBuy / WAVELET))) + " waves expected"))
311+ then throw((("min " + toString((minWavesAmountNsbtBuy / MULT8))) + " waves expected"))
224312 else {
225313 let ownerAddress = i.caller
226314 let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
251339 if ((pmt.assetId != nsbtAssetId))
252340 then throw("can use NSBT only")
253341 else if ((minNsbtSell > pmtAmount))
254- then throw((("min " + toString((minNsbtSell / PAULI))) + " nsbt expected"))
342+ then throw((("min " + toString((minNsbtSell / MULT6))) + " nsbt expected"))
255343 else {
256344 let newPrice = asInt(asAnyList(invoke(mathContract, "calcContractNsbtPriceSYSREADONLY", [-(pmtAmount)], nil))[0])
257- if ((PAULI > newPrice))
345+ if ((MULT6 > newPrice))
258346 then throw((("resulting nsbt price would be < 1 (" + toString(newPrice)) + " usdn)"))
259347 else {
260348 let transf = invoke(neutrinoContract, "transferUsdnToUser", [pmtAmount, toString(i.caller)], nil)
292380 func minNsbtAmountForSellSYSREADONLY () = $Tuple2(nil, minNsbtSell)
293381
294382
383+
384+@Callable(i)
385+func minWavesAmountSurfBuySYSREADONLY () = $Tuple2(nil, minWavesAmountSurfBuy)
386+
387+
388+
389+@Callable(i)
390+func minUsdnAmountSurfBuySYSREADONLY () = $Tuple2(nil, minUsdnAmountSurfBuy)
391+
392+
393+
394+@Callable(i)
395+func buySurf (averagePriceWanted,maxTolerancePerc,autoStake) = {
396+ let testAccounts = valueOrElse(getString(this, "testAccounts"), "")
397+ if (if ((testAccounts != ""))
398+ then !(contains(testAccounts, toString(i.caller)))
399+ else false)
400+ then throw("Be patient! Need to test in mainnet before launch.")
401+ else if ((size(i.payments) != 1))
402+ then throw("exactly 1 payment must be attached")
403+ else if ((0 >= averagePriceWanted))
404+ then throw("averagePriceWanted should be positive")
405+ else if ((0 >= maxTolerancePerc))
406+ then throw("maxTolerancePerc should be positive")
407+ else {
408+ let pmt = i.payments[0]
409+ let amt = pmt.amount
410+ let pmtAssetId = valueOrElse(pmt.assetId, WAVESID)
411+ if (if ((pmtAssetId != neutrinoAssetId))
412+ then (pmtAssetId != WAVESID)
413+ else false)
414+ then throw("Unsupported payment asset")
415+ else if (if ((pmtAssetId == neutrinoAssetId))
416+ then (minUsdnAmountSurfBuy > amt)
417+ else false)
418+ then throw((("min " + toString((minUsdnAmountSurfBuy / MULT6))) + " USDN expected"))
419+ else if (if ((pmtAssetId == WAVESID))
420+ then (minWavesAmountSurfBuy > amt)
421+ else false)
422+ then throw((("min " + toString((minWavesAmountSurfBuy / MULT8))) + " WAVES expected"))
423+ else {
424+ let surfResult = asAnyList(invoke(mathContract, "surfFunctionREADONLY", [amt, pmtAssetId], nil))
425+ let spentWaves = asInt(surfResult[bFuncIdxWaves])
426+ let spentUsdn = asInt(surfResult[bFuncIdxUsdn])
427+ let surfAmount = asInt(surfResult[bFuncIdxSurf])
428+ let surfAmountX6 = toBigInt(surfAmount)
429+ let spentActualX18 = if ((pmtAssetId == WAVESID))
430+ then (toBigInt(spentWaves) * MULTX10)
431+ else (toBigInt(spentUsdn) * MULTX12)
432+ if ((spentActualX18 > ((toBigInt((maxTolerancePerc + MULT6)) * toBigInt(averagePriceWanted)) * surfAmountX6)))
433+ then throw((((((("Tolerance " + toString(maxTolerancePerc)) + " exceeded: spent ") + (if ((pmtAssetId == WAVESID))
434+ then (toString(spentWaves) + " WAVES")
435+ else (toString(spentUsdn) + " USDN"))) + " for ") + toString(surfAmount)) + " SURF"))
436+ else {
437+ let rest = asInt(surfResult[bFuncIdxRest])
438+ let transfer = if ((pmtAssetId == WAVESID))
439+ then {
440+ let wavesAmt = invoke(neutrinoContract, "acceptWaves", nil, [AttachedPayment(unit, (amt - rest))])
441+ if ((wavesAmt == wavesAmt))
442+ then if ((rest > 0))
443+ then [ScriptTransfer(i.caller, rest, unit)]
444+ else nil
445+ else throw("Strict value is not equal to itself.")
446+ }
447+ else if ((rest > 0))
448+ then [ScriptTransfer(neutrinoContract, (amt - rest), neutrinoAssetId), ScriptTransfer(i.caller, rest, neutrinoAssetId)]
449+ else [ScriptTransfer(neutrinoContract, (amt - rest), neutrinoAssetId)]
450+ let surfAssetId = asBytes(invoke(this, "issueSurf", [surfAmount], nil))
451+ let surfAction = if (autoStake)
452+ then {
453+ let stakingInv = invoke(surfStakingContract, "stakeByOriginCaller", nil, [AttachedPayment(surfAssetId, surfAmount)])
454+ if ((stakingInv == stakingInv))
455+ then nil
456+ else throw("Strict value is not equal to itself.")
457+ }
458+ else [ScriptTransfer(i.caller, surfAmount, surfAssetId)]
459+ ((transfer ++ [surfData(surfResult)]) ++ surfAction)
460+ }
461+ }
462+ }
463+ }
464+
465+
466+
467+@Callable(i)
468+func issueSurf (surfAmount) = {
469+ let surfAssetId = fromBase58String(getStringValue(SurfAssetIdKey))
470+ if ((i.caller != this))
471+ then throw("issueSurf - permission denied")
472+ else $Tuple2([Reissue(surfAssetId, surfAmount, true)], surfAssetId)
473+ }
474+
475+
295476 @Verifier(tx)
296477 func verify () = {
297478 let pubKeyAdminsListStr = makeString(["GJdLSaLiv5K7xuejac8mcRcHoyo3dPrESrvktG3a6MAR", "EYwZmURd5KKaQRBjsVa6g8DPisFoS6SovRJtFiL5gMHU", "DtmAfuDdCrHK8spdAeAYzq6MsZegeD9gnsrpuTRkCbVA", "5WRXFSjwcTbNfKcJs8ZqXmSSWYsSVJUtMvMqZj5hH4Nc"], SEP)
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 5 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4+let revisionNum = "cbd0bdc8bbba91db64066b16a84913a4c965e23e"
5+
46 func getNumberByKey (key) = valueOrElse(getInteger(this, key), 0)
57
68
79 func getStringByKey (key) = valueOrElse(getString(this, key), "")
810
911
1012 func getBoolByAddressAndKey (address,key) = valueOrElse(getBoolean(address, key), false)
1113
1214
1315 func getStringByAddressAndKey (address,key) = valueOrElse(getString(address, key), "")
1416
1517
1618 func getNumberByAddressAndKey (address,key) = valueOrElse(getInteger(address, key), 0)
1719
1820
1921 func asAnyList (val) = match val {
2022 case valAnyLyst: List[Any] =>
2123 valAnyLyst
2224 case _ =>
2325 throw("fail to cast into List[Any]")
2426 }
2527
2628
2729 func asString (val) = match val {
2830 case valStr: String =>
2931 valStr
3032 case _ =>
3133 throw("fail to cast into String")
3234 }
3335
3436
3537 func asInt (val) = match val {
3638 case valInt: Int =>
3739 valInt
3840 case _ =>
3941 throw("fail to cast into Int")
4042 }
4143
4244
45+func asBytes (val) = match val {
46+ case valByte: ByteVector =>
47+ valByte
48+ case _ =>
49+ throw("fail to cast into Int")
50+}
51+
52+
4353 let SEP = "__"
4454
45-let WAVELET = 100000000
55+let MULT6 = 1000000
4656
47-let PAULI = 1000000
57+let MULT8 = 100000000
4858
49-let BIGPAULI = toBigInt(1000000)
59+let MULTX10 = toBigInt(10000000000)
5060
51-let PRICELET = 1000000
61+let MULTX12 = toBigInt(1000000000000)
5262
53-let MULT = 100000000
54-
55-let BIGMULT16 = toBigInt(10000000000000000)
56-
57-let SCALE8 = 8
58-
59-let SCALE16 = 16
60-
61-let MINORDERTOTAL = (10 * WAVELET)
62-
63-let MAXROI = 95
63+let MULTX16 = toBigInt(10000000000000000)
6464
6565 let CANCELED = "canceled"
6666
6767 let NEW = "new"
6868
6969 let FILLED = "filled"
70+
71+let WAVESID = fromBase58String("WAVES")
72+
73+let nMetricIdxPrice = 0
74+
75+let nMetricIdxUsdnLockedBalance = 1
76+
77+let nMetricIdxWavesLockedBalance = 2
78+
79+let nMetricIdxReserve = 3
80+
81+let nMetricIdxReserveInUsdn = 4
82+
83+let nMetricIdxUsdnSupply = 5
84+
85+let nMetricIdxSurplus = 6
86+
87+let nMetricIdxSurplusPercent = 7
88+
89+let nMetricIdxBR = 8
90+
91+let nMetricIdxNsbtSupply = 9
92+
93+let nMetricIdxMaxNsbtSupply = 10
94+
95+let nMetricIdxSurfSupply = 11
96+
97+let bFuncIdxSurf = 0
98+
99+let bFuncIdxWaves = 1
100+
101+let bFuncIdxUsdn = 2
102+
103+let bFuncIdxReserveStart = 3
104+
105+let bFuncIdxSupplyStart = 4
106+
107+let bFuncIdxBRStart = 5
108+
109+let bFuncIdxReserveEnd = 6
110+
111+let bFuncIdxSupplyEnd = 7
112+
113+let bFuncIdxBREnd = 8
114+
115+let bFuncIdxRest = 9
116+
117+let bFuncIdxWavesPrice = 10
118+
119+let IdxControlCfgNeutrinoDapp = 1
120+
121+let IdxControlCfgAuctionDapp = 2
122+
123+let IdxControlCfgRpdDapp = 3
124+
125+let IdxControlCfgMathDapp = 4
126+
127+let IdxControlCfgLiquidationDapp = 5
128+
129+let IdxControlCfgRestDapp = 6
130+
131+let IdxControlCfgNodeRegistryDapp = 7
132+
133+let IdxControlCfgNsbtStakingDapp = 8
134+
135+let IdxControlCfgMediatorDapp = 9
136+
137+let IdxControlCfgSurfStakingDapp = 10
138+
139+let IdxControlCfgGnsbtControllerDapp = 11
140+
141+func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), (((("mandatory " + toString(address)) + ".") + key) + " is not defined"))
142+
143+
144+func keyControlAddress () = "%s%s__config__controlAddress"
145+
146+
147+func keyControlCfg () = "%s__controlConfig"
148+
149+
150+func readControlCfgOrFail (control) = split(getStringOrFail(control, keyControlCfg()), SEP)
151+
152+
153+func getContractAddressOrFail (controlCfg,idx) = valueOrErrorMessage(addressFromString(controlCfg[idx]), ("Control cfg doesn't contain address at index " + toString(idx)))
154+
155+
156+let controlContract = addressFromStringValue(valueOrElse(getString(this, keyControlAddress()), "3P5Bfd58PPfNvBM2Hy8QfbcDqMeNtzg7KfP"))
157+
158+let controlCfg = readControlCfgOrFail(controlContract)
159+
160+let mathContract = getContractAddressOrFail(controlCfg, IdxControlCfgMathDapp)
161+
162+let neutrinoContract = getContractAddressOrFail(controlCfg, IdxControlCfgNeutrinoDapp)
163+
164+let surfStakingContract = getContractAddressOrFail(controlCfg, IdxControlCfgSurfStakingDapp)
70165
71166 let PriceKey = "price"
72167
73168 let NsbtAssetIdKey = "bond_asset_id"
74169
75170 let NeutrinoAssetIdKey = "neutrino_asset_id"
76171
77172 let SurfAssetIdKey = "surf_asset_id"
78173
79174 let BalanceLockedkKey = "balance_lock_"
80175
81176 let WavesLockedBalanceKey = (BalanceLockedkKey + "waves")
82177
83178 let NeutrinoLockedBalanceKey = (BalanceLockedkKey + "neutrino")
84179
85180 let FirstOrderKey = "order_first"
86181
87182 let MathContractKey = "math_contract"
88183
89184 let MinWavesForNsbtBuyKey = "min_waves_nsbt_buy"
90185
91186 let MinNsbtSellKey = "min_nsbt_sell"
92187
93188 let MinWavesForSurfBuyKey = "min_waves_surf_buy"
94189
95190 let MinUsdnForSurfBuyKey = "min_usdn_surf_buy"
96191
97192 func getRoiByOrderIdKey (orderId) = ("debug_order_roi_" + orderId)
98193
99194
100195 func getOrderPriceKey (orderId) = ("order_price_" + orderId)
101196
102197
103198 func getOrderTotalKey (orderId) = ("order_total_" + orderId)
104199
105200
106201 func getOrderOwnerKey (orderId) = ("order_owner_" + orderId)
107202
108203
109204 func getOrderHeightKey (orderId) = ("order_height_" + orderId)
110205
111206
112207 func getOrderStatusKey (orderId) = ("order_status_" + orderId)
113208
114209
115210 func getOrderFilledTotalKey (orderId) = ("order_filled_total_" + orderId)
116211
117212
118213 func getPrevOrderKey (orderId) = ("order_prev_" + orderId)
119214
120215
121216 func getNextOrderKey (orderId) = ("order_next_" + orderId)
122217
123218
124-func convertNeutrinoToWaves (amount,price) = fraction(fraction(amount, PRICELET, price), WAVELET, PAULI)
219+func convertNeutrinoToWaves (amount,price) = fraction(amount, MULT8, price)
125220
126221
127-func convertWavesToNeutrino (amount,price) = fraction(fraction(amount, price, PRICELET), PAULI, WAVELET)
222+func convertWavesToNeutrino (amount,price) = fraction(amount, price, MULT8)
128223
129224
130-func convertWavesToBond (amount,price) = convertWavesToNeutrino(amount, price)
225+func toX16 (origVal,origScaleMult) = fraction(toBigInt(origVal), MULTX16, toBigInt(origScaleMult))
131226
132227
133-func convertBondToWaves (amount,price) = convertNeutrinoToWaves(amount, price)
228+func fromX16 (val,resultScaleMult) = toInt(fraction(val, toBigInt(resultScaleMult), MULTX16))
134229
135-
136-func toX16 (origVal,origScaleMult) = fraction(toBigInt(origVal), BIGMULT16, toBigInt(origScaleMult))
137-
138-
139-func fromX16 (val,resultScaleMult) = toInt(fraction(val, toBigInt(resultScaleMult), BIGMULT16))
140-
141-
142-let neutrinoContract = Address(base58'3PC9BfRwJWWiw9AREE2B3eWzCks3CYtg4yo')
143-
144-let controlContract = Address(base58'3P5Bfd58PPfNvBM2Hy8QfbcDqMeNtzg7KfP')
145-
146-let liquidationContract = Address(base58'3P4PCxsJqMzQBALo8zANHtBDZRRquobHQp7')
147-
148-let mathContract = addressFromStringValue(getStringByKey(MathContractKey))
149230
150231 let neutrinoAssetId = base58'DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p'
151232
152233 let nsbtAssetId = base58'6nSpVyNH7yM69eg446wrQR94ipbbcmZMU1ENPwanC97g'
153234
154235 let isBlocked = getBoolByAddressAndKey(controlContract, "is_blocked")
155236
156237 let minWavesAmountNsbtBuy = valueOrElse(getInteger(this, MinWavesForNsbtBuyKey), 1000000000)
157238
158239 let minNsbtSell = valueOrElse(getInteger(this, MinNsbtSellKey), 1000000)
240+
241+let minWavesAmountSurfBuy = valueOrElse(getInteger(this, MinWavesForSurfBuyKey), 100000000)
242+
243+let minUsdnAmountSurfBuy = valueOrElse(getInteger(this, MinUsdnForSurfBuyKey), 10000000)
159244
160245 let firstOrder = getStringByKey(FirstOrderKey)
161246
162247 func getOrderPrice (id) = getNumberByKey(getOrderPriceKey(id))
163248
164249
165250 func getOrderTotal (id) = getNumberByKey(getOrderTotalKey(id))
166251
167252
168253 func getOrderOwner (id) = getStringByKey(getOrderOwnerKey(id))
169254
170255
171256 func getOrderStatus (id) = getStringByKey(getOrderStatusKey(id))
172257
173258
174259 func getOrderFilledTotal (id) = getNumberByKey(getOrderFilledTotalKey(id))
175260
176261
177262 func getPrevOrder (id) = getStringByKey(getPrevOrderKey(id))
178263
179264
180265 func getNextOrder (id) = getStringByKey(getNextOrderKey(id))
181266
182267
183-func getReversePrice (price) = ((PRICELET * PRICELET) / price)
268+func getReversePrice (price) = ((MULT6 * MULT6) / price)
184269
185270
186-func calcNsbt2WavesPriceRaw (spentWavesRaw,receivedNsbtRaw) = fraction(toBigInt(spentWavesRaw), toBigInt((PAULI * PRICELET)), toBigInt(receivedNsbtRaw))
271+func calcNsbt2WavesPriceRaw (spentWavesRaw,receivedNsbtRaw) = fraction(toBigInt(spentWavesRaw), toBigInt((MULT6 * MULT6)), toBigInt(receivedNsbtRaw))
187272
188273
189274 func orderData (orderId,totalWavelets,filledWavelets,owner,status,roi,price,currentPrice) = [StringEntry(getOrderPriceKey(orderId), toString(price)), IntegerEntry(getOrderTotalKey(orderId), totalWavelets), IntegerEntry(getOrderFilledTotalKey(orderId), filledWavelets), StringEntry(getOrderOwnerKey(orderId), owner), IntegerEntry(getOrderHeightKey(orderId), height), StringEntry(getOrderStatusKey(orderId), status), IntegerEntry(("debug_order_currentPrice_" + orderId), currentPrice), IntegerEntry(getRoiByOrderIdKey(orderId), roi)]
190275
191276
192277 func toStr (name,curveResult) = (((((((((((((((((((((((((((((((((((name + "[nsbtAmountRaw=") + toString(asInt(curveResult[0]))) + " usdnPayment=") + toString(asInt(curveResult[1]))) + " wRaw=") + toString(asInt(curveResult[2]))) + " uRaw=") + toString(asInt(curveResult[3]))) + " mRaw=") + toString(asInt(curveResult[4]))) + " sRaw=") + toString(asInt(curveResult[5]))) + " nsbtCurveParam_a=") + toString(asInt(curveResult[6]))) + " nsbtCurveParam_b=") + toString(asInt(curveResult[7]))) + " wReservesInUsdn=") + toString(asInt(curveResult[8]))) + " price=") + toString(asInt(curveResult[9]))) + " multBR=") + toString(asInt(curveResult[10]))) + " multPower=") + toString(asInt(curveResult[11]))) + " multExpInPower=") + asString(curveResult[12])) + " multK=") + asString(curveResult[13])) + " step1=") + asString(curveResult[14])) + " step2=") + asString(curveResult[15])) + " step3=") + toString(asInt(curveResult[16]))) + "]")
278+
279+
280+func surfData (surfResult) = StringEntry("debug_surfResult", makeString(["%d%d%d%d%d%d%d%d%d%d%d", toString(asInt(surfResult[bFuncIdxSurf])), toString(asInt(surfResult[bFuncIdxWaves])), toString(asInt(surfResult[bFuncIdxUsdn])), toString(asInt(surfResult[bFuncIdxReserveStart])), toString(asInt(surfResult[bFuncIdxSupplyStart])), toString(asInt(surfResult[bFuncIdxBRStart])), toString(asInt(surfResult[bFuncIdxReserveEnd])), toString(asInt(surfResult[bFuncIdxSupplyEnd])), toString(asInt(surfResult[bFuncIdxBREnd])), toString(asInt(surfResult[bFuncIdxRest])), toString(asInt(surfResult[bFuncIdxWavesPrice]))], SEP))
193281
194282
195283 @Callable(i)
196284 func constructor (mathContractAddress,minWavesForNsbtBuy,minNsbtSell) = if ((i.caller != this))
197285 then throw("Permission denied")
198286 else [StringEntry(MathContractKey, mathContractAddress), IntegerEntry(MinNsbtSellKey, minNsbtSell), IntegerEntry(MinWavesForNsbtBuyKey, minWavesForNsbtBuy)]
199287
200288
201289
202290 @Callable(i)
203291 func constructorV2 (minWavesForSurfBuyKey,minUsdnForSurfBuyKey,description) = if ((i.caller != this))
204292 then throw("Permission denied")
205293 else {
206294 let issue = Issue("SURF", description, 0, 6, true, unit, 0)
207295 let assetId = calculateAssetId(issue)
208296 [issue, StringEntry(SurfAssetIdKey, toBase58String(assetId)), IntegerEntry(MinWavesForSurfBuyKey, minWavesForSurfBuyKey), IntegerEntry(MinUsdnForSurfBuyKey, minUsdnForSurfBuyKey)]
209297 }
210298
211299
212300
213301 @Callable(i)
214302 func buyNsbt () = {
215303 let pmt = value(i.payments[0])
216304 let pmtAmount = pmt.amount
217305 let wavesPay = pmtAmount
218306 if (isBlocked)
219307 then throw("contract is blocked by EMERGENCY SHUTDOWN actions until reactivation by emergency oracles")
220308 else if (isDefined(pmt.assetId))
221309 then throw("can use waves only")
222310 else if ((minWavesAmountNsbtBuy > pmtAmount))
223- then throw((("min " + toString((minWavesAmountNsbtBuy / WAVELET))) + " waves expected"))
311+ then throw((("min " + toString((minWavesAmountNsbtBuy / MULT8))) + " waves expected"))
224312 else {
225313 let ownerAddress = i.caller
226314 let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
227315 let currentPrice = asInt(neutrinoMetrics[0])
228316 let curveResult = asAnyList(invoke(mathContract, "curveFunctionREADONLY", [wavesPay], nil))
229317 let nsbtAmount = asInt(curveResult[0])
230318 if ((0 >= nsbtAmount))
231319 then throw("nsbtAmount <= 0")
232320 else {
233321 let nsbt2WavesPriceRaw = calcNsbt2WavesPriceRaw(wavesPay, nsbtAmount)
234322 let roi = 0
235323 let amountLeased = invoke(neutrinoContract, "acceptWaves", nil, i.payments)
236324 if ((amountLeased == amountLeased))
237325 then $Tuple2((orderData(toBase58String(i.transactionId), pmtAmount, pmtAmount, toString(ownerAddress), FILLED, roi, nsbt2WavesPriceRaw, currentPrice) ++ [ScriptTransfer(ownerAddress, nsbtAmount, nsbtAssetId), StringEntry("debug_curveResult", toStr("curveResult", curveResult))]), nsbtAmount)
238326 else throw("Strict value is not equal to itself.")
239327 }
240328 }
241329 }
242330
243331
244332
245333 @Callable(i)
246334 func sellNsbt () = if (isBlocked)
247335 then throw("contract is blocked by EMERGENCY SHUTDOWN actions until reactivation by emergency oracles")
248336 else {
249337 let pmt = value(i.payments[0])
250338 let pmtAmount = pmt.amount
251339 if ((pmt.assetId != nsbtAssetId))
252340 then throw("can use NSBT only")
253341 else if ((minNsbtSell > pmtAmount))
254- then throw((("min " + toString((minNsbtSell / PAULI))) + " nsbt expected"))
342+ then throw((("min " + toString((minNsbtSell / MULT6))) + " nsbt expected"))
255343 else {
256344 let newPrice = asInt(asAnyList(invoke(mathContract, "calcContractNsbtPriceSYSREADONLY", [-(pmtAmount)], nil))[0])
257- if ((PAULI > newPrice))
345+ if ((MULT6 > newPrice))
258346 then throw((("resulting nsbt price would be < 1 (" + toString(newPrice)) + " usdn)"))
259347 else {
260348 let transf = invoke(neutrinoContract, "transferUsdnToUser", [pmtAmount, toString(i.caller)], nil)
261349 if ((transf == transf))
262350 then $Tuple2(nil, newPrice)
263351 else throw("Strict value is not equal to itself.")
264352 }
265353 }
266354 }
267355
268356
269357
270358 @Callable(i)
271359 func cancelOrder (orderId) = {
272360 let owner = getOrderOwner(orderId)
273361 let amount = (getOrderTotal(orderId) - getOrderFilledTotal(orderId))
274362 let caller = toString(i.caller)
275363 let nextOrder = getNextOrder(orderId)
276364 let prevOrder = getPrevOrder(orderId)
277365 if ((getOrderStatus(orderId) != NEW))
278366 then throw("invalid order status")
279367 else [StringEntry(FirstOrderKey, if ((firstOrder == orderId))
280368 then nextOrder
281369 else firstOrder), StringEntry(getNextOrderKey(prevOrder), nextOrder), StringEntry(getPrevOrderKey(nextOrder), prevOrder), StringEntry(getOrderStatusKey(orderId), CANCELED), ScriptTransfer(i.caller, amount, unit)]
282370 }
283371
284372
285373
286374 @Callable(i)
287375 func minWavesAmountNsbtBuySYSREADONLY () = $Tuple2(nil, minWavesAmountNsbtBuy)
288376
289377
290378
291379 @Callable(i)
292380 func minNsbtAmountForSellSYSREADONLY () = $Tuple2(nil, minNsbtSell)
293381
294382
383+
384+@Callable(i)
385+func minWavesAmountSurfBuySYSREADONLY () = $Tuple2(nil, minWavesAmountSurfBuy)
386+
387+
388+
389+@Callable(i)
390+func minUsdnAmountSurfBuySYSREADONLY () = $Tuple2(nil, minUsdnAmountSurfBuy)
391+
392+
393+
394+@Callable(i)
395+func buySurf (averagePriceWanted,maxTolerancePerc,autoStake) = {
396+ let testAccounts = valueOrElse(getString(this, "testAccounts"), "")
397+ if (if ((testAccounts != ""))
398+ then !(contains(testAccounts, toString(i.caller)))
399+ else false)
400+ then throw("Be patient! Need to test in mainnet before launch.")
401+ else if ((size(i.payments) != 1))
402+ then throw("exactly 1 payment must be attached")
403+ else if ((0 >= averagePriceWanted))
404+ then throw("averagePriceWanted should be positive")
405+ else if ((0 >= maxTolerancePerc))
406+ then throw("maxTolerancePerc should be positive")
407+ else {
408+ let pmt = i.payments[0]
409+ let amt = pmt.amount
410+ let pmtAssetId = valueOrElse(pmt.assetId, WAVESID)
411+ if (if ((pmtAssetId != neutrinoAssetId))
412+ then (pmtAssetId != WAVESID)
413+ else false)
414+ then throw("Unsupported payment asset")
415+ else if (if ((pmtAssetId == neutrinoAssetId))
416+ then (minUsdnAmountSurfBuy > amt)
417+ else false)
418+ then throw((("min " + toString((minUsdnAmountSurfBuy / MULT6))) + " USDN expected"))
419+ else if (if ((pmtAssetId == WAVESID))
420+ then (minWavesAmountSurfBuy > amt)
421+ else false)
422+ then throw((("min " + toString((minWavesAmountSurfBuy / MULT8))) + " WAVES expected"))
423+ else {
424+ let surfResult = asAnyList(invoke(mathContract, "surfFunctionREADONLY", [amt, pmtAssetId], nil))
425+ let spentWaves = asInt(surfResult[bFuncIdxWaves])
426+ let spentUsdn = asInt(surfResult[bFuncIdxUsdn])
427+ let surfAmount = asInt(surfResult[bFuncIdxSurf])
428+ let surfAmountX6 = toBigInt(surfAmount)
429+ let spentActualX18 = if ((pmtAssetId == WAVESID))
430+ then (toBigInt(spentWaves) * MULTX10)
431+ else (toBigInt(spentUsdn) * MULTX12)
432+ if ((spentActualX18 > ((toBigInt((maxTolerancePerc + MULT6)) * toBigInt(averagePriceWanted)) * surfAmountX6)))
433+ then throw((((((("Tolerance " + toString(maxTolerancePerc)) + " exceeded: spent ") + (if ((pmtAssetId == WAVESID))
434+ then (toString(spentWaves) + " WAVES")
435+ else (toString(spentUsdn) + " USDN"))) + " for ") + toString(surfAmount)) + " SURF"))
436+ else {
437+ let rest = asInt(surfResult[bFuncIdxRest])
438+ let transfer = if ((pmtAssetId == WAVESID))
439+ then {
440+ let wavesAmt = invoke(neutrinoContract, "acceptWaves", nil, [AttachedPayment(unit, (amt - rest))])
441+ if ((wavesAmt == wavesAmt))
442+ then if ((rest > 0))
443+ then [ScriptTransfer(i.caller, rest, unit)]
444+ else nil
445+ else throw("Strict value is not equal to itself.")
446+ }
447+ else if ((rest > 0))
448+ then [ScriptTransfer(neutrinoContract, (amt - rest), neutrinoAssetId), ScriptTransfer(i.caller, rest, neutrinoAssetId)]
449+ else [ScriptTransfer(neutrinoContract, (amt - rest), neutrinoAssetId)]
450+ let surfAssetId = asBytes(invoke(this, "issueSurf", [surfAmount], nil))
451+ let surfAction = if (autoStake)
452+ then {
453+ let stakingInv = invoke(surfStakingContract, "stakeByOriginCaller", nil, [AttachedPayment(surfAssetId, surfAmount)])
454+ if ((stakingInv == stakingInv))
455+ then nil
456+ else throw("Strict value is not equal to itself.")
457+ }
458+ else [ScriptTransfer(i.caller, surfAmount, surfAssetId)]
459+ ((transfer ++ [surfData(surfResult)]) ++ surfAction)
460+ }
461+ }
462+ }
463+ }
464+
465+
466+
467+@Callable(i)
468+func issueSurf (surfAmount) = {
469+ let surfAssetId = fromBase58String(getStringValue(SurfAssetIdKey))
470+ if ((i.caller != this))
471+ then throw("issueSurf - permission denied")
472+ else $Tuple2([Reissue(surfAssetId, surfAmount, true)], surfAssetId)
473+ }
474+
475+
295476 @Verifier(tx)
296477 func verify () = {
297478 let pubKeyAdminsListStr = makeString(["GJdLSaLiv5K7xuejac8mcRcHoyo3dPrESrvktG3a6MAR", "EYwZmURd5KKaQRBjsVa6g8DPisFoS6SovRJtFiL5gMHU", "DtmAfuDdCrHK8spdAeAYzq6MsZegeD9gnsrpuTRkCbVA", "5WRXFSjwcTbNfKcJs8ZqXmSSWYsSVJUtMvMqZj5hH4Nc"], SEP)
298479 let pubKeyAdminsList = split(valueOrElse(getString(controlContract, "%s__multisig"), pubKeyAdminsListStr), SEP)
299480 let count = ((((if (sigVerify(tx.bodyBytes, tx.proofs[0], fromBase58String(pubKeyAdminsList[0])))
300481 then 1
301482 else 0) + (if (sigVerify(tx.bodyBytes, tx.proofs[1], fromBase58String(pubKeyAdminsList[1])))
302483 then 1
303484 else 0)) + (if (sigVerify(tx.bodyBytes, tx.proofs[2], fromBase58String(pubKeyAdminsList[2])))
304485 then 1
305486 else 0)) + (if (sigVerify(tx.bodyBytes, tx.proofs[3], fromBase58String(pubKeyAdminsList[3])))
306487 then 2
307488 else 0))
308489 (count >= 3)
309490 }
310491

github/deemru/w8io/6500d08 
62.54 ms