tx · FCdtaYaWWff2Vf8uFLmaDwSj2o1SsMU9DrFo6E8rUXNA

3PLJHro4tbUssVMHY538QqsVZWPVHTUpHir:  -0.01000000 Waves

2023.05.20 10:40 [3651482] smart account 3PLJHro4tbUssVMHY538QqsVZWPVHTUpHir > SELF 0.00000000 Waves

{ "type": 13, "id": "FCdtaYaWWff2Vf8uFLmaDwSj2o1SsMU9DrFo6E8rUXNA", "fee": 1000000, "feeAssetId": null, "timestamp": 1684568473748, "version": 2, "chainId": 87, "sender": "3PLJHro4tbUssVMHY538QqsVZWPVHTUpHir", "senderPublicKey": "8er5GibY1hbf7RjN9rdnQW5Ua9xM7UtDohqbdEukAT7v", "proofs": [ "4Xof2ApCzxnboNVpY25Sde66hb7jbwSDWWCqKFgUiJtKwwRwWLQ7ZWJaK8K8P9KygjCjkajd5WV985Nr5ARm8ncj" ], "script": "base64:BgIfCAISBgoECAgBGBIDCgEIEgMKAQgSBAoCCBgSAwoBCAoAEExhc3RDb250ZXN0SWRLZXkCD2xhc3RfY29udGVzdF9pZAANQ29udGVzdFByZWZpeAIIY29udGVzdF8ADFN0YXR1c19EcmFmdAIFZHJhZnQADVN0YXR1c19BY3RpdmUCBmFjdGl2ZQALU3RhdHVzX1N0b3ACBHN0b3AADVN0YXR1c19EZWx0ZWQCB2RlbGV0ZWQADVN0YXR1c19GaW5pc2gCBmZpbmlzaAENY2FsY1ByaXplRnVuZAEIcGF5bWVudHMKAQRjYWxjAgVhY2N1bQRuZXh0BAlhc3NldE5hbWUEByRtYXRjaDAIBQRuZXh0B2Fzc2V0SWQDCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQBdAUHJG1hdGNoMAkA2AQBBQF0AgVXQVZFUwMDCQBmAgkAsQIBBQlhc3NldE5hbWUAAAkAZgIIBQRuZXh0BmFtb3VudAAABwkAzQgCBQVhY2N1bQkArAICCQCsAgIFCWFzc2V0TmFtZQIBOgkApAMBCAUEbmV4dAZhbW91bnQFBWFjY3VtCQC6CQIKAAIkbAUIcGF5bWVudHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBBGNhbGMCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoCAXwBEWdldFByaXplVHJhbnNmZXJzAgxwcml6ZUZ1bmRTdHIJcmVjaXBpZW50CgEEY2FsYwIFYWNjdW0EbmV4dAQFcGFydHMJALUJAgUEbmV4dAIBOgQHYXNzZXRJZAMJAAACCQCRAwIFBXBhcnRzAAACBVdBVkVTBQR1bml0CQDZBAEJAJEDAgUFcGFydHMAAAkAzQgCBQVhY2N1bQkBDlNjcmlwdFRyYW5zZmVyAwUJcmVjaXBpZW50CQEFdmFsdWUBCQC2CQEJAJEDAgUFcGFydHMAAQUHYXNzZXRJZAoAAiRsCQC8CQIFDHByaXplRnVuZFN0cgIBfAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEEY2FsYwIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgEPZ2V0UmFuZG9tTnVtYmVyBAh2YXJpYW50cwR0eElkC2Jsb2NrSGVpZ2h0Bm9mZnNldAQPcmFuZG9tU2VlZEJsb2NrCQEFdmFsdWUBCQDtBwEJAGUCBQtibG9ja0hlaWdodAABBApyYW5kb21IYXNoCQD3AwEJAMsBAgUEdHhJZAkBBXZhbHVlAQgFD3JhbmRvbVNlZWRCbG9jawN2cmYJAGoCCQCyCQIFCnJhbmRvbUhhc2gJAGgCBQZvZmZzZXQACAUIdmFyaWFudHMFAWkBBmNyZWF0ZQQEbmFtZQRkZXNjCWVuZEhlaWdodAV0YXNrcwQMcHJpemVGdW5kU3RyCQENY2FsY1ByaXplRnVuZAEIBQFpCHBheW1lbnRzAwkAAAIJALECAQUMcHJpemVGdW5kU3RyAAAJAAIBAgtObyBwYXltZW50cwMJAAACCQCQAwEFBXRhc2tzAAAJAAIBAhBUYXNrcyBsaXN0IGVtcHR5AwkAAAIJALECAQUEbmFtZQAACQACAQIKTmFtZSBlbXB0eQMJAAACCQCxAgEFBGRlc2MAAAkAAgECCkRlc2MgZW1wdHkDCQBmAgUGaGVpZ2h0BQllbmRIZWlnaHQJAAIBAhBJbnZhbGlkIGRhdGUgZW5kBAljb250ZXN0SWQJAQt2YWx1ZU9yRWxzZQIJAJ8IAQUQTGFzdENvbnRlc3RJZEtleQABCQCUCgIJAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICCQCsAgIFDUNvbnRlc3RQcmVmaXgJAKQDAQUJY29udGVzdElkAgVfbmFtZQUEbmFtZQkAzAgCCQELU3RyaW5nRW50cnkCCQCsAgIJAKwCAgUNQ29udGVzdFByZWZpeAkApAMBBQljb250ZXN0SWQCBV9kZXNjBQRkZXNjCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgUNQ29udGVzdFByZWZpeAkApAMBBQljb250ZXN0SWQCDF9zdGFydEhlaWdodAUGaGVpZ2h0CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgUNQ29udGVzdFByZWZpeAkApAMBBQljb250ZXN0SWQCCl9lbmRIZWlnaHQFCWVuZEhlaWdodAkAzAgCCQELU3RyaW5nRW50cnkCCQCsAgIJAKwCAgUNQ29udGVzdFByZWZpeAkApAMBBQljb250ZXN0SWQCBl9vd25lcgkApQgBCAUBaQZjYWxsZXIJAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICCQCsAgIFDUNvbnRlc3RQcmVmaXgJAKQDAQUJY29udGVzdElkAgpfcHJpemVGdW5kBQxwcml6ZUZ1bmRTdHIJAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICCQCsAgIFDUNvbnRlc3RQcmVmaXgJAKQDAQUJY29udGVzdElkAgZfdGFza3MJALoJAgUFdGFza3MCATsJAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICCQCsAgIFDUNvbnRlc3RQcmVmaXgJAKQDAQUJY29udGVzdElkAgdfc3RhdHVzBQ1TdGF0dXNfQWN0aXZlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRBMYXN0Q29udGVzdElkS2V5CQBkAgUJY29udGVzdElkAAEFA25pbAUJY29udGVzdElkAWkBC3BhcnRpY2lwYXRlAQljb250ZXN0SWQEDENvbnRlc3RJZFN0cgkArAICBQ1Db250ZXN0UHJlZml4BQljb250ZXN0SWQEGENvbnRlc3RQYXJ0aWNpcGFudFByZWZpeAkArAICCQCsAgIFDENvbnRlc3RJZFN0cgINX3BhcnRpY2lwYW50XwkApQgBCAUBaQZjYWxsZXIEHENvbnRlc3RQYXJ0aWNpcGFudEFkZHJlc3NLZXkJAKwCAgUYQ29udGVzdFBhcnRpY2lwYW50UHJlZml4AghfYWRkcmVzcwQHaXNPd25lcgQHJG1hdGNoMAkAoggBCQCsAgIFDENvbnRlc3RJZFN0cgIGX293bmVyAwkAAQIFByRtYXRjaDACBlN0cmluZwQBdAUHJG1hdGNoMAkAAAIFAXQJAKUIAQgFAWkGY2FsbGVyCQACAQIURGF0YSBnZXQgb3duZXIgZXJyb3IEB2lzRXhpc3QEByRtYXRjaDAJAKIIAQUcQ29udGVzdFBhcnRpY2lwYW50QWRkcmVzc0tleQMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAXQFByRtYXRjaDAGBwQRcGFydGljaXBhbnRzQ291bnQJAQt2YWx1ZU9yRWxzZQIJAJ8IAQkArAICBQxDb250ZXN0SWRTdHICEl9wYXJ0aWNpcGFudHNDb3VudAAAAwUHaXNPd25lcgkAAgECGE93bmVyIGNhbm5vdCBwYXJ0aWNpcGF0ZQMFB2lzRXhpc3QJAAIBAh1Zb3UgYXJlIGFscmVhZHkgcGFydGljaXBhdGluZwkAzAgCCQELU3RyaW5nRW50cnkCBRxDb250ZXN0UGFydGljaXBhbnRBZGRyZXNzS2V5CQClCAEIBQFpBmNhbGxlcgkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICBRhDb250ZXN0UGFydGljaXBhbnRQcmVmaXgCCl9zdGFydGVkQXQFBmhlaWdodAkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICBQxDb250ZXN0SWRTdHICEl9wYXJ0aWNpcGFudHNDb3VudAkAZAIFEXBhcnRpY2lwYW50c0NvdW50AAEFA25pbAFpAQ11bnBhcnRpY2lwYXRlAQljb250ZXN0SWQEDENvbnRlc3RJZFN0cgkArAICBQ1Db250ZXN0UHJlZml4BQljb250ZXN0SWQEGENvbnRlc3RQYXJ0aWNpcGFudFByZWZpeAkArAICCQCsAgIFDENvbnRlc3RJZFN0cgINX3BhcnRpY2lwYW50XwkApQgBCAUBaQZjYWxsZXIEHENvbnRlc3RQYXJ0aWNpcGFudEFkZHJlc3NLZXkJAKwCAgUYQ29udGVzdFBhcnRpY2lwYW50UHJlZml4AghfYWRkcmVzcwQHaXNFeGlzdAQHJG1hdGNoMAkAoggBBRxDb250ZXN0UGFydGljaXBhbnRBZGRyZXNzS2V5AwkAAQIFByRtYXRjaDACBlN0cmluZwQBdAUHJG1hdGNoMAYHBBFwYXJ0aWNpcGFudHNDb3VudAkBC3ZhbHVlT3JFbHNlAgkAnwgBCQCsAgIFDENvbnRlc3RJZFN0cgISX3BhcnRpY2lwYW50c0NvdW50AAADCQEBIQEFB2lzRXhpc3QJAAIBAhlZb3UgYXJlIG5vdCBwYXJ0aWNpcGF0aW5nCQDMCAIJAQtEZWxldGVFbnRyeQEFHENvbnRlc3RQYXJ0aWNpcGFudEFkZHJlc3NLZXkJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICBRhDb250ZXN0UGFydGljaXBhbnRQcmVmaXgCCl9zdGFydGVkQXQJAMwIAgMJAAACCQBlAgURcGFydGljaXBhbnRzQ291bnQAAQAACQELRGVsZXRlRW50cnkBCQCsAgIFDENvbnRlc3RJZFN0cgISX3BhcnRpY2lwYW50c0NvdW50CQEMSW50ZWdlckVudHJ5AgkArAICBQxDb250ZXN0SWRTdHICEl9wYXJ0aWNpcGFudHNDb3VudAkAZQIFEXBhcnRpY2lwYW50c0NvdW50AAEFA25pbAFpAQxjaG9vc2VXaW5uZXICCWNvbnRlc3RJZAlhZGRyZXNzZXMEDENvbnRlc3RJZFN0cgkArAICBQ1Db250ZXN0UHJlZml4BQljb250ZXN0SWQEDHByaXplRnVuZFN0cgkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCiCAEJAKwCAgUMQ29udGVzdElkU3RyAgpfcHJpemVGdW5kAhlQcml6ZSBmdW5kIGRhdGEgbm90IGZvdW5kBAdpc093bmVyBAckbWF0Y2gwCQCiCAEJAKwCAgUMQ29udGVzdElkU3RyAgZfb3duZXIDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAF0BQckbWF0Y2gwCQAAAgUBdAkApQgBCAUBaQZjYWxsZXIJAAIBAhREYXRhIGdldCBvd25lciBlcnJvcgQLd2lubmVySW5kZXgJAQ9nZXRSYW5kb21OdW1iZXIECQCQAwEFCWFkZHJlc3NlcwgFAWkNdHJhbnNhY3Rpb25JZAUGaGVpZ2h0AAAEEHdpbm5lckFkZHJlc3NTdHIJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAkQMCBQlhZGRyZXNzZXMFC3dpbm5lckluZGV4AhZJbnZhbGlkIHdpbm5lciBhZGRyZXNzBBNpc1dpbm5lclBhcnRpY2lwYXRlBAckbWF0Y2gwCQCiCAEJAKwCAgkArAICCQCsAgIFDENvbnRlc3RJZFN0cgINX3BhcnRpY2lwYW50XwUQd2lubmVyQWRkcmVzc1N0cgIIX2FkZHJlc3MDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAF0BQckbWF0Y2gwBgcECWVuZEhlaWdodAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCfCAEJAKwCAgUMQ29udGVzdElkU3RyAgpfZW5kSGVpZ2h0AhVObyBlbmQgaGVpZ2h0IGNvbnRlc3QDCQEBIQEFB2lzT3duZXIJAAIBAhVZb3UgYXJlIG5vdCB0aGUgb3duZXIDCQBmAgUGaGVpZ2h0BQllbmRIZWlnaHQJAAIBAhhDb250ZXN0IGhhc24ndCBlbmRlZCB5ZXQDCQEBIQEFE2lzV2lubmVyUGFydGljaXBhdGUJAAIBAiRXaW5uZGVyJ3MgYWRkcmVzcyBkaWRuJ3QgcGFydGljaXBhdGUDCQAAAgkAkAMBBQlhZGRyZXNzZXMAAAkAAgECFUFkZHJlc3MgbGlzdCBpcyBlbXB0eQkAzggCCQDMCAIJAQtTdHJpbmdFbnRyeQIJAKwCAgkArAICCQCsAgIJAKwCAgIHd2lubmVyXwUQd2lubmVyQWRkcmVzc1N0cgIBXwUMQ29udGVzdElkU3RyAgpfcHJpemVGdW5kBQxwcml6ZUZ1bmRTdHIJAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICBQxDb250ZXN0SWRTdHICDl93aW5uZXJBZGRyZXNzBRB3aW5uZXJBZGRyZXNzU3RyCQDMCAIJAQtTdHJpbmdFbnRyeQIJAKwCAgUMQ29udGVzdElkU3RyAgdfc3RhdHVzBQ1TdGF0dXNfRmluaXNoBQNuaWwJARFnZXRQcml6ZVRyYW5zZmVycwIFDHByaXplRnVuZFN0cgkBB0FkZHJlc3MBCQDZBAEFEHdpbm5lckFkZHJlc3NTdHIBaQEGcmVtb3ZlAQljb250ZXN0SWQEDENvbnRlc3RJZFN0cgkArAICBQ1Db250ZXN0UHJlZml4BQljb250ZXN0SWQEEXBhcnRpY2lwYW50c0NvdW50CQELdmFsdWVPckVsc2UCCQCfCAEJAKwCAgUMQ29udGVzdElkU3RyAhJfcGFydGljaXBhbnRzQ291bnQAAAQMcHJpemVGdW5kU3RyCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKIIAQkArAICBQxDb250ZXN0SWRTdHICCl9wcml6ZUZ1bmQCGVByaXplIGZ1bmQgZGF0YSBub3QgZm91bmQEB2lzT3duZXIEByRtYXRjaDAJAKIIAQkArAICBQxDb250ZXN0SWRTdHICBl9vd25lcgMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAXQFByRtYXRjaDAJAAACBQF0CQClCAEIBQFpBmNhbGxlcgkAAgECFERhdGEgZ2V0IG93bmVyIGVycm9yAwkBASEBBQdpc093bmVyCQACAQIVWW91IGFyZSBub3QgdGhlIG93bmVyAwkAZgIFEXBhcnRpY2lwYW50c0NvdW50AAAJAAIBAi9UaGUgbnVtYmVyIG9mIHBhcnRpY2lwYW50cyBpcyBncmVhdGVyIHRoYW4gemVybwkAzggCCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgUMQ29udGVzdElkU3RyAgVfbmFtZQkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgIFDENvbnRlc3RJZFN0cgIFX2Rlc2MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICBQxDb250ZXN0SWRTdHICDF9zdGFydEhlaWdodAkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgIFDENvbnRlc3RJZFN0cgIKX2VuZEhlaWdodAkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgIFDENvbnRlc3RJZFN0cgIGX293bmVyCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgUMQ29udGVzdElkU3RyAgpfcHJpemVGdW5kCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgUMQ29udGVzdElkU3RyAgZfdGFza3MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICBQxDb250ZXN0SWRTdHICB19zdGF0dXMJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICBQxDb250ZXN0SWRTdHICEl9wYXJ0aWNpcGFudHNDb3VudAUDbmlsCQERZ2V0UHJpemVUcmFuc2ZlcnMCBQxwcml6ZUZ1bmRTdHIIBQFpBmNhbGxlcgECdHgBBnZlcmlmeQAJAPQDAwgFAnR4CWJvZHlCeXRlcwkAkQMCCAUCdHgGcHJvb2ZzAAAIBQJ0eA9zZW5kZXJQdWJsaWNLZXn6AThR", "height": 3651482, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: AhM1RL3w52YmkfxYrmQdSaVfzxuvBZjvw1HE9fPBX65P Next: none Diff:
OldNewDifferences
1212 let Status_Stop = "stop"
1313
1414 let Status_Delted = "deleted"
15+
16+let Status_Finish = "finish"
1517
1618 func calcPrizeFund (payments) = {
1719 func calc (accum,next) = {
6668 else throw("List size exceeds 10")
6769
6870 $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)
71+ }
72+
73+
74+func getRandomNumber (variants,txId,blockHeight,offset) = {
75+ let randomSeedBlock = value(blockInfoByHeight((blockHeight - 1)))
76+ let randomHash = sha256((txId + value(randomSeedBlock.vrf)))
77+ (toInt(randomHash, (offset * 8)) % variants)
6978 }
7079
7180
139148
140149
141150 @Callable(i)
151+func chooseWinner (contestId,addresses) = {
152+ let ContestIdStr = (ContestPrefix + contestId)
153+ let prizeFundStr = valueOrErrorMessage(getString((ContestIdStr + "_prizeFund")), "Prize fund data not found")
154+ let isOwner = match getString((ContestIdStr + "_owner")) {
155+ case t: String =>
156+ (t == toString(i.caller))
157+ case _ =>
158+ throw("Data get owner error")
159+ }
160+ let winnerIndex = getRandomNumber(size(addresses), i.transactionId, height, 0)
161+ let winnerAddressStr = valueOrErrorMessage(addresses[winnerIndex], "Invalid winner address")
162+ let isWinnerParticipate = match getString((((ContestIdStr + "_participant_") + winnerAddressStr) + "_address")) {
163+ case t: String =>
164+ true
165+ case _ =>
166+ false
167+ }
168+ let endHeight = valueOrErrorMessage(getInteger((ContestIdStr + "_endHeight")), "No end height contest")
169+ if (!(isOwner))
170+ then throw("You are not the owner")
171+ else if ((height > endHeight))
172+ then throw("Contest hasn't ended yet")
173+ else if (!(isWinnerParticipate))
174+ then throw("Winnder's address didn't participate")
175+ else if ((size(addresses) == 0))
176+ then throw("Address list is empty")
177+ else ([StringEntry((((("winner_" + winnerAddressStr) + "_") + ContestIdStr) + "_prizeFund"), prizeFundStr), StringEntry((ContestIdStr + "_winnerAddress"), winnerAddressStr), StringEntry((ContestIdStr + "_status"), Status_Finish)] ++ getPrizeTransfers(prizeFundStr, Address(fromBase58String(winnerAddressStr))))
178+ }
179+
180+
181+
182+@Callable(i)
142183 func remove (contestId) = {
143184 let ContestIdStr = (ContestPrefix + contestId)
144185 let participantsCount = valueOrElse(getInteger((ContestIdStr + "_participantsCount")), 0)
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let LastContestIdKey = "last_contest_id"
55
66 let ContestPrefix = "contest_"
77
88 let Status_Draft = "draft"
99
1010 let Status_Active = "active"
1111
1212 let Status_Stop = "stop"
1313
1414 let Status_Delted = "deleted"
15+
16+let Status_Finish = "finish"
1517
1618 func calcPrizeFund (payments) = {
1719 func calc (accum,next) = {
1820 let assetName = match next.assetId {
1921 case t: ByteVector =>
2022 toBase58String(t)
2123 case _ =>
2224 "WAVES"
2325 }
2426 if (if ((size(assetName) > 0))
2527 then (next.amount > 0)
2628 else false)
2729 then (accum :+ ((assetName + ":") + toString(next.amount)))
2830 else accum
2931 }
3032
3133 makeString_2C({
3234 let $l = payments
3335 let $s = size($l)
3436 let $acc0 = nil
3537 func $f0_1 ($a,$i) = if (($i >= $s))
3638 then $a
3739 else calc($a, $l[$i])
3840
3941 func $f0_2 ($a,$i) = if (($i >= $s))
4042 then $a
4143 else throw("List size exceeds 10")
4244
4345 $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)
4446 }, "|")
4547 }
4648
4749
4850 func getPrizeTransfers (prizeFundStr,recipient) = {
4951 func calc (accum,next) = {
5052 let parts = split(next, ":")
5153 let assetId = if ((parts[0] == "WAVES"))
5254 then unit
5355 else fromBase58String(parts[0])
5456 (accum :+ ScriptTransfer(recipient, value(parseInt(parts[1])), assetId))
5557 }
5658
5759 let $l = split_4C(prizeFundStr, "|")
5860 let $s = size($l)
5961 let $acc0 = nil
6062 func $f0_1 ($a,$i) = if (($i >= $s))
6163 then $a
6264 else calc($a, $l[$i])
6365
6466 func $f0_2 ($a,$i) = if (($i >= $s))
6567 then $a
6668 else throw("List size exceeds 10")
6769
6870 $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)
71+ }
72+
73+
74+func getRandomNumber (variants,txId,blockHeight,offset) = {
75+ let randomSeedBlock = value(blockInfoByHeight((blockHeight - 1)))
76+ let randomHash = sha256((txId + value(randomSeedBlock.vrf)))
77+ (toInt(randomHash, (offset * 8)) % variants)
6978 }
7079
7180
7281 @Callable(i)
7382 func create (name,desc,endHeight,tasks) = {
7483 let prizeFundStr = calcPrizeFund(i.payments)
7584 if ((size(prizeFundStr) == 0))
7685 then throw("No payments")
7786 else if ((size(tasks) == 0))
7887 then throw("Tasks list empty")
7988 else if ((size(name) == 0))
8089 then throw("Name empty")
8190 else if ((size(desc) == 0))
8291 then throw("Desc empty")
8392 else if ((height > endHeight))
8493 then throw("Invalid date end")
8594 else {
8695 let contestId = valueOrElse(getInteger(LastContestIdKey), 1)
8796 $Tuple2([StringEntry(((ContestPrefix + toString(contestId)) + "_name"), name), StringEntry(((ContestPrefix + toString(contestId)) + "_desc"), desc), IntegerEntry(((ContestPrefix + toString(contestId)) + "_startHeight"), height), IntegerEntry(((ContestPrefix + toString(contestId)) + "_endHeight"), endHeight), StringEntry(((ContestPrefix + toString(contestId)) + "_owner"), toString(i.caller)), StringEntry(((ContestPrefix + toString(contestId)) + "_prizeFund"), prizeFundStr), StringEntry(((ContestPrefix + toString(contestId)) + "_tasks"), makeString_2C(tasks, ";")), StringEntry(((ContestPrefix + toString(contestId)) + "_status"), Status_Active), IntegerEntry(LastContestIdKey, (contestId + 1))], contestId)
8897 }
8998 }
9099
91100
92101
93102 @Callable(i)
94103 func participate (contestId) = {
95104 let ContestIdStr = (ContestPrefix + contestId)
96105 let ContestParticipantPrefix = ((ContestIdStr + "_participant_") + toString(i.caller))
97106 let ContestParticipantAddressKey = (ContestParticipantPrefix + "_address")
98107 let isOwner = match getString((ContestIdStr + "_owner")) {
99108 case t: String =>
100109 (t == toString(i.caller))
101110 case _ =>
102111 throw("Data get owner error")
103112 }
104113 let isExist = match getString(ContestParticipantAddressKey) {
105114 case t: String =>
106115 true
107116 case _ =>
108117 false
109118 }
110119 let participantsCount = valueOrElse(getInteger((ContestIdStr + "_participantsCount")), 0)
111120 if (isOwner)
112121 then throw("Owner cannot participate")
113122 else if (isExist)
114123 then throw("You are already participating")
115124 else [StringEntry(ContestParticipantAddressKey, toString(i.caller)), IntegerEntry((ContestParticipantPrefix + "_startedAt"), height), IntegerEntry((ContestIdStr + "_participantsCount"), (participantsCount + 1))]
116125 }
117126
118127
119128
120129 @Callable(i)
121130 func unparticipate (contestId) = {
122131 let ContestIdStr = (ContestPrefix + contestId)
123132 let ContestParticipantPrefix = ((ContestIdStr + "_participant_") + toString(i.caller))
124133 let ContestParticipantAddressKey = (ContestParticipantPrefix + "_address")
125134 let isExist = match getString(ContestParticipantAddressKey) {
126135 case t: String =>
127136 true
128137 case _ =>
129138 false
130139 }
131140 let participantsCount = valueOrElse(getInteger((ContestIdStr + "_participantsCount")), 0)
132141 if (!(isExist))
133142 then throw("You are not participating")
134143 else [DeleteEntry(ContestParticipantAddressKey), DeleteEntry((ContestParticipantPrefix + "_startedAt")), if (((participantsCount - 1) == 0))
135144 then DeleteEntry((ContestIdStr + "_participantsCount"))
136145 else IntegerEntry((ContestIdStr + "_participantsCount"), (participantsCount - 1))]
137146 }
138147
139148
140149
141150 @Callable(i)
151+func chooseWinner (contestId,addresses) = {
152+ let ContestIdStr = (ContestPrefix + contestId)
153+ let prizeFundStr = valueOrErrorMessage(getString((ContestIdStr + "_prizeFund")), "Prize fund data not found")
154+ let isOwner = match getString((ContestIdStr + "_owner")) {
155+ case t: String =>
156+ (t == toString(i.caller))
157+ case _ =>
158+ throw("Data get owner error")
159+ }
160+ let winnerIndex = getRandomNumber(size(addresses), i.transactionId, height, 0)
161+ let winnerAddressStr = valueOrErrorMessage(addresses[winnerIndex], "Invalid winner address")
162+ let isWinnerParticipate = match getString((((ContestIdStr + "_participant_") + winnerAddressStr) + "_address")) {
163+ case t: String =>
164+ true
165+ case _ =>
166+ false
167+ }
168+ let endHeight = valueOrErrorMessage(getInteger((ContestIdStr + "_endHeight")), "No end height contest")
169+ if (!(isOwner))
170+ then throw("You are not the owner")
171+ else if ((height > endHeight))
172+ then throw("Contest hasn't ended yet")
173+ else if (!(isWinnerParticipate))
174+ then throw("Winnder's address didn't participate")
175+ else if ((size(addresses) == 0))
176+ then throw("Address list is empty")
177+ else ([StringEntry((((("winner_" + winnerAddressStr) + "_") + ContestIdStr) + "_prizeFund"), prizeFundStr), StringEntry((ContestIdStr + "_winnerAddress"), winnerAddressStr), StringEntry((ContestIdStr + "_status"), Status_Finish)] ++ getPrizeTransfers(prizeFundStr, Address(fromBase58String(winnerAddressStr))))
178+ }
179+
180+
181+
182+@Callable(i)
142183 func remove (contestId) = {
143184 let ContestIdStr = (ContestPrefix + contestId)
144185 let participantsCount = valueOrElse(getInteger((ContestIdStr + "_participantsCount")), 0)
145186 let prizeFundStr = valueOrErrorMessage(getString((ContestIdStr + "_prizeFund")), "Prize fund data not found")
146187 let isOwner = match getString((ContestIdStr + "_owner")) {
147188 case t: String =>
148189 (t == toString(i.caller))
149190 case _ =>
150191 throw("Data get owner error")
151192 }
152193 if (!(isOwner))
153194 then throw("You are not the owner")
154195 else if ((participantsCount > 0))
155196 then throw("The number of participants is greater than zero")
156197 else ([DeleteEntry((ContestIdStr + "_name")), DeleteEntry((ContestIdStr + "_desc")), DeleteEntry((ContestIdStr + "_startHeight")), DeleteEntry((ContestIdStr + "_endHeight")), DeleteEntry((ContestIdStr + "_owner")), DeleteEntry((ContestIdStr + "_prizeFund")), DeleteEntry((ContestIdStr + "_tasks")), DeleteEntry((ContestIdStr + "_status")), DeleteEntry((ContestIdStr + "_participantsCount"))] ++ getPrizeTransfers(prizeFundStr, i.caller))
157198 }
158199
159200
160201 @Verifier(tx)
161202 func verify () = sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
162203

github/deemru/w8io/3ef1775 
38.07 ms