tx · 63qQEr8Cnd575N6xmZoz6hfFSs6wpqXKvf1xn41xP1EN

3MumkGGztCKAXpWDqxkddofqXSUbqQkvSJy:  -0.01200000 Waves

2022.10.05 15:20 [2259022] smart account 3MumkGGztCKAXpWDqxkddofqXSUbqQkvSJy > SELF 0.00000000 Waves

{ "type": 13, "id": "63qQEr8Cnd575N6xmZoz6hfFSs6wpqXKvf1xn41xP1EN", "fee": 1200000, "feeAssetId": null, "timestamp": 1664972430956, "version": 2, "chainId": 84, "sender": "3MumkGGztCKAXpWDqxkddofqXSUbqQkvSJy", "senderPublicKey": "C3PaRKeL8AUKbwUqdniMQtThgcTh5DYHV1777Hkxy7rp", "proofs": [ "2huYCdTWo97tun7S6iMgPJA6aupNfEkscRBrzZj3MktvNCYZ39Sq9gZ25fow8rmbdRPZiKnh22vGPpD62eL16X9Q" ], "script": "base64:BgIlCAISBAoCAQESBwoFCAgBARgSBwoFCAgBARgSBAoCAQgSAwoBATwAC3JldmlzaW9uTnVtAgAAA1NFUAICX18ADURFRkFVTFRRVU9SVU0AoMIeAApVUkxQQVRURVJOAhpodHRwczovL2ZvcnVtLm5ldXRyaW5vLmF0LwAITUFYVElUTEUAoAEADU1BWFZPVElOR1RJTUUAgJDkwAQABU1VTFQ2AMCEPQASZ292SWR4UHJvcG9zYWxUeElkAAEACmdvdklkeFR5cGUAAgAMZ292SWR4QXV0aG9yAAMACWdvdklkeFVybAAEAAtnb3ZJZHhUaXRsZQAFABJnb3ZJZHhDcmVhdGlvblRpbWUABgALZ292SWR4U3RhcnQABwAJZ292SWR4RW5kAAgAC2dvdklkeFR4SWRzAAkACWdvdklkeEF1eAAKAQ9nZXRTdHJpbmdPckZhaWwCB2FkZHJlc3MDa2V5CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ0IAgUHYWRkcmVzcwUDa2V5CQC5CQIJAMwIAgIKbWFuZGF0b3J5IAkAzAgCCQClCAEFB2FkZHJlc3MJAMwIAgIBLgkAzAgCBQNrZXkJAMwIAgIPIGlzIG5vdCBkZWZpbmVkBQNuaWwCAAEMZ2V0SW50T3JFbHNlAgNrZXkKZGVmYXVsdFZhbAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQNrZXkFCmRlZmF1bHRWYWwAGUlkeENvbnRyb2xDZmdOZXV0cmlub0RhcHAAAQAYSWR4Q29udHJvbENmZ0F1Y3Rpb25EYXBwAAIAFElkeENvbnRyb2xDZmdScGREYXBwAAMAFUlkeENvbnRyb2xDZmdNYXRoRGFwcAAEABxJZHhDb250cm9sQ2ZnTGlxdWlkYXRpb25EYXBwAAUAFUlkeENvbnRyb2xDZmdSZXN0RGFwcAAGAB1JZHhDb250cm9sQ2ZnTm9kZVJlZ2lzdHJ5RGFwcAAHABxJZHhDb250cm9sQ2ZnTnNidFN0YWtpbmdEYXBwAAgAGUlkeENvbnRyb2xDZmdNZWRpYXRvckRhcHAACQAcSWR4Q29udHJvbENmZ1N1cmZTdGFraW5nRGFwcAAKACBJZHhDb250cm9sQ2ZnR25zYnRDb250cm9sbGVyRGFwcAALARFrZXlDb250cm9sQWRkcmVzcwACHCVzJXNfX2NvbmZpZ19fY29udHJvbEFkZHJlc3MBDWtleUNvbnRyb2xDZmcAAhElc19fY29udHJvbENvbmZpZwEUcmVhZENvbnRyb2xDZmdPckZhaWwBB2NvbnRyb2wJALUJAgkBD2dldFN0cmluZ09yRmFpbAIFB2NvbnRyb2wJAQ1rZXlDb250cm9sQ2ZnAAUDU0VQARhnZXRDb250cmFjdEFkZHJlc3NPckZhaWwCCmNvbnRyb2xDZmcDaWR4CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkAkQMCBQpjb250cm9sQ2ZnBQNpZHgJAKwCAgItQ29udHJvbCBjZmcgZG9lc24ndCBjb250YWluIGFkZHJlc3MgYXQgaW5kZXggCQCkAwEFA2lkeAAPY29udHJvbENvbnRyYWN0CQERQGV4dHJOYXRpdmUoMTA2MikBCQELdmFsdWVPckVsc2UCCQCdCAIFBHRoaXMJARFrZXlDb250cm9sQWRkcmVzcwACIzNQNUJmZDU4UFBmTnZCTTJIeThRZmJjRHFNZU50emc3S2ZQAApjb250cm9sQ2ZnCQEUcmVhZENvbnRyb2xDZmdPckZhaWwBBQ9jb250cm9sQ29udHJhY3QAF2duc2J0Q29udHJvbGxlckNvbnRyYWN0CQEYZ2V0Q29udHJhY3RBZGRyZXNzT3JGYWlsAgUKY29udHJvbENmZwUgSWR4Q29udHJvbENmZ0duc2J0Q29udHJvbGxlckRhcHABEWtleUxhc3RQcm9wb3NhbElkAAIOJXNfX3Byb3Bvc2FsSWQBGWtleVByb3Bvc2FsU3RhdHVzRGF0YUJ5SWQBCnByb3Bvc2FsSWQJAKwCAgIaJXMlZF9fcHJvcG9zYWxTdGF0dXNEYXRhX18JAKQDAQUKcHJvcG9zYWxJZAEVa2V5UHJvcG9zYWxRdW9ydW1CeUlkAQpwcm9wb3NhbElkCQCsAgICFiVzJWRfX3F1b3J1bVJlcXVpcmVkX18JAKQDAQUKcHJvcG9zYWxJZAETa2V5UHJvcG9zYWxEYXRhQnlJZAEKcHJvcG9zYWxJZAkArAICAhQlcyVkX19wcm9wb3NhbERhdGFfXwkApAMBBQpwcm9wb3NhbElkARlrZXlQcm9wb3NhbFRvdGFsVm90ZXNCeUlkAQpwcm9wb3NhbElkCQCsAgICGiVzJWRfX3Byb3Bvc2FsVG90YWxWb3Rlc19fCQCkAwEFCnByb3Bvc2FsSWQBFmtleVByb3Bvc2FsT3B0aW9uc0J5SWQBCnByb3Bvc2FsSWQJAKwCAgIXJXMlZF9fcHJvcG9zYWxPcHRpb25zX18JAKQDAQUKcHJvcG9zYWxJZAEca2V5UHJvcG9zYWxXaW5uaW5nT3B0aW9uQnlJZAEKcHJvcG9zYWxJZAkArAICAhglcyVkX19jdXJyV2lubmVyT3B0aW9uX18JAKQDAQUKcHJvcG9zYWxJZAEba2V5UHJvcG9zYWxXaW5uaW5nVm90ZXNCeUlkAQpwcm9wb3NhbElkCQCsAgICFyVzJWRfX2N1cnJXaW5uZXJWb3Rlc19fCQCkAwEFCnByb3Bvc2FsSWQBHWtleVByb3Bvc2FsVm90ZXNCeUlkQW5kT3B0aW9uAgpwcm9wb3NhbElkA29wdAkAuQkCCQDMCAICBiVzJWQlZAkAzAgCAgp2b3Rlc0J5T3B0CQDMCAIJAKQDAQUKcHJvcG9zYWxJZAkAzAgCCQCkAwEFA29wdAUDbmlsBQNTRVABIWtleVByb3Bvc2FsVm90ZXNCeUlkVXNlckFuZE9wdGlvbgMKcHJvcG9zYWxJZAh1c2VyQWRkcgNvcHQJALkJAgkAzAgCAgglcyVkJXMlZAkAzAgCAg52b3Rlc0J5VXNlck9wdAkAzAgCCQCkAwEFCnByb3Bvc2FsSWQJAMwIAgUIdXNlckFkZHIJAMwIAgkApAMBBQNvcHQFA25pbAUDU0VQARxrZXlQcm9wb3NhbENob2ljZUJ5SWRBbmRVc2VyAgpwcm9wb3NhbElkCHVzZXJBZGRyCQC5CQIJAMwIAgIGJXMlZCVzCQDMCAICDG9wdGlvbkJ5VXNlcgkAzAgCCQCkAwEFCnByb3Bvc2FsSWQJAMwIAgUIdXNlckFkZHIFA25pbAUDU0VQAR5rZXlOdW1VbmlxdWVWb3RlcnNCeVByb3Bvc2FsSWQBCnByb3Bvc2FsSWQJAKwCAgIRJXMlZF9fbnVtVm90ZXJzX18JAKQDAQUKcHJvcG9zYWxJZAEYa2V5U3RhdHNBdmVyVW5pcXVlVm90ZXJzAAIgJXMlcyVzX19zdGF0c19fYXZnX191bmlxdWVWb3RlcnMBFmtleVN0YXRzQXZlckduc2J0Vm90ZWQAAh4lcyVzJXNfX3N0YXRzX19hdmdfX2duc2J0Vm90ZWQBFWtleVN0YXRzVW5pcXVlQXV0aG9ycwACGiVzJXNfX3N0YXRzX191bmlxdWVBdXRob3JzARdrZXlOdW1Qcm9wb3NhbHNCeUF1dGhvcgEKYWRkcmVzc1N0cgkArAICAhwlcyVzX19udW1Qcm9wb3NhbHNCeUF1dGhvcl9fBQphZGRyZXNzU3RyAQlhc0FueUxpc3QBAXYEByRtYXRjaDAFAXYDCQABAgUHJG1hdGNoMAIJTGlzdFtBbnldBAFsBQckbWF0Y2gwBQFsCQACAQIbZmFpbCB0byBjYXN0IGludG8gTGlzdFtBbnldAQVhc0ludAEBdgQHJG1hdGNoMAUBdgMJAAECBQckbWF0Y2gwAgNJbnQEAWkFByRtYXRjaDAFAWkJAAIBAhVmYWlsIHRvIGNhc3QgaW50byBJbnQBCnN0YXR1c0RhdGEFDWlzVm90aW5nVmFsaWQJd2luT3B0aW9uEWFyZVNjcmlwdHNBcHBsaWVkEHNjcmlwdHNUaW1lc3RhbXAOY2FuY2VsZWRCeVRlYW0JALkJAgkAzAgCAgolYiVzJWIlZCViCQDMCAIJAKUDAQUNaXNWb3RpbmdWYWxpZAkAzAgCBQl3aW5PcHRpb24JAMwIAgkApQMBBRFhcmVTY3JpcHRzQXBwbGllZAkAzAgCCQCkAwEFEHNjcmlwdHNUaW1lc3RhbXAJAMwIAgkApQMBBQ5jYW5jZWxlZEJ5VGVhbQUDbmlsBQNTRVABDHByb3Bvc2FsRGF0YQoMcHJvcG9zYWxUeElkBHR5cGUGYXV0aG9yCWZvcnVtTGluawV0aXRsZQxwcm9wb3NhbFRpbWUPdm90aW5nU3RhcnRUaW1lDXZvdGluZ0VuZFRpbWUFdHhJZHMHYXV4SW5mbwkAuQkCCQDMCAICFCVzJXMlcyVzJXMlZCVkJWQlcyVzCQDMCAIFDHByb3Bvc2FsVHhJZAkAzAgCBQR0eXBlCQDMCAIFBmF1dGhvcgkAzAgCBQlmb3J1bUxpbmsJAMwIAgUFdGl0bGUJAMwIAgkApAMBBQxwcm9wb3NhbFRpbWUJAMwIAgkApAMBBQ92b3RpbmdTdGFydFRpbWUJAMwIAgkApAMBBQ12b3RpbmdFbmRUaW1lCQDMCAIFBXR4SWRzCQDMCAIFB2F1eEluZm8FA25pbAUDU0VQAQtjaGVja1R4TGlzdAEGdHhMaXN0AwkAZgIJAJADAQUGdHhMaXN0ABQJAAIBCQCsAgICF1RvbyBtYW55IHRyYW5zYWN0aW9uczogCQCkAwEJAJADAQUGdHhMaXN0CgEIY29tYmluZXICA2FjYwJ0eAMJAQEhAQkBCWlzRGVmaW5lZAEJAOkHAQkA2QQBBQJ0eAkAAgEJAKwCAgILV3JvbmcgdHhJZDoFAnR4AwkAAAIFA2FjYwIABQJ0eAkArAICCQCsAgIFA2FjYwIBOgUCdHgKAAIkbAUGdHhMaXN0CgACJHMJAJADAQUCJGwKAAUkYWNjMAIACgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQhjb21iaW5lcgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMjAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgALAAwADQAOAA8AEAARABIAEwAUAQ5pbml0aWF0ZVZvdGluZwoMcHJvcG9zYWxUeElkBHR5cGUGYXV0aG9yCWZvcnVtTGluawV0aXRsZQ92b3RpbmdTdGFydFRpbWUNdm90aW5nRW5kVGltZQZzdGF0dXMGdHhMaXN0C29wdGlvbnNMaXN0AwkBAiE9AgkBBXZhbHVlAQkAswkCBQlmb3J1bUxpbmsFClVSTFBBVFRFUk4AAAkAAgECC0ludmFsaWQgdXJsAwkAZgIJALECAQUFdGl0bGUFCE1BWFRJVExFCQACAQIOVG9vIGxvbmcgdGl0bGUEDHByb3Bvc2FsVGltZQgFCWxhc3RCbG9jawl0aW1lc3RhbXADCQBmAgUMcHJvcG9zYWxUaW1lBQ92b3RpbmdTdGFydFRpbWUJAAIBCQCsAgIJAKwCAgkArAICAhB2b3RpbmdTdGFydFRpbWU9CQCkAwEFD3ZvdGluZ1N0YXJ0VGltZQIQIDwgcHJvcG9zYWxUaW1lPQkApAMBBQxwcm9wb3NhbFRpbWUDCQBmAgUPdm90aW5nU3RhcnRUaW1lBQ12b3RpbmdFbmRUaW1lCQACAQkArAICCQCsAgIJAKwCAgIOdm90aW5nRW5kVGltZT0JAKQDAQUNdm90aW5nRW5kVGltZQITIDwgdm90aW5nU3RhcnRUaW1lPQkApAMBBQ92b3RpbmdTdGFydFRpbWUDCQBmAgkAZQIFDXZvdGluZ0VuZFRpbWUFD3ZvdGluZ1N0YXJ0VGltZQUNTUFYVk9USU5HVElNRQkAAgEJAKwCAgkArAICCQCsAgICG1ZvdGluZyBwZXJpb2QgZXhjZWVkcyBtYXg6IAkApAMBCQBlAgUNdm90aW5nRW5kVGltZQUPdm90aW5nU3RhcnRUaW1lAgMgPiAJAKQDAQUNTUFYVk9USU5HVElNRQQFdHhJZHMDCQAAAgUEdHlwZQIESURFQQIACQELY2hlY2tUeExpc3QBBQZ0eExpc3QDCQBnAgABCQCQAwEFC29wdGlvbnNMaXN0CQACAQIXVG9vIGZldyBjaG9pY2VzIHRvIHZvdGUECnByb3Bvc2FsSWQJAGQCCQEMZ2V0SW50T3JFbHNlAgkBEWtleUxhc3RQcm9wb3NhbElkAAAAAAEEBnF1b3J1bQkBDGdldEludE9yRWxzZQIJARVrZXlQcm9wb3NhbFF1b3J1bUJ5SWQBBQpwcm9wb3NhbElkBQ1ERUZBVUxUUVVPUlVNBBRudW1Qcm9wb3NhbHNCeUF1dGhvcgkAZAIJAQxnZXRJbnRPckVsc2UCCQEXa2V5TnVtUHJvcG9zYWxzQnlBdXRob3IBBQZhdXRob3IAAAABBAt1bmlxQXV0aG9ycwkAZAIJAQxnZXRJbnRPckVsc2UCCQEVa2V5U3RhdHNVbmlxdWVBdXRob3JzAAAAAwkAAAIFFG51bVByb3Bvc2Fsc0J5QXV0aG9yAAEAAQAABA1zdGF0dXNEYXRhU3RyCQEKc3RhdHVzRGF0YQUHAgAHAAAHBApvcHRpb25zU3RyCQC5CQIFC29wdGlvbnNMaXN0BQNTRVAJAJQKAgkAzAgCCQELU3RyaW5nRW50cnkCCQEWa2V5UHJvcG9zYWxPcHRpb25zQnlJZAEFCnByb3Bvc2FsSWQFCm9wdGlvbnNTdHIJAMwIAgkBDEludGVnZXJFbnRyeQIJARFrZXlMYXN0UHJvcG9zYWxJZAAFCnByb3Bvc2FsSWQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBGWtleVByb3Bvc2FsU3RhdHVzRGF0YUJ5SWQBBQpwcm9wb3NhbElkBQ1zdGF0dXNEYXRhU3RyCQDMCAIJAQtTdHJpbmdFbnRyeQIJARNrZXlQcm9wb3NhbERhdGFCeUlkAQUKcHJvcG9zYWxJZAkBDHByb3Bvc2FsRGF0YQoFDHByb3Bvc2FsVHhJZAUEdHlwZQUGYXV0aG9yBQlmb3J1bUxpbmsFBXRpdGxlBQxwcm9wb3NhbFRpbWUFD3ZvdGluZ1N0YXJ0VGltZQUNdm90aW5nRW5kVGltZQUFdHhJZHMCAAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBF2tleU51bVByb3Bvc2Fsc0J5QXV0aG9yAQUGYXV0aG9yBRRudW1Qcm9wb3NhbHNCeUF1dGhvcgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBFWtleVN0YXRzVW5pcXVlQXV0aG9ycwAFC3VuaXFBdXRob3JzBQNuaWwFDHByb3Bvc2FsVHhJZAENY2FsY1dpbk9wdGlvbgcKcHJvcG9zYWxJZAtvcHRpb25zTGlzdA5pc1ByZXZPcHRpb25hbAlvbGRDaG9pY2UQb3B0aW9uYWxUb3RhbE9sZAluZXdDaG9pY2UTbmV3VG90YWxCeU5ld0Nob2ljZQoBCGZpbmRCZXN0AgNhY2MEZWxlbQQDaWR4CQEFdmFsdWUBCQDPCAIFC29wdGlvbnNMaXN0BQRlbGVtBAN2YWwJAQxnZXRJbnRPckVsc2UCCQEda2V5UHJvcG9zYWxWb3Rlc0J5SWRBbmRPcHRpb24CBQpwcm9wb3NhbElkBQNpZHgAAAMJAGYCCAUDYWNjAl8yBQN2YWwFA2FjYwkAlAoCBQNpZHgFA3ZhbAQMY2hvaWNlQW5kVmFsAwUOaXNQcmV2T3B0aW9uYWwJAJQKAgUJbmV3Q2hvaWNlBRNuZXdUb3RhbEJ5TmV3Q2hvaWNlAwkAZgIFE25ld1RvdGFsQnlOZXdDaG9pY2UFEG9wdGlvbmFsVG90YWxPbGQJAJQKAgUJbmV3Q2hvaWNlBRNuZXdUb3RhbEJ5TmV3Q2hvaWNlCQCUCgIFEG9wdGlvbmFsVG90YWxPbGQJAQV2YWx1ZQEFCW9sZENob2ljZQQEYmVzdAoAAiRsBQtvcHRpb25zTGlzdAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFDGNob2ljZUFuZFZhbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEIZmluZEJlc3QCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoJAJUKAwgFBGJlc3QCXzEJAJEDAgULb3B0aW9uc0xpc3QIBQRiZXN0Al8xCAUEYmVzdAJfMgUBaQEIY2FzdFZvdGUCCnByb3Bvc2FsSWQGY2hvaWNlBA51c2VyQWRkcmVzc1N0cgkApQgBCAUBaQZjYWxsZXIECWN1clN0YXR1cwkBD2dldFN0cmluZ09yRmFpbAIFBHRoaXMJARlrZXlQcm9wb3NhbFN0YXR1c0RhdGFCeUlkAQUKcHJvcG9zYWxJZAQQYXZhaWxhYmxlT3B0aW9ucwkAtQkCCQEPZ2V0U3RyaW5nT3JGYWlsAgUEdGhpcwkBFmtleVByb3Bvc2FsT3B0aW9uc0J5SWQBBQpwcm9wb3NhbElkBQNTRVAECm51bU9wdGlvbnMJAJADAQUQYXZhaWxhYmxlT3B0aW9ucwMJAGcCAAEFCm51bU9wdGlvbnMJAAIBAhdUb28gZmV3IGNob2ljZXMgdG8gdm90ZQMJAGcCBQZjaG9pY2UFCm51bU9wdGlvbnMJAAIBCQCsAgICG1Vua25vd24gY2hvaWNlISBNdXN0IGJlIDAuLgkApAMBCQBlAgUKbnVtT3B0aW9ucwABBAhwcm9wRGF0YQkAtQkCCQEPZ2V0U3RyaW5nT3JGYWlsAgUEdGhpcwkBE2tleVByb3Bvc2FsRGF0YUJ5SWQBBQpwcm9wb3NhbElkBQNTRVAEBXN0YXJ0CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUIcHJvcERhdGEFC2dvdklkeFN0YXJ0BANlbmQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQhwcm9wRGF0YQUJZ292SWR4RW5kBANub3cIBQlsYXN0QmxvY2sJdGltZXN0YW1wAwkAZgIFBXN0YXJ0BQNub3cJAAIBAhZWb3Rpbmcgbm90IHN0YXJ0ZWQgeWV0AwkAZwIFA25vdwUDZW5kCQACAQIXVm90aW5nIGFscmVhZHkgZmluaXNoZWQECWduc2J0RGF0YQkBCWFzQW55TGlzdAEJAPwHBAUXZ25zYnRDb250cm9sbGVyQ29udHJhY3QCFGduc2J0SW5mb1NZU1JFQURPTkxZCQDMCAIFDnVzZXJBZGRyZXNzU3RyCQDMCAIAAAkAzAgCAAAFA25pbAUDbmlsBAhnbnNidEFtdAkBBWFzSW50AQkAkQMCBQlnbnNidERhdGEAAAMJAGcCAAAFCGduc2J0QW10CQACAQIQbm8gZ25zYnQgdG8gdm90ZQQKZ25zYnRUb3RhbAkBBWFzSW50AQkAkQMCBQlnbnNidERhdGEAAQQJb2xkQ2hvaWNlCQCfCAEJARxrZXlQcm9wb3NhbENob2ljZUJ5SWRBbmRVc2VyAgUKcHJvcG9zYWxJZAUOdXNlckFkZHJlc3NTdHIEDG9sZFVzZXJWb3RlcwMJAQEhAQkBCWlzRGVmaW5lZAEFCW9sZENob2ljZQAACQEMZ2V0SW50T3JFbHNlAgkBIWtleVByb3Bvc2FsVm90ZXNCeUlkVXNlckFuZE9wdGlvbgMFCnByb3Bvc2FsSWQFDnVzZXJBZGRyZXNzU3RyCQEFdmFsdWUBBQlvbGRDaG9pY2UAAAQTb2xkVG90YWxCeU9sZENob2ljZQMJAQlpc0RlZmluZWQBBQlvbGRDaG9pY2UJAQxnZXRJbnRPckVsc2UCCQEda2V5UHJvcG9zYWxWb3Rlc0J5SWRBbmRPcHRpb24CBQpwcm9wb3NhbElkCQEFdmFsdWUBBQlvbGRDaG9pY2UAAAAABBNvbGRUb3RhbEJ5TmV3Q2hvaWNlCQEMZ2V0SW50T3JFbHNlAgkBHWtleVByb3Bvc2FsVm90ZXNCeUlkQW5kT3B0aW9uAgUKcHJvcG9zYWxJZAUGY2hvaWNlAAAECG9sZFRvdGFsCQEMZ2V0SW50T3JFbHNlAgkBGWtleVByb3Bvc2FsVG90YWxWb3Rlc0J5SWQBBQpwcm9wb3NhbElkAAAEE25ld1RvdGFsQnlPbGRDaG9pY2UDCQEBIQEJAQlpc0RlZmluZWQBBQlvbGRDaG9pY2UAAAkAZAIJAGUCBRNvbGRUb3RhbEJ5T2xkQ2hvaWNlBQxvbGRVc2VyVm90ZXMDCQAAAgkBBXZhbHVlAQUJb2xkQ2hvaWNlBQZjaG9pY2UFCGduc2J0QW10AAAEE25ld1RvdGFsQnlOZXdDaG9pY2UDAwkBCWlzRGVmaW5lZAEFCW9sZENob2ljZQkAAAIJAQV2YWx1ZQEFCW9sZENob2ljZQUGY2hvaWNlBwUTbmV3VG90YWxCeU9sZENob2ljZQkAZAIFE29sZFRvdGFsQnlOZXdDaG9pY2UFCGduc2J0QW10BAhuZXdUb3RhbAkAZAIJAGUCBQhvbGRUb3RhbAUMb2xkVXNlclZvdGVzBQhnbnNidEFtdAQPaXNRdW9ydW1SZWFjaGVkCQBmAgkAawMFCG5ld1RvdGFsBQVNVUxUNgUKZ25zYnRUb3RhbAkBDGdldEludE9yRWxzZQIJARVrZXlQcm9wb3NhbFF1b3J1bUJ5SWQBBQpwcm9wb3NhbElkBQ1ERUZBVUxUUVVPUlVNBBVudW1Wb3RlcnNCeVByb3Bvc2FsSWQJAQxnZXRJbnRPckVsc2UCCQEea2V5TnVtVW5pcXVlVm90ZXJzQnlQcm9wb3NhbElkAQUKcHJvcG9zYWxJZAAABBRvbGRBdmVyVW5pcXVlVm90ZXJzNgkBDGdldEludE9yRWxzZQIJARhrZXlTdGF0c0F2ZXJVbmlxdWVWb3RlcnMAAAAEDG51bVByb3Bvc2FscwkBEUBleHRyTmF0aXZlKDEwNTUpAQkBEWtleUxhc3RQcm9wb3NhbElkAAQKdW5pcXVlRGlmZgMJAAACBQxvbGRVc2VyVm90ZXMAAAABAAAEFG5ld0F2ZXJVbmlxdWVWb3RlcnM2CQBkAgUUb2xkQXZlclVuaXF1ZVZvdGVyczYJAGsDBQp1bmlxdWVEaWZmBQVNVUxUNgUMbnVtUHJvcG9zYWxzBAxvbGRBdmVyR25zYnQJAQxnZXRJbnRPckVsc2UCCQEWa2V5U3RhdHNBdmVyR25zYnRWb3RlZAAAAAQMbmV3QXZlckduc2J0CQBkAgUMb2xkQXZlckduc2J0CQBpAgkAZQIFCGduc2J0QW10BQxvbGRVc2VyVm90ZXMFDG51bVByb3Bvc2FscwQPb3B0aW9uYWxVc2VyT2xkAwkBASEBCQEJaXNEZWZpbmVkAQUJb2xkQ2hvaWNlBQNuaWwJAMwIAgkBDEludGVnZXJFbnRyeQIJASFrZXlQcm9wb3NhbFZvdGVzQnlJZFVzZXJBbmRPcHRpb24DBQpwcm9wb3NhbElkBQ51c2VyQWRkcmVzc1N0cgkBBXZhbHVlAQUJb2xkQ2hvaWNlAAAFA25pbAQOaXNQcmV2T3B0aW9uYWwDCQEBIQEJAQlpc0RlZmluZWQBBQlvbGRDaG9pY2UGCQAAAgkBBXZhbHVlAQUJb2xkQ2hvaWNlBQZjaG9pY2UEEG9wdGlvbmFsVG90YWxPbGQDBQ5pc1ByZXZPcHRpb25hbAUDbmlsCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEda2V5UHJvcG9zYWxWb3Rlc0J5SWRBbmRPcHRpb24CBQpwcm9wb3NhbElkCQEFdmFsdWUBBQlvbGRDaG9pY2UFE25ld1RvdGFsQnlPbGRDaG9pY2UFA25pbAQGd2luT3B0CQENY2FsY1dpbk9wdGlvbgcFCnByb3Bvc2FsSWQFEGF2YWlsYWJsZU9wdGlvbnMFDmlzUHJldk9wdGlvbmFsBQlvbGRDaG9pY2UFE25ld1RvdGFsQnlPbGRDaG9pY2UFBmNob2ljZQUTbmV3VG90YWxCeU5ld0Nob2ljZQkAlAoCCQDOCAIJAM4IAgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBHGtleVByb3Bvc2FsQ2hvaWNlQnlJZEFuZFVzZXICBQpwcm9wb3NhbElkBQ51c2VyQWRkcmVzc1N0cgUGY2hvaWNlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEha2V5UHJvcG9zYWxWb3Rlc0J5SWRVc2VyQW5kT3B0aW9uAwUKcHJvcG9zYWxJZAUOdXNlckFkZHJlc3NTdHIFBmNob2ljZQUIZ25zYnRBbXQJAMwIAgkBDEludGVnZXJFbnRyeQIJAR1rZXlQcm9wb3NhbFZvdGVzQnlJZEFuZE9wdGlvbgIFCnByb3Bvc2FsSWQFBmNob2ljZQUTbmV3VG90YWxCeU5ld0Nob2ljZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBGWtleVByb3Bvc2FsVG90YWxWb3Rlc0J5SWQBBQpwcm9wb3NhbElkBQhuZXdUb3RhbAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBHmtleU51bVVuaXF1ZVZvdGVyc0J5UHJvcG9zYWxJZAEFCnByb3Bvc2FsSWQJAGQCBRVudW1Wb3RlcnNCeVByb3Bvc2FsSWQFCnVuaXF1ZURpZmYJAMwIAgkBDEludGVnZXJFbnRyeQIJARhrZXlTdGF0c0F2ZXJVbmlxdWVWb3RlcnMABRRuZXdBdmVyVW5pcXVlVm90ZXJzNgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBFmtleVN0YXRzQXZlckduc2J0Vm90ZWQABQxuZXdBdmVyR25zYnQJAMwIAgkBDEludGVnZXJFbnRyeQIJARxrZXlQcm9wb3NhbFdpbm5pbmdPcHRpb25CeUlkAQUKcHJvcG9zYWxJZAgFBndpbk9wdAJfMQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBG2tleVByb3Bvc2FsV2lubmluZ1ZvdGVzQnlJZAEFCnByb3Bvc2FsSWQIBQZ3aW5PcHQCXzMJAMwIAgkBC1N0cmluZ0VudHJ5AgkBGWtleVByb3Bvc2FsU3RhdHVzRGF0YUJ5SWQBBQpwcm9wb3NhbElkCQEKc3RhdHVzRGF0YQUFD2lzUXVvcnVtUmVhY2hlZAgFBndpbk9wdAJfMgcAAAcFA25pbAUPb3B0aW9uYWxVc2VyT2xkBRBvcHRpb25hbFRvdGFsT2xkBQR1bml0AWkBEmluaXRpYXRlSWRlYVZvdGluZwUJZm9ydW1MaW5rBXRpdGxlD3ZvdGluZ1N0YXJ0VGltZQ12b3RpbmdFbmRUaW1lC29wdGlvbnNMaXN0CQEOaW5pdGlhdGVWb3RpbmcKCQDYBAEIBQFpDXRyYW5zYWN0aW9uSWQCBElERUEJAKUIAQgFAWkGY2FsbGVyBQlmb3J1bUxpbmsFBXRpdGxlBQ92b3RpbmdTdGFydFRpbWUFDXZvdGluZ0VuZFRpbWUCB1BFTkRJTkcFA25pbAULb3B0aW9uc0xpc3QBaQEUaW5pdGlhdGVVcGRhdGVWb3RpbmcFCWZvcnVtTGluawV0aXRsZQ92b3RpbmdTdGFydFRpbWUNdm90aW5nRW5kVGltZQZ0eExpc3QJAQ5pbml0aWF0ZVZvdGluZwoJANgEAQgFAWkNdHJhbnNhY3Rpb25JZAIGVVBEQVRFCQClCAEIBQFpBmNhbGxlcgUJZm9ydW1MaW5rBQV0aXRsZQUPdm90aW5nU3RhcnRUaW1lBQ12b3RpbmdFbmRUaW1lAgdQRU5ESU5HBQZ0eExpc3QJAMwIAgICTk8JAMwIAgIDWUVTBQNuaWwBaQEMY2FuY2VsVm90aW5nAgpwcm9wb3NhbElkBnJlYXNvbgMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECDm5vdCBhdXRob3JpemVkBAtjdXJyZW50RGF0YQkBD2dldFN0cmluZ09yRmFpbAIFBHRoaXMJARNrZXlQcm9wb3NhbERhdGFCeUlkAQUKcHJvcG9zYWxJZAQLdXBkYXRlZERhdGEJAKwCAgkArAICCQCvAgIFC2N1cnJlbnREYXRhCQEFdmFsdWUBCQC3CQIFC2N1cnJlbnREYXRhBQNTRVAFA1NFUAUGcmVhc29uCQCUCgIJAMwIAgkBC1N0cmluZ0VudHJ5AgkBGWtleVByb3Bvc2FsU3RhdHVzRGF0YUJ5SWQBBQpwcm9wb3NhbElkCQEKc3RhdHVzRGF0YQUHAgAHAAAGCQDMCAIJAQtTdHJpbmdFbnRyeQIJARNrZXlQcm9wb3NhbERhdGFCeUlkAQUKcHJvcG9zYWxJZAULdXBkYXRlZERhdGEFA25pbAUEdW5pdAFpAQthcHBseVZvdGluZwEKcHJvcG9zYWxJZAkAlAoCBQNuaWwFBHVuaXQA1tN/Zg==", "height": 2259022, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: HXDyrG1adHJ6Z78hcKyawZqaW8kTCFLxFfpuLjbXdhr3 Next: 2XAP9FkahRAzYdW4YaJzaEvxaHbWBxog1nssdiNXaXGo Diff:
OldNewDifferences
1212 let MAXTITLE = 160
1313
1414 let MAXVOTINGTIME = 1209600000
15+
16+let MULT6 = 1000000
1517
1618 let govIdxProposalTxId = 1
1719
7981
8082 let gnsbtControllerContract = getContractAddressOrFail(controlCfg, IdxControlCfgGnsbtControllerDapp)
8183
82-func keyProposalId () = "%s__proposalId"
84+func keyLastProposalId () = "%s__proposalId"
8385
8486
85-func keyProposalStatusById (proposalId) = ("%s%d__proposalStatus__" + toString(proposalId))
87+func keyProposalStatusDataById (proposalId) = ("%s%d__proposalStatusData__" + toString(proposalId))
8688
8789
8890 func keyProposalQuorumById (proposalId) = ("%s%d__quorumRequired__" + toString(proposalId))
9193 func keyProposalDataById (proposalId) = ("%s%d__proposalData__" + toString(proposalId))
9294
9395
94-func keyProposalYesVotesById (proposalId) = ("%s%d__proposalYes__" + toString(proposalId))
96+func keyProposalTotalVotesById (proposalId) = ("%s%d__proposalTotalVotes__" + toString(proposalId))
9597
9698
97-func keyProposalNoVotesById (proposalId) = ("%s%d__proposalNo__" + toString(proposalId))
99+func keyProposalOptionsById (proposalId) = ("%s%d__proposalOptions__" + toString(proposalId))
98100
99101
100-func keyProposalYesByIdAndUser (proposalId,userAddr) = makeString(["%s%d%s", "proposalUserYes", toString(proposalId), userAddr], SEP)
102+func keyProposalWinningOptionById (proposalId) = ("%s%d__currWinnerOption__" + toString(proposalId))
101103
102104
103-func keyProposalNoByIdAndUser (proposalId,userAddr) = makeString(["%s%d%s", "proposalUserNo", toString(proposalId), userAddr], SEP)
105+func keyProposalWinningVotesById (proposalId) = ("%s%d__currWinnerVotes__" + toString(proposalId))
106+
107+
108+func keyProposalVotesByIdAndOption (proposalId,opt) = makeString(["%s%d%d", "votesByOpt", toString(proposalId), toString(opt)], SEP)
109+
110+
111+func keyProposalVotesByIdUserAndOption (proposalId,userAddr,opt) = makeString(["%s%d%s%d", "votesByUserOpt", toString(proposalId), userAddr, toString(opt)], SEP)
112+
113+
114+func keyProposalChoiceByIdAndUser (proposalId,userAddr) = makeString(["%s%d%s", "optionByUser", toString(proposalId), userAddr], SEP)
115+
116+
117+func keyNumUniqueVotersByProposalId (proposalId) = ("%s%d__numVoters__" + toString(proposalId))
118+
119+
120+func keyStatsAverUniqueVoters () = "%s%s%s__stats__avg__uniqueVoters"
121+
122+
123+func keyStatsAverGnsbtVoted () = "%s%s%s__stats__avg__gnsbtVoted"
124+
125+
126+func keyStatsUniqueAuthors () = "%s%s__stats__uniqueAuthors"
127+
128+
129+func keyNumProposalsByAuthor (addressStr) = ("%s%s__numProposalsByAuthor__" + addressStr)
104130
105131
106132 func asAnyList (v) = match v {
117143 case _ =>
118144 throw("fail to cast into Int")
119145 }
146+
147+
148+func statusData (isVotingValid,winOption,areScriptsApplied,scriptsTimestamp,canceledByTeam) = makeString(["%b%s%b%d%b", toString(isVotingValid), winOption, toString(areScriptsApplied), toString(scriptsTimestamp), toString(canceledByTeam)], SEP)
120149
121150
122151 func proposalData (proposalTxId,type,author,forumLink,title,proposalTime,votingStartTime,votingEndTime,txIds,auxInfo) = makeString(["%s%s%s%s%s%d%d%d%s%s", proposalTxId, type, author, forumLink, title, toString(proposalTime), toString(votingStartTime), toString(votingEndTime), txIds, auxInfo], SEP)
146175 }
147176
148177
149-func initiateVoting (proposalTxId,type,author,forumLink,title,votingStartTime,votingEndTime,status,txList) = if ((value(indexOf(forumLink, URLPATTERN)) != 0))
178+func initiateVoting (proposalTxId,type,author,forumLink,title,votingStartTime,votingEndTime,status,txList,optionsList) = if ((value(indexOf(forumLink, URLPATTERN)) != 0))
150179 then throw("Invalid url")
151180 else if ((size(title) > MAXTITLE))
152181 then throw("Too long title")
162191 let txIds = if ((type == "IDEA"))
163192 then ""
164193 else checkTxList(txList)
165- let proposalId = (getIntOrElse(keyProposalId(), 0) + 1)
166- let quorum = getIntOrElse(keyProposalQuorumById(proposalId), DEFAULTQUORUM)
167- $Tuple2([IntegerEntry(keyProposalId(), proposalId), IntegerEntry(keyProposalYesVotesById(proposalId), 0), IntegerEntry(keyProposalNoVotesById(proposalId), 0), StringEntry(keyProposalStatusById(proposalId), status), StringEntry(keyProposalDataById(proposalId), proposalData(proposalTxId, type, author, forumLink, title, proposalTime, votingStartTime, votingEndTime, txIds, ""))], proposalTxId)
194+ if ((1 >= size(optionsList)))
195+ then throw("Too few choices to vote")
196+ else {
197+ let proposalId = (getIntOrElse(keyLastProposalId(), 0) + 1)
198+ let quorum = getIntOrElse(keyProposalQuorumById(proposalId), DEFAULTQUORUM)
199+ let numProposalsByAuthor = (getIntOrElse(keyNumProposalsByAuthor(author), 0) + 1)
200+ let uniqAuthors = (getIntOrElse(keyStatsUniqueAuthors(), 0) + (if ((numProposalsByAuthor == 1))
201+ then 1
202+ else 0))
203+ let statusDataStr = statusData(false, "", false, 0, false)
204+ let optionsStr = makeString(optionsList, SEP)
205+ $Tuple2([StringEntry(keyProposalOptionsById(proposalId), optionsStr), IntegerEntry(keyLastProposalId(), proposalId), StringEntry(keyProposalStatusDataById(proposalId), statusDataStr), StringEntry(keyProposalDataById(proposalId), proposalData(proposalTxId, type, author, forumLink, title, proposalTime, votingStartTime, votingEndTime, txIds, "")), IntegerEntry(keyNumProposalsByAuthor(author), numProposalsByAuthor), IntegerEntry(keyStatsUniqueAuthors(), uniqAuthors)], proposalTxId)
206+ }
168207 }
169208 }
170209
171210
172-func castVote (proposalId,userAddressStr,positive) = {
173- let curStatus = getStringOrFail(this, keyProposalStatusById(proposalId))
174- if ((curStatus != "ACTIVE"))
175- then throw(("Can't vote: status is " + curStatus))
176- else {
177- let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", [userAddressStr, 0, 0], nil))
178- let gnsbtAmt = asInt(gnsbtData[0])
179- let yesDiff = if (positive)
180- then gnsbtAmt
181- else 0
182- let noDiff = if (positive)
183- then 0
184- else gnsbtAmt
185- let oldUserYes = getIntOrElse(keyProposalYesByIdAndUser(proposalId, userAddressStr), 0)
186- let oldUserNo = getIntOrElse(keyProposalNoByIdAndUser(proposalId, userAddressStr), 0)
187- let oldTotalYes = getIntOrElse(keyProposalYesVotesById(proposalId), 0)
188- let oldTotalNo = getIntOrElse(keyProposalNoVotesById(proposalId), 0)
189- $Tuple2([IntegerEntry(keyProposalYesByIdAndUser(proposalId, userAddressStr), yesDiff), IntegerEntry(keyProposalNoByIdAndUser(proposalId, userAddressStr), noDiff), IntegerEntry(keyProposalYesVotesById(proposalId), ((oldTotalYes - oldUserYes) + yesDiff)), IntegerEntry(keyProposalNoVotesById(proposalId), ((oldTotalNo - oldUserNo) + noDiff))], unit)
190- }
211+func calcWinOption (proposalId,optionsList,isPrevOptional,oldChoice,optionalTotalOld,newChoice,newTotalByNewChoice) = {
212+ func findBest (acc,elem) = {
213+ let idx = value(indexOf(optionsList, elem))
214+ let val = getIntOrElse(keyProposalVotesByIdAndOption(proposalId, idx), 0)
215+ if ((acc._2 > val))
216+ then acc
217+ else $Tuple2(idx, val)
218+ }
219+
220+ let choiceAndVal = if (isPrevOptional)
221+ then $Tuple2(newChoice, newTotalByNewChoice)
222+ else if ((newTotalByNewChoice > optionalTotalOld))
223+ then $Tuple2(newChoice, newTotalByNewChoice)
224+ else $Tuple2(optionalTotalOld, value(oldChoice))
225+ let best = {
226+ let $l = optionsList
227+ let $s = size($l)
228+ let $acc0 = choiceAndVal
229+ func $f0_1 ($a,$i) = if (($i >= $s))
230+ then $a
231+ else findBest($a, $l[$i])
232+
233+ func $f0_2 ($a,$i) = if (($i >= $s))
234+ then $a
235+ else throw("List size exceeds 10")
236+
237+ $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)
238+ }
239+ $Tuple3(best._1, optionsList[best._1], best._2)
191240 }
192241
193242
194243 @Callable(i)
195-func initiateIdeaVoting (forumLink,title,votingStartTime,votingEndTime) = initiateVoting(toBase58String(i.transactionId), "IDEA", toString(i.caller), forumLink, title, votingStartTime, votingEndTime, "PENDING", nil)
244+func castVote (proposalId,choice) = {
245+ let userAddressStr = toString(i.caller)
246+ let curStatus = getStringOrFail(this, keyProposalStatusDataById(proposalId))
247+ let availableOptions = split(getStringOrFail(this, keyProposalOptionsById(proposalId)), SEP)
248+ let numOptions = size(availableOptions)
249+ if ((1 >= numOptions))
250+ then throw("Too few choices to vote")
251+ else if ((choice >= numOptions))
252+ then throw(("Unknown choice! Must be 0.." + toString((numOptions - 1))))
253+ else {
254+ let propData = split(getStringOrFail(this, keyProposalDataById(proposalId)), SEP)
255+ let start = parseIntValue(propData[govIdxStart])
256+ let end = parseIntValue(propData[govIdxEnd])
257+ let now = lastBlock.timestamp
258+ if ((start > now))
259+ then throw("Voting not started yet")
260+ else if ((now >= end))
261+ then throw("Voting already finished")
262+ else {
263+ let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", [userAddressStr, 0, 0], nil))
264+ let gnsbtAmt = asInt(gnsbtData[0])
265+ if ((0 >= gnsbtAmt))
266+ then throw("no gnsbt to vote")
267+ else {
268+ let gnsbtTotal = asInt(gnsbtData[1])
269+ let oldChoice = getInteger(keyProposalChoiceByIdAndUser(proposalId, userAddressStr))
270+ let oldUserVotes = if (!(isDefined(oldChoice)))
271+ then 0
272+ else getIntOrElse(keyProposalVotesByIdUserAndOption(proposalId, userAddressStr, value(oldChoice)), 0)
273+ let oldTotalByOldChoice = if (isDefined(oldChoice))
274+ then getIntOrElse(keyProposalVotesByIdAndOption(proposalId, value(oldChoice)), 0)
275+ else 0
276+ let oldTotalByNewChoice = getIntOrElse(keyProposalVotesByIdAndOption(proposalId, choice), 0)
277+ let oldTotal = getIntOrElse(keyProposalTotalVotesById(proposalId), 0)
278+ let newTotalByOldChoice = if (!(isDefined(oldChoice)))
279+ then 0
280+ else ((oldTotalByOldChoice - oldUserVotes) + (if ((value(oldChoice) == choice))
281+ then gnsbtAmt
282+ else 0))
283+ let newTotalByNewChoice = if (if (isDefined(oldChoice))
284+ then (value(oldChoice) == choice)
285+ else false)
286+ then newTotalByOldChoice
287+ else (oldTotalByNewChoice + gnsbtAmt)
288+ let newTotal = ((oldTotal - oldUserVotes) + gnsbtAmt)
289+ let isQuorumReached = (fraction(newTotal, MULT6, gnsbtTotal) > getIntOrElse(keyProposalQuorumById(proposalId), DEFAULTQUORUM))
290+ let numVotersByProposalId = getIntOrElse(keyNumUniqueVotersByProposalId(proposalId), 0)
291+ let oldAverUniqueVoters6 = getIntOrElse(keyStatsAverUniqueVoters(), 0)
292+ let numProposals = getIntegerValue(keyLastProposalId())
293+ let uniqueDiff = if ((oldUserVotes == 0))
294+ then 1
295+ else 0
296+ let newAverUniqueVoters6 = (oldAverUniqueVoters6 + fraction(uniqueDiff, MULT6, numProposals))
297+ let oldAverGnsbt = getIntOrElse(keyStatsAverGnsbtVoted(), 0)
298+ let newAverGnsbt = (oldAverGnsbt + ((gnsbtAmt - oldUserVotes) / numProposals))
299+ let optionalUserOld = if (!(isDefined(oldChoice)))
300+ then nil
301+ else [IntegerEntry(keyProposalVotesByIdUserAndOption(proposalId, userAddressStr, value(oldChoice)), 0)]
302+ let isPrevOptional = if (!(isDefined(oldChoice)))
303+ then true
304+ else (value(oldChoice) == choice)
305+ let optionalTotalOld = if (isPrevOptional)
306+ then nil
307+ else [IntegerEntry(keyProposalVotesByIdAndOption(proposalId, value(oldChoice)), newTotalByOldChoice)]
308+ let winOpt = calcWinOption(proposalId, availableOptions, isPrevOptional, oldChoice, newTotalByOldChoice, choice, newTotalByNewChoice)
309+ $Tuple2((([IntegerEntry(keyProposalChoiceByIdAndUser(proposalId, userAddressStr), choice), IntegerEntry(keyProposalVotesByIdUserAndOption(proposalId, userAddressStr, choice), gnsbtAmt), IntegerEntry(keyProposalVotesByIdAndOption(proposalId, choice), newTotalByNewChoice), IntegerEntry(keyProposalTotalVotesById(proposalId), newTotal), IntegerEntry(keyNumUniqueVotersByProposalId(proposalId), (numVotersByProposalId + uniqueDiff)), IntegerEntry(keyStatsAverUniqueVoters(), newAverUniqueVoters6), IntegerEntry(keyStatsAverGnsbtVoted(), newAverGnsbt), IntegerEntry(keyProposalWinningOptionById(proposalId), winOpt._1), IntegerEntry(keyProposalWinningVotesById(proposalId), winOpt._3), StringEntry(keyProposalStatusDataById(proposalId), statusData(isQuorumReached, winOpt._2, false, 0, false))] ++ optionalUserOld) ++ optionalTotalOld), unit)
310+ }
311+ }
312+ }
313+ }
196314
197315
198316
199317 @Callable(i)
200-func initiateUpdateVoting (forumLink,title,votingStartTime,votingEndTime,txList) = initiateVoting(toBase58String(i.transactionId), "UPDATE", toString(i.caller), forumLink, title, votingStartTime, votingEndTime, "PENDING", txList)
318+func initiateIdeaVoting (forumLink,title,votingStartTime,votingEndTime,optionsList) = initiateVoting(toBase58String(i.transactionId), "IDEA", toString(i.caller), forumLink, title, votingStartTime, votingEndTime, "PENDING", nil, optionsList)
319+
320+
321+
322+@Callable(i)
323+func initiateUpdateVoting (forumLink,title,votingStartTime,votingEndTime,txList) = initiateVoting(toBase58String(i.transactionId), "UPDATE", toString(i.caller), forumLink, title, votingStartTime, votingEndTime, "PENDING", txList, ["NO", "YES"])
201324
202325
203326
205328 func cancelVoting (proposalId,reason) = if ((i.caller != this))
206329 then throw("not authorized")
207330 else {
208- let currentData = getStringOrFail(this, keyProposalStatusById(proposalId))
331+ let currentData = getStringOrFail(this, keyProposalDataById(proposalId))
209332 let updatedData = ((take(currentData, value(lastIndexOf(currentData, SEP))) + SEP) + reason)
210- $Tuple2([StringEntry(keyProposalStatusById(proposalId), "CANCELED"), StringEntry(keyProposalDataById(proposalId), updatedData)], unit)
333+ $Tuple2([StringEntry(keyProposalStatusDataById(proposalId), statusData(false, "", false, 0, true)), StringEntry(keyProposalDataById(proposalId), updatedData)], unit)
211334 }
212-
213-
214-
215-@Callable(i)
216-func voteYes (proposalId) = castVote(proposalId, toString(i.caller), true)
217-
218-
219-
220-@Callable(i)
221-func voteNo (proposalId) = castVote(proposalId, toString(i.caller), false)
222335
223336
224337
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let revisionNum = ""
55
66 let SEP = "__"
77
88 let DEFAULTQUORUM = 500000
99
1010 let URLPATTERN = "https://forum.neutrino.at/"
1111
1212 let MAXTITLE = 160
1313
1414 let MAXVOTINGTIME = 1209600000
15+
16+let MULT6 = 1000000
1517
1618 let govIdxProposalTxId = 1
1719
1820 let govIdxType = 2
1921
2022 let govIdxAuthor = 3
2123
2224 let govIdxUrl = 4
2325
2426 let govIdxTitle = 5
2527
2628 let govIdxCreationTime = 6
2729
2830 let govIdxStart = 7
2931
3032 let govIdxEnd = 8
3133
3234 let govIdxTxIds = 9
3335
3436 let govIdxAux = 10
3537
3638 func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], ""))
3739
3840
3941 func getIntOrElse (key,defaultVal) = valueOrElse(getInteger(this, key), defaultVal)
4042
4143
4244 let IdxControlCfgNeutrinoDapp = 1
4345
4446 let IdxControlCfgAuctionDapp = 2
4547
4648 let IdxControlCfgRpdDapp = 3
4749
4850 let IdxControlCfgMathDapp = 4
4951
5052 let IdxControlCfgLiquidationDapp = 5
5153
5254 let IdxControlCfgRestDapp = 6
5355
5456 let IdxControlCfgNodeRegistryDapp = 7
5557
5658 let IdxControlCfgNsbtStakingDapp = 8
5759
5860 let IdxControlCfgMediatorDapp = 9
5961
6062 let IdxControlCfgSurfStakingDapp = 10
6163
6264 let IdxControlCfgGnsbtControllerDapp = 11
6365
6466 func keyControlAddress () = "%s%s__config__controlAddress"
6567
6668
6769 func keyControlCfg () = "%s__controlConfig"
6870
6971
7072 func readControlCfgOrFail (control) = split(getStringOrFail(control, keyControlCfg()), SEP)
7173
7274
7375 func getContractAddressOrFail (controlCfg,idx) = valueOrErrorMessage(addressFromString(controlCfg[idx]), ("Control cfg doesn't contain address at index " + toString(idx)))
7476
7577
7678 let controlContract = addressFromStringValue(valueOrElse(getString(this, keyControlAddress()), "3P5Bfd58PPfNvBM2Hy8QfbcDqMeNtzg7KfP"))
7779
7880 let controlCfg = readControlCfgOrFail(controlContract)
7981
8082 let gnsbtControllerContract = getContractAddressOrFail(controlCfg, IdxControlCfgGnsbtControllerDapp)
8183
82-func keyProposalId () = "%s__proposalId"
84+func keyLastProposalId () = "%s__proposalId"
8385
8486
85-func keyProposalStatusById (proposalId) = ("%s%d__proposalStatus__" + toString(proposalId))
87+func keyProposalStatusDataById (proposalId) = ("%s%d__proposalStatusData__" + toString(proposalId))
8688
8789
8890 func keyProposalQuorumById (proposalId) = ("%s%d__quorumRequired__" + toString(proposalId))
8991
9092
9193 func keyProposalDataById (proposalId) = ("%s%d__proposalData__" + toString(proposalId))
9294
9395
94-func keyProposalYesVotesById (proposalId) = ("%s%d__proposalYes__" + toString(proposalId))
96+func keyProposalTotalVotesById (proposalId) = ("%s%d__proposalTotalVotes__" + toString(proposalId))
9597
9698
97-func keyProposalNoVotesById (proposalId) = ("%s%d__proposalNo__" + toString(proposalId))
99+func keyProposalOptionsById (proposalId) = ("%s%d__proposalOptions__" + toString(proposalId))
98100
99101
100-func keyProposalYesByIdAndUser (proposalId,userAddr) = makeString(["%s%d%s", "proposalUserYes", toString(proposalId), userAddr], SEP)
102+func keyProposalWinningOptionById (proposalId) = ("%s%d__currWinnerOption__" + toString(proposalId))
101103
102104
103-func keyProposalNoByIdAndUser (proposalId,userAddr) = makeString(["%s%d%s", "proposalUserNo", toString(proposalId), userAddr], SEP)
105+func keyProposalWinningVotesById (proposalId) = ("%s%d__currWinnerVotes__" + toString(proposalId))
106+
107+
108+func keyProposalVotesByIdAndOption (proposalId,opt) = makeString(["%s%d%d", "votesByOpt", toString(proposalId), toString(opt)], SEP)
109+
110+
111+func keyProposalVotesByIdUserAndOption (proposalId,userAddr,opt) = makeString(["%s%d%s%d", "votesByUserOpt", toString(proposalId), userAddr, toString(opt)], SEP)
112+
113+
114+func keyProposalChoiceByIdAndUser (proposalId,userAddr) = makeString(["%s%d%s", "optionByUser", toString(proposalId), userAddr], SEP)
115+
116+
117+func keyNumUniqueVotersByProposalId (proposalId) = ("%s%d__numVoters__" + toString(proposalId))
118+
119+
120+func keyStatsAverUniqueVoters () = "%s%s%s__stats__avg__uniqueVoters"
121+
122+
123+func keyStatsAverGnsbtVoted () = "%s%s%s__stats__avg__gnsbtVoted"
124+
125+
126+func keyStatsUniqueAuthors () = "%s%s__stats__uniqueAuthors"
127+
128+
129+func keyNumProposalsByAuthor (addressStr) = ("%s%s__numProposalsByAuthor__" + addressStr)
104130
105131
106132 func asAnyList (v) = match v {
107133 case l: List[Any] =>
108134 l
109135 case _ =>
110136 throw("fail to cast into List[Any]")
111137 }
112138
113139
114140 func asInt (v) = match v {
115141 case i: Int =>
116142 i
117143 case _ =>
118144 throw("fail to cast into Int")
119145 }
146+
147+
148+func statusData (isVotingValid,winOption,areScriptsApplied,scriptsTimestamp,canceledByTeam) = makeString(["%b%s%b%d%b", toString(isVotingValid), winOption, toString(areScriptsApplied), toString(scriptsTimestamp), toString(canceledByTeam)], SEP)
120149
121150
122151 func proposalData (proposalTxId,type,author,forumLink,title,proposalTime,votingStartTime,votingEndTime,txIds,auxInfo) = makeString(["%s%s%s%s%s%d%d%d%s%s", proposalTxId, type, author, forumLink, title, toString(proposalTime), toString(votingStartTime), toString(votingEndTime), txIds, auxInfo], SEP)
123152
124153
125154 func checkTxList (txList) = if ((size(txList) > 20))
126155 then throw(("Too many transactions: " + toString(size(txList))))
127156 else {
128157 func combiner (acc,tx) = if (!(isDefined(transactionHeightById(fromBase58String(tx)))))
129158 then throw(("Wrong txId:" + tx))
130159 else if ((acc == ""))
131160 then tx
132161 else ((acc + ":") + tx)
133162
134163 let $l = txList
135164 let $s = size($l)
136165 let $acc0 = ""
137166 func $f0_1 ($a,$i) = if (($i >= $s))
138167 then $a
139168 else combiner($a, $l[$i])
140169
141170 func $f0_2 ($a,$i) = if (($i >= $s))
142171 then $a
143172 else throw("List size exceeds 20")
144173
145174 $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($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), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20)
146175 }
147176
148177
149-func initiateVoting (proposalTxId,type,author,forumLink,title,votingStartTime,votingEndTime,status,txList) = if ((value(indexOf(forumLink, URLPATTERN)) != 0))
178+func initiateVoting (proposalTxId,type,author,forumLink,title,votingStartTime,votingEndTime,status,txList,optionsList) = if ((value(indexOf(forumLink, URLPATTERN)) != 0))
150179 then throw("Invalid url")
151180 else if ((size(title) > MAXTITLE))
152181 then throw("Too long title")
153182 else {
154183 let proposalTime = lastBlock.timestamp
155184 if ((proposalTime > votingStartTime))
156185 then throw(((("votingStartTime=" + toString(votingStartTime)) + " < proposalTime=") + toString(proposalTime)))
157186 else if ((votingStartTime > votingEndTime))
158187 then throw(((("votingEndTime=" + toString(votingEndTime)) + " < votingStartTime=") + toString(votingStartTime)))
159188 else if (((votingEndTime - votingStartTime) > MAXVOTINGTIME))
160189 then throw(((("Voting period exceeds max: " + toString((votingEndTime - votingStartTime))) + " > ") + toString(MAXVOTINGTIME)))
161190 else {
162191 let txIds = if ((type == "IDEA"))
163192 then ""
164193 else checkTxList(txList)
165- let proposalId = (getIntOrElse(keyProposalId(), 0) + 1)
166- let quorum = getIntOrElse(keyProposalQuorumById(proposalId), DEFAULTQUORUM)
167- $Tuple2([IntegerEntry(keyProposalId(), proposalId), IntegerEntry(keyProposalYesVotesById(proposalId), 0), IntegerEntry(keyProposalNoVotesById(proposalId), 0), StringEntry(keyProposalStatusById(proposalId), status), StringEntry(keyProposalDataById(proposalId), proposalData(proposalTxId, type, author, forumLink, title, proposalTime, votingStartTime, votingEndTime, txIds, ""))], proposalTxId)
194+ if ((1 >= size(optionsList)))
195+ then throw("Too few choices to vote")
196+ else {
197+ let proposalId = (getIntOrElse(keyLastProposalId(), 0) + 1)
198+ let quorum = getIntOrElse(keyProposalQuorumById(proposalId), DEFAULTQUORUM)
199+ let numProposalsByAuthor = (getIntOrElse(keyNumProposalsByAuthor(author), 0) + 1)
200+ let uniqAuthors = (getIntOrElse(keyStatsUniqueAuthors(), 0) + (if ((numProposalsByAuthor == 1))
201+ then 1
202+ else 0))
203+ let statusDataStr = statusData(false, "", false, 0, false)
204+ let optionsStr = makeString(optionsList, SEP)
205+ $Tuple2([StringEntry(keyProposalOptionsById(proposalId), optionsStr), IntegerEntry(keyLastProposalId(), proposalId), StringEntry(keyProposalStatusDataById(proposalId), statusDataStr), StringEntry(keyProposalDataById(proposalId), proposalData(proposalTxId, type, author, forumLink, title, proposalTime, votingStartTime, votingEndTime, txIds, "")), IntegerEntry(keyNumProposalsByAuthor(author), numProposalsByAuthor), IntegerEntry(keyStatsUniqueAuthors(), uniqAuthors)], proposalTxId)
206+ }
168207 }
169208 }
170209
171210
172-func castVote (proposalId,userAddressStr,positive) = {
173- let curStatus = getStringOrFail(this, keyProposalStatusById(proposalId))
174- if ((curStatus != "ACTIVE"))
175- then throw(("Can't vote: status is " + curStatus))
176- else {
177- let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", [userAddressStr, 0, 0], nil))
178- let gnsbtAmt = asInt(gnsbtData[0])
179- let yesDiff = if (positive)
180- then gnsbtAmt
181- else 0
182- let noDiff = if (positive)
183- then 0
184- else gnsbtAmt
185- let oldUserYes = getIntOrElse(keyProposalYesByIdAndUser(proposalId, userAddressStr), 0)
186- let oldUserNo = getIntOrElse(keyProposalNoByIdAndUser(proposalId, userAddressStr), 0)
187- let oldTotalYes = getIntOrElse(keyProposalYesVotesById(proposalId), 0)
188- let oldTotalNo = getIntOrElse(keyProposalNoVotesById(proposalId), 0)
189- $Tuple2([IntegerEntry(keyProposalYesByIdAndUser(proposalId, userAddressStr), yesDiff), IntegerEntry(keyProposalNoByIdAndUser(proposalId, userAddressStr), noDiff), IntegerEntry(keyProposalYesVotesById(proposalId), ((oldTotalYes - oldUserYes) + yesDiff)), IntegerEntry(keyProposalNoVotesById(proposalId), ((oldTotalNo - oldUserNo) + noDiff))], unit)
190- }
211+func calcWinOption (proposalId,optionsList,isPrevOptional,oldChoice,optionalTotalOld,newChoice,newTotalByNewChoice) = {
212+ func findBest (acc,elem) = {
213+ let idx = value(indexOf(optionsList, elem))
214+ let val = getIntOrElse(keyProposalVotesByIdAndOption(proposalId, idx), 0)
215+ if ((acc._2 > val))
216+ then acc
217+ else $Tuple2(idx, val)
218+ }
219+
220+ let choiceAndVal = if (isPrevOptional)
221+ then $Tuple2(newChoice, newTotalByNewChoice)
222+ else if ((newTotalByNewChoice > optionalTotalOld))
223+ then $Tuple2(newChoice, newTotalByNewChoice)
224+ else $Tuple2(optionalTotalOld, value(oldChoice))
225+ let best = {
226+ let $l = optionsList
227+ let $s = size($l)
228+ let $acc0 = choiceAndVal
229+ func $f0_1 ($a,$i) = if (($i >= $s))
230+ then $a
231+ else findBest($a, $l[$i])
232+
233+ func $f0_2 ($a,$i) = if (($i >= $s))
234+ then $a
235+ else throw("List size exceeds 10")
236+
237+ $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)
238+ }
239+ $Tuple3(best._1, optionsList[best._1], best._2)
191240 }
192241
193242
194243 @Callable(i)
195-func initiateIdeaVoting (forumLink,title,votingStartTime,votingEndTime) = initiateVoting(toBase58String(i.transactionId), "IDEA", toString(i.caller), forumLink, title, votingStartTime, votingEndTime, "PENDING", nil)
244+func castVote (proposalId,choice) = {
245+ let userAddressStr = toString(i.caller)
246+ let curStatus = getStringOrFail(this, keyProposalStatusDataById(proposalId))
247+ let availableOptions = split(getStringOrFail(this, keyProposalOptionsById(proposalId)), SEP)
248+ let numOptions = size(availableOptions)
249+ if ((1 >= numOptions))
250+ then throw("Too few choices to vote")
251+ else if ((choice >= numOptions))
252+ then throw(("Unknown choice! Must be 0.." + toString((numOptions - 1))))
253+ else {
254+ let propData = split(getStringOrFail(this, keyProposalDataById(proposalId)), SEP)
255+ let start = parseIntValue(propData[govIdxStart])
256+ let end = parseIntValue(propData[govIdxEnd])
257+ let now = lastBlock.timestamp
258+ if ((start > now))
259+ then throw("Voting not started yet")
260+ else if ((now >= end))
261+ then throw("Voting already finished")
262+ else {
263+ let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", [userAddressStr, 0, 0], nil))
264+ let gnsbtAmt = asInt(gnsbtData[0])
265+ if ((0 >= gnsbtAmt))
266+ then throw("no gnsbt to vote")
267+ else {
268+ let gnsbtTotal = asInt(gnsbtData[1])
269+ let oldChoice = getInteger(keyProposalChoiceByIdAndUser(proposalId, userAddressStr))
270+ let oldUserVotes = if (!(isDefined(oldChoice)))
271+ then 0
272+ else getIntOrElse(keyProposalVotesByIdUserAndOption(proposalId, userAddressStr, value(oldChoice)), 0)
273+ let oldTotalByOldChoice = if (isDefined(oldChoice))
274+ then getIntOrElse(keyProposalVotesByIdAndOption(proposalId, value(oldChoice)), 0)
275+ else 0
276+ let oldTotalByNewChoice = getIntOrElse(keyProposalVotesByIdAndOption(proposalId, choice), 0)
277+ let oldTotal = getIntOrElse(keyProposalTotalVotesById(proposalId), 0)
278+ let newTotalByOldChoice = if (!(isDefined(oldChoice)))
279+ then 0
280+ else ((oldTotalByOldChoice - oldUserVotes) + (if ((value(oldChoice) == choice))
281+ then gnsbtAmt
282+ else 0))
283+ let newTotalByNewChoice = if (if (isDefined(oldChoice))
284+ then (value(oldChoice) == choice)
285+ else false)
286+ then newTotalByOldChoice
287+ else (oldTotalByNewChoice + gnsbtAmt)
288+ let newTotal = ((oldTotal - oldUserVotes) + gnsbtAmt)
289+ let isQuorumReached = (fraction(newTotal, MULT6, gnsbtTotal) > getIntOrElse(keyProposalQuorumById(proposalId), DEFAULTQUORUM))
290+ let numVotersByProposalId = getIntOrElse(keyNumUniqueVotersByProposalId(proposalId), 0)
291+ let oldAverUniqueVoters6 = getIntOrElse(keyStatsAverUniqueVoters(), 0)
292+ let numProposals = getIntegerValue(keyLastProposalId())
293+ let uniqueDiff = if ((oldUserVotes == 0))
294+ then 1
295+ else 0
296+ let newAverUniqueVoters6 = (oldAverUniqueVoters6 + fraction(uniqueDiff, MULT6, numProposals))
297+ let oldAverGnsbt = getIntOrElse(keyStatsAverGnsbtVoted(), 0)
298+ let newAverGnsbt = (oldAverGnsbt + ((gnsbtAmt - oldUserVotes) / numProposals))
299+ let optionalUserOld = if (!(isDefined(oldChoice)))
300+ then nil
301+ else [IntegerEntry(keyProposalVotesByIdUserAndOption(proposalId, userAddressStr, value(oldChoice)), 0)]
302+ let isPrevOptional = if (!(isDefined(oldChoice)))
303+ then true
304+ else (value(oldChoice) == choice)
305+ let optionalTotalOld = if (isPrevOptional)
306+ then nil
307+ else [IntegerEntry(keyProposalVotesByIdAndOption(proposalId, value(oldChoice)), newTotalByOldChoice)]
308+ let winOpt = calcWinOption(proposalId, availableOptions, isPrevOptional, oldChoice, newTotalByOldChoice, choice, newTotalByNewChoice)
309+ $Tuple2((([IntegerEntry(keyProposalChoiceByIdAndUser(proposalId, userAddressStr), choice), IntegerEntry(keyProposalVotesByIdUserAndOption(proposalId, userAddressStr, choice), gnsbtAmt), IntegerEntry(keyProposalVotesByIdAndOption(proposalId, choice), newTotalByNewChoice), IntegerEntry(keyProposalTotalVotesById(proposalId), newTotal), IntegerEntry(keyNumUniqueVotersByProposalId(proposalId), (numVotersByProposalId + uniqueDiff)), IntegerEntry(keyStatsAverUniqueVoters(), newAverUniqueVoters6), IntegerEntry(keyStatsAverGnsbtVoted(), newAverGnsbt), IntegerEntry(keyProposalWinningOptionById(proposalId), winOpt._1), IntegerEntry(keyProposalWinningVotesById(proposalId), winOpt._3), StringEntry(keyProposalStatusDataById(proposalId), statusData(isQuorumReached, winOpt._2, false, 0, false))] ++ optionalUserOld) ++ optionalTotalOld), unit)
310+ }
311+ }
312+ }
313+ }
196314
197315
198316
199317 @Callable(i)
200-func initiateUpdateVoting (forumLink,title,votingStartTime,votingEndTime,txList) = initiateVoting(toBase58String(i.transactionId), "UPDATE", toString(i.caller), forumLink, title, votingStartTime, votingEndTime, "PENDING", txList)
318+func initiateIdeaVoting (forumLink,title,votingStartTime,votingEndTime,optionsList) = initiateVoting(toBase58String(i.transactionId), "IDEA", toString(i.caller), forumLink, title, votingStartTime, votingEndTime, "PENDING", nil, optionsList)
319+
320+
321+
322+@Callable(i)
323+func initiateUpdateVoting (forumLink,title,votingStartTime,votingEndTime,txList) = initiateVoting(toBase58String(i.transactionId), "UPDATE", toString(i.caller), forumLink, title, votingStartTime, votingEndTime, "PENDING", txList, ["NO", "YES"])
201324
202325
203326
204327 @Callable(i)
205328 func cancelVoting (proposalId,reason) = if ((i.caller != this))
206329 then throw("not authorized")
207330 else {
208- let currentData = getStringOrFail(this, keyProposalStatusById(proposalId))
331+ let currentData = getStringOrFail(this, keyProposalDataById(proposalId))
209332 let updatedData = ((take(currentData, value(lastIndexOf(currentData, SEP))) + SEP) + reason)
210- $Tuple2([StringEntry(keyProposalStatusById(proposalId), "CANCELED"), StringEntry(keyProposalDataById(proposalId), updatedData)], unit)
333+ $Tuple2([StringEntry(keyProposalStatusDataById(proposalId), statusData(false, "", false, 0, true)), StringEntry(keyProposalDataById(proposalId), updatedData)], unit)
211334 }
212-
213-
214-
215-@Callable(i)
216-func voteYes (proposalId) = castVote(proposalId, toString(i.caller), true)
217-
218-
219-
220-@Callable(i)
221-func voteNo (proposalId) = castVote(proposalId, toString(i.caller), false)
222335
223336
224337
225338 @Callable(i)
226339 func applyVoting (proposalId) = $Tuple2(nil, unit)
227340
228341

github/deemru/w8io/c3f4982 
53.07 ms