tx · 5ZdWShJqCUVN578vvEZFHEdBw7e8fC9mPHkjZj68bip 3MuZayPFVLM2GSiVHDbo1SCGagfLQh6pQEr: -0.01900000 Waves 2022.09.27 02:48 [2246772] smart account 3MuZayPFVLM2GSiVHDbo1SCGagfLQh6pQEr > SELF 0.00000000 Waves
{ "type": 13, "id": "5ZdWShJqCUVN578vvEZFHEdBw7e8fC9mPHkjZj68bip", "fee": 1900000, "feeAssetId": null, "timestamp": 1664236132503, "version": 2, "chainId": 84, "sender": "3MuZayPFVLM2GSiVHDbo1SCGagfLQh6pQEr", "senderPublicKey": "GscL7UdayRbv4gkUuDa4FDPnDR2s81kqve8sM5MpDKdN", "proofs": [ "4S8Lm4TKqf9nxiBRCCocGuKuFQ9AL8LCLChAyhzNrgMm1JRjcsuGKk7qvKt3W9gQJR5niCk7G211r5cnf89RF3s4" ], "script": "base64:AAIEAAAAAAAAACAIAhIAEgQKAggBEgMKAQgSAwoBCBIAEgASABIECgIICAAAADEAAAAAE2dhbWVNYXN0ZXJQdWJsaWNLZXkJAAJZAAAAAQIAAAAsOWNlSmtLRFZZcmJjall1R1NwczNOYUFlUHRRUGpCY3lFZzNMR2thcFhpeVgAAAAADmdhbWVUb2tlbkxhYmVsAgAAAAlHX1RPS0VOSUQAAAAAEGdhbWVCYWxhbmNlTGFiZWwCAAAACUdfQkFMQU5DRQAAAAAVZ2FtZUNvbW11bml0eVBvdExhYmVsAgAAAA5HX0NPTU1VTklUWVBPVAEAAAARZ2FtZVByaXplUG90TGFiZWwAAAABAAAACmdhbWVOdW1iZXIJAAEsAAAAAgkAASwAAAACAgAAAAJHXwkAAaQAAAABBQAAAApnYW1lTnVtYmVyAgAAAAlfUFJJWkVQT1QBAAAAGWdhbWVQcml6ZVNoYXJlQW1vdW50TGFiZWwAAAABAAAACmdhbWVOdW1iZXIJAAEsAAAAAgkAASwAAAACAgAAAAJHXwkAAaQAAAABBQAAAApnYW1lTnVtYmVyAgAAABFfUFJJWkVTSEFSRUFNT1VOVAAAAAAQZ2FtZUNvdW50ZXJMYWJlbAIAAAAOR19HQU1FU0NPVU5URVIBAAAAEmdhbWVUb3RhbEJldHNMYWJlbAAAAAEAAAAKZ2FtZU51bWJlcgkAASwAAAACCQABLAAAAAICAAAAAkdfCQABpAAAAAEFAAAACmdhbWVOdW1iZXICAAAACl9UT1RBTEJFVFMBAAAAFmdhbWVQcm9jZXNzZWRCZXRzTGFiZWwAAAABAAAACmdhbWVOdW1iZXIJAAEsAAAAAgkAASwAAAACAgAAAAJHXwkAAaQAAAABBQAAAApnYW1lTnVtYmVyAgAAAA5fUFJPQ0VTU0VEQkVUUwEAAAAXZ2FtZVdpbm5lcnNDb3VudGVyTGFiZWwAAAABAAAACmdhbWVOdW1iZXIJAAEsAAAAAgkAASwAAAACAgAAAAJHXwkAAaQAAAABBQAAAApnYW1lTnVtYmVyAgAAAA1fV0lOTkVSU0NPVU5UAQAAABlnYW1lUHJvY2Vzc2VkV2lubmVyc0xhYmVsAAAAAQAAAApnYW1lTnVtYmVyCQABLAAAAAIJAAEsAAAAAgIAAAACR18JAAGkAAAAAQUAAAAKZ2FtZU51bWJlcgIAAAARX1BST0NFU1NFRFdJTk5FUlMBAAAAD2dhbWVSZXN1bHRMYWJlbAAAAAEAAAAKZ2FtZU51bWJlcgkAASwAAAACCQABLAAAAAICAAAAAkdfCQABpAAAAAEFAAAACmdhbWVOdW1iZXICAAAAB19SRVNVTFQBAAAAD2JldERldGFpbHNMYWJlbAAAAAIAAAAKZ2FtZU51bWJlcgAAAAliZXROdW1iZXIJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgIAAAACR18JAAGkAAAAAQUAAAAKZ2FtZU51bWJlcgIAAAADX0JfCQABpAAAAAEFAAAACWJldE51bWJlcgIAAAALX0JFVERFVEFJTFMBAAAAEndpbm5lckRldGFpbHNMYWJlbAAAAAIAAAAKZ2FtZU51bWJlcgAAAAx3aW5uZXJOdW1iZXIJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgIAAAACR18JAAGkAAAAAQUAAAAKZ2FtZU51bWJlcgIAAAADX1dfCQABpAAAAAEFAAAADHdpbm5lck51bWJlcgIAAAAOX1dJTk5FUkRFVEFJTFMBAAAADmdhbWVTdGF0ZUxhYmVsAAAAAQAAAApnYW1lTnVtYmVyCQABLAAAAAIJAAEsAAAAAgIAAAACR18JAAGkAAAAAQUAAAAKZ2FtZU51bWJlcgIAAAAGX1NUQVRFAQAAABNnYW1lUmFuZG9tSGFzaExhYmVsAAAAAQAAAApnYW1lTnVtYmVyCQABLAAAAAIJAAEsAAAAAgIAAAACR18JAAGkAAAAAQUAAAAKZ2FtZU51bWJlcgIAAAALX1JBTkRPTUhBU0gBAAAAD2dhbWVTdW1TaGFMYWJlbAAAAAEAAAAKZ2FtZU51bWJlcgkAASwAAAACCQABLAAAAAICAAAAAkdfCQABpAAAAAEFAAAACmdhbWVOdW1iZXICAAAAB19TVU1TSEEAAAAAEmdhbWVSU0FQdWJsaWNMYWJlbAIAAAALR19SU0FQVUJMSUMBAAAAFGdhbWVTdGFydEhlaWdodExhYmVsAAAAAQAAAApnYW1lTnVtYmVyCQABLAAAAAIJAAEsAAAAAgIAAAACR18JAAGkAAAAAQUAAAAKZ2FtZU51bWJlcgIAAAAMX1NUQVJUSEVJR0hUAQAAABJnYW1lRW5kSGVpZ2h0TGFiZWwAAAABAAAACmdhbWVOdW1iZXIJAAEsAAAAAgkAASwAAAACAgAAAAJHXwkAAaQAAAABBQAAAApnYW1lTnVtYmVyAgAAAApfRU5ESEVJR0hUAAAAABRnYW1lVGlja2V0UHJpY2VMYWJlbAIAAAANR19USUNLRVRQUklDRQEAAAALZ2FtZUJhbGFuY2UAAAAACQAEGgAAAAIFAAAABHRoaXMFAAAAEGdhbWVCYWxhbmNlTGFiZWwBAAAAEGdhbWVDb21tdW5pdHlQb3QAAAAACQAEGgAAAAIFAAAABHRoaXMFAAAAFWdhbWVDb21tdW5pdHlQb3RMYWJlbAEAAAAMZ2FtZVByaXplUG90AAAAAQAAAApnYW1lTnVtYmVyCQAEGgAAAAIFAAAABHRoaXMJAQAAABFnYW1lUHJpemVQb3RMYWJlbAAAAAEFAAAACmdhbWVOdW1iZXIBAAAAFGdhbWVQcml6ZVNoYXJlQW1vdW50AAAAAQAAAApnYW1lTnVtYmVyCQAEGgAAAAIFAAAABHRoaXMJAQAAABlnYW1lUHJpemVTaGFyZUFtb3VudExhYmVsAAAAAQUAAAAKZ2FtZU51bWJlcgEAAAAPZ2FtZXNHZXRDb3VudGVyAAAAAAkABBoAAAACBQAAAAR0aGlzBQAAABBnYW1lQ291bnRlckxhYmVsAQAAAA1nYW1lVG90YWxCZXRzAAAAAQAAAApnYW1lTnVtYmVyCQAEGgAAAAIFAAAABHRoaXMJAQAAABJnYW1lVG90YWxCZXRzTGFiZWwAAAABBQAAAApnYW1lTnVtYmVyAQAAABFnYW1lUHJvY2Vzc2VkQmV0cwAAAAEAAAAKZ2FtZU51bWJlcgkABBoAAAACBQAAAAR0aGlzCQEAAAAWZ2FtZVByb2Nlc3NlZEJldHNMYWJlbAAAAAEFAAAACmdhbWVOdW1iZXIBAAAAEmdhbWVXaW5uZXJzQ291bnRlcgAAAAEAAAAKZ2FtZU51bWJlcgkABBoAAAACBQAAAAR0aGlzCQEAAAAXZ2FtZVdpbm5lcnNDb3VudGVyTGFiZWwAAAABBQAAAApnYW1lTnVtYmVyAQAAABRnYW1lUHJvY2Vzc2VkV2lubmVycwAAAAEAAAAKZ2FtZU51bWJlcgkABBoAAAACBQAAAAR0aGlzCQEAAAAZZ2FtZVByb2Nlc3NlZFdpbm5lcnNMYWJlbAAAAAEFAAAACmdhbWVOdW1iZXIBAAAADWdhbWVHZXRSZXN1bHQAAAABAAAACmdhbWVOdW1iZXIJAQAAABFAZXh0ck5hdGl2ZSgxMDUzKQAAAAIFAAAABHRoaXMJAQAAAA9nYW1lUmVzdWx0TGFiZWwAAAABBQAAAApnYW1lTnVtYmVyAQAAAApiZXREZXRhaWxzAAAAAgAAAApnYW1lTnVtYmVyAAAACWJldE51bWJlcgkBAAAAEUBleHRyTmF0aXZlKDEwNTMpAAAAAgUAAAAEdGhpcwkBAAAAD2JldERldGFpbHNMYWJlbAAAAAIFAAAACmdhbWVOdW1iZXIFAAAACWJldE51bWJlcgEAAAANd2lubmVyRGV0YWlscwAAAAIAAAAKZ2FtZU51bWJlcgAAAAx3aW5uZXJOdW1iZXIJAQAAABFAZXh0ck5hdGl2ZSgxMDUzKQAAAAIFAAAABHRoaXMJAQAAABJ3aW5uZXJEZXRhaWxzTGFiZWwAAAACBQAAAApnYW1lTnVtYmVyBQAAAAx3aW5uZXJOdW1iZXIBAAAADGdhbWVHZXRTdGF0ZQAAAAEAAAAKZ2FtZU51bWJlcgkABBoAAAACBQAAAAR0aGlzCQEAAAAOZ2FtZVN0YXRlTGFiZWwAAAABBQAAAApnYW1lTnVtYmVyAQAAAA1nYW1lR2V0U3VtU2hhAAAAAQAAAApnYW1lTnVtYmVyCQAEHQAAAAIFAAAABHRoaXMJAQAAAA9nYW1lU3VtU2hhTGFiZWwAAAABBQAAAApnYW1lTnVtYmVyAQAAABNnYW1lUlNBUHVibGljU3RyaW5nAAAAAAkBAAAAEUBleHRyTmF0aXZlKDEwNTMpAAAAAgUAAAAEdGhpcwUAAAASZ2FtZVJTQVB1YmxpY0xhYmVsAQAAAA1nYW1lUlNBUHVibGljAAAAAAkAAlsAAAABAgAAANhNSUdmTUEwR0NTcUdTSWIzRFFFQkFRVUFBNEdOQURDQmlRS0JnUUQxRllSbkd4Kzk4UmJkVTVNMnFpd2pQWmU5T0o3OSs1cXEveEJ0dHpQVnJNRkhucVFtVHdzNk8ydFBhcHBha1gwOWhTTU1tWHA1NTgzRzgyVUZuc0NuUWU0MnRrYzNzdnVnY2QwUnYzeThhbHJMM3JXdElpV3gzY2l5RWhFZEdJdXd0UTgwMTA4aHFldldlS1BSdmdVeHpHbms0MjJyaStZaGFrck9IZ3JoNlFJREFRQUIBAAAAD2dhbWVUaWNrZXRQcmljZQAAAAAJAAQaAAAAAgUAAAAEdGhpcwUAAAAUZ2FtZVRpY2tldFByaWNlTGFiZWwBAAAAD2NoZWNrUGVybWlzc2lvbgAAAAEAAAAPY2FsbGVyUHVibGljS2V5CQEAAAACIT0AAAACBQAAAA9jYWxsZXJQdWJsaWNLZXkFAAAAE2dhbWVNYXN0ZXJQdWJsaWNLZXkBAAAADGdldEdhbWVUb2tlbgAAAAAEAAAAByRtYXRjaDAJAAQdAAAAAgUAAAAEdGhpcwUAAAAOZ2FtZVRva2VuTGFiZWwDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABlN0cmluZwQAAAAHdG9rZW5JZAUAAAAHJG1hdGNoMAMJAAAAAAAAAgUAAAAHdG9rZW5JZAIAAAAABQAAAAR1bml0CQACWQAAAAEFAAAAB3Rva2VuSWQFAAAABHVuaXQBAAAAEmdldEdhbWVUaWNrZXRQcmljZQAAAAAEAAAAByRtYXRjaDAJAQAAAA9nYW1lVGlja2V0UHJpY2UAAAAAAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAANJbnQEAAAAC3RpY2tldFByaWNlBQAAAAckbWF0Y2gwBQAAAAt0aWNrZXRQcmljZQkAAAIAAAABAgAAADZHYW1lIGhhcyBub3QgYmVlbiBpbml0aWFsaXplZCwgdGlja2V0IHByaWNlIG5vdCBmb3VuZC4BAAAADmdldEN1cnJlbnRHYW1lAAAAAAQAAAAHJG1hdGNoMAkBAAAAD2dhbWVzR2V0Q291bnRlcgAAAAADCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAA0ludAQAAAALY3VycmVudEdhbWUFAAAAByRtYXRjaDAFAAAAC2N1cnJlbnRHYW1lCQAAAgAAAAECAAAANUdhbWUgaGFzIG5vdCBiZWVuIGluaXRpYWxpemVkLCB0b3RhbCBnYW1lcyBub3QgZm91bmQuAQAAAAxnZXRHYW1lU3RhdGUAAAABAAAAC2N1cnJlbnRHYW1lBAAAAAckbWF0Y2gwCQEAAAAMZ2FtZUdldFN0YXRlAAAAAQUAAAALY3VycmVudEdhbWUDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAA0ludAQAAAAJZ2FtZVN0YXRlBQAAAAckbWF0Y2gwBQAAAAlnYW1lU3RhdGUJAAACAAAAAQIAAAAVR2FtZSBzdGF0ZSBub3QgZm91bmQuAQAAAAxnZXRUb3RhbEJldHMAAAABAAAAC2N1cnJlbnRHYW1lBAAAAAckbWF0Y2gwCQEAAAANZ2FtZVRvdGFsQmV0cwAAAAEFAAAAC2N1cnJlbnRHYW1lAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAANJbnQEAAAACXRvdGFsQmV0cwUAAAAHJG1hdGNoMAUAAAAJdG90YWxCZXRzCQAAAgAAAAECAAAANEdhbWUgaGFzIG5vdCBiZWVuIGluaXRpYWxpemVkLCB0b3RhbCBiZXRzIG5vdCBmb3VuZC4BAAAAFWdldFRvdGFsUHJvY2Vzc2VkQmV0cwAAAAEAAAALY3VycmVudEdhbWUEAAAAByRtYXRjaDAJAQAAABFnYW1lUHJvY2Vzc2VkQmV0cwAAAAEFAAAAC2N1cnJlbnRHYW1lAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAANJbnQEAAAAEnRvdGFsUHJvY2Vzc2VkQmV0cwUAAAAHJG1hdGNoMAUAAAASdG90YWxQcm9jZXNzZWRCZXRzCQAAAgAAAAECAAAAPkdhbWUgaGFzIG5vdCBiZWVuIGluaXRpYWxpemVkLCB0b3RhbCBwcm9jZXNzZWQgYmV0cyBub3QgZm91bmQuAQAAABFnZXRXaW5uZXJzQ291bnRlcgAAAAEAAAALY3VycmVudEdhbWUEAAAAByRtYXRjaDAJAQAAABJnYW1lV2lubmVyc0NvdW50ZXIAAAABBQAAAAtjdXJyZW50R2FtZQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAx3aW5uZXJzQ291bnQFAAAAByRtYXRjaDAFAAAADHdpbm5lcnNDb3VudAkAAAIAAAABAgAAADdHYW1lIGhhcyBub3QgYmVlbiBpbml0aWFsaXplZCwgdG90YWwgd2lubmVycyBub3QgZm91bmQuAQAAABhnZXRUb3RhbFByb2Nlc3NlZFdpbm5lcnMAAAABAAAAC2N1cnJlbnRHYW1lBAAAAAckbWF0Y2gwCQEAAAAUZ2FtZVByb2Nlc3NlZFdpbm5lcnMAAAABBQAAAAtjdXJyZW50R2FtZQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAABV0b3RhbFByb2Nlc3NlZFdpbm5lcnMFAAAAByRtYXRjaDAFAAAAFXRvdGFsUHJvY2Vzc2VkV2lubmVycwkAAAIAAAABAgAAAEFHYW1lIGhhcyBub3QgYmVlbiBpbml0aWFsaXplZCwgdG90YWwgcHJvY2Vzc2VkIHdpbm5lcnMgbm90IGZvdW5kLgEAAAATZ2V0R2FtZUNvbW11bml0eVBvdAAAAAAEAAAAByRtYXRjaDAJAQAAABBnYW1lQ29tbXVuaXR5UG90AAAAAAMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAxjb21tdW5pdHlQb3QFAAAAByRtYXRjaDAFAAAADGNvbW11bml0eVBvdAkAAAIAAAABAgAAADNHYW1lIGhhcyBub3QgYmVlbiBpbml0aWFsaXplZCwgcHJpemUgcG90IG5vdCBmb3VuZC4BAAAAD2dldEdhbWVQcml6ZVBvdAAAAAEAAAALY3VycmVudEdhbWUEAAAAByRtYXRjaDAJAQAAAAxnYW1lUHJpemVQb3QAAAABBQAAAAtjdXJyZW50R2FtZQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAhwcml6ZVBvdAUAAAAHJG1hdGNoMAUAAAAIcHJpemVQb3QJAAACAAAAAQIAAAAzR2FtZSBoYXMgbm90IGJlZW4gaW5pdGlhbGl6ZWQsIHByaXplIHBvdCBub3QgZm91bmQuAAAACAAAAAFpAQAAAAhpbml0R2FtZQAAAAADCQEAAAAPY2hlY2tQZXJtaXNzaW9uAAAAAQgFAAAAAWkAAAAPY2FsbGVyUHVibGljS2V5CQAAAgAAAAECAAAAEmluaXRHYW1lX0ZPUkJCSURFTgQAAAAHJG1hdGNoMAkBAAAAD2dhbWVzR2V0Q291bnRlcgAAAAADCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAA0ludAQAAAAMR0FNRVNDT1VOVEVSBQAAAAckbWF0Y2gwCQAAAgAAAAECAAAAGEdhbWUgYWxyZWFkeSBpbml0aWFsaXplZAkABEwAAAACCQEAAAAMSW50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TAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAAUZ2FtZVN0YXJ0SGVpZ2h0TGFiZWwAAAABBQAAAAtjdXJyZW50R2FtZQgFAAAACWxhc3RCbG9jawAAAAZoZWlnaHQJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAAEGdhbWVDb3VudGVyTGFiZWwFAAAAB25ld0dhbWUJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIJAQAAABFnYW1lUHJpemVQb3RMYWJlbAAAAAEFAAAAB25ld0dhbWUFAAAACHByaXplUG90CQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAAZZ2FtZVByaXplU2hhcmVBbW91bnRMYWJlbAAAAAEFAAAAB25ld0dhbWUAAAAAAAAAAAAJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIJAQAAABJnYW1lVG90YWxCZXRzTGFiZWwAAAABBQAAAAduZXdHYW1lAAAAAAAAAAAACQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAAWZ2FtZVByb2Nlc3NlZEJldHNMYWJlbAAAAAEFAAAAB25ld0dhbWUAAAAAAAAAAAAJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIJAQAAABdnYW1lV2lubmVyc0NvdW50ZXJMYWJlbAAAAAEFAAAAB25ld0dhbWUAAAAAAAAAAAAJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIJAQAAABlnYW1lUHJvY2Vzc2VkV2lubmVyc0xhYmVsAAAAAQUAAAAHbmV3R2FtZQAAAAAAAAAAAAkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgkBAAAADmdhbWVTdGF0ZUxhYmVsAAAAAQUAAAAHbmV3R2FtZQAAAAAAAAAAAAkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACCQEAAAAPZ2FtZVN1bVNoYUxhYmVsAAAAAQUAAAAHbmV3R2FtZQkAAlgAAAABCQAB9wAAAAEJAAJbAAAAAQUAAAAKcmFuZG9tSGFzaAkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgkBAAAAFGdhbWVTdGFydEhlaWdodExhYmVsAAAAAQUAAAAHbmV3R2FtZQgFAAAACWxhc3RCbG9jawAAAAZoZWlnaHQJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIJAQAAABJnYW1lRW5kSGVpZ2h0TGFiZWwAAAABBQAAAAduZXdHYW1lCQAAZAAAAAIFAAAABmhlaWdodAUAAAAMYmxvY2tJblJvdW5kBQAAAANuaWwEAAAACHByaXplUG90CQAAZQAAAAIFAAAAB2JhbGFuY2UFAAAAEmNvbW11bml0eVBvdEFtb3VudAkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgkBAAAAFGdhbWVTdGFydEhlaWdodExhYmVsAAAAAQUAAAALY3VycmVudEdhbWUIBQAAAAlsYXN0QmxvY2sAAAAGaGVpZ2h0CQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAABBnYW1lQ291bnRlckxhYmVsBQAAAAduZXdHYW1lCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAARZ2FtZVByaXplUG90TGFiZWwAAAABBQAAAAduZXdHYW1lBQAAAAhwcml6ZVBvdAkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgkBAAAAGWdhbWVQcml6ZVNoYXJlQW1vdW50TGFiZWwAAAABBQAAAAduZXdHYW1lAAAAAAAAAAAACQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAASZ2FtZVRvdGFsQmV0c0xhYmVsAAAAAQUAAAAHbmV3R2FtZQAAAAAAAAAAAAkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgkBAAAAFmdhbWVQcm9jZXNzZWRCZXRzTGFiZWwAAAABBQAAAAduZXdHYW1lAAAAAAAAAAAACQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAAXZ2FtZVdpbm5lcnNDb3VudGVyTGFiZWwAAAABBQAAAAduZXdHYW1lAAAAAAAAAAAACQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAAZZ2FtZVByb2Nlc3NlZFdpbm5lcnNMYWJlbAAAAAEFAAAAB25ld0dhbWUAAAAAAAAAAAAJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAA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YXRlCQEAAAAMZ2V0R2FtZVN0YXRlAAAAAQUAAAALY3VycmVudEdhbWUDCQAAAAAAAAIFAAAACWdhbWVTdGF0ZQAAAAAAAAAAAAkAAAIAAAABAgAAAB9MYXN0IGdhbWUgaGFzIG5vdCBmaW5pc2hlZCB5ZXQuBAAAAAl0b3RhbEJldHMJAQAAAAxnZXRUb3RhbEJldHMAAAABBQAAAAtjdXJyZW50R2FtZQQAAAAQbGFzdFByb2Nlc3NlZEJldAkBAAAAFWdldFRvdGFsUHJvY2Vzc2VkQmV0cwAAAAEFAAAAC2N1cnJlbnRHYW1lBAAAAAduZXh0QmV0CQAAZAAAAAIFAAAAEGxhc3RQcm9jZXNzZWRCZXQAAAAAAAAAAAEDCQAAZgAAAAIFAAAAB25leHRCZXQFAAAACXRvdGFsQmV0cwkAAAIAAAABAgAAAB1OZXh0IGJldCBoYXMgbm90IGJlZW4gcGxhY2VkLgQAAAAMd2lubmVyc0NvdW50CQEAAAARZ2V0V2lubmVyc0NvdW50ZXIAAAABBQAAAAtjdXJyZW50R2FtZQQAAAAGcmVzdWx0CQEAAAANZ2FtZUdldFJlc3VsdAAAAAEFAAAAC2N1cnJlbnRHYW1lBAAAAAliZXREZXRhaWwJAAGRAAAAAgkABLUAAAACCQEAAAAKYmV0RGV0YWlscwAAAAIFAAAAC2N1cnJlbnRHYW1lBQAAAAduZXh0QmV0AgAAAAF8AAAAAAAAAAAABAAAAApiZXRBZGRyZXNzCQABkQAAAAIJAAS1AAAAAgkBAAAACmJldERldGFpbHMAAAACBQAAAAtjdXJyZW50R2FtZQUAAAAHbmV4dEJldAIAAAABfAAAAAAAAAAAAQMJAAAAAAAAAgUAAAAJYmV0RGV0YWlsBQAAAAZyZXN1bHQEAAAAD25ld1dpbm5lcnNDb3VudAkAAGQAAAACBQAAAAx3aW5uZXJzQ291bnQAAAAAAAAAAAEJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIJAQAAABZnYW1lUHJvY2Vzc2VkQmV0c0xhYmVsAAAAAQUAAAALY3VycmVudEdhbWUFAAAAB25leHRCZXQJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIJAQAAABdnYW1lV2lubmVyc0NvdW50ZXJMYWJlbAAAAAEFAAAAC2N1cnJlbnRHYW1lBQAAAA9uZXdXaW5uZXJzQ291bnQJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgkBAAAAEndpbm5lckRldGFpbHNMYWJlbAAAAAIFAAAAC2N1cnJlbnRHYW1lBQAAAA9uZXdXaW5uZXJzQ291bnQFAAAACmJldEFkZHJlc3MFAAAAA25pbAkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgkBAAAAFmdhbWVQcm9jZXNzZWRCZXRzTGFiZWwAAAABBQAAAAtjdXJyZW50R2FtZQUAAAAHbmV4dEJldAUAAAADbmlsAAAAAWkBAAAADmNhbGN1bGF0ZVByaXplAAAAAAMJAQAAAA9jaGVja1Blcm1pc3Npb24AAAABCAUAAAABaQAAAA9jYWxsZXJQdWJsaWNLZXkJAAACAAAAAQIAAAATc3RhcnRHYW1lX0ZPUkJCSURFTgQAAAALY3VycmVudEdhbWUJAQAAAA5nZXRDdXJyZW50R2FtZQAAAAAEAAAACWdhbWVTdGF0ZQkBAAAADGdldEdhbWVTdGF0ZQAAAAEFAAAAC2N1cnJlbnRHYW1lAwkAAAAAAAACBQAAAAlnYW1lU3RhdGUAAAAAAAAAAAAJAAACAAAAAQIAAAAfTGFzdCBnYW1lIGhhcyBub3QgZmluaXNoZWQgeWV0LgQAAAAJdG90YWxCZXRzCQEAAAAMZ2V0VG90YWxCZXRzAAAAAQUAAAALY3VycmVudEdhbWUEAAAAEGxhc3RQcm9jZXNzZWRCZXQJAQAAABVnZXRUb3RhbFByb2Nlc3NlZEJldHMAAAABBQAAAAtjdXJyZW50R2FtZQMJAAAAAAAAAgUAAAAJdG90YWxCZXRzBQAAABBsYXN0UHJvY2Vzc2VkQmV0BAAAAAx3aW5uZXJzQ291bnQJAQAAABFnZXRXaW5uZXJzQ291bnRlcgAAAAEFAAAAC2N1cnJlbnRHYW1lAwkAAAAAAAACBQAAAAx3aW5uZXJzQ291bnQAAAAAAAAAAAAJAAACAAAAAQIAAAAgVGhlcmUgYXJlIG5vIHdpbm5lcnMgdGhpcyByb3VuZC4EAAAAByRtYXRjaDAJAQAAAAxnYW1lUHJpemVQb3QAAAABBQAAAAtjdXJyZW50R2FtZQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAA5wcml6ZVBvdEFtb3VudAUAAAAHJG1hdGNoMAQAAAAQcHJpemVTaGFyZUFtb3VudAkAAGkAAAACBQAAAA5wcml6ZVBvdEFtb3VudAUAAAAMd2lubmVyc0NvdW50CQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAAZZ2FtZVByaXplU2hhcmVBbW91bnRMYWJlbAAAAAEFAAAAC2N1cnJlbnRHYW1lBQAAABBwcml6ZVNoYXJlQW1vdW50BQAAAANuaWwJAAACAAAAAQIAAAA6R2FtZSBoYXMgbm90IGJlZW4gaW5pdGlhbGl6ZWQsIFByaXplIFBvdCBBbW91bnQgbm90IGZvdW5kLgkAAAIAAAABAgAAAEtUaGVyZSBhcmUgc3RpbGwgYmV0cyB0aGF0IG5lZWQgdG8gYmUgcHJvY2Vzc2VkLiBDYW5ub3QgY2FsY3VsYXRlIHByaXplIHlldC4AAAABaQEAAAARcHJvY2Vzc05leHRXaW5uZXIAAAAAAwkBAAAAD2NoZWNrUGVybWlzc2lvbgAAAAEIBQAAAAFpAAAAD2NhbGxlclB1YmxpY0tleQkAAAIAAAABAgAAABNzdGFydEdhbWVfRk9SQkJJREVOBAAAAAtjdXJyZW50R2FtZQkBAAAADmdldEN1cnJlbnRHYW1lAAAAAAQAAAAJZ2FtZVN0YXRlCQEAAAAMZ2V0R2FtZVN0YXRlAAAAAQUAAAALY3VycmVudEdhbWUDCQAAAAAAAAIFAAAACWdhbWVTdGF0ZQAAAAAAAAAAAAkAAAIAAAABAgAAAB9MYXN0IGdhbWUgaGFzIG5vdCBmaW5pc2hlZCB5ZXQuBAAAAAx0b3RhbFdpbm5lcnMJAQAAABFnZXRXaW5uZXJzQ291bnRlcgAAAAEFAAAAC2N1cnJlbnRHYW1lAwkAAAAAAAACBQAAAAx0b3RhbFdpbm5lcnMAAAAAAAAAAAAJAAACAAAAAQIAAAAgVGhlcmUgYXJlIG5vIHdpbm5lcnMgdGhpcyByb3VuZC4EAAAAE2xhc3RQcm9jZXNzZWRXaW5uZXIJAQAAABhnZXRUb3RhbFByb2Nlc3NlZFdpbm5lcnMAAAABBQAAAAtjdXJyZW50R2FtZQQAAAAKbmV4dFdpbm5lcgkAAGQAAAACBQAAABNsYXN0UHJvY2Vzc2VkV2lubmVyAAAAAAAAAAABAwkAAGYAAAACBQAAAApuZXh0V2lubmVyBQAAAAx0b3RhbFdpbm5lcnMJAAACAAAAAQIAAAAgTm8gbW9yZSB3aW5uZXJzIHRvIGJlIHByb2Nlc3NlZC4EAAAAByRtYXRjaDAJAQAAABRnYW1lUHJpemVTaGFyZUFtb3VudAAAAAEFAAAAC2N1cnJlbnRHYW1lAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAANJbnQEAAAAEHByaXplU2hhcmVBbW91bnQFAAAAByRtYXRjaDADCQAAAAAAAAIFAAAAEHByaXplU2hhcmVBbW91bnQAAAAAAAAAAAAJAAACAAAAAQIAAAAvUHJpemUgc2hhcmUgYW1vdW50IGhhcyBub3QgYmVlbiBjYWxjdWxhdGVkIHlldC4EAAAACWJldFBsYWNlcgkBAAAADXdpbm5lckRldGFpbHMAAAACBQAAAAtjdXJyZW50R2FtZQUAAAAKbmV4dFdpbm5lcgQAAAAHYWRkcmVzcwkBAAAABXZhbHVlAAAAAQkABCYAAAABBQAAAAliZXRQbGFjZXIJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIJAQAAABlnYW1lUHJvY2Vzc2VkV2lubmVyc0xhYmVsAAAAAQUAAAALY3VycmVudEdhbWUFAAAACm5leHRXaW5uZXIJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwUAAAAHYWRkcmVzcwUAAAAQcHJpemVTaGFyZUFtb3VudAkBAAAADGdldEdhbWVUb2tlbgAAAAAFAAAAA25pbAkAAAIAAAABAgAAAC9Qcml6ZSBzaGFyZSBhbW91bnQgaGFzIG5vdCBiZWVuIGNhbGN1bGF0ZWQgeWV0LgAAAAFpAQAAAAxzZXRQYXJhbWV0ZXIAAAACAAAADXBhcmFtZXRlck5hbWUAAAAOcGFyYW1ldGVyVmFsdWUDCQEAAAAPY2hlY2tQZXJtaXNzaW9uAAAAAQgFAAAAAWkAAAAPY2FsbGVyUHVibGljS2V5CQAAAgAAAAECAAAAFnNldFBhcmFtZXRlcl9GT1JCQklERU4DCQAAAAAAAAIFAAAADXBhcmFtZXRlck5hbWUCAAAAEWNoYW5nZVRpY2tldFByaWNlBAAAABB0aWNrZXRQcmljZVZhbHVlCQEAAAALdmFsdWVPckVsc2UAAAACCQEAAAANcGFyc2VJbnRWYWx1ZQAAAAEFAAAADnBhcmFtZXRlclZhbHVlAAAAAAAAAAAAAwkAAGYAAAACAAAAAAAAAAAABQAAABB0aWNrZXRQcmljZVZhbHVlCQAAAgAAAAECAAAAHHZhbHVlIGNhbm5vdCBiZSBsb3dlciB0aGFuIDAJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAAFGdhbWVUaWNrZXRQcmljZUxhYmVsBQAAABB0aWNrZXRQcmljZVZhbHVlBQAAAANuaWwDCQAAAAAAAAIFAAAADXBhcmFtZXRlck5hbWUCAAAACWNoYW5nZVJTQQQAAAAHJG1hdGNoMAkBAAAAD2dhbWVzR2V0Q291bnRlcgAAAAADCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAA0ludAQAAAAMR0FNRVNDT1VOVEVSBQAAAAckbWF0Y2gwBAAAAAckbWF0Y2gxCQEAAAAMZ2FtZUdldFN0YXRlAAAAAQUAAAAMR0FNRVNDT1VOVEVSAwkAAAEAAAACBQAAAAckbWF0Y2gxAgAAAANJbnQEAAAABXN0YXRlBQAAAAckbWF0Y2gxAwkBAAAAAiE9AAAAAgUAAAAFc3RhdGUAAAAAAAAAAAEJAAACAAAAAQIAAAAYR2FtZSBoYXMgdG8gYmUgZmluaXNoZWQuCQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAAEmdhbWVSU0FQdWJsaWNMYWJlbAUAAAAOcGFyYW1ldGVyVmFsdWUFAAAAA25pbAkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACBQAAABJnYW1lUlNBUHVibGljTGFiZWwFAAAADnBhcmFtZXRlclZhbHVlBQAAAANuaWwJAAACAAAAAQIAAAAdR2FtZSBuZWVkcyB0byBiZSBpbml0aWFsaXplZC4DCQAAAAAAAAIFAAAADXBhcmFtZXRlck5hbWUCAAAAD2NoYW5nZUVuZEhlaWdodAQAAAAHJG1hdGNoMAkBAAAAD2dhbWVzR2V0Q291bnRlcgAAAAADCQAAAQAAAAIFAAAAByRtYXRjaDACAAAAA0ludAQAAAAMR0FNRVNDT1VOVEVSBQAAAAckbWF0Y2gwBAAAAA5lbmRIZWlnaHRWYWx1ZQkBAAAAC3ZhbHVlT3JFbHNlAAAAAgkBAAAADXBhcnNlSW50VmFsdWUAAAABBQAAAA5wYXJhbWV0ZXJWYWx1ZQAAAAAAAAAAAAMJAABmAAAAAgAAAAAAAAAAAAUAAAAOZW5kSGVpZ2h0VmFsdWUJAAACAAAAAQIAAAAcdmFsdWUgY2Fubm90IGJlIGxvd2VyIHRoYW4gMAkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgkBAAAAEmdhbWVFbmRIZWlnaHRMYWJlbAAAAAEFAAAADEdBTUVTQ09VTlRFUgUAAAAOZW5kSGVpZ2h0VmFsdWUFAAAAA25pbAkAAAIAAAABAgAAAB1HYW1lIG5lZWRzIHRvIGJlIGluaXRpYWxpemVkLgkAAAIAAAABAgAAADhTZXR0aW5nIG5vdCBmb3VuZC4gQWxsb3dlZDogY2hhbmdlVGlja2V0UHJpY2UsIGNoYW5nZVJTQQAAAADhe2X/", "height": 2246772, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 7da6B6VMRwNn1VK5wdiir1PRmhtaiQkqzLYgEcNHB9uX Next: none Diff:
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 4 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | + | let gameMasterPublicKey = fromBase58String("9ceJkKDVYrbcjYuGSps3NaAePtQPjBcyEg3LGkapXiyX") | |
5 | + | ||
4 | 6 | let gameTokenLabel = "G_TOKENID" | |
5 | 7 | ||
6 | 8 | let gameBalanceLabel = "G_BALANCE" | |
10 | 12 | func gamePrizePotLabel (gameNumber) = (("G_" + toString(gameNumber)) + "_PRIZEPOT") | |
11 | 13 | ||
12 | 14 | ||
13 | - | func gamePrizeShareAmountLabel (gameNumber) = (("G_" + toString(gameNumber)) + " | |
15 | + | func gamePrizeShareAmountLabel (gameNumber) = (("G_" + toString(gameNumber)) + "_PRIZESHAREAMOUNT") | |
14 | 16 | ||
15 | 17 | ||
16 | 18 | let gameCounterLabel = "G_GAMESCOUNTER" | |
30 | 32 | func gameResultLabel (gameNumber) = (("G_" + toString(gameNumber)) + "_RESULT") | |
31 | 33 | ||
32 | 34 | ||
33 | - | func betDetailsLabel (betNumber) = (("B_" + toString(betNumber)) + "_BETDETAILS") | |
35 | + | func betDetailsLabel (gameNumber,betNumber) = (((("G_" + toString(gameNumber)) + "_B_") + toString(betNumber)) + "_BETDETAILS") | |
34 | 36 | ||
35 | 37 | ||
36 | - | func winnerDetailsLabel (winnerNumber) = (("W_" + toString(winnerNumber)) + "_WINNERDETAILS") | |
38 | + | func winnerDetailsLabel (gameNumber,winnerNumber) = (((("G_" + toString(gameNumber)) + "_W_") + toString(winnerNumber)) + "_WINNERDETAILS") | |
37 | 39 | ||
38 | 40 | ||
39 | 41 | func gameStateLabel (gameNumber) = (("G_" + toString(gameNumber)) + "_STATE") | |
40 | 42 | ||
43 | + | ||
44 | + | func gameRandomHashLabel (gameNumber) = (("G_" + toString(gameNumber)) + "_RANDOMHASH") | |
45 | + | ||
46 | + | ||
47 | + | func gameSumShaLabel (gameNumber) = (("G_" + toString(gameNumber)) + "_SUMSHA") | |
48 | + | ||
49 | + | ||
50 | + | let gameRSAPublicLabel = "G_RSAPUBLIC" | |
51 | + | ||
52 | + | func gameStartHeightLabel (gameNumber) = (("G_" + toString(gameNumber)) + "_STARTHEIGHT") | |
53 | + | ||
54 | + | ||
55 | + | func gameEndHeightLabel (gameNumber) = (("G_" + toString(gameNumber)) + "_ENDHEIGHT") | |
56 | + | ||
57 | + | ||
58 | + | let gameTicketPriceLabel = "G_TICKETPRICE" | |
41 | 59 | ||
42 | 60 | func gameBalance () = getInteger(this, gameBalanceLabel) | |
43 | 61 | ||
69 | 87 | func gameGetResult (gameNumber) = getStringValue(this, gameResultLabel(gameNumber)) | |
70 | 88 | ||
71 | 89 | ||
72 | - | func betDetails (betNumber) = getStringValue(this, betDetailsLabel(betNumber)) | |
90 | + | func betDetails (gameNumber,betNumber) = getStringValue(this, betDetailsLabel(gameNumber, betNumber)) | |
73 | 91 | ||
74 | 92 | ||
75 | - | func winnerDetails (winnerNumber) = getStringValue(this, winnerDetailsLabel(winnerNumber)) | |
93 | + | func winnerDetails (gameNumber,winnerNumber) = getStringValue(this, winnerDetailsLabel(gameNumber, winnerNumber)) | |
76 | 94 | ||
77 | 95 | ||
78 | 96 | func gameGetState (gameNumber) = getInteger(this, gameStateLabel(gameNumber)) | |
79 | 97 | ||
80 | 98 | ||
81 | - | func gameToken () = match getString(this, gameTokenLabel) { | |
99 | + | func gameGetSumSha (gameNumber) = getString(this, gameSumShaLabel(gameNumber)) | |
100 | + | ||
101 | + | ||
102 | + | func gameRSAPublicString () = getStringValue(this, gameRSAPublicLabel) | |
103 | + | ||
104 | + | ||
105 | + | func gameRSAPublic () = fromBase64String("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD1FYRnGx+98RbdU5M2qiwjPZe9OJ79+5qq/xBttzPVrMFHnqQmTws6O2tPappakX09hSMMmXp5583G82UFnsCnQe42tkc3svugcd0Rv3y8alrL3rWtIiWx3ciyEhEdGIuwtQ80108hqevWeKPRvgUxzGnk422ri+YhakrOHgrh6QIDAQAB") | |
106 | + | ||
107 | + | ||
108 | + | func gameTicketPrice () = getInteger(this, gameTicketPriceLabel) | |
109 | + | ||
110 | + | ||
111 | + | func checkPermission (callerPublicKey) = (callerPublicKey != gameMasterPublicKey) | |
112 | + | ||
113 | + | ||
114 | + | func getGameToken () = match getString(this, gameTokenLabel) { | |
82 | 115 | case tokenId: String => | |
83 | 116 | if ((tokenId == "")) | |
84 | 117 | then unit | |
88 | 121 | } | |
89 | 122 | ||
90 | 123 | ||
91 | - | @Callable(i) | |
92 | - | func initGame () = [IntegerEntry(gameBalanceLabel, 0), IntegerEntry(gameCommunityPotLabel, 0), IntegerEntry(gameCounterLabel, 0), IntegerEntry(gameStateLabel(0), 1), IntegerEntry(gameWinnersCounterLabel(0), 0), IntegerEntry(gameProcessedWinnersLabel(0), 0), IntegerEntry(gameTotalBetsLabel(0), 0), IntegerEntry(gameProcessedBetsLabel(0), 0)] | |
124 | + | func getGameTicketPrice () = match gameTicketPrice() { | |
125 | + | case ticketPrice: Int => | |
126 | + | ticketPrice | |
127 | + | case _ => | |
128 | + | throw("Game has not been initialized, ticket price not found.") | |
129 | + | } | |
93 | 130 | ||
94 | 131 | ||
95 | - | ||
96 | - | @Callable(i) | |
97 | - | func startGame () = match gamesGetCounter() { | |
132 | + | func getCurrentGame () = match gamesGetCounter() { | |
98 | 133 | case currentGame: Int => | |
99 | - | match gameGetState(currentGame) { | |
100 | - | case gameState: Int => | |
101 | - | if ((gameState == 0)) | |
102 | - | then throw("Last game has not finished yet.") | |
103 | - | else match gameTotalBets(currentGame) { | |
104 | - | case totalBets: Int => | |
105 | - | match gameProcessedBets(currentGame) { | |
106 | - | case totalProcessedBets: Int => | |
107 | - | if ((totalBets == totalProcessedBets)) | |
108 | - | then match gameWinnersCounter(currentGame) { | |
109 | - | case totalWinners: Int => | |
110 | - | match gameProcessedWinners(currentGame) { | |
111 | - | case lastProcessedWinner: Int => | |
112 | - | if ((totalWinners == lastProcessedWinner)) | |
113 | - | then { | |
114 | - | let newGame = (currentGame + 1) | |
115 | - | [IntegerEntry(gameCounterLabel, newGame), IntegerEntry(gamePrizePotLabel(newGame), 100000000), IntegerEntry(gamePrizeShareAmountLabel(newGame), 0), IntegerEntry(gameTotalBetsLabel(newGame), 0), IntegerEntry(gameProcessedBetsLabel(newGame), 0), IntegerEntry(gameWinnersCounterLabel(newGame), 0), IntegerEntry(gameProcessedWinnersLabel(newGame), 0), IntegerEntry(gameStateLabel(newGame), 0)] | |
116 | - | } | |
117 | - | else throw("All winners have not been processed yet. Cannot start new game.") | |
118 | - | case _ => | |
119 | - | throw("Game has not been initialized, total processed winners not found.") | |
120 | - | } | |
121 | - | case _ => | |
122 | - | throw("Game has not been initialized, total winners not found.") | |
123 | - | } | |
124 | - | else throw("All bets have not been processed yet. Cannot start new game.") | |
125 | - | case _ => | |
126 | - | throw("Game has not been initialized, total processed bets not found.") | |
127 | - | } | |
128 | - | case _ => | |
129 | - | throw("Game has not been initialized, total bets not found.") | |
130 | - | } | |
131 | - | case _ => | |
132 | - | throw("Game state not found.") | |
133 | - | } | |
134 | + | currentGame | |
134 | 135 | case _ => | |
135 | 136 | throw("Game has not been initialized, total games not found.") | |
136 | 137 | } | |
137 | 138 | ||
138 | 139 | ||
140 | + | func getGameState (currentGame) = match gameGetState(currentGame) { | |
141 | + | case gameState: Int => | |
142 | + | gameState | |
143 | + | case _ => | |
144 | + | throw("Game state not found.") | |
145 | + | } | |
146 | + | ||
147 | + | ||
148 | + | func getTotalBets (currentGame) = match gameTotalBets(currentGame) { | |
149 | + | case totalBets: Int => | |
150 | + | totalBets | |
151 | + | case _ => | |
152 | + | throw("Game has not been initialized, total bets not found.") | |
153 | + | } | |
154 | + | ||
155 | + | ||
156 | + | func getTotalProcessedBets (currentGame) = match gameProcessedBets(currentGame) { | |
157 | + | case totalProcessedBets: Int => | |
158 | + | totalProcessedBets | |
159 | + | case _ => | |
160 | + | throw("Game has not been initialized, total processed bets not found.") | |
161 | + | } | |
162 | + | ||
163 | + | ||
164 | + | func getWinnersCounter (currentGame) = match gameWinnersCounter(currentGame) { | |
165 | + | case winnersCount: Int => | |
166 | + | winnersCount | |
167 | + | case _ => | |
168 | + | throw("Game has not been initialized, total winners not found.") | |
169 | + | } | |
170 | + | ||
171 | + | ||
172 | + | func getTotalProcessedWinners (currentGame) = match gameProcessedWinners(currentGame) { | |
173 | + | case totalProcessedWinners: Int => | |
174 | + | totalProcessedWinners | |
175 | + | case _ => | |
176 | + | throw("Game has not been initialized, total processed winners not found.") | |
177 | + | } | |
178 | + | ||
179 | + | ||
180 | + | func getGameCommunityPot () = match gameCommunityPot() { | |
181 | + | case communityPot: Int => | |
182 | + | communityPot | |
183 | + | case _ => | |
184 | + | throw("Game has not been initialized, prize pot not found.") | |
185 | + | } | |
186 | + | ||
187 | + | ||
188 | + | func getGamePrizePot (currentGame) = match gamePrizePot(currentGame) { | |
189 | + | case prizePot: Int => | |
190 | + | prizePot | |
191 | + | case _ => | |
192 | + | throw("Game has not been initialized, prize pot not found.") | |
193 | + | } | |
194 | + | ||
139 | 195 | ||
140 | 196 | @Callable(i) | |
141 | - | func placeBet (guessValue) = match gamesGetCounter() { | |
142 | - | case currentGame: Int => | |
143 | - | match gameGetState(currentGame) { | |
144 | - | case gameState: Int => | |
145 | - | if ((gameState == 1)) | |
146 | - | then throw("Game is finished and next game has not started.") | |
147 | - | else match gameTotalBets(currentGame) { | |
148 | - | case totalBets: Int => | |
149 | - | let newBet = (totalBets + 1) | |
150 | - | let bet = guessValue | |
151 | - | [IntegerEntry(gameTotalBetsLabel(currentGame), newBet), StringEntry(betDetailsLabel(newBet), ((("G" + toString(currentGame)) + "-") + bet))] | |
152 | - | case _ => | |
153 | - | throw("Game has not been initialized, total bets not found.") | |
154 | - | } | |
155 | - | case _ => | |
156 | - | throw("Game state not found.") | |
157 | - | } | |
158 | - | case _ => | |
159 | - | throw("Game has not been initialized, total games not found.") | |
160 | - | } | |
197 | + | func initGame () = if (checkPermission(i.callerPublicKey)) | |
198 | + | then throw("initGame_FORBBIDEN") | |
199 | + | else match gamesGetCounter() { | |
200 | + | case GAMESCOUNTER: Int => | |
201 | + | throw("Game already initialized") | |
202 | + | case _ => | |
203 | + | [IntegerEntry(gameBalanceLabel, 0), IntegerEntry(gameCommunityPotLabel, 0), IntegerEntry(gameCounterLabel, 0), IntegerEntry(gameStateLabel(0), 1), IntegerEntry(gameWinnersCounterLabel(0), 0), IntegerEntry(gameProcessedWinnersLabel(0), 0), IntegerEntry(gameTotalBetsLabel(0), 0), IntegerEntry(gameProcessedBetsLabel(0), 0), StringEntry(gameTokenLabel, ""), IntegerEntry(gameTicketPriceLabel, 1000000)] | |
204 | + | } | |
161 | 205 | ||
162 | 206 | ||
163 | 207 | ||
164 | 208 | @Callable(i) | |
165 | - | func endGame () = match gamesGetCounter() { | |
166 | - | case currentGame: Int => | |
167 | - | match gameGetState(currentGame) { | |
168 | - | case gameState: Int => | |
169 | - | if ((gameState == 1)) | |
170 | - | then throw("Game is finished and next game has not started.") | |
171 | - | else [StringEntry(gameResultLabel(currentGame), ((("G" + toString(currentGame)) + "-") + "1,2,3")), IntegerEntry(gameStateLabel(currentGame), 1)] | |
172 | - | case _ => | |
173 | - | throw("Game state not found.") | |
209 | + | func startGame (randomHash,blockInRound) = if (checkPermission(i.callerPublicKey)) | |
210 | + | then throw("startGame_FORBBIDEN") | |
211 | + | else { | |
212 | + | let currentGame = getCurrentGame() | |
213 | + | let gameState = getGameState(currentGame) | |
214 | + | if ((gameState == 0)) | |
215 | + | then throw("Last game has not finished yet.") | |
216 | + | else { | |
217 | + | let totalBets = getTotalBets(currentGame) | |
218 | + | let totalProcessedBets = getTotalProcessedBets(currentGame) | |
219 | + | if ((totalBets == totalProcessedBets)) | |
220 | + | then { | |
221 | + | let totalWinners = getWinnersCounter(currentGame) | |
222 | + | let lastProcessedWinner = getTotalProcessedWinners(currentGame) | |
223 | + | if ((totalWinners == lastProcessedWinner)) | |
224 | + | then { | |
225 | + | let newGame = (currentGame + 1) | |
226 | + | match gameCommunityPot() { | |
227 | + | case communityPotAmount: Int => | |
228 | + | let balance = 10000000 | |
229 | + | let generator = (toInt(sha256(take(i.transactionId, 16))) % 17729) | |
230 | + | let randomNumber = ((toInt(toBytes(pow(generator, 0, 2, 0, 0, UP))) + currentGame) % 100) | |
231 | + | if ((randomNumber == 50)) | |
232 | + | then { | |
233 | + | let prizePot = balance | |
234 | + | [IntegerEntry(gameStartHeightLabel(currentGame), lastBlock.height), IntegerEntry(gameCounterLabel, newGame), IntegerEntry(gamePrizePotLabel(newGame), prizePot), IntegerEntry(gamePrizeShareAmountLabel(newGame), 0), IntegerEntry(gameTotalBetsLabel(newGame), 0), IntegerEntry(gameProcessedBetsLabel(newGame), 0), IntegerEntry(gameWinnersCounterLabel(newGame), 0), IntegerEntry(gameProcessedWinnersLabel(newGame), 0), IntegerEntry(gameStateLabel(newGame), 0), StringEntry(gameSumShaLabel(newGame), toBase58String(sha256(fromBase64String(randomHash)))), IntegerEntry(gameStartHeightLabel(newGame), lastBlock.height), IntegerEntry(gameEndHeightLabel(newGame), (height + blockInRound))] | |
235 | + | } | |
236 | + | else { | |
237 | + | let prizePot = (balance - communityPotAmount) | |
238 | + | [IntegerEntry(gameStartHeightLabel(currentGame), lastBlock.height), IntegerEntry(gameCounterLabel, newGame), IntegerEntry(gamePrizePotLabel(newGame), prizePot), IntegerEntry(gamePrizeShareAmountLabel(newGame), 0), IntegerEntry(gameTotalBetsLabel(newGame), 0), IntegerEntry(gameProcessedBetsLabel(newGame), 0), IntegerEntry(gameWinnersCounterLabel(newGame), 0), IntegerEntry(gameProcessedWinnersLabel(newGame), 0), IntegerEntry(gameStateLabel(newGame), 0), StringEntry(gameSumShaLabel(newGame), toBase58String(sha256(fromBase64String(randomHash)))), IntegerEntry(gameStartHeightLabel(newGame), lastBlock.height), IntegerEntry(gameEndHeightLabel(newGame), (height + blockInRound))] | |
239 | + | } | |
240 | + | case _ => | |
241 | + | throw("Game has not been initialized, total community pot not found.") | |
242 | + | } | |
243 | + | } | |
244 | + | else throw("All winners have not been processed yet. Cannot start new game.") | |
245 | + | } | |
246 | + | else throw("All bets have not been processed yet. Cannot start new game.") | |
247 | + | } | |
174 | 248 | } | |
175 | - | case _ => | |
176 | - | throw("Game has not been initialized, total games not found.") | |
177 | - | } | |
178 | 249 | ||
179 | 250 | ||
180 | 251 | ||
181 | 252 | @Callable(i) | |
182 | - | func processNextBet () = match gamesGetCounter() { | |
183 | - | case currentGame: Int => | |
184 | - | match gameGetState(currentGame) { | |
185 | - | case gameState: Int => | |
186 | - | if ((gameState == 0)) | |
187 | - | then throw("Last game has not finished yet.") | |
188 | - | else match gameTotalBets(currentGame) { | |
189 | - | case totalBets: Int => | |
190 | - | match gameProcessedBets(currentGame) { | |
191 | - | case lastProcessedBet: Int => | |
192 | - | let nextBet = (lastProcessedBet + 1) | |
193 | - | if ((nextBet > totalBets)) | |
194 | - | then throw("Next bet has not been placed.") | |
195 | - | else match gamesGetCounter() { | |
196 | - | case gameNumber: Int => | |
197 | - | match gameWinnersCounter(currentGame) { | |
198 | - | case winnersCount: Int => | |
199 | - | let result = gameGetResult(gameNumber) | |
200 | - | let betDetail = betDetails(nextBet) | |
201 | - | if ((betDetail == result)) | |
202 | - | then { | |
203 | - | let newWinnersCount = (winnersCount + 1) | |
204 | - | [IntegerEntry(gameProcessedBetsLabel(currentGame), nextBet), IntegerEntry(gameWinnersCounterLabel(currentGame), newWinnersCount), StringEntry(winnerDetailsLabel(newWinnersCount), toBase58String(i.caller.bytes))] | |
205 | - | } | |
206 | - | else [IntegerEntry(gameProcessedBetsLabel(currentGame), nextBet)] | |
207 | - | case _ => | |
208 | - | throw("Game has not been initialized, total winners not found.") | |
209 | - | } | |
210 | - | case _ => | |
211 | - | throw("Game has not been initialized, total games not found.") | |
212 | - | } | |
213 | - | case _ => | |
214 | - | throw("Game has not been initialized, total processed bets not found.") | |
215 | - | } | |
216 | - | case _ => | |
217 | - | throw("Game has not been initialized, total bets not found.") | |
218 | - | } | |
219 | - | case _ => | |
220 | - | throw("Game state not found.") | |
221 | - | } | |
222 | - | case _ => | |
223 | - | throw("Game has not been initialized, total games not found.") | |
224 | - | } | |
253 | + | func placeBet (guessValue) = { | |
254 | + | let currentGame = getCurrentGame() | |
255 | + | let gameState = getGameState(currentGame) | |
256 | + | if ((gameState == 1)) | |
257 | + | then throw("Game is finished and next game has not started.") | |
258 | + | else if ((size(i.payments) != 1)) | |
259 | + | then throw("Payment not attached or there is more then 1 payment attached.") | |
260 | + | else { | |
261 | + | let ticketPrice = getGameTicketPrice() | |
262 | + | if ((i.payments[0].amount != ticketPrice)) | |
263 | + | then throw("Incorrect payment amount.") | |
264 | + | else { | |
265 | + | let totalBets = getTotalBets(currentGame) | |
266 | + | let newBet = (totalBets + 1) | |
267 | + | let bet = guessValue | |
268 | + | let prizePot = getGamePrizePot(currentGame) | |
269 | + | let communityPot = getGameCommunityPot() | |
270 | + | [IntegerEntry(gameCounterLabel, currentGame), IntegerEntry(gameTotalBetsLabel(currentGame), newBet), StringEntry(betDetailsLabel(currentGame, newBet), ((((("G" + toString(currentGame)) + "-") + bet) + "|") + toBase58String(i.caller.bytes))), IntegerEntry(gamePrizePotLabel(currentGame), (prizePot + ((ticketPrice * 9) / 10))), IntegerEntry(gameCommunityPotLabel, (communityPot + ((ticketPrice * 1) / 10)))] | |
271 | + | } | |
272 | + | } | |
273 | + | } | |
225 | 274 | ||
226 | 275 | ||
227 | 276 | ||
228 | 277 | @Callable(i) | |
229 | - | func calculatePrize () = match gamesGetCounter() { | |
230 | - | case currentGame: Int => | |
231 | - | match gameGetState(currentGame) { | |
232 | - | case gameState: Int => | |
233 | - | if ((gameState == 0)) | |
234 | - | then throw("Last game has not finished yet.") | |
235 | - | else match gameTotalBets(currentGame) { | |
236 | - | case totalBets: Int => | |
237 | - | match gameProcessedBets(currentGame) { | |
238 | - | case lastProcessedBet: Int => | |
239 | - | if ((totalBets == lastProcessedBet)) | |
240 | - | then match gameWinnersCounter(currentGame) { | |
241 | - | case winnersCount: Int => | |
242 | - | if ((winnersCount == 0)) | |
243 | - | then throw("There are no winners this round.") | |
244 | - | else match gamePrizePot(currentGame) { | |
245 | - | case prizePotAmount: Int => | |
246 | - | let prizeShareAmount = (prizePotAmount / winnersCount) | |
247 | - | [IntegerEntry(gamePrizeShareAmountLabel(currentGame), prizeShareAmount)] | |
248 | - | case _ => | |
249 | - | throw("Game has not been initialized, total games not found.") | |
250 | - | } | |
251 | - | case _ => | |
252 | - | throw("Game has not been initialized, total winners not found.") | |
253 | - | } | |
254 | - | else throw("There are still bets that need to be processed. Cannot calculate prize yet.") | |
255 | - | case _ => | |
256 | - | throw("Game has not been initialized, total processed bets not found.") | |
278 | + | func endGame (rsaSign) = if (checkPermission(i.callerPublicKey)) | |
279 | + | then throw("startGame_FORBBIDEN") | |
280 | + | else { | |
281 | + | let currentGame = getCurrentGame() | |
282 | + | let gameState = getGameState(currentGame) | |
283 | + | if ((gameState == 1)) | |
284 | + | then throw("Game is finished and next game has not started.") | |
285 | + | else match gameGetSumSha(currentGame) { | |
286 | + | case SUMSHA: String => | |
287 | + | let sig = fromBase64String(rsaSign) | |
288 | + | let rsaSigValid = rsaVerify(SHA256, fromBase58String(SUMSHA), sig, gameRSAPublic()) | |
289 | + | if (!(rsaSigValid)) | |
290 | + | then throw((("INVALID_RSA_SIGN " + "on game ") + toString(currentGame))) | |
291 | + | else { | |
292 | + | let generator = (toInt(sha256((take(sig, 16) + take(i.transactionId, 16)))) % 17729) | |
293 | + | let generatedResult1 = ((toInt(toBytes(pow(generator, 0, 2, 0, 0, UP))) + currentGame) % 26) | |
294 | + | let generatedResult2 = ((toInt(toBytes(pow(generator, 0, 3, 0, 0, UP))) + currentGame) % 26) | |
295 | + | let generatedResult3 = ((toInt(toBytes(pow(generator, 0, 4, 0, 0, UP))) + currentGame) % 26) | |
296 | + | if (if (if ((generatedResult1 == generatedResult2)) | |
297 | + | then true | |
298 | + | else (generatedResult1 == generatedResult3)) | |
299 | + | then true | |
300 | + | else (generatedResult2 == generatedResult3)) | |
301 | + | then throw("Collision detected between randomly generated results.") | |
302 | + | else { | |
303 | + | let resultsList = [generatedResult1, generatedResult2, generatedResult3] | |
304 | + | let orderedResult1 = min(resultsList) | |
305 | + | let indexResult1 = indexOf(resultsList, orderedResult1) | |
306 | + | let resultsList1 = removeByIndex(resultsList, valueOrElse(indexResult1, 0)) | |
307 | + | let orderedResult2 = min(resultsList1) | |
308 | + | let indexResult2 = indexOf(resultsList1, orderedResult2) | |
309 | + | let resultsList2 = removeByIndex(resultsList1, valueOrElse(indexResult2, 0)) | |
310 | + | let orderedResult3 = resultsList2[0] | |
311 | + | [StringEntry(gameResultLabel(currentGame), ((((((("G" + toString(currentGame)) + "-") + toString(orderedResult1)) + ",") + toString(orderedResult2)) + ",") + toString(orderedResult3))), IntegerEntry(gameStateLabel(currentGame), 1), IntegerEntry(gameCounterLabel, currentGame)] | |
312 | + | } | |
257 | 313 | } | |
258 | - | case _ => | |
259 | - | throw("Game has not been initialized, total bets not found.") | |
260 | - | } | |
261 | - | case _ => | |
262 | - | throw("Game state not found.") | |
314 | + | case _ => | |
315 | + | throw("SHA does not exist") | |
316 | + | } | |
263 | 317 | } | |
264 | - | case _ => | |
265 | - | throw("Game has not been initialized, total games not found") | |
266 | - | } | |
267 | 318 | ||
268 | 319 | ||
269 | 320 | ||
270 | 321 | @Callable(i) | |
271 | - | func processNextWinner () = match gamesGetCounter() { | |
272 | - | case currentGame: Int => | |
273 | - | match gameGetState(currentGame) { | |
274 | - | case gameState: Int => | |
275 | - | if ((gameState == 0)) | |
276 | - | then throw("Last game has not finished yet.") | |
277 | - | else match gamePrizeShareAmount(currentGame) { | |
278 | - | case prizeShareAmount: Int => | |
279 | - | if ((prizeShareAmount == 0)) | |
280 | - | then throw("Prize share amount has not been calculated yet.") | |
281 | - | else match gameWinnersCounter(currentGame) { | |
282 | - | case totalWinners: Int => | |
283 | - | if ((totalWinners == 0)) | |
284 | - | then throw("There are no winners this round.") | |
285 | - | else match gameProcessedWinners(currentGame) { | |
286 | - | case lastProcessedWinner: Int => | |
287 | - | let nextWinner = (lastProcessedWinner + 1) | |
288 | - | if ((nextWinner > totalWinners)) | |
289 | - | then throw("No more winners to be processed.") | |
290 | - | else { | |
291 | - | let betPlacer = winnerDetails(nextWinner) | |
292 | - | let address = value(addressFromString(betPlacer)) | |
293 | - | [ScriptTransfer(address, prizeShareAmount, gameToken()), IntegerEntry(gameProcessedWinnersLabel(currentGame), nextWinner)] | |
294 | - | } | |
295 | - | case _ => | |
296 | - | throw("Game has not been initialized, total processed winners not found.") | |
322 | + | func processNextBet () = if (checkPermission(i.callerPublicKey)) | |
323 | + | then throw("startGame_FORBBIDEN") | |
324 | + | else { | |
325 | + | let currentGame = getCurrentGame() | |
326 | + | let gameState = getGameState(currentGame) | |
327 | + | if ((gameState == 0)) | |
328 | + | then throw("Last game has not finished yet.") | |
329 | + | else { | |
330 | + | let totalBets = getTotalBets(currentGame) | |
331 | + | let lastProcessedBet = getTotalProcessedBets(currentGame) | |
332 | + | let nextBet = (lastProcessedBet + 1) | |
333 | + | if ((nextBet > totalBets)) | |
334 | + | then throw("Next bet has not been placed.") | |
335 | + | else { | |
336 | + | let winnersCount = getWinnersCounter(currentGame) | |
337 | + | let result = gameGetResult(currentGame) | |
338 | + | let betDetail = split(betDetails(currentGame, nextBet), "|")[0] | |
339 | + | let betAddress = split(betDetails(currentGame, nextBet), "|")[1] | |
340 | + | if ((betDetail == result)) | |
341 | + | then { | |
342 | + | let newWinnersCount = (winnersCount + 1) | |
343 | + | [IntegerEntry(gameProcessedBetsLabel(currentGame), nextBet), IntegerEntry(gameWinnersCounterLabel(currentGame), newWinnersCount), StringEntry(winnerDetailsLabel(currentGame, newWinnersCount), betAddress)] | |
344 | + | } | |
345 | + | else [IntegerEntry(gameProcessedBetsLabel(currentGame), nextBet)] | |
346 | + | } | |
347 | + | } | |
348 | + | } | |
349 | + | ||
350 | + | ||
351 | + | ||
352 | + | @Callable(i) | |
353 | + | func calculatePrize () = if (checkPermission(i.callerPublicKey)) | |
354 | + | then throw("startGame_FORBBIDEN") | |
355 | + | else { | |
356 | + | let currentGame = getCurrentGame() | |
357 | + | let gameState = getGameState(currentGame) | |
358 | + | if ((gameState == 0)) | |
359 | + | then throw("Last game has not finished yet.") | |
360 | + | else { | |
361 | + | let totalBets = getTotalBets(currentGame) | |
362 | + | let lastProcessedBet = getTotalProcessedBets(currentGame) | |
363 | + | if ((totalBets == lastProcessedBet)) | |
364 | + | then { | |
365 | + | let winnersCount = getWinnersCounter(currentGame) | |
366 | + | if ((winnersCount == 0)) | |
367 | + | then throw("There are no winners this round.") | |
368 | + | else match gamePrizePot(currentGame) { | |
369 | + | case prizePotAmount: Int => | |
370 | + | let prizeShareAmount = (prizePotAmount / winnersCount) | |
371 | + | [IntegerEntry(gamePrizeShareAmountLabel(currentGame), prizeShareAmount)] | |
372 | + | case _ => | |
373 | + | throw("Game has not been initialized, Prize Pot Amount not found.") | |
374 | + | } | |
375 | + | } | |
376 | + | else throw("There are still bets that need to be processed. Cannot calculate prize yet.") | |
377 | + | } | |
378 | + | } | |
379 | + | ||
380 | + | ||
381 | + | ||
382 | + | @Callable(i) | |
383 | + | func processNextWinner () = if (checkPermission(i.callerPublicKey)) | |
384 | + | then throw("startGame_FORBBIDEN") | |
385 | + | else { | |
386 | + | let currentGame = getCurrentGame() | |
387 | + | let gameState = getGameState(currentGame) | |
388 | + | if ((gameState == 0)) | |
389 | + | then throw("Last game has not finished yet.") | |
390 | + | else { | |
391 | + | let totalWinners = getWinnersCounter(currentGame) | |
392 | + | if ((totalWinners == 0)) | |
393 | + | then throw("There are no winners this round.") | |
394 | + | else { | |
395 | + | let lastProcessedWinner = getTotalProcessedWinners(currentGame) | |
396 | + | let nextWinner = (lastProcessedWinner + 1) | |
397 | + | if ((nextWinner > totalWinners)) | |
398 | + | then throw("No more winners to be processed.") | |
399 | + | else match gamePrizeShareAmount(currentGame) { | |
400 | + | case prizeShareAmount: Int => | |
401 | + | if ((prizeShareAmount == 0)) | |
402 | + | then throw("Prize share amount has not been calculated yet.") | |
403 | + | else { | |
404 | + | let betPlacer = winnerDetails(currentGame, nextWinner) | |
405 | + | let address = value(addressFromString(betPlacer)) | |
406 | + | [IntegerEntry(gameProcessedWinnersLabel(currentGame), nextWinner), ScriptTransfer(address, prizeShareAmount, getGameToken())] | |
297 | 407 | } | |
298 | - | case _ => | |
299 | - | throw("Game has not been initialized, total winners not found.") | |
300 | - | } | |
408 | + | case _ => | |
409 | + | throw("Prize share amount has not been calculated yet.") | |
410 | + | } | |
411 | + | } | |
412 | + | } | |
413 | + | } | |
414 | + | ||
415 | + | ||
416 | + | ||
417 | + | @Callable(i) | |
418 | + | func setParameter (parameterName,parameterValue) = if (checkPermission(i.callerPublicKey)) | |
419 | + | then throw("setParameter_FORBBIDEN") | |
420 | + | else if ((parameterName == "changeTicketPrice")) | |
421 | + | then { | |
422 | + | let ticketPriceValue = valueOrElse(parseIntValue(parameterValue), 0) | |
423 | + | if ((0 > ticketPriceValue)) | |
424 | + | then throw("value cannot be lower than 0") | |
425 | + | else [IntegerEntry(gameTicketPriceLabel, ticketPriceValue)] | |
426 | + | } | |
427 | + | else if ((parameterName == "changeRSA")) | |
428 | + | then match gamesGetCounter() { | |
429 | + | case GAMESCOUNTER: Int => | |
430 | + | match gameGetState(GAMESCOUNTER) { | |
431 | + | case state: Int => | |
432 | + | if ((state != 1)) | |
433 | + | then throw("Game has to be finished.") | |
434 | + | else [StringEntry(gameRSAPublicLabel, parameterValue)] | |
301 | 435 | case _ => | |
302 | - | ||
436 | + | [StringEntry(gameRSAPublicLabel, parameterValue)] | |
303 | 437 | } | |
304 | - | case _ => | |
305 | - | throw("Game state not found.") | |
306 | - | } | |
307 | - | case _ => | |
308 | - | throw("Game has not been initialized, total games not found.") | |
309 | - | } | |
438 | + | case _ => | |
439 | + | throw("Game needs to be initialized.") | |
440 | + | } | |
441 | + | else if ((parameterName == "changeEndHeight")) | |
442 | + | then match gamesGetCounter() { | |
443 | + | case GAMESCOUNTER: Int => | |
444 | + | let endHeightValue = valueOrElse(parseIntValue(parameterValue), 0) | |
445 | + | if ((0 > endHeightValue)) | |
446 | + | then throw("value cannot be lower than 0") | |
447 | + | else [IntegerEntry(gameEndHeightLabel(GAMESCOUNTER), endHeightValue)] | |
448 | + | case _ => | |
449 | + | throw("Game needs to be initialized.") | |
450 | + | } | |
451 | + | else throw("Setting not found. Allowed: changeTicketPrice, changeRSA") | |
310 | 452 | ||
311 | 453 |
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 4 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | + | let gameMasterPublicKey = fromBase58String("9ceJkKDVYrbcjYuGSps3NaAePtQPjBcyEg3LGkapXiyX") | |
5 | + | ||
4 | 6 | let gameTokenLabel = "G_TOKENID" | |
5 | 7 | ||
6 | 8 | let gameBalanceLabel = "G_BALANCE" | |
7 | 9 | ||
8 | 10 | let gameCommunityPotLabel = "G_COMMUNITYPOT" | |
9 | 11 | ||
10 | 12 | func gamePrizePotLabel (gameNumber) = (("G_" + toString(gameNumber)) + "_PRIZEPOT") | |
11 | 13 | ||
12 | 14 | ||
13 | - | func gamePrizeShareAmountLabel (gameNumber) = (("G_" + toString(gameNumber)) + " | |
15 | + | func gamePrizeShareAmountLabel (gameNumber) = (("G_" + toString(gameNumber)) + "_PRIZESHAREAMOUNT") | |
14 | 16 | ||
15 | 17 | ||
16 | 18 | let gameCounterLabel = "G_GAMESCOUNTER" | |
17 | 19 | ||
18 | 20 | func gameTotalBetsLabel (gameNumber) = (("G_" + toString(gameNumber)) + "_TOTALBETS") | |
19 | 21 | ||
20 | 22 | ||
21 | 23 | func gameProcessedBetsLabel (gameNumber) = (("G_" + toString(gameNumber)) + "_PROCESSEDBETS") | |
22 | 24 | ||
23 | 25 | ||
24 | 26 | func gameWinnersCounterLabel (gameNumber) = (("G_" + toString(gameNumber)) + "_WINNERSCOUNT") | |
25 | 27 | ||
26 | 28 | ||
27 | 29 | func gameProcessedWinnersLabel (gameNumber) = (("G_" + toString(gameNumber)) + "_PROCESSEDWINNERS") | |
28 | 30 | ||
29 | 31 | ||
30 | 32 | func gameResultLabel (gameNumber) = (("G_" + toString(gameNumber)) + "_RESULT") | |
31 | 33 | ||
32 | 34 | ||
33 | - | func betDetailsLabel (betNumber) = (("B_" + toString(betNumber)) + "_BETDETAILS") | |
35 | + | func betDetailsLabel (gameNumber,betNumber) = (((("G_" + toString(gameNumber)) + "_B_") + toString(betNumber)) + "_BETDETAILS") | |
34 | 36 | ||
35 | 37 | ||
36 | - | func winnerDetailsLabel (winnerNumber) = (("W_" + toString(winnerNumber)) + "_WINNERDETAILS") | |
38 | + | func winnerDetailsLabel (gameNumber,winnerNumber) = (((("G_" + toString(gameNumber)) + "_W_") + toString(winnerNumber)) + "_WINNERDETAILS") | |
37 | 39 | ||
38 | 40 | ||
39 | 41 | func gameStateLabel (gameNumber) = (("G_" + toString(gameNumber)) + "_STATE") | |
40 | 42 | ||
43 | + | ||
44 | + | func gameRandomHashLabel (gameNumber) = (("G_" + toString(gameNumber)) + "_RANDOMHASH") | |
45 | + | ||
46 | + | ||
47 | + | func gameSumShaLabel (gameNumber) = (("G_" + toString(gameNumber)) + "_SUMSHA") | |
48 | + | ||
49 | + | ||
50 | + | let gameRSAPublicLabel = "G_RSAPUBLIC" | |
51 | + | ||
52 | + | func gameStartHeightLabel (gameNumber) = (("G_" + toString(gameNumber)) + "_STARTHEIGHT") | |
53 | + | ||
54 | + | ||
55 | + | func gameEndHeightLabel (gameNumber) = (("G_" + toString(gameNumber)) + "_ENDHEIGHT") | |
56 | + | ||
57 | + | ||
58 | + | let gameTicketPriceLabel = "G_TICKETPRICE" | |
41 | 59 | ||
42 | 60 | func gameBalance () = getInteger(this, gameBalanceLabel) | |
43 | 61 | ||
44 | 62 | ||
45 | 63 | func gameCommunityPot () = getInteger(this, gameCommunityPotLabel) | |
46 | 64 | ||
47 | 65 | ||
48 | 66 | func gamePrizePot (gameNumber) = getInteger(this, gamePrizePotLabel(gameNumber)) | |
49 | 67 | ||
50 | 68 | ||
51 | 69 | func gamePrizeShareAmount (gameNumber) = getInteger(this, gamePrizeShareAmountLabel(gameNumber)) | |
52 | 70 | ||
53 | 71 | ||
54 | 72 | func gamesGetCounter () = getInteger(this, gameCounterLabel) | |
55 | 73 | ||
56 | 74 | ||
57 | 75 | func gameTotalBets (gameNumber) = getInteger(this, gameTotalBetsLabel(gameNumber)) | |
58 | 76 | ||
59 | 77 | ||
60 | 78 | func gameProcessedBets (gameNumber) = getInteger(this, gameProcessedBetsLabel(gameNumber)) | |
61 | 79 | ||
62 | 80 | ||
63 | 81 | func gameWinnersCounter (gameNumber) = getInteger(this, gameWinnersCounterLabel(gameNumber)) | |
64 | 82 | ||
65 | 83 | ||
66 | 84 | func gameProcessedWinners (gameNumber) = getInteger(this, gameProcessedWinnersLabel(gameNumber)) | |
67 | 85 | ||
68 | 86 | ||
69 | 87 | func gameGetResult (gameNumber) = getStringValue(this, gameResultLabel(gameNumber)) | |
70 | 88 | ||
71 | 89 | ||
72 | - | func betDetails (betNumber) = getStringValue(this, betDetailsLabel(betNumber)) | |
90 | + | func betDetails (gameNumber,betNumber) = getStringValue(this, betDetailsLabel(gameNumber, betNumber)) | |
73 | 91 | ||
74 | 92 | ||
75 | - | func winnerDetails (winnerNumber) = getStringValue(this, winnerDetailsLabel(winnerNumber)) | |
93 | + | func winnerDetails (gameNumber,winnerNumber) = getStringValue(this, winnerDetailsLabel(gameNumber, winnerNumber)) | |
76 | 94 | ||
77 | 95 | ||
78 | 96 | func gameGetState (gameNumber) = getInteger(this, gameStateLabel(gameNumber)) | |
79 | 97 | ||
80 | 98 | ||
81 | - | func gameToken () = match getString(this, gameTokenLabel) { | |
99 | + | func gameGetSumSha (gameNumber) = getString(this, gameSumShaLabel(gameNumber)) | |
100 | + | ||
101 | + | ||
102 | + | func gameRSAPublicString () = getStringValue(this, gameRSAPublicLabel) | |
103 | + | ||
104 | + | ||
105 | + | func gameRSAPublic () = fromBase64String("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD1FYRnGx+98RbdU5M2qiwjPZe9OJ79+5qq/xBttzPVrMFHnqQmTws6O2tPappakX09hSMMmXp5583G82UFnsCnQe42tkc3svugcd0Rv3y8alrL3rWtIiWx3ciyEhEdGIuwtQ80108hqevWeKPRvgUxzGnk422ri+YhakrOHgrh6QIDAQAB") | |
106 | + | ||
107 | + | ||
108 | + | func gameTicketPrice () = getInteger(this, gameTicketPriceLabel) | |
109 | + | ||
110 | + | ||
111 | + | func checkPermission (callerPublicKey) = (callerPublicKey != gameMasterPublicKey) | |
112 | + | ||
113 | + | ||
114 | + | func getGameToken () = match getString(this, gameTokenLabel) { | |
82 | 115 | case tokenId: String => | |
83 | 116 | if ((tokenId == "")) | |
84 | 117 | then unit | |
85 | 118 | else fromBase58String(tokenId) | |
86 | 119 | case _ => | |
87 | 120 | unit | |
88 | 121 | } | |
89 | 122 | ||
90 | 123 | ||
91 | - | @Callable(i) | |
92 | - | func initGame () = [IntegerEntry(gameBalanceLabel, 0), IntegerEntry(gameCommunityPotLabel, 0), IntegerEntry(gameCounterLabel, 0), IntegerEntry(gameStateLabel(0), 1), IntegerEntry(gameWinnersCounterLabel(0), 0), IntegerEntry(gameProcessedWinnersLabel(0), 0), IntegerEntry(gameTotalBetsLabel(0), 0), IntegerEntry(gameProcessedBetsLabel(0), 0)] | |
124 | + | func getGameTicketPrice () = match gameTicketPrice() { | |
125 | + | case ticketPrice: Int => | |
126 | + | ticketPrice | |
127 | + | case _ => | |
128 | + | throw("Game has not been initialized, ticket price not found.") | |
129 | + | } | |
93 | 130 | ||
94 | 131 | ||
95 | - | ||
96 | - | @Callable(i) | |
97 | - | func startGame () = match gamesGetCounter() { | |
132 | + | func getCurrentGame () = match gamesGetCounter() { | |
98 | 133 | case currentGame: Int => | |
99 | - | match gameGetState(currentGame) { | |
100 | - | case gameState: Int => | |
101 | - | if ((gameState == 0)) | |
102 | - | then throw("Last game has not finished yet.") | |
103 | - | else match gameTotalBets(currentGame) { | |
104 | - | case totalBets: Int => | |
105 | - | match gameProcessedBets(currentGame) { | |
106 | - | case totalProcessedBets: Int => | |
107 | - | if ((totalBets == totalProcessedBets)) | |
108 | - | then match gameWinnersCounter(currentGame) { | |
109 | - | case totalWinners: Int => | |
110 | - | match gameProcessedWinners(currentGame) { | |
111 | - | case lastProcessedWinner: Int => | |
112 | - | if ((totalWinners == lastProcessedWinner)) | |
113 | - | then { | |
114 | - | let newGame = (currentGame + 1) | |
115 | - | [IntegerEntry(gameCounterLabel, newGame), IntegerEntry(gamePrizePotLabel(newGame), 100000000), IntegerEntry(gamePrizeShareAmountLabel(newGame), 0), IntegerEntry(gameTotalBetsLabel(newGame), 0), IntegerEntry(gameProcessedBetsLabel(newGame), 0), IntegerEntry(gameWinnersCounterLabel(newGame), 0), IntegerEntry(gameProcessedWinnersLabel(newGame), 0), IntegerEntry(gameStateLabel(newGame), 0)] | |
116 | - | } | |
117 | - | else throw("All winners have not been processed yet. Cannot start new game.") | |
118 | - | case _ => | |
119 | - | throw("Game has not been initialized, total processed winners not found.") | |
120 | - | } | |
121 | - | case _ => | |
122 | - | throw("Game has not been initialized, total winners not found.") | |
123 | - | } | |
124 | - | else throw("All bets have not been processed yet. Cannot start new game.") | |
125 | - | case _ => | |
126 | - | throw("Game has not been initialized, total processed bets not found.") | |
127 | - | } | |
128 | - | case _ => | |
129 | - | throw("Game has not been initialized, total bets not found.") | |
130 | - | } | |
131 | - | case _ => | |
132 | - | throw("Game state not found.") | |
133 | - | } | |
134 | + | currentGame | |
134 | 135 | case _ => | |
135 | 136 | throw("Game has not been initialized, total games not found.") | |
136 | 137 | } | |
137 | 138 | ||
138 | 139 | ||
140 | + | func getGameState (currentGame) = match gameGetState(currentGame) { | |
141 | + | case gameState: Int => | |
142 | + | gameState | |
143 | + | case _ => | |
144 | + | throw("Game state not found.") | |
145 | + | } | |
146 | + | ||
147 | + | ||
148 | + | func getTotalBets (currentGame) = match gameTotalBets(currentGame) { | |
149 | + | case totalBets: Int => | |
150 | + | totalBets | |
151 | + | case _ => | |
152 | + | throw("Game has not been initialized, total bets not found.") | |
153 | + | } | |
154 | + | ||
155 | + | ||
156 | + | func getTotalProcessedBets (currentGame) = match gameProcessedBets(currentGame) { | |
157 | + | case totalProcessedBets: Int => | |
158 | + | totalProcessedBets | |
159 | + | case _ => | |
160 | + | throw("Game has not been initialized, total processed bets not found.") | |
161 | + | } | |
162 | + | ||
163 | + | ||
164 | + | func getWinnersCounter (currentGame) = match gameWinnersCounter(currentGame) { | |
165 | + | case winnersCount: Int => | |
166 | + | winnersCount | |
167 | + | case _ => | |
168 | + | throw("Game has not been initialized, total winners not found.") | |
169 | + | } | |
170 | + | ||
171 | + | ||
172 | + | func getTotalProcessedWinners (currentGame) = match gameProcessedWinners(currentGame) { | |
173 | + | case totalProcessedWinners: Int => | |
174 | + | totalProcessedWinners | |
175 | + | case _ => | |
176 | + | throw("Game has not been initialized, total processed winners not found.") | |
177 | + | } | |
178 | + | ||
179 | + | ||
180 | + | func getGameCommunityPot () = match gameCommunityPot() { | |
181 | + | case communityPot: Int => | |
182 | + | communityPot | |
183 | + | case _ => | |
184 | + | throw("Game has not been initialized, prize pot not found.") | |
185 | + | } | |
186 | + | ||
187 | + | ||
188 | + | func getGamePrizePot (currentGame) = match gamePrizePot(currentGame) { | |
189 | + | case prizePot: Int => | |
190 | + | prizePot | |
191 | + | case _ => | |
192 | + | throw("Game has not been initialized, prize pot not found.") | |
193 | + | } | |
194 | + | ||
139 | 195 | ||
140 | 196 | @Callable(i) | |
141 | - | func placeBet (guessValue) = match gamesGetCounter() { | |
142 | - | case currentGame: Int => | |
143 | - | match gameGetState(currentGame) { | |
144 | - | case gameState: Int => | |
145 | - | if ((gameState == 1)) | |
146 | - | then throw("Game is finished and next game has not started.") | |
147 | - | else match gameTotalBets(currentGame) { | |
148 | - | case totalBets: Int => | |
149 | - | let newBet = (totalBets + 1) | |
150 | - | let bet = guessValue | |
151 | - | [IntegerEntry(gameTotalBetsLabel(currentGame), newBet), StringEntry(betDetailsLabel(newBet), ((("G" + toString(currentGame)) + "-") + bet))] | |
152 | - | case _ => | |
153 | - | throw("Game has not been initialized, total bets not found.") | |
154 | - | } | |
155 | - | case _ => | |
156 | - | throw("Game state not found.") | |
157 | - | } | |
158 | - | case _ => | |
159 | - | throw("Game has not been initialized, total games not found.") | |
160 | - | } | |
197 | + | func initGame () = if (checkPermission(i.callerPublicKey)) | |
198 | + | then throw("initGame_FORBBIDEN") | |
199 | + | else match gamesGetCounter() { | |
200 | + | case GAMESCOUNTER: Int => | |
201 | + | throw("Game already initialized") | |
202 | + | case _ => | |
203 | + | [IntegerEntry(gameBalanceLabel, 0), IntegerEntry(gameCommunityPotLabel, 0), IntegerEntry(gameCounterLabel, 0), IntegerEntry(gameStateLabel(0), 1), IntegerEntry(gameWinnersCounterLabel(0), 0), IntegerEntry(gameProcessedWinnersLabel(0), 0), IntegerEntry(gameTotalBetsLabel(0), 0), IntegerEntry(gameProcessedBetsLabel(0), 0), StringEntry(gameTokenLabel, ""), IntegerEntry(gameTicketPriceLabel, 1000000)] | |
204 | + | } | |
161 | 205 | ||
162 | 206 | ||
163 | 207 | ||
164 | 208 | @Callable(i) | |
165 | - | func endGame () = match gamesGetCounter() { | |
166 | - | case currentGame: Int => | |
167 | - | match gameGetState(currentGame) { | |
168 | - | case gameState: Int => | |
169 | - | if ((gameState == 1)) | |
170 | - | then throw("Game is finished and next game has not started.") | |
171 | - | else [StringEntry(gameResultLabel(currentGame), ((("G" + toString(currentGame)) + "-") + "1,2,3")), IntegerEntry(gameStateLabel(currentGame), 1)] | |
172 | - | case _ => | |
173 | - | throw("Game state not found.") | |
209 | + | func startGame (randomHash,blockInRound) = if (checkPermission(i.callerPublicKey)) | |
210 | + | then throw("startGame_FORBBIDEN") | |
211 | + | else { | |
212 | + | let currentGame = getCurrentGame() | |
213 | + | let gameState = getGameState(currentGame) | |
214 | + | if ((gameState == 0)) | |
215 | + | then throw("Last game has not finished yet.") | |
216 | + | else { | |
217 | + | let totalBets = getTotalBets(currentGame) | |
218 | + | let totalProcessedBets = getTotalProcessedBets(currentGame) | |
219 | + | if ((totalBets == totalProcessedBets)) | |
220 | + | then { | |
221 | + | let totalWinners = getWinnersCounter(currentGame) | |
222 | + | let lastProcessedWinner = getTotalProcessedWinners(currentGame) | |
223 | + | if ((totalWinners == lastProcessedWinner)) | |
224 | + | then { | |
225 | + | let newGame = (currentGame + 1) | |
226 | + | match gameCommunityPot() { | |
227 | + | case communityPotAmount: Int => | |
228 | + | let balance = 10000000 | |
229 | + | let generator = (toInt(sha256(take(i.transactionId, 16))) % 17729) | |
230 | + | let randomNumber = ((toInt(toBytes(pow(generator, 0, 2, 0, 0, UP))) + currentGame) % 100) | |
231 | + | if ((randomNumber == 50)) | |
232 | + | then { | |
233 | + | let prizePot = balance | |
234 | + | [IntegerEntry(gameStartHeightLabel(currentGame), lastBlock.height), IntegerEntry(gameCounterLabel, newGame), IntegerEntry(gamePrizePotLabel(newGame), prizePot), IntegerEntry(gamePrizeShareAmountLabel(newGame), 0), IntegerEntry(gameTotalBetsLabel(newGame), 0), IntegerEntry(gameProcessedBetsLabel(newGame), 0), IntegerEntry(gameWinnersCounterLabel(newGame), 0), IntegerEntry(gameProcessedWinnersLabel(newGame), 0), IntegerEntry(gameStateLabel(newGame), 0), StringEntry(gameSumShaLabel(newGame), toBase58String(sha256(fromBase64String(randomHash)))), IntegerEntry(gameStartHeightLabel(newGame), lastBlock.height), IntegerEntry(gameEndHeightLabel(newGame), (height + blockInRound))] | |
235 | + | } | |
236 | + | else { | |
237 | + | let prizePot = (balance - communityPotAmount) | |
238 | + | [IntegerEntry(gameStartHeightLabel(currentGame), lastBlock.height), IntegerEntry(gameCounterLabel, newGame), IntegerEntry(gamePrizePotLabel(newGame), prizePot), IntegerEntry(gamePrizeShareAmountLabel(newGame), 0), IntegerEntry(gameTotalBetsLabel(newGame), 0), IntegerEntry(gameProcessedBetsLabel(newGame), 0), IntegerEntry(gameWinnersCounterLabel(newGame), 0), IntegerEntry(gameProcessedWinnersLabel(newGame), 0), IntegerEntry(gameStateLabel(newGame), 0), StringEntry(gameSumShaLabel(newGame), toBase58String(sha256(fromBase64String(randomHash)))), IntegerEntry(gameStartHeightLabel(newGame), lastBlock.height), IntegerEntry(gameEndHeightLabel(newGame), (height + blockInRound))] | |
239 | + | } | |
240 | + | case _ => | |
241 | + | throw("Game has not been initialized, total community pot not found.") | |
242 | + | } | |
243 | + | } | |
244 | + | else throw("All winners have not been processed yet. Cannot start new game.") | |
245 | + | } | |
246 | + | else throw("All bets have not been processed yet. Cannot start new game.") | |
247 | + | } | |
174 | 248 | } | |
175 | - | case _ => | |
176 | - | throw("Game has not been initialized, total games not found.") | |
177 | - | } | |
178 | 249 | ||
179 | 250 | ||
180 | 251 | ||
181 | 252 | @Callable(i) | |
182 | - | func processNextBet () = match gamesGetCounter() { | |
183 | - | case currentGame: Int => | |
184 | - | match gameGetState(currentGame) { | |
185 | - | case gameState: Int => | |
186 | - | if ((gameState == 0)) | |
187 | - | then throw("Last game has not finished yet.") | |
188 | - | else match gameTotalBets(currentGame) { | |
189 | - | case totalBets: Int => | |
190 | - | match gameProcessedBets(currentGame) { | |
191 | - | case lastProcessedBet: Int => | |
192 | - | let nextBet = (lastProcessedBet + 1) | |
193 | - | if ((nextBet > totalBets)) | |
194 | - | then throw("Next bet has not been placed.") | |
195 | - | else match gamesGetCounter() { | |
196 | - | case gameNumber: Int => | |
197 | - | match gameWinnersCounter(currentGame) { | |
198 | - | case winnersCount: Int => | |
199 | - | let result = gameGetResult(gameNumber) | |
200 | - | let betDetail = betDetails(nextBet) | |
201 | - | if ((betDetail == result)) | |
202 | - | then { | |
203 | - | let newWinnersCount = (winnersCount + 1) | |
204 | - | [IntegerEntry(gameProcessedBetsLabel(currentGame), nextBet), IntegerEntry(gameWinnersCounterLabel(currentGame), newWinnersCount), StringEntry(winnerDetailsLabel(newWinnersCount), toBase58String(i.caller.bytes))] | |
205 | - | } | |
206 | - | else [IntegerEntry(gameProcessedBetsLabel(currentGame), nextBet)] | |
207 | - | case _ => | |
208 | - | throw("Game has not been initialized, total winners not found.") | |
209 | - | } | |
210 | - | case _ => | |
211 | - | throw("Game has not been initialized, total games not found.") | |
212 | - | } | |
213 | - | case _ => | |
214 | - | throw("Game has not been initialized, total processed bets not found.") | |
215 | - | } | |
216 | - | case _ => | |
217 | - | throw("Game has not been initialized, total bets not found.") | |
218 | - | } | |
219 | - | case _ => | |
220 | - | throw("Game state not found.") | |
221 | - | } | |
222 | - | case _ => | |
223 | - | throw("Game has not been initialized, total games not found.") | |
224 | - | } | |
253 | + | func placeBet (guessValue) = { | |
254 | + | let currentGame = getCurrentGame() | |
255 | + | let gameState = getGameState(currentGame) | |
256 | + | if ((gameState == 1)) | |
257 | + | then throw("Game is finished and next game has not started.") | |
258 | + | else if ((size(i.payments) != 1)) | |
259 | + | then throw("Payment not attached or there is more then 1 payment attached.") | |
260 | + | else { | |
261 | + | let ticketPrice = getGameTicketPrice() | |
262 | + | if ((i.payments[0].amount != ticketPrice)) | |
263 | + | then throw("Incorrect payment amount.") | |
264 | + | else { | |
265 | + | let totalBets = getTotalBets(currentGame) | |
266 | + | let newBet = (totalBets + 1) | |
267 | + | let bet = guessValue | |
268 | + | let prizePot = getGamePrizePot(currentGame) | |
269 | + | let communityPot = getGameCommunityPot() | |
270 | + | [IntegerEntry(gameCounterLabel, currentGame), IntegerEntry(gameTotalBetsLabel(currentGame), newBet), StringEntry(betDetailsLabel(currentGame, newBet), ((((("G" + toString(currentGame)) + "-") + bet) + "|") + toBase58String(i.caller.bytes))), IntegerEntry(gamePrizePotLabel(currentGame), (prizePot + ((ticketPrice * 9) / 10))), IntegerEntry(gameCommunityPotLabel, (communityPot + ((ticketPrice * 1) / 10)))] | |
271 | + | } | |
272 | + | } | |
273 | + | } | |
225 | 274 | ||
226 | 275 | ||
227 | 276 | ||
228 | 277 | @Callable(i) | |
229 | - | func calculatePrize () = match gamesGetCounter() { | |
230 | - | case currentGame: Int => | |
231 | - | match gameGetState(currentGame) { | |
232 | - | case gameState: Int => | |
233 | - | if ((gameState == 0)) | |
234 | - | then throw("Last game has not finished yet.") | |
235 | - | else match gameTotalBets(currentGame) { | |
236 | - | case totalBets: Int => | |
237 | - | match gameProcessedBets(currentGame) { | |
238 | - | case lastProcessedBet: Int => | |
239 | - | if ((totalBets == lastProcessedBet)) | |
240 | - | then match gameWinnersCounter(currentGame) { | |
241 | - | case winnersCount: Int => | |
242 | - | if ((winnersCount == 0)) | |
243 | - | then throw("There are no winners this round.") | |
244 | - | else match gamePrizePot(currentGame) { | |
245 | - | case prizePotAmount: Int => | |
246 | - | let prizeShareAmount = (prizePotAmount / winnersCount) | |
247 | - | [IntegerEntry(gamePrizeShareAmountLabel(currentGame), prizeShareAmount)] | |
248 | - | case _ => | |
249 | - | throw("Game has not been initialized, total games not found.") | |
250 | - | } | |
251 | - | case _ => | |
252 | - | throw("Game has not been initialized, total winners not found.") | |
253 | - | } | |
254 | - | else throw("There are still bets that need to be processed. Cannot calculate prize yet.") | |
255 | - | case _ => | |
256 | - | throw("Game has not been initialized, total processed bets not found.") | |
278 | + | func endGame (rsaSign) = if (checkPermission(i.callerPublicKey)) | |
279 | + | then throw("startGame_FORBBIDEN") | |
280 | + | else { | |
281 | + | let currentGame = getCurrentGame() | |
282 | + | let gameState = getGameState(currentGame) | |
283 | + | if ((gameState == 1)) | |
284 | + | then throw("Game is finished and next game has not started.") | |
285 | + | else match gameGetSumSha(currentGame) { | |
286 | + | case SUMSHA: String => | |
287 | + | let sig = fromBase64String(rsaSign) | |
288 | + | let rsaSigValid = rsaVerify(SHA256, fromBase58String(SUMSHA), sig, gameRSAPublic()) | |
289 | + | if (!(rsaSigValid)) | |
290 | + | then throw((("INVALID_RSA_SIGN " + "on game ") + toString(currentGame))) | |
291 | + | else { | |
292 | + | let generator = (toInt(sha256((take(sig, 16) + take(i.transactionId, 16)))) % 17729) | |
293 | + | let generatedResult1 = ((toInt(toBytes(pow(generator, 0, 2, 0, 0, UP))) + currentGame) % 26) | |
294 | + | let generatedResult2 = ((toInt(toBytes(pow(generator, 0, 3, 0, 0, UP))) + currentGame) % 26) | |
295 | + | let generatedResult3 = ((toInt(toBytes(pow(generator, 0, 4, 0, 0, UP))) + currentGame) % 26) | |
296 | + | if (if (if ((generatedResult1 == generatedResult2)) | |
297 | + | then true | |
298 | + | else (generatedResult1 == generatedResult3)) | |
299 | + | then true | |
300 | + | else (generatedResult2 == generatedResult3)) | |
301 | + | then throw("Collision detected between randomly generated results.") | |
302 | + | else { | |
303 | + | let resultsList = [generatedResult1, generatedResult2, generatedResult3] | |
304 | + | let orderedResult1 = min(resultsList) | |
305 | + | let indexResult1 = indexOf(resultsList, orderedResult1) | |
306 | + | let resultsList1 = removeByIndex(resultsList, valueOrElse(indexResult1, 0)) | |
307 | + | let orderedResult2 = min(resultsList1) | |
308 | + | let indexResult2 = indexOf(resultsList1, orderedResult2) | |
309 | + | let resultsList2 = removeByIndex(resultsList1, valueOrElse(indexResult2, 0)) | |
310 | + | let orderedResult3 = resultsList2[0] | |
311 | + | [StringEntry(gameResultLabel(currentGame), ((((((("G" + toString(currentGame)) + "-") + toString(orderedResult1)) + ",") + toString(orderedResult2)) + ",") + toString(orderedResult3))), IntegerEntry(gameStateLabel(currentGame), 1), IntegerEntry(gameCounterLabel, currentGame)] | |
312 | + | } | |
257 | 313 | } | |
258 | - | case _ => | |
259 | - | throw("Game has not been initialized, total bets not found.") | |
260 | - | } | |
261 | - | case _ => | |
262 | - | throw("Game state not found.") | |
314 | + | case _ => | |
315 | + | throw("SHA does not exist") | |
316 | + | } | |
263 | 317 | } | |
264 | - | case _ => | |
265 | - | throw("Game has not been initialized, total games not found") | |
266 | - | } | |
267 | 318 | ||
268 | 319 | ||
269 | 320 | ||
270 | 321 | @Callable(i) | |
271 | - | func processNextWinner () = match gamesGetCounter() { | |
272 | - | case currentGame: Int => | |
273 | - | match gameGetState(currentGame) { | |
274 | - | case gameState: Int => | |
275 | - | if ((gameState == 0)) | |
276 | - | then throw("Last game has not finished yet.") | |
277 | - | else match gamePrizeShareAmount(currentGame) { | |
278 | - | case prizeShareAmount: Int => | |
279 | - | if ((prizeShareAmount == 0)) | |
280 | - | then throw("Prize share amount has not been calculated yet.") | |
281 | - | else match gameWinnersCounter(currentGame) { | |
282 | - | case totalWinners: Int => | |
283 | - | if ((totalWinners == 0)) | |
284 | - | then throw("There are no winners this round.") | |
285 | - | else match gameProcessedWinners(currentGame) { | |
286 | - | case lastProcessedWinner: Int => | |
287 | - | let nextWinner = (lastProcessedWinner + 1) | |
288 | - | if ((nextWinner > totalWinners)) | |
289 | - | then throw("No more winners to be processed.") | |
290 | - | else { | |
291 | - | let betPlacer = winnerDetails(nextWinner) | |
292 | - | let address = value(addressFromString(betPlacer)) | |
293 | - | [ScriptTransfer(address, prizeShareAmount, gameToken()), IntegerEntry(gameProcessedWinnersLabel(currentGame), nextWinner)] | |
294 | - | } | |
295 | - | case _ => | |
296 | - | throw("Game has not been initialized, total processed winners not found.") | |
322 | + | func processNextBet () = if (checkPermission(i.callerPublicKey)) | |
323 | + | then throw("startGame_FORBBIDEN") | |
324 | + | else { | |
325 | + | let currentGame = getCurrentGame() | |
326 | + | let gameState = getGameState(currentGame) | |
327 | + | if ((gameState == 0)) | |
328 | + | then throw("Last game has not finished yet.") | |
329 | + | else { | |
330 | + | let totalBets = getTotalBets(currentGame) | |
331 | + | let lastProcessedBet = getTotalProcessedBets(currentGame) | |
332 | + | let nextBet = (lastProcessedBet + 1) | |
333 | + | if ((nextBet > totalBets)) | |
334 | + | then throw("Next bet has not been placed.") | |
335 | + | else { | |
336 | + | let winnersCount = getWinnersCounter(currentGame) | |
337 | + | let result = gameGetResult(currentGame) | |
338 | + | let betDetail = split(betDetails(currentGame, nextBet), "|")[0] | |
339 | + | let betAddress = split(betDetails(currentGame, nextBet), "|")[1] | |
340 | + | if ((betDetail == result)) | |
341 | + | then { | |
342 | + | let newWinnersCount = (winnersCount + 1) | |
343 | + | [IntegerEntry(gameProcessedBetsLabel(currentGame), nextBet), IntegerEntry(gameWinnersCounterLabel(currentGame), newWinnersCount), StringEntry(winnerDetailsLabel(currentGame, newWinnersCount), betAddress)] | |
344 | + | } | |
345 | + | else [IntegerEntry(gameProcessedBetsLabel(currentGame), nextBet)] | |
346 | + | } | |
347 | + | } | |
348 | + | } | |
349 | + | ||
350 | + | ||
351 | + | ||
352 | + | @Callable(i) | |
353 | + | func calculatePrize () = if (checkPermission(i.callerPublicKey)) | |
354 | + | then throw("startGame_FORBBIDEN") | |
355 | + | else { | |
356 | + | let currentGame = getCurrentGame() | |
357 | + | let gameState = getGameState(currentGame) | |
358 | + | if ((gameState == 0)) | |
359 | + | then throw("Last game has not finished yet.") | |
360 | + | else { | |
361 | + | let totalBets = getTotalBets(currentGame) | |
362 | + | let lastProcessedBet = getTotalProcessedBets(currentGame) | |
363 | + | if ((totalBets == lastProcessedBet)) | |
364 | + | then { | |
365 | + | let winnersCount = getWinnersCounter(currentGame) | |
366 | + | if ((winnersCount == 0)) | |
367 | + | then throw("There are no winners this round.") | |
368 | + | else match gamePrizePot(currentGame) { | |
369 | + | case prizePotAmount: Int => | |
370 | + | let prizeShareAmount = (prizePotAmount / winnersCount) | |
371 | + | [IntegerEntry(gamePrizeShareAmountLabel(currentGame), prizeShareAmount)] | |
372 | + | case _ => | |
373 | + | throw("Game has not been initialized, Prize Pot Amount not found.") | |
374 | + | } | |
375 | + | } | |
376 | + | else throw("There are still bets that need to be processed. Cannot calculate prize yet.") | |
377 | + | } | |
378 | + | } | |
379 | + | ||
380 | + | ||
381 | + | ||
382 | + | @Callable(i) | |
383 | + | func processNextWinner () = if (checkPermission(i.callerPublicKey)) | |
384 | + | then throw("startGame_FORBBIDEN") | |
385 | + | else { | |
386 | + | let currentGame = getCurrentGame() | |
387 | + | let gameState = getGameState(currentGame) | |
388 | + | if ((gameState == 0)) | |
389 | + | then throw("Last game has not finished yet.") | |
390 | + | else { | |
391 | + | let totalWinners = getWinnersCounter(currentGame) | |
392 | + | if ((totalWinners == 0)) | |
393 | + | then throw("There are no winners this round.") | |
394 | + | else { | |
395 | + | let lastProcessedWinner = getTotalProcessedWinners(currentGame) | |
396 | + | let nextWinner = (lastProcessedWinner + 1) | |
397 | + | if ((nextWinner > totalWinners)) | |
398 | + | then throw("No more winners to be processed.") | |
399 | + | else match gamePrizeShareAmount(currentGame) { | |
400 | + | case prizeShareAmount: Int => | |
401 | + | if ((prizeShareAmount == 0)) | |
402 | + | then throw("Prize share amount has not been calculated yet.") | |
403 | + | else { | |
404 | + | let betPlacer = winnerDetails(currentGame, nextWinner) | |
405 | + | let address = value(addressFromString(betPlacer)) | |
406 | + | [IntegerEntry(gameProcessedWinnersLabel(currentGame), nextWinner), ScriptTransfer(address, prizeShareAmount, getGameToken())] | |
297 | 407 | } | |
298 | - | case _ => | |
299 | - | throw("Game has not been initialized, total winners not found.") | |
300 | - | } | |
408 | + | case _ => | |
409 | + | throw("Prize share amount has not been calculated yet.") | |
410 | + | } | |
411 | + | } | |
412 | + | } | |
413 | + | } | |
414 | + | ||
415 | + | ||
416 | + | ||
417 | + | @Callable(i) | |
418 | + | func setParameter (parameterName,parameterValue) = if (checkPermission(i.callerPublicKey)) | |
419 | + | then throw("setParameter_FORBBIDEN") | |
420 | + | else if ((parameterName == "changeTicketPrice")) | |
421 | + | then { | |
422 | + | let ticketPriceValue = valueOrElse(parseIntValue(parameterValue), 0) | |
423 | + | if ((0 > ticketPriceValue)) | |
424 | + | then throw("value cannot be lower than 0") | |
425 | + | else [IntegerEntry(gameTicketPriceLabel, ticketPriceValue)] | |
426 | + | } | |
427 | + | else if ((parameterName == "changeRSA")) | |
428 | + | then match gamesGetCounter() { | |
429 | + | case GAMESCOUNTER: Int => | |
430 | + | match gameGetState(GAMESCOUNTER) { | |
431 | + | case state: Int => | |
432 | + | if ((state != 1)) | |
433 | + | then throw("Game has to be finished.") | |
434 | + | else [StringEntry(gameRSAPublicLabel, parameterValue)] | |
301 | 435 | case _ => | |
302 | - | ||
436 | + | [StringEntry(gameRSAPublicLabel, parameterValue)] | |
303 | 437 | } | |
304 | - | case _ => | |
305 | - | throw("Game state not found.") | |
306 | - | } | |
307 | - | case _ => | |
308 | - | throw("Game has not been initialized, total games not found.") | |
309 | - | } | |
438 | + | case _ => | |
439 | + | throw("Game needs to be initialized.") | |
440 | + | } | |
441 | + | else if ((parameterName == "changeEndHeight")) | |
442 | + | then match gamesGetCounter() { | |
443 | + | case GAMESCOUNTER: Int => | |
444 | + | let endHeightValue = valueOrElse(parseIntValue(parameterValue), 0) | |
445 | + | if ((0 > endHeightValue)) | |
446 | + | then throw("value cannot be lower than 0") | |
447 | + | else [IntegerEntry(gameEndHeightLabel(GAMESCOUNTER), endHeightValue)] | |
448 | + | case _ => | |
449 | + | throw("Game needs to be initialized.") | |
450 | + | } | |
451 | + | else throw("Setting not found. Allowed: changeTicketPrice, changeRSA") | |
310 | 452 | ||
311 | 453 |
github/deemru/w8io/169f3d6 80.44 ms ◑