tx · A2rM6otoebBz8613pNXWwx6WGV7jsjspKmBNDar2z9NW 3NC2gxrsMW5rEBsJCVMjJwBhcB3nnBrUG4f: -0.01000000 Waves 2023.11.16 16:56 [2846020] smart account 3NC2gxrsMW5rEBsJCVMjJwBhcB3nnBrUG4f > SELF 0.00000000 Waves
{ "type": 13, "id": "A2rM6otoebBz8613pNXWwx6WGV7jsjspKmBNDar2z9NW", "fee": 1000000, "feeAssetId": null, "timestamp": 1700143016636, "version": 2, "chainId": 84, "sender": "3NC2gxrsMW5rEBsJCVMjJwBhcB3nnBrUG4f", "senderPublicKey": "E1AzspvmVgU66Pn9sgPQTc586F4eJ4nnWDadbPWyqqXN", "proofs": [ "Y3eXeUyWrPu1e35YigkseVd8YmENo7bxXH8Y5W81yQhWQdhYm2TQqY3zQAfL9eyHKmNLx3mwTiS6H7Mg5W3mvZp" ], "script": "base64:BgIaCAISBgoECAgBCBIDCgEEEgMKAQgSBAoCCAJBAANTRVACAl9fAAdXQVZFU0lEAQQTq9kzAAZXQVZFU0QAgMLXLwAJR0FNRV9OQU1FAg9DYXJkIG9mIHRoZSBEYXkADFJBTkRPTV9SQU5HRQAoAAhOVU1fQkVUUwABAQxnZXRTdHJPckZhaWwCB2FkZHJlc3MDa2V5CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ0IAgUHYWRkcmVzcwUDa2V5CQC5CQIJAMwIAgIKbWFuZGF0b3J5IAkAzAgCCQClCAEFB2FkZHJlc3MJAMwIAgIBLgkAzAgCBQNrZXkJAMwIAgIPIGlzIG5vdCBkZWZpbmVkBQNuaWwCAAEMZ2V0SW50T3JGYWlsAgdhZGRyZXNzA2tleQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFB2FkZHJlc3MFA2tleQkAuQkCCQDMCAICCm1hbmRhdG9yeSAJAMwIAgkApQgBBQdhZGRyZXNzCQDMCAICAS4JAMwIAgUDa2V5CQDMCAICDyBpcyBub3QgZGVmaW5lZAUDbmlsAgABDWdldEJvb2xPckZhaWwCB2FkZHJlc3MDa2V5CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJsIAgUHYWRkcmVzcwUDa2V5CQC5CQIJAMwIAgIKbWFuZGF0b3J5IAkAzAgCCQClCAEFB2FkZHJlc3MJAMwIAgIBLgkAzAgCBQNrZXkJAMwIAgIPIGlzIG5vdCBkZWZpbmVkBQNuaWwCAAAQYWxsb3dlZEFzc2V0c0tleQIYJXMlc19fY2ZnX19hbGxvd2VkQXNzZXRzABFhc3NldHNEZWNpbWFsc0tleQIZJXMlc19fY2ZnX19hc3NldHNEZWNpbWFscwAOYmV0RGl2aWRlcnNLZXkCHCVzJXNfX2NmZ19fYXNzZXRzQmV0RGl2aWRlcnMADlJTQVBVQkxJQzY0S0VZAhYlcyVzX19jZmdfX3JzYVB1YmxpYzY0ABBTRVJWRVJBRERSRVNTS0VZAhYlcyVzX19jZmdfX2JlbnpBZGRyZXNzABBSQU5EVElNRUZSQU1FS0VZAhwlcyVzX19jZmdfX3dpdGhkcmF3VGltZUZyYW1lAA9HQU1FU0NPVU5URVJLRVkCFiVzJXNfX3J1bnRpbWVfX2dhbWVOdW0ACmJsb2NrZWRLZXkCICVzJXNfX3J1bnRpbWVfX2NvbnRyYWN0SXNCbG9ja2VkAQtnZXRJbnRBcnJheQEDa2V5BAFhCQEMZ2V0U3RyT3JGYWlsAgUEdGhpcwUDa2V5CgEGZmlsbGVyAgNhY2MCZWwJAM0IAgUDYWNjCQENcGFyc2VJbnRWYWx1ZQEFAmVsCgACJGwJALUJAgUBYQUDU0VQCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQZmaWxsZXICBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoABkFTU0VUUwkAtQkCCQEMZ2V0U3RyT3JGYWlsAgUEdGhpcwUQYWxsb3dlZEFzc2V0c0tleQUDU0VQAAhERUNJTUFMUwkBC2dldEludEFycmF5AQURYXNzZXRzRGVjaW1hbHNLZXkAC0JFVERJVklERVJTCQELZ2V0SW50QXJyYXkBBQ5iZXREaXZpZGVyc0tleQEYa2V5UmVzZXJ2YXRpb25CeUFzc2V0U3RyAQhhc3NldFN0cgkArAICAhEkUkVTRVJWRURfQU1PVU5UXwUIYXNzZXRTdHIBGGtleVJlc2VydmF0aW9uQnlBc3NldElkeAEIYXNzZXRJZHgJARhrZXlSZXNlcnZhdGlvbkJ5QXNzZXRTdHIBCQCRAwIFBkFTU0VUUwUIYXNzZXRJZHgAC01JTkZFRVdBVkVTCQBpAgkAaAIABQUGV0FWRVNEAOgHAAlpZHhBc3NldHMAAAALaWR4RGVjaW1hbHMAAQALaWR4RGl2aWRlcnMAAgAEQkVUMQABAARCRVQyAAIABEJFVDQABAAEQkVUOAAIAAVCRVQxNAAOAAhSQVRFTVVMVACQTgAEUkFURQCgjQYABEJFVFMJAMwIAgUEQkVUMgUDbmlsAAxJZHhHYW1lU3RhdGUAAAAPSWR4UGxheWVyQ2hvaWNlAAEAEUlkeFBsYXllclB1YktleTU4AAIAEElkeFN0YXJ0ZWRIZWlnaHQAAwAMSWR4V2luQW1vdW50AAQACklkeEFzc2V0SWQABQAOU1RBVEVTVUJNSVRURUQCCVNVQk1JVFRFRAAIU1RBVEVXT04CA1dPTgAJU1RBVEVMT1NUAgRMT1NUAQ9nZXRTdHJpbmdPckZhaWwBA2tleQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFBHRoaXMFA2tleQkArAICBQNrZXkCIyBrZXkgaXMgbm90IHNwZWNpZmllZCBpbiB0aGlzLnN0YXRlAAlSU0FQVUJMSUMJANsEAQkBD2dldFN0cmluZ09yRmFpbAEFDlJTQVBVQkxJQzY0S0VZAAZTRVJWRVIJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAQ9nZXRTdHJpbmdPckZhaWwBBRBTRVJWRVJBRERSRVNTS0VZABNSQU5ET1JBQ0xFVElNRUZSQU1FCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFEFJBTkRUSU1FRlJBTUVLRVkAoDgBCGdldEludE9yAgNrZXkHZGVmYXVsdAMJAQlpc0RlZmluZWQBCQCfCAEFA2tleQkBEUBleHRyTmF0aXZlKDEwNTUpAQUDa2V5BQdkZWZhdWx0AQZzZXRJbnQCA2tleQV2YWx1ZQkBDEludGVnZXJFbnRyeQIFA2tleQUFdmFsdWUBDGluY3JlbWVudEludAEDa2V5CQEGc2V0SW50AgUDa2V5CQBkAgkBCGdldEludE9yAgUDa2V5AP///////////wEAAQEJY2hhbmdlSW50AgNrZXkCYnkJAQZzZXRJbnQCBQNrZXkJAGQCCQEIZ2V0SW50T3ICBQNrZXkAAAUCYnkBDGFzc2V0SWRUb1N0cgENYXNzZXRJZE9yVW5pdAQHJG1hdGNoMAUNYXNzZXRJZE9yVW5pdAMJAAECBQckbWF0Y2gwAgpCeXRlVmVjdG9yBAFiBQckbWF0Y2gwCQDYBAEFAWICBVdBVkVTAQ5hc3NldElkRnJvbVN0cgEKYXNzZXRJZFN0cgMJAAACBQphc3NldElkU3RyAgVXQVZFUwUEdW5pdAkA2QQBBQphc3NldElkU3RyAQ9nZXRBc3NldEJhbGFuY2UBDWFzc2V0SWRPclVuaXQEByRtYXRjaDAFDWFzc2V0SWRPclVuaXQDCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQHYXNzZXRJZAUHJG1hdGNoMAkA8AcCBQR0aGlzBQdhc3NldElkCAkA7wcBBQR0aGlzCWF2YWlsYWJsZQEVaW5jcmVhc2VSZXNlcnZlQW1vdW50Agl3aW5BbW91bnQIYXNzZXRJZHgECmFzc2V0SWRTdHIJAJEDAgUGQVNTRVRTBQhhc3NldElkeAQRbmV3UmVzZXJ2ZWRBbW91bnQJAGQCCQEIZ2V0SW50T3ICCQEYa2V5UmVzZXJ2YXRpb25CeUFzc2V0SWR4AQUIYXNzZXRJZHgAAAUJd2luQW1vdW50AwkAZgIFEW5ld1Jlc2VydmVkQW1vdW50CQEPZ2V0QXNzZXRCYWxhbmNlAQkBDmFzc2V0SWRGcm9tU3RyAQUKYXNzZXRJZFN0cgkAAgEJAKwCAgkArAICAhZJbnN1ZmZpY2llbnQgZnVuZHMgb24gBQlHQU1FX05BTUUCMyBhY2NvdW50LiBUcmFuc2FjdGlvbiB3YXMgcmVqZWN0ZWQgZm9yIHlvdXIgc2FmZXR5LgURbmV3UmVzZXJ2ZWRBbW91bnQBFmRlY3JlYXNlUmVzZXJ2ZWRBbW91bnQDBmdhbWVJZAhhc3NldElkeAl3aW5BbW91bnQDCQBmAgAACQBlAgkBCGdldEludE9yAgkBGGtleVJlc2VydmF0aW9uQnlBc3NldElkeAEFCGFzc2V0SWR4AAAFCXdpbkFtb3VudAkAAgEJAKwCAgkArAICAghJbnZhbGlkIAUJR0FNRV9OQU1FAi8gYWNjb3VudCBzdGF0ZSAtIHJlc2VydmVkIGFtb3VudCBpcyBsZXNzIHRoYW4gMAkBCWNoYW5nZUludAIJARhrZXlSZXNlcnZhdGlvbkJ5QXNzZXRJZHgBBQhhc3NldElkeAkBAS0BBQl3aW5BbW91bnQBFnZhbGlkYXRlQW5kR2V0QXNzZXRJZHgBCmFzc2V0SWRTdHIEA2lkeAkAzwgCBQZBU1NFVFMFCmFzc2V0SWRTdHIDCQEBIQEJAQlpc0RlZmluZWQBBQNpZHgJAAIBAhVJbnZhbGlkIHBheW1lbnQgYXNzZXQJAQV2YWx1ZQEFA2lkeAEadmFsaWRhdGVCZXRBbmRHZXRXaW5BbW91bnQDA2JldBBpbnRlcm5hbEFzc2V0SWR4DHBsYXllckNob2ljZQQKZGljZXNDb3VudAkAsQIBBQxwbGF5ZXJDaG9pY2UKAQtjaGVja0Ftb3VudAIBYQF4AwUBYQYJAAACBQNiZXQJAGkCCQBoAgUBeAkAkQMCBQhERUNJTUFMUwUQaW50ZXJuYWxBc3NldElkeAkAkQMCBQtCRVRESVZJREVSUwUQaW50ZXJuYWxBc3NldElkeAMJAQEhAQoAAiRsBQRCRVRTCgACJHMJAJADAQUCJGwKAAUkYWNjMAcKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBC2NoZWNrQW1vdW50AgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhNMaXN0IHNpemUgZXhjZWVkcyA1CQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQkAAgECF0JldCBhbW91bnQgaXMgbm90IHZhbGlkAwkAAAIJALYJAQUMcGxheWVyQ2hvaWNlBQR1bml0CQACAQIXSW52YWxpZCBwbGF5ZXIncyBjaG9pY2UDCQECIT0CBQpkaWNlc0NvdW50BQhOVU1fQkVUUwkAAgECIUludmFsaWQgbGVuZ3RoIG9mIHBsYXllcidzIGNob2ljZQkAawMFA2JldAUEUkFURQUIUkFURU1VTFQBEmdlbmVyYXRlUmFuZENob2ljZQMGZ2FtZUlkB3JzYVNpZ24McGxheWVyQ2hvaWNlBAtyc2FTaWdWYWxpZAkAqBQEBQZTSEEyNTYJAJsDAQUGZ2FtZUlkBQdyc2FTaWduBQlSU0FQVUJMSUMDCQEBIQEFC3JzYVNpZ1ZhbGlkCQACAQIVSW52YWxpZCBSU0Egc2lnbmF0dXJlBARyYW5kCQBqAgkAsQkBCQD3AwEJAMsBAgUHcnNhU2lnbgkAmwMBBQxwbGF5ZXJDaG9pY2UFDFJBTkRPTV9SQU5HRQkApAMBBQRyYW5kAQtpc1BsYXllcldpbgIMcGxheWVyQ2hvaWNlCnJhbmRDaG9pc2UDCQAAAgkAsQIBBQxwbGF5ZXJDaG9pY2UFCE5VTV9CRVRTCQAAAgUMcGxheWVyQ2hvaWNlBQpyYW5kQ2hvaXNlBwEPZm9ybWF0R2FtZURhdGFTBwpnYW1lU3RhdHVzDHBsYXllckNob2ljZQ5wbGF5ZXJQdWJLZXk1OA1zdGFydGVkSGVpZ2h0CXdpbkFtb3VudAhhc3NldElkeAtyYW5kT3JFbXB0eQkAuQkCCQDMCAIFCmdhbWVTdGF0dXMJAMwIAgUMcGxheWVyQ2hvaWNlCQDMCAIFDnBsYXllclB1YktleTU4CQDMCAIFDXN0YXJ0ZWRIZWlnaHQJAMwIAgUJd2luQW1vdW50CQDMCAIFCGFzc2V0SWR4CQDMCAIDCQAAAgULcmFuZE9yRW1wdHkCAAIABQtyYW5kT3JFbXB0eQUDbmlsAgFfAQ5mb3JtYXRHYW1lRGF0YQcKZ2FtZVN0YXR1cwxwbGF5ZXJDaG9pY2UOcGxheWVyUHViS2V5NTgNc3RhcnRlZEhlaWdodAl3aW5BbW91bnQIYXNzZXRJZHgLcmFuZE9yRW1wdHkJAQ9mb3JtYXRHYW1lRGF0YVMHBQpnYW1lU3RhdHVzBQxwbGF5ZXJDaG9pY2UFDnBsYXllclB1YktleTU4CQCkAwEFDXN0YXJ0ZWRIZWlnaHQJAKQDAQUJd2luQW1vdW50CQCkAwEFCGFzc2V0SWR4BQtyYW5kT3JFbXB0eQEOZmluaXNoR2FtZURhdGEEDG9yaWdHYW1lRGF0YQpnYW1lU3RhdHVzBHJhbmQMd2luQnlUaW1lb3V0BA5maW5pc2hHYW1lRGF0YQkBD2Zvcm1hdEdhbWVEYXRhUwcFCmdhbWVTdGF0dXMJAJEDAgUMb3JpZ0dhbWVEYXRhBQ9JZHhQbGF5ZXJDaG9pY2UJAJEDAgUMb3JpZ0dhbWVEYXRhBRFJZHhQbGF5ZXJQdWJLZXk1OAkAkQMCBQxvcmlnR2FtZURhdGEFEElkeFN0YXJ0ZWRIZWlnaHQJAJEDAgUMb3JpZ0dhbWVEYXRhBQxJZHhXaW5BbW91bnQJAJEDAgUMb3JpZ0dhbWVEYXRhBQpJZHhBc3NldElkBQRyYW5kAwUMd2luQnlUaW1lb3V0CQCsAgIFDmZpbmlzaEdhbWVEYXRhAghfVElNRU9VVAUOZmluaXNoR2FtZURhdGEBD2V4dHJhY3RHYW1lRGF0YQEGZ2FtZUlkCQC1CQIEByRtYXRjaDAJAJ0IAgUEdGhpcwUGZ2FtZUlkAwkAAQIFByRtYXRjaDACBlN0cmluZwQDc3RyBQckbWF0Y2gwBQNzdHIJAAIBCQCsAgIJAKwCAgIGR2FtZTogBQZnYW1lSWQCCyBub3QgZm91bmQuAgFfBAFpAQ1jb25zdHJ1Y3RvclYxBAtyc2FQdWJsaWM2NAtiZW56QWRkcmVzcxNyYW5kT3JhY2xlVGltZUZyYW1lEHRva2Vuc0Rlc2NyaXB0b3IDCQECIT0CCAUBaQZjYWxsZXIFBlNFUlZFUgkAAgECDm5vdCBhdXRob3JpemVkCgEIc3BsaXR0ZXICA2FjYwRlbGVtBAd0b2tMaXN0CQC1CQIFBGVsZW0CAToDCQECIT0CCQCQAwEFB3Rva0xpc3QABAkAAgECFEludmFsaWQgYXNzZXQgcmVjb3JkCQCVCgMJAM0IAggFA2FjYwJfMQkAkQMCBQd0b2tMaXN0BQlpZHhBc3NldHMJAM0IAggFA2FjYwJfMgkAkQMCBQd0b2tMaXN0BQtpZHhEZWNpbWFscwkAzQgCCAUDYWNjAl8zCQCRAwIFB3Rva0xpc3QFC2lkeERpdmlkZXJzBAFyCgACJGwJALwJAgUQdG9rZW5zRGVzY3JpcHRvcgIBXwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAJAJUKAwUDbmlsBQNuaWwFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEIc3BsaXR0ZXICBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoJAMwIAgkBC1N0cmluZ0VudHJ5AgUOUlNBUFVCTElDNjRLRVkFC3JzYVB1YmxpYzY0CQDMCAIJAQtTdHJpbmdFbnRyeQIFEFNFUlZFUkFERFJFU1NLRVkFC2JlbnpBZGRyZXNzCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRBSQU5EVElNRUZSQU1FS0VZBRNyYW5kT3JhY2xlVGltZUZyYW1lCQDMCAIJAQtTdHJpbmdFbnRyeQIFEGFsbG93ZWRBc3NldHNLZXkJALoJAggFAXICXzEFA1NFUAkAzAgCCQELU3RyaW5nRW50cnkCBRFhc3NldHNEZWNpbWFsc0tleQkAuQkCCAUBcgJfMgUDU0VQCQDMCAIJAQtTdHJpbmdFbnRyeQIFDmJldERpdmlkZXJzS2V5CQC5CQIIBQFyAl8zBQNTRVAFA25pbAFpAQttYWludGVuYW5jZQEHYmxvY2tlZAMJAQIhPQIIBQFpBmNhbGxlcgUGU0VSVkVSCQACAQIObm90IGF1dGhvcml6ZWQJAMwIAgkBDEJvb2xlYW5FbnRyeQIFCmJsb2NrZWRLZXkFB2Jsb2NrZWQFA25pbAFpAQNiZXQBDHBsYXllckNob2ljZQMJAQt2YWx1ZU9yRWxzZQIJAKAIAQUKYmxvY2tlZEtleQcJAAIBAh9HYW1lIGlzIHN0b3BwZWQgZm9yIG1haW50ZW5lbmNlBAZnYW1lSWQJANgEAQgFAWkNdHJhbnNhY3Rpb25JZAMJAGcCAAEJAJADAQgFAWkIcGF5bWVudHMJAAIBAhsyIHBheW1lbnRzIG11c3QgYmUgYXR0YWNoZWQDCQEJaXNEZWZpbmVkAQkAnQgCBQR0aGlzBQZnYW1lSWQJAAIBCQCsAgIJAKwCAgIJQmV0IGZvcjogBQZnYW1lSWQCEiB3YXMgYWxyZWFkeSBtYWRlLgQGYmV0UG10CQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAAEBmZlZVBtdAkBBXZhbHVlAQkAkQMCCAUBaQhwYXltZW50cwABAwkBCWlzRGVmaW5lZAEIBQZmZWVQbXQHYXNzZXRJZAkAAgECLWZlZVBtdCAoMm5kIHBheW1lbnQpIGFzc2V0SWQgbXVzdCBiZSBpbiBXYXZlcwMJAGYCBQtNSU5GRUVXQVZFUwgFBmZlZVBtdAZhbW91bnQJAAIBAitmZWVQbXQgKDJuZCBwYXltZW50KSBtdXN0IGJlID49IDAuMDA1IFdhdmVzBAphc3NldElkU3RyCQEMYXNzZXRJZFRvU3RyAQgFBmJldFBtdAdhc3NldElkBBBpbnRlcm5hbEFzc2V0SWR4CQEWdmFsaWRhdGVBbmRHZXRBc3NldElkeAEFCmFzc2V0SWRTdHIECmNvbW1pc3Npb24IBQZmZWVQbXQGYW1vdW50BAl3aW5BbW91bnQJARp2YWxpZGF0ZUJldEFuZEdldFdpbkFtb3VudAMIBQZiZXRQbXQGYW1vdW50BRBpbnRlcm5hbEFzc2V0SWR4BQxwbGF5ZXJDaG9pY2UEDnBsYXllclB1YktleTU4CQDYBAEIBQFpD2NhbGxlclB1YmxpY0tleQQIZ2FtZURhdGEJAQ5mb3JtYXRHYW1lRGF0YQcFDlNUQVRFU1VCTUlUVEVEBQxwbGF5ZXJDaG9pY2UFDnBsYXllclB1YktleTU4BQZoZWlnaHQFCXdpbkFtb3VudAUQaW50ZXJuYWxBc3NldElkeAIACQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEYa2V5UmVzZXJ2YXRpb25CeUFzc2V0SWR4AQUQaW50ZXJuYWxBc3NldElkeAkBFWluY3JlYXNlUmVzZXJ2ZUFtb3VudAIFCXdpbkFtb3VudAUQaW50ZXJuYWxBc3NldElkeAkAzAgCCQEMaW5jcmVtZW50SW50AQUPR0FNRVNDT1VOVEVSS0VZCQDMCAIJAQtTdHJpbmdFbnRyeQIFBmdhbWVJZAUIZ2FtZURhdGEJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwUGU0VSVkVSBQpjb21taXNzaW9uCAUGZmVlUG10B2Fzc2V0SWQFA25pbAFpAQh3aXRoZHJhdwIGZ2FtZUlkB3JzYVNpZ24ECGdhbWVEYXRhCQEPZXh0cmFjdEdhbWVEYXRhAQUGZ2FtZUlkBAlnYW1lU3RhdGUJAJEDAgUIZ2FtZURhdGEFDElkeEdhbWVTdGF0ZQQMcGxheWVyQ2hvaWNlCQCRAwIFCGdhbWVEYXRhBQ9JZHhQbGF5ZXJDaG9pY2UEDXN0YXJ0ZWRIZWlnaHQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQhnYW1lRGF0YQUQSWR4U3RhcnRlZEhlaWdodAQJd2luQW1vdW50CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUIZ2FtZURhdGEFDElkeFdpbkFtb3VudAQIYXNzZXRJZHgJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQhnYW1lRGF0YQUKSWR4QXNzZXRJZAQOcGxheWVyUHViS2V5NTgJAJEDAgUIZ2FtZURhdGEFEUlkeFBsYXllclB1YktleTU4BA1wbGF5ZXJBZGRyZXNzCQCnCAEJANkEAQUOcGxheWVyUHViS2V5NTgDCQECIT0CBQlnYW1lU3RhdGUFDlNUQVRFU1VCTUlUVEVECQACAQIkSW52YWxpZCBnYW1lIHN0YXRlIGZvciBwYXNzZWQgZ2FtZUlkAwkBAiE9AggFAWkGY2FsbGVyBQZTRVJWRVIJAAIBAitSZWd1bGFyIHdpdGhkcmF3IGNhbiBiZSBkb25lIGJ5IHNlcnZlciBvbmx5BAx3aW5CeVRpbWVvdXQJAGYCCQBlAgUGaGVpZ2h0BQ1zdGFydGVkSGVpZ2h0BRNSQU5ET1JBQ0xFVElNRUZSQU1FBApyYW5kQ2hvaXNlAwUMd2luQnlUaW1lb3V0BQxwbGF5ZXJDaG9pY2UJARJnZW5lcmF0ZVJhbmRDaG9pY2UDBQZnYW1lSWQFB3JzYVNpZ24FDHBsYXllckNob2ljZQQJcGxheWVyV2luCQELaXNQbGF5ZXJXaW4CBQxwbGF5ZXJDaG9pY2UFCnJhbmRDaG9pc2UEDW5ld0dhbWVTdGF0dXMDBQlwbGF5ZXJXaW4FCFNUQVRFV09OBQlTVEFURUxPU1QEC25ld0dhbWVEYXRhCQEOZmluaXNoR2FtZURhdGEEBQhnYW1lRGF0YQUNbmV3R2FtZVN0YXR1cwUKcmFuZENob2lzZQUMd2luQnlUaW1lb3V0CQDOCAIJAMwIAgkBC1N0cmluZ0VudHJ5AgUGZ2FtZUlkBQtuZXdHYW1lRGF0YQkAzAgCCQEWZGVjcmVhc2VSZXNlcnZlZEFtb3VudAMFBmdhbWVJZAUIYXNzZXRJZHgFCXdpbkFtb3VudAUDbmlsAwUJcGxheWVyV2luCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMFDXBsYXllckFkZHJlc3MFCXdpbkFtb3VudAkBDmFzc2V0SWRGcm9tU3RyAQkAkQMCBQZBU1NFVFMFCGFzc2V0SWR4BQNuaWwFA25pbADnwxzM", "height": 2846020, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: GciyrmMFZABJKwnkB6KJEpRFg9YM63CfdbGiKEf7oWpN Next: 8icnVbJR6Fws6qEwH1XpXYhenGANTmaWS6a9fN6PDScv Full:
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 6 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | - | let x = ["a", "b"] | |
4 | + | let SEP = "__" | |
5 | + | ||
6 | + | let WAVESID = base58'WAVES' | |
7 | + | ||
8 | + | let WAVESD = 100000000 | |
9 | + | ||
10 | + | let GAME_NAME = "Card of the Day" | |
11 | + | ||
12 | + | let RANDOM_RANGE = 40 | |
13 | + | ||
14 | + | let NUM_BETS = 1 | |
15 | + | ||
16 | + | func getStrOrFail (address,key) = valueOrErrorMessage(getString(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], "")) | |
17 | + | ||
18 | + | ||
19 | + | func getIntOrFail (address,key) = valueOrErrorMessage(getInteger(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], "")) | |
20 | + | ||
21 | + | ||
22 | + | func getBoolOrFail (address,key) = valueOrErrorMessage(getBoolean(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], "")) | |
23 | + | ||
24 | + | ||
25 | + | let allowedAssetsKey = "%s%s__cfg__allowedAssets" | |
26 | + | ||
27 | + | let assetsDecimalsKey = "%s%s__cfg__assetsDecimals" | |
28 | + | ||
29 | + | let betDividersKey = "%s%s__cfg__assetsBetDividers" | |
30 | + | ||
31 | + | let RSAPUBLIC64KEY = "%s%s__cfg__rsaPublic64" | |
32 | + | ||
33 | + | let SERVERADDRESSKEY = "%s%s__cfg__benzAddress" | |
34 | + | ||
35 | + | let RANDTIMEFRAMEKEY = "%s%s__cfg__withdrawTimeFrame" | |
36 | + | ||
37 | + | let GAMESCOUNTERKEY = "%s%s__runtime__gameNum" | |
38 | + | ||
39 | + | let blockedKey = "%s%s__runtime__contractIsBlocked" | |
40 | + | ||
41 | + | func getIntArray (key) = { | |
42 | + | let a = getStrOrFail(this, key) | |
43 | + | func filler (acc,el) = (acc :+ parseIntValue(el)) | |
44 | + | ||
45 | + | let $l = split(a, SEP) | |
46 | + | let $s = size($l) | |
47 | + | let $acc0 = nil | |
48 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
49 | + | then $a | |
50 | + | else filler($a, $l[$i]) | |
51 | + | ||
52 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
53 | + | then $a | |
54 | + | else throw("List size exceeds 10") | |
55 | + | ||
56 | + | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10) | |
57 | + | } | |
58 | + | ||
59 | + | ||
60 | + | let ASSETS = split(getStrOrFail(this, allowedAssetsKey), SEP) | |
61 | + | ||
62 | + | let DECIMALS = getIntArray(assetsDecimalsKey) | |
63 | + | ||
64 | + | let BETDIVIDERS = getIntArray(betDividersKey) | |
65 | + | ||
66 | + | func keyReservationByAssetStr (assetStr) = ("$RESERVED_AMOUNT_" + assetStr) | |
67 | + | ||
68 | + | ||
69 | + | func keyReservationByAssetIdx (assetIdx) = keyReservationByAssetStr(ASSETS[assetIdx]) | |
70 | + | ||
71 | + | ||
72 | + | let MINFEEWAVES = ((5 * WAVESD) / 1000) | |
73 | + | ||
74 | + | let idxAssets = 0 | |
75 | + | ||
76 | + | let idxDecimals = 1 | |
77 | + | ||
78 | + | let idxDividers = 2 | |
79 | + | ||
80 | + | let BET1 = 1 | |
81 | + | ||
82 | + | let BET2 = 2 | |
83 | + | ||
84 | + | let BET4 = 4 | |
85 | + | ||
86 | + | let BET8 = 8 | |
87 | + | ||
88 | + | let BET14 = 14 | |
89 | + | ||
90 | + | let RATEMULT = 10000 | |
91 | + | ||
92 | + | let RATE = 100000 | |
93 | + | ||
94 | + | let BETS = [BET2] | |
95 | + | ||
96 | + | let IdxGameState = 0 | |
97 | + | ||
98 | + | let IdxPlayerChoice = 1 | |
99 | + | ||
100 | + | let IdxPlayerPubKey58 = 2 | |
101 | + | ||
102 | + | let IdxStartedHeight = 3 | |
103 | + | ||
104 | + | let IdxWinAmount = 4 | |
105 | + | ||
106 | + | let IdxAssetId = 5 | |
107 | + | ||
108 | + | let STATESUBMITTED = "SUBMITTED" | |
109 | + | ||
110 | + | let STATEWON = "WON" | |
111 | + | ||
112 | + | let STATELOST = "LOST" | |
113 | + | ||
114 | + | func getStringOrFail (key) = valueOrErrorMessage(getString(this, key), (key + " key is not specified in this.state")) | |
115 | + | ||
116 | + | ||
117 | + | let RSAPUBLIC = fromBase64String(getStringOrFail(RSAPUBLIC64KEY)) | |
118 | + | ||
119 | + | let SERVER = addressFromStringValue(getStringOrFail(SERVERADDRESSKEY)) | |
120 | + | ||
121 | + | let RANDORACLETIMEFRAME = valueOrElse(getInteger(this, RANDTIMEFRAMEKEY), 7200) | |
122 | + | ||
123 | + | func getIntOr (key,default) = if (isDefined(getInteger(key))) | |
124 | + | then getIntegerValue(key) | |
125 | + | else default | |
126 | + | ||
127 | + | ||
128 | + | func setInt (key,value) = IntegerEntry(key, value) | |
129 | + | ||
130 | + | ||
131 | + | func incrementInt (key) = setInt(key, (getIntOr(key, -1) + 1)) | |
132 | + | ||
133 | + | ||
134 | + | func changeInt (key,by) = setInt(key, (getIntOr(key, 0) + by)) | |
135 | + | ||
136 | + | ||
137 | + | func assetIdToStr (assetIdOrUnit) = match assetIdOrUnit { | |
138 | + | case b: ByteVector => | |
139 | + | toBase58String(b) | |
140 | + | case _ => | |
141 | + | "WAVES" | |
142 | + | } | |
143 | + | ||
144 | + | ||
145 | + | func assetIdFromStr (assetIdStr) = if ((assetIdStr == "WAVES")) | |
146 | + | then unit | |
147 | + | else fromBase58String(assetIdStr) | |
148 | + | ||
149 | + | ||
150 | + | func getAssetBalance (assetIdOrUnit) = match assetIdOrUnit { | |
151 | + | case assetId: ByteVector => | |
152 | + | assetBalance(this, assetId) | |
153 | + | case _ => | |
154 | + | wavesBalance(this).available | |
155 | + | } | |
156 | + | ||
157 | + | ||
158 | + | func increaseReserveAmount (winAmount,assetIdx) = { | |
159 | + | let assetIdStr = ASSETS[assetIdx] | |
160 | + | let newReservedAmount = (getIntOr(keyReservationByAssetIdx(assetIdx), 0) + winAmount) | |
161 | + | if ((newReservedAmount > getAssetBalance(assetIdFromStr(assetIdStr)))) | |
162 | + | then throw((("Insufficient funds on " + GAME_NAME) + " account. Transaction was rejected for your safety.")) | |
163 | + | else newReservedAmount | |
164 | + | } | |
165 | + | ||
166 | + | ||
167 | + | func decreaseReservedAmount (gameId,assetIdx,winAmount) = if ((0 > (getIntOr(keyReservationByAssetIdx(assetIdx), 0) - winAmount))) | |
168 | + | then throw((("Invalid " + GAME_NAME) + " account state - reserved amount is less than 0")) | |
169 | + | else changeInt(keyReservationByAssetIdx(assetIdx), -(winAmount)) | |
170 | + | ||
171 | + | ||
172 | + | func validateAndGetAssetIdx (assetIdStr) = { | |
173 | + | let idx = indexOf(ASSETS, assetIdStr) | |
174 | + | if (!(isDefined(idx))) | |
175 | + | then throw("Invalid payment asset") | |
176 | + | else value(idx) | |
177 | + | } | |
178 | + | ||
179 | + | ||
180 | + | func validateBetAndGetWinAmount (bet,internalAssetIdx,playerChoice) = { | |
181 | + | let dicesCount = size(playerChoice) | |
182 | + | func checkAmount (a,x) = if (a) | |
183 | + | then true | |
184 | + | else (bet == ((x * DECIMALS[internalAssetIdx]) / BETDIVIDERS[internalAssetIdx])) | |
185 | + | ||
186 | + | if (!({ | |
187 | + | let $l = BETS | |
188 | + | let $s = size($l) | |
189 | + | let $acc0 = false | |
190 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
191 | + | then $a | |
192 | + | else checkAmount($a, $l[$i]) | |
193 | + | ||
194 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
195 | + | then $a | |
196 | + | else throw("List size exceeds 5") | |
197 | + | ||
198 | + | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5) | |
199 | + | })) | |
200 | + | then throw("Bet amount is not valid") | |
201 | + | else if ((parseInt(playerChoice) == unit)) | |
202 | + | then throw("Invalid player's choice") | |
203 | + | else if ((dicesCount != NUM_BETS)) | |
204 | + | then throw("Invalid length of player's choice") | |
205 | + | else fraction(bet, RATE, RATEMULT) | |
206 | + | } | |
207 | + | ||
208 | + | ||
209 | + | func generateRandChoice (gameId,rsaSign,playerChoice) = { | |
210 | + | let rsaSigValid = rsaVerify_16Kb(SHA256, toBytes(gameId), rsaSign, RSAPUBLIC) | |
211 | + | if (!(rsaSigValid)) | |
212 | + | then throw("Invalid RSA signature") | |
213 | + | else { | |
214 | + | let rand = (toInt(sha256((rsaSign + toBytes(playerChoice)))) % RANDOM_RANGE) | |
215 | + | toString(rand) | |
216 | + | } | |
217 | + | } | |
218 | + | ||
219 | + | ||
220 | + | func isPlayerWin (playerChoice,randChoise) = if ((size(playerChoice) == NUM_BETS)) | |
221 | + | then (playerChoice == randChoise) | |
222 | + | else false | |
223 | + | ||
224 | + | ||
225 | + | func formatGameDataS (gameStatus,playerChoice,playerPubKey58,startedHeight,winAmount,assetIdx,randOrEmpty) = makeString([gameStatus, playerChoice, playerPubKey58, startedHeight, winAmount, assetIdx, if ((randOrEmpty == "")) | |
226 | + | then "" | |
227 | + | else randOrEmpty], "_") | |
228 | + | ||
229 | + | ||
230 | + | func formatGameData (gameStatus,playerChoice,playerPubKey58,startedHeight,winAmount,assetIdx,randOrEmpty) = formatGameDataS(gameStatus, playerChoice, playerPubKey58, toString(startedHeight), toString(winAmount), toString(assetIdx), randOrEmpty) | |
231 | + | ||
232 | + | ||
233 | + | func finishGameData (origGameData,gameStatus,rand,winByTimeout) = { | |
234 | + | let finishGameData = formatGameDataS(gameStatus, origGameData[IdxPlayerChoice], origGameData[IdxPlayerPubKey58], origGameData[IdxStartedHeight], origGameData[IdxWinAmount], origGameData[IdxAssetId], rand) | |
235 | + | if (winByTimeout) | |
236 | + | then (finishGameData + "_TIMEOUT") | |
237 | + | else finishGameData | |
238 | + | } | |
239 | + | ||
240 | + | ||
241 | + | func extractGameData (gameId) = split(match getString(this, gameId) { | |
242 | + | case str: String => | |
243 | + | str | |
244 | + | case _ => | |
245 | + | throw((("Game: " + gameId) + " not found.")) | |
246 | + | }, "_") | |
247 | + | ||
5 | 248 | ||
6 | 249 | @Callable(i) | |
7 | - | func test () = $Tuple2(nil, x) | |
250 | + | func constructorV1 (rsaPublic64,benzAddress,randOracleTimeFrame,tokensDescriptor) = if ((i.caller != SERVER)) | |
251 | + | then throw("not authorized") | |
252 | + | else { | |
253 | + | func splitter (acc,elem) = { | |
254 | + | let tokList = split(elem, ":") | |
255 | + | if ((size(tokList) != 4)) | |
256 | + | then throw("Invalid asset record") | |
257 | + | else $Tuple3((acc._1 :+ tokList[idxAssets]), (acc._2 :+ tokList[idxDecimals]), (acc._3 :+ tokList[idxDividers])) | |
258 | + | } | |
259 | + | ||
260 | + | let r = { | |
261 | + | let $l = split_4C(tokensDescriptor, "_") | |
262 | + | let $s = size($l) | |
263 | + | let $acc0 = $Tuple3(nil, nil, nil) | |
264 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
265 | + | then $a | |
266 | + | else splitter($a, $l[$i]) | |
267 | + | ||
268 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
269 | + | then $a | |
270 | + | else throw("List size exceeds 10") | |
271 | + | ||
272 | + | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10) | |
273 | + | } | |
274 | + | [StringEntry(RSAPUBLIC64KEY, rsaPublic64), StringEntry(SERVERADDRESSKEY, benzAddress), IntegerEntry(RANDTIMEFRAMEKEY, randOracleTimeFrame), StringEntry(allowedAssetsKey, makeString_2C(r._1, SEP)), StringEntry(assetsDecimalsKey, makeString(r._2, SEP)), StringEntry(betDividersKey, makeString(r._3, SEP))] | |
275 | + | } | |
276 | + | ||
277 | + | ||
278 | + | ||
279 | + | @Callable(i) | |
280 | + | func maintenance (blocked) = if ((i.caller != SERVER)) | |
281 | + | then throw("not authorized") | |
282 | + | else [BooleanEntry(blockedKey, blocked)] | |
283 | + | ||
284 | + | ||
285 | + | ||
286 | + | @Callable(i) | |
287 | + | func bet (playerChoice) = if (valueOrElse(getBoolean(blockedKey), false)) | |
288 | + | then throw("Game is stopped for maintenence") | |
289 | + | else { | |
290 | + | let gameId = toBase58String(i.transactionId) | |
291 | + | if ((1 >= size(i.payments))) | |
292 | + | then throw("2 payments must be attached") | |
293 | + | else if (isDefined(getString(this, gameId))) | |
294 | + | then throw((("Bet for: " + gameId) + " was already made.")) | |
295 | + | else { | |
296 | + | let betPmt = value(i.payments[0]) | |
297 | + | let feePmt = value(i.payments[1]) | |
298 | + | if (isDefined(feePmt.assetId)) | |
299 | + | then throw("feePmt (2nd payment) assetId must be in Waves") | |
300 | + | else if ((MINFEEWAVES > feePmt.amount)) | |
301 | + | then throw("feePmt (2nd payment) must be >= 0.005 Waves") | |
302 | + | else { | |
303 | + | let assetIdStr = assetIdToStr(betPmt.assetId) | |
304 | + | let internalAssetIdx = validateAndGetAssetIdx(assetIdStr) | |
305 | + | let commission = feePmt.amount | |
306 | + | let winAmount = validateBetAndGetWinAmount(betPmt.amount, internalAssetIdx, playerChoice) | |
307 | + | let playerPubKey58 = toBase58String(i.callerPublicKey) | |
308 | + | let gameData = formatGameData(STATESUBMITTED, playerChoice, playerPubKey58, height, winAmount, internalAssetIdx, "") | |
309 | + | [IntegerEntry(keyReservationByAssetIdx(internalAssetIdx), increaseReserveAmount(winAmount, internalAssetIdx)), incrementInt(GAMESCOUNTERKEY), StringEntry(gameId, gameData), ScriptTransfer(SERVER, commission, feePmt.assetId)] | |
310 | + | } | |
311 | + | } | |
312 | + | } | |
313 | + | ||
314 | + | ||
315 | + | ||
316 | + | @Callable(i) | |
317 | + | func withdraw (gameId,rsaSign) = { | |
318 | + | let gameData = extractGameData(gameId) | |
319 | + | let gameState = gameData[IdxGameState] | |
320 | + | let playerChoice = gameData[IdxPlayerChoice] | |
321 | + | let startedHeight = parseIntValue(gameData[IdxStartedHeight]) | |
322 | + | let winAmount = parseIntValue(gameData[IdxWinAmount]) | |
323 | + | let assetIdx = parseIntValue(gameData[IdxAssetId]) | |
324 | + | let playerPubKey58 = gameData[IdxPlayerPubKey58] | |
325 | + | let playerAddress = addressFromPublicKey(fromBase58String(playerPubKey58)) | |
326 | + | if ((gameState != STATESUBMITTED)) | |
327 | + | then throw("Invalid game state for passed gameId") | |
328 | + | else if ((i.caller != SERVER)) | |
329 | + | then throw("Regular withdraw can be done by server only") | |
330 | + | else { | |
331 | + | let winByTimeout = ((height - startedHeight) > RANDORACLETIMEFRAME) | |
332 | + | let randChoise = if (winByTimeout) | |
333 | + | then playerChoice | |
334 | + | else generateRandChoice(gameId, rsaSign, playerChoice) | |
335 | + | let playerWin = isPlayerWin(playerChoice, randChoise) | |
336 | + | let newGameStatus = if (playerWin) | |
337 | + | then STATEWON | |
338 | + | else STATELOST | |
339 | + | let newGameData = finishGameData(gameData, newGameStatus, randChoise, winByTimeout) | |
340 | + | ([StringEntry(gameId, newGameData), decreaseReservedAmount(gameId, assetIdx, winAmount)] ++ (if (playerWin) | |
341 | + | then [ScriptTransfer(playerAddress, winAmount, assetIdFromStr(ASSETS[assetIdx]))] | |
342 | + | else nil)) | |
343 | + | } | |
344 | + | } | |
8 | 345 | ||
9 | 346 |
github/deemru/w8io/026f985 28.89 ms ◑