tx · BLkGpTER364v5dYwS5DP78cGnj4hCKtceNRnMcWRupXv

3Mu5kJR7ECoKqV4RjdtjBkeKaQoTgR1WBZc:  -0.02400000 Waves

2023.05.05 16:40 [2564593] smart account 3Mu5kJR7ECoKqV4RjdtjBkeKaQoTgR1WBZc > SELF 0.00000000 Waves

{ "type": 13, "id": "BLkGpTER364v5dYwS5DP78cGnj4hCKtceNRnMcWRupXv", "fee": 2400000, "feeAssetId": null, "timestamp": 1683294063374, "version": 2, "chainId": 84, "sender": "3Mu5kJR7ECoKqV4RjdtjBkeKaQoTgR1WBZc", "senderPublicKey": "242mibE5dTci8wD6vghuCGxjDZdnNJr88H7gcWWehpEX", "proofs": [ "2tAhK8pQKbrdPBD4aekqDKVYCwu3AKLM9QxAbBP9LUxPeyFNSb6XjQ16TdoZc6sJv6XysdMDThwrRKQHtB4AYx7j" ], "script": "base64:BgI1CAISBwoFCAEBAQESBAoCAQESBwoFCAgBARgSBwoFCAgBARgSAwoBARIDCgEBEgASBAoCAQhcAAtyZXZpc2lvbk51bQIAAANTRVACAl9fAAdMSVNUU0VQAgE6AA1ERUZBVUxUUVVPUlVNAKDCHgAKVVJMUEFUVEVSTgIaaHR0cHM6Ly9mb3J1bS5uZXV0cmluby5hdC8ACE1BWFRJVExFAPoBAAZNQVhVUkwA+gEADU1BWFZPVElOR1RJTUUAgJDkwAQABU1VTFQ2AMCEPQAOREVGQVVMVFBBWU1FTlQAgJTr3AMAFERFRkFVTFRDUkVBVElPTkdOU0JUAICU69wDAApQQVNUTUFSR0lOAIC6twMADEZVVFVSRU1BUkdJTgDAy8kCABRERUZBVUxURklSU1RQUk9QT1NBTABvABJnb3ZJZHhQcm9wb3NhbFR4SWQAAQAKZ292SWR4VHlwZQACAAxnb3ZJZHhBdXRob3IAAwAJZ292SWR4VXJsAAQAC2dvdklkeFRpdGxlAAUAEmdvdklkeENyZWF0aW9uVGltZQAGAAtnb3ZJZHhTdGFydAAHAAlnb3ZJZHhFbmQACAALZ292SWR4VHhJZHMACQAMZ292SWR4UXVvcnVtAAoADWdvdklkeE9wdGlvbnMACwATZ292U3RhdHVzSWR4SXNWYWxpZAABABJnb3ZTdGF0dXNJZHhXaW5PcHQAAgAUZ292U3RhdHVzSWR4V2luVm90ZXMAAwAWZ292U3RhdHVzSWR4VG90YWxWb3RlcwAEABVnb3ZTdGF0dXNJZHhTY0FwcGxpZWQABQASZ292U3RhdHVzSWR4U2NUaW1lAAYAFmdvdlN0YXR1c0lkeElzQ2FuY2VsZWQABwAWZ292U3RhdHVzSWR4SW1wbFN0YXR1cwAIAQ9nZXRTdHJpbmdPckZhaWwCB2FkZHJlc3MDa2V5CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ0IAgUHYWRkcmVzcwUDa2V5CQC5CQIJAMwIAgIKbWFuZGF0b3J5IAkAzAgCCQClCAEFB2FkZHJlc3MJAMwIAgIBLgkAzAgCBQNrZXkJAMwIAgIPIGlzIG5vdCBkZWZpbmVkBQNuaWwCAAEMZ2V0SW50T3JFbHNlAgNrZXkKZGVmYXVsdFZhbAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQNrZXkFCmRlZmF1bHRWYWwAGUlkeENvbnRyb2xDZmdOZXV0cmlub0RhcHAAAQAYSWR4Q29udHJvbENmZ0F1Y3Rpb25EYXBwAAIAFElkeENvbnRyb2xDZmdScGREYXBwAAMAFUlkeENvbnRyb2xDZmdNYXRoRGFwcAAEABxJZHhDb250cm9sQ2ZnTGlxdWlkYXRpb25EYXBwAAUAFUlkeENvbnRyb2xDZmdSZXN0RGFwcAAGAB1JZHhDb250cm9sQ2ZnTm9kZVJlZ2lzdHJ5RGFwcAAHABxJZHhDb250cm9sQ2ZnTnNidFN0YWtpbmdEYXBwAAgAGUlkeENvbnRyb2xDZmdNZWRpYXRvckRhcHAACQAcSWR4Q29udHJvbENmZ1N1cmZTdGFraW5nRGFwcAAKACBJZHhDb250cm9sQ2ZnR25zYnRDb250cm9sbGVyRGFwcAALABdJZHhDb250cm9sQ2ZnUmVzdFYyRGFwcAAMABtJZHhDb250cm9sQ2ZnR292ZXJuYW5jZURhcHAADQERa2V5Q29udHJvbEFkZHJlc3MAAhwlcyVzX19jb25maWdfX2NvbnRyb2xBZGRyZXNzAQ1rZXlDb250cm9sQ2ZnAAIRJXNfX2NvbnRyb2xDb25maWcBFHJlYWRDb250cm9sQ2ZnT3JGYWlsAQdjb250cm9sCQC8CQIJAQ9nZXRTdHJpbmdPckZhaWwCBQdjb250cm9sCQENa2V5Q29udHJvbENmZwAFA1NFUAEYZ2V0Q29udHJhY3RBZGRyZXNzT3JGYWlsAgpjb250cm9sQ2ZnA2lkeAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJAJEDAgUKY29udHJvbENmZwUDaWR4CQCsAgICLUNvbnRyb2wgY2ZnIGRvZXNuJ3QgY29udGFpbiBhZGRyZXNzIGF0IGluZGV4IAkApAMBBQNpZHgAD2NvbnRyb2xDb250cmFjdAkBEUBleHRyTmF0aXZlKDEwNjIpAQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzCQERa2V5Q29udHJvbEFkZHJlc3MAAiMzTjROUzdkNEpvOWE2RjE0TGlGVUtLWVZkVWtrZjJlUDRaeAAKY29udHJvbENmZwkBFHJlYWRDb250cm9sQ2ZnT3JGYWlsAQUPY29udHJvbENvbnRyYWN0ABBuZXV0cmlub0NvbnRyYWN0CQEYZ2V0Q29udHJhY3RBZGRyZXNzT3JGYWlsAgUKY29udHJvbENmZwUZSWR4Q29udHJvbENmZ05ldXRyaW5vRGFwcAAXZ25zYnRDb250cm9sbGVyQ29udHJhY3QJARhnZXRDb250cmFjdEFkZHJlc3NPckZhaWwCBQpjb250cm9sQ2ZnBSBJZHhDb250cm9sQ2ZnR25zYnRDb250cm9sbGVyRGFwcAATc3VyZlN0YWtpbmdDb250cmFjdAkBGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAIFCmNvbnRyb2xDZmcFHElkeENvbnRyb2xDZmdTdXJmU3Rha2luZ0RhcHABFWtleUxhc3RCYXNlNThQcm9wb3NhbAACFiVzX19sYXN0QmFzZTU4UHJvcG9zYWwBGGtleVF1b3J1bVJlcXVpcmVkUGVyY2VudAEEdHlwZQkArAICAhYlcyVzX19xdW9ydW1SZXF1aXJlZF9fBQR0eXBlARJrZXlQYXltZW50UmVxdWlyZWQAAhMlc19fcGF5bWVudFJlcXVpcmVkARBrZXlHbnNidFJlcXVpcmVkAAIRJXNfX2dOc2J0UmVxdWlyZWQBEWtleUxhc3RQcm9wb3NhbElkAAIOJXNfX3Byb3Bvc2FsSWQBEmtleUZpcnN0UHJvcG9zYWxJZAACEyVzX19maXJzdFByb3Bvc2FsSWQBFGtleUxhc3RVcGRhdGVWZXJzaW9uAAIRJXNfX3VwZGF0ZVZlcnNpb24BGWtleVByb3Bvc2FsU3RhdHVzRGF0YUJ5SWQBCnByb3Bvc2FsSWQJAKwCAgIaJXMlZF9fcHJvcG9zYWxTdGF0dXNEYXRhX18JAKQDAQUKcHJvcG9zYWxJZAETa2V5UHJvcG9zYWxEYXRhQnlJZAEKcHJvcG9zYWxJZAkArAICAhQlcyVkX19wcm9wb3NhbERhdGFfXwkApAMBBQpwcm9wb3NhbElkAR1rZXlQcm9wb3NhbFZvdGVzQnlJZEFuZE9wdGlvbgIKcHJvcG9zYWxJZANvcHQJALkJAgkAzAgCAgYlcyVkJWQJAMwIAgIKdm90ZXNCeU9wdAkAzAgCCQCkAwEFCnByb3Bvc2FsSWQJAMwIAgkApAMBBQNvcHQFA25pbAUDU0VQARtrZXlQcm9wb3NhbFZvdGVzQnlJZEFuZFVzZXICCnByb3Bvc2FsSWQIdXNlckFkZHIJALkJAgkAzAgCAgYlcyVkJXMJAMwIAgILdm90ZXNCeVVzZXIJAMwIAgkApAMBBQpwcm9wb3NhbElkCQDMCAIFCHVzZXJBZGRyBQNuaWwFA1NFUAEca2V5UHJvcG9zYWxDaG9pY2VCeUlkQW5kVXNlcgIKcHJvcG9zYWxJZAh1c2VyQWRkcgkAuQkCCQDMCAICBiVzJWQlcwkAzAgCAgxvcHRpb25CeVVzZXIJAMwIAgkApAMBBQpwcm9wb3NhbElkCQDMCAIFCHVzZXJBZGRyBQNuaWwFA1NFUAESa2V5QXBwbHlJblByb2dyZXNzAAITJXNfX2FwcGx5SW5Qcm9ncmVzcwEWa2V5UHJvcG9zYWxJZEJ5VG9waWNJZAEHdG9waWNJZAkArAICAhslcyVkX19wcm9wb3NhbElkQnlUb3BpY0lkX18JAKQDAQUHdG9waWNJZAEXa2V5VXNlckduc2J0UmVsZWFzZVRpbWUBCHVzZXJBZGRyCQCsAgICGyVzJXNfdXNlckduc2J0UmVsZWFzZVRpbWVfXwUIdXNlckFkZHIBHmtleU51bVVuaXF1ZVZvdGVyc0J5UHJvcG9zYWxJZAEKcHJvcG9zYWxJZAkArAICAhElcyVkX19udW1Wb3RlcnNfXwkApAMBBQpwcm9wb3NhbElkARhrZXlTdGF0c0F2ZXJVbmlxdWVWb3RlcnMAAiAlcyVzJXNfX3N0YXRzX19hdmdfX3VuaXF1ZVZvdGVycwEWa2V5U3RhdHNBdmVyR25zYnRWb3RlZAACHiVzJXMlc19fc3RhdHNfX2F2Z19fZ25zYnRWb3RlZAEVa2V5U3RhdHNVbmlxdWVBdXRob3JzAAIaJXMlc19fc3RhdHNfX3VuaXF1ZUF1dGhvcnMBF2tleU51bVByb3Bvc2Fsc0J5QXV0aG9yAQphZGRyZXNzU3RyCQCsAgICHCVzJXNfX251bVByb3Bvc2Fsc0J5QXV0aG9yX18FCmFkZHJlc3NTdHIBD2tleUFwcGx5SGlzdG9yeQEJdGltZXN0YW1wCQCsAgICFCVzJWRfX2FwcGx5SGlzdG9yeV9fCQCkAwEFCXRpbWVzdGFtcAEJYXNBbnlMaXN0AQF2BAckbWF0Y2gwBQF2AwkAAQIFByRtYXRjaDACCUxpc3RbQW55XQQBbAUHJG1hdGNoMAUBbAkAAgECG2ZhaWwgdG8gY2FzdCBpbnRvIExpc3RbQW55XQEFYXNJbnQBAXYEByRtYXRjaDAFAXYDCQABAgUHJG1hdGNoMAIDSW50BAFpBQckbWF0Y2gwBQFpCQACAQIVZmFpbCB0byBjYXN0IGludG8gSW50AQpzdGF0dXNEYXRhCA1pc1ZvdGluZ1ZhbGlkCXdpbk9wdGlvbg53aW5PcHRpb25Wb3Rlcwp0b3RhbFZvdGVzEWFyZVNjcmlwdHNBcHBsaWVkEHNjcmlwdHNUaW1lc3RhbXAOY2FuY2VsZWRCeVRlYW0KaW1wbFN0YXR1cwkAuQkCCQDMCAICECViJWQlZCVkJWIlZCViJXMJAMwIAgkApQMBBQ1pc1ZvdGluZ1ZhbGlkCQDMCAIJAKQDAQUJd2luT3B0aW9uCQDMCAIJAKQDAQUOd2luT3B0aW9uVm90ZXMJAMwIAgkApAMBBQp0b3RhbFZvdGVzCQDMCAIJAKUDAQURYXJlU2NyaXB0c0FwcGxpZWQJAMwIAgkApAMBBRBzY3JpcHRzVGltZXN0YW1wCQDMCAIJAKUDAQUOY2FuY2VsZWRCeVRlYW0JAMwIAgUKaW1wbFN0YXR1cwUDbmlsBQNTRVABDHByb3Bvc2FsRGF0YQsMcHJvcG9zYWxUeElkBHR5cGUGYXV0aG9yCWZvcnVtTGluawV0aXRsZQxwcm9wb3NhbFRpbWUPdm90aW5nU3RhcnRUaW1lDXZvdGluZ0VuZFRpbWUFdHhJZHMNcXVvcnVtSW5HbnNidAdvcHRpb25zCQC5CQIJAMwIAgIWJXMlcyVzJXMlcyVkJWQlZCVzJWQlcwkAzAgCBQxwcm9wb3NhbFR4SWQJAMwIAgUEdHlwZQkAzAgCBQZhdXRob3IJAMwIAgUJZm9ydW1MaW5rCQDMCAIFBXRpdGxlCQDMCAIJAKQDAQUMcHJvcG9zYWxUaW1lCQDMCAIJAKQDAQUPdm90aW5nU3RhcnRUaW1lCQDMCAIJAKQDAQUNdm90aW5nRW5kVGltZQkAzAgCBQV0eElkcwkAzAgCCQCkAwEFDXF1b3J1bUluR25zYnQJAMwIAgUHb3B0aW9ucwUDbmlsBQNTRVABC2NoZWNrVHhMaXN0AQZ0eExpc3QDCQBmAgkAkAMBBQZ0eExpc3QAFAkAAgEJAKwCAgIXVG9vIG1hbnkgdHJhbnNhY3Rpb25zOiAJAKQDAQkAkAMBBQZ0eExpc3QKAQhjb21iaW5lcgIDYWNjAnR4AwkBAiE9AgkAyAEBCQDZBAEFAnR4ACAJAAIBCQCsAgICDFdyb25nIHR4SWQ6IAUCdHgDCQAAAgUDYWNjAgAFAnR4CQCsAgIJAKwCAgUDYWNjBQdMSVNUU0VQBQJ0eAoAAiRsBQZ0eExpc3QKAAIkcwkAkAMBBQIkbAoABSRhY2MwAgAKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBCGNvbWJpbmVyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAyMAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAC0lkeEVmZlRvdGFsAAAACklkeEVmZlVzZXIAAQERZ2V0RWZmZWN0aXZlR25zYnQBEnVzZXJBZGRyU3RyT3JFbXB0eQQDdXBkAwkBCWlzRGVmaW5lZAEJAKYIAQUSdXNlckFkZHJTdHJPckVtcHR5CQD8BwQFE3N1cmZTdGFraW5nQ29udHJhY3QCEXVwZGF0ZVZvdGluZ1Bvd2VyCQDMCAIFEnVzZXJBZGRyU3RyT3JFbXB0eQUDbmlsBQNuaWwFBHVuaXQDCQAAAgUDdXBkBQN1cGQECWduc2J0RGF0YQkBCWFzQW55TGlzdAEJAPwHBAUXZ25zYnRDb250cm9sbGVyQ29udHJhY3QCFGduc2J0SW5mb1NZU1JFQURPTkxZCQDMCAIFEnVzZXJBZGRyU3RyT3JFbXB0eQkAzAgCAAAJAMwIAgAABQNuaWwFA25pbAQIbnNidERhdGEJAQlhc0FueUxpc3QBCQCRAwIFCWduc2J0RGF0YQACBAx1c2VyRnJvbU5zYnQJAQVhc0ludAEJAJEDAgUIbnNidERhdGEAAgQNdG90YWxGcm9tTnNidAkBBWFzSW50AQkAkQMCBQhuc2J0RGF0YQADBBJ1c2VyTWF0dXJlRnJvbVN1cmYJAQVhc0ludAEJAJEDAgUJZ25zYnREYXRhAAkEE3RvdGFsTWF0dXJlRnJvbVN1cmYJAQVhc0ludAEJAJEDAgUJZ25zYnREYXRhAAYJAMwIAgkAZAIFDXRvdGFsRnJvbU5zYnQFE3RvdGFsTWF0dXJlRnJvbVN1cmYJAMwIAgkAZAIFDHVzZXJGcm9tTnNidAUSdXNlck1hdHVyZUZyb21TdXJmBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BDHZhbGlkYXRlTGluawEDdXJsAwkBAiE9AgkBBXZhbHVlAQkAswkCBQN1cmwFClVSTFBBVFRFUk4AAAkAAgECC0ludmFsaWQgdXJsAwkAZgIJALECAQUDdXJsBQZNQVhVUkwJAAIBAg1VcmwgdG9vIGxvbmchBAd0b3BpY0lkCQETdmFsdWVPckVycm9yTWVzc2FnZQIJALYJAQkAsAICBQN1cmwJAGQCCQEFdmFsdWUBCQC3CQIFA3VybAIBLwABAg1Xcm9uZyB0b3BpY0lkBAxyZWdpc3RlcmVkSWQJAJ8IAQkBFmtleVByb3Bvc2FsSWRCeVRvcGljSWQBBQd0b3BpY0lkAwkBCWlzRGVmaW5lZAEFDHJlZ2lzdGVyZWRJZAkAAgEJAKwCAgI4Vm90aW5nIHdpdGggc3VjaCBmb3J1bSBsaW5rIGlzIGFscmVhZHkgcmVnaXN0ZXJlZCBieSBpZD0JAKQDAQkBBXZhbHVlAQUMcmVnaXN0ZXJlZElkBQd0b3BpY0lkAQ5pbml0aWF0ZVZvdGluZwsHcGF5bWVudAxwcm9wb3NhbFR4SWQEdHlwZQZhdXRob3IJZm9ydW1MaW5rBXRpdGxlD3ZvdGluZ1N0YXJ0VGltZQ12b3RpbmdFbmRUaW1lBnN0YXR1cwZ0eExpc3QLb3B0aW9uc0xpc3QDCQECIT0CCAUHcGF5bWVudAdhc3NldElkBQR1bml0CQACAQIbQWxsb3dlZCBXQVZFUyBwYXltZW50IG9ubHkhBAZwbXRSZXEJAQxnZXRJbnRPckVsc2UCCQESa2V5UGF5bWVudFJlcXVpcmVkAAUOREVGQVVMVFBBWU1FTlQDCQBmAgUGcG10UmVxCAUHcGF5bWVudAZhbW91bnQJAAIBCQCsAgICJFBheW1lbnQgYXR0YWNoZWQgc2hvdWxkIGJlIGF0IGxlYXN0IAkApAMBBQZwbXRSZXEEB3RvcGljSWQJAQx2YWxpZGF0ZUxpbmsBBQlmb3J1bUxpbmsDCQAAAgUFdGl0bGUCAAkAAgECDlRpdGxlIGlzIGVtcHR5AwkAZgIJALECAQUFdGl0bGUFCE1BWFRJVExFCQACAQIOVG9vIGxvbmcgdGl0bGUEDHByb3Bvc2FsVGltZQgFCWxhc3RCbG9jawl0aW1lc3RhbXADCQBmAgUMcHJvcG9zYWxUaW1lBQ92b3RpbmdTdGFydFRpbWUJAAIBCQCsAgIJAKwCAgkArAICAhB2b3RpbmdTdGFydFRpbWU9CQCkAwEFD3ZvdGluZ1N0YXJ0VGltZQIQIDwgcHJvcG9zYWxUaW1lPQkApAMBBQxwcm9wb3NhbFRpbWUDCQBmAgUPdm90aW5nU3RhcnRUaW1lBQ12b3RpbmdFbmRUaW1lCQACAQkArAICCQCsAgIJAKwCAgIOdm90aW5nRW5kVGltZT0JAKQDAQUNdm90aW5nRW5kVGltZQITIDwgdm90aW5nU3RhcnRUaW1lPQkApAMBBQ92b3RpbmdTdGFydFRpbWUDCQBmAgkAZQIFDXZvdGluZ0VuZFRpbWUFD3ZvdGluZ1N0YXJ0VGltZQUNTUFYVk9USU5HVElNRQkAAgEJAKwCAgkArAICCQCsAgICG1ZvdGluZyBwZXJpb2QgZXhjZWVkcyBtYXg6IAkApAMBCQBlAgUNdm90aW5nRW5kVGltZQUPdm90aW5nU3RhcnRUaW1lAgMgPiAJAKQDAQUNTUFYVk9USU5HVElNRQQFdHhJZHMDCQAAAgUEdHlwZQIESURFQQIACQELY2hlY2tUeExpc3QBBQZ0eExpc3QDCQBnAgABCQCQAwEFC29wdGlvbnNMaXN0CQACAQIXVG9vIGZldyBjaG9pY2VzIHRvIHZvdGUEA2VmZgkBEWdldEVmZmVjdGl2ZUduc2J0AQUGYXV0aG9yBApnbnNidFRvdGFsCQCRAwIFA2VmZgULSWR4RWZmVG90YWwECWdOc2J0VXNlcgkAkQMCBQNlZmYFCklkeEVmZlVzZXIECGduc2J0UmVxCQEMZ2V0SW50T3JFbHNlAgkBEGtleUduc2J0UmVxdWlyZWQABRRERUZBVUxUQ1JFQVRJT05HTlNCVAMJAGYCBQhnbnNidFJlcQUJZ05zYnRVc2VyCQACAQkArAICCQCsAgICEllvdSBuZWVkIGF0IGxlYXN0IAkApAMBBQhnbnNidFJlcQIXIGdOc2J0IHRvIGNyZWF0ZSB2b3RpbmcEDGFtb3VudExlYXNlZAkA/AcEBRBuZXV0cmlub0NvbnRyYWN0AgthY2NlcHRXYXZlcwUDbmlsCQDMCAIFB3BheW1lbnQFA25pbAMJAAACBQxhbW91bnRMZWFzZWQFDGFtb3VudExlYXNlZAQGcXVvcnVtCQEMZ2V0SW50T3JFbHNlAgkBGGtleVF1b3J1bVJlcXVpcmVkUGVyY2VudAEFBHR5cGUFDURFRkFVTFRRVU9SVU0EDXF1b3J1bUluR25zYnQJAGsDBQZxdW9ydW0FCmduc2J0VG90YWwFBU1VTFQ2BApwcm9wb3NhbElkCQBkAgkBDGdldEludE9yRWxzZQIJARFrZXlMYXN0UHJvcG9zYWxJZAAAAAABBBRudW1Qcm9wb3NhbHNCeUF1dGhvcgkAZAIJAQxnZXRJbnRPckVsc2UCCQEXa2V5TnVtUHJvcG9zYWxzQnlBdXRob3IBBQZhdXRob3IAAAABBAt1bmlxQXV0aG9ycwkAZAIJAQxnZXRJbnRPckVsc2UCCQEVa2V5U3RhdHNVbmlxdWVBdXRob3JzAAAAAwkAAAIFFG51bVByb3Bvc2Fsc0J5QXV0aG9yAAEAAQAABApvcHRpb25zU3RyCQC5CQIFC29wdGlvbnNMaXN0BQdMSVNUU0VQBBJsYXN0QmFzZTU4UHJvcG9zYWwJAJ8IAQkBFWtleUxhc3RCYXNlNThQcm9wb3NhbAAEGm9wdGlvbmFsbGFzdEJhc2U1OFByb3Bvc2FsAwkBAiE9AgUSbGFzdEJhc2U1OFByb3Bvc2FsBQR1bml0BQNuaWwJAMwIAgkBDEludGVnZXJFbnRyeQIJARVrZXlMYXN0QmFzZTU4UHJvcG9zYWwACQBlAgUKcHJvcG9zYWxJZAABBQNuaWwJAJQKAgkAzggCCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQERa2V5TGFzdFByb3Bvc2FsSWQABQpwcm9wb3NhbElkCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEWa2V5UHJvcG9zYWxJZEJ5VG9waWNJZAEFB3RvcGljSWQFCnByb3Bvc2FsSWQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBGWtleVByb3Bvc2FsU3RhdHVzRGF0YUJ5SWQBBQpwcm9wb3NhbElkCQEKc3RhdHVzRGF0YQgHAAAAAAAABwUNdm90aW5nRW5kVGltZQcCBkFDVElWRQkAzAgCCQELU3RyaW5nRW50cnkCCQETa2V5UHJvcG9zYWxEYXRhQnlJZAEFCnByb3Bvc2FsSWQJAQxwcm9wb3NhbERhdGELBQxwcm9wb3NhbFR4SWQFBHR5cGUFBmF1dGhvcgkA3AQBCQCbAwEFCWZvcnVtTGluawkA3AQBCQCbAwEFBXRpdGxlBQxwcm9wb3NhbFRpbWUFD3ZvdGluZ1N0YXJ0VGltZQUNdm90aW5nRW5kVGltZQUFdHhJZHMFDXF1b3J1bUluR25zYnQFCm9wdGlvbnNTdHIJAMwIAgkBDEludGVnZXJFbnRyeQIJARdrZXlOdW1Qcm9wb3NhbHNCeUF1dGhvcgEFBmF1dGhvcgUUbnVtUHJvcG9zYWxzQnlBdXRob3IJAMwIAgkBDEludGVnZXJFbnRyeQIJARVrZXlTdGF0c1VuaXF1ZUF1dGhvcnMABQt1bmlxQXV0aG9ycwUDbmlsBRpvcHRpb25hbGxhc3RCYXNlNThQcm9wb3NhbAUMcHJvcG9zYWxUeElkCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAQ1jYWxjV2luT3B0aW9uBwpwcm9wb3NhbElkC29wdGlvbnNMaXN0DmlzUHJldk9wdGlvbmFsCW9sZENob2ljZRBvcHRpb25hbFRvdGFsT2xkCW5ld0Nob2ljZRNuZXdUb3RhbEJ5TmV3Q2hvaWNlCgEIZmluZEJlc3QCA2FjYwRlbGVtBANpZHgJAQV2YWx1ZQEJAM8IAgULb3B0aW9uc0xpc3QFBGVsZW0EA3ZhbAMFDmlzUHJldk9wdGlvbmFsAwkAAAIFA2lkeAUJbmV3Q2hvaWNlBRNuZXdUb3RhbEJ5TmV3Q2hvaWNlCQEMZ2V0SW50T3JFbHNlAgkBHWtleVByb3Bvc2FsVm90ZXNCeUlkQW5kT3B0aW9uAgUKcHJvcG9zYWxJZAUDaWR4AAADCQAAAgUDaWR4CQEFdmFsdWUBBQlvbGRDaG9pY2UFEG9wdGlvbmFsVG90YWxPbGQDCQAAAgUDaWR4BQluZXdDaG9pY2UFE25ld1RvdGFsQnlOZXdDaG9pY2UJAQxnZXRJbnRPckVsc2UCCQEda2V5UHJvcG9zYWxWb3Rlc0J5SWRBbmRPcHRpb24CBQpwcm9wb3NhbElkBQNpZHgAAAMJAGYCCAUDYWNjAl8yBQN2YWwFA2FjYwkAlAoCBQNpZHgFA3ZhbAoAAiRsBQtvcHRpb25zTGlzdAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAJAJQKAgAAAAAKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBCGZpbmRCZXN0AgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKARB1cGRhdGVTdGF0dXNEYXRhBAdvbGREYXRhB2lzVmFsaWQJbmV3V2luT3B0DW5ld1RvdGFsVm90ZXMJALkJAgkAzAgCAhAlYiVkJWQlZCViJWQlYiVzCQDMCAIJAKUDAQUHaXNWYWxpZAkAzAgCCQCkAwEIBQluZXdXaW5PcHQCXzEJAMwIAgkApAMBCAUJbmV3V2luT3B0Al8yCQDMCAIJAKQDAQUNbmV3VG90YWxWb3RlcwkAzAgCCQCRAwIFB29sZERhdGEFFWdvdlN0YXR1c0lkeFNjQXBwbGllZAkAzAgCCQCRAwIFB29sZERhdGEFEmdvdlN0YXR1c0lkeFNjVGltZQkAzAgCCQCRAwIFB29sZERhdGEFFmdvdlN0YXR1c0lkeElzQ2FuY2VsZWQJAMwIAgkAkQMCBQdvbGREYXRhBRZnb3ZTdGF0dXNJZHhJbXBsU3RhdHVzBQNuaWwFA1NFUAERc3RhdHVzQXBwbHlTY3JpcHQBB29sZERhdGEJALkJAgkAzAgCAhAlYiVkJWQlZCViJWQlYiVzCQDMCAIJAJEDAgUHb2xkRGF0YQUTZ292U3RhdHVzSWR4SXNWYWxpZAkAzAgCCQCRAwIFB29sZERhdGEFEmdvdlN0YXR1c0lkeFdpbk9wdAkAzAgCCQCRAwIFB29sZERhdGEFFGdvdlN0YXR1c0lkeFdpblZvdGVzCQDMCAIJAJEDAgUHb2xkRGF0YQUWZ292U3RhdHVzSWR4VG90YWxWb3RlcwkAzAgCAgR0cnVlCQDMCAIJAJEDAgUHb2xkRGF0YQUSZ292U3RhdHVzSWR4U2NUaW1lCQDMCAIJAJEDAgUHb2xkRGF0YQUWZ292U3RhdHVzSWR4SXNDYW5jZWxlZAkAzAgCCQCRAwIFB29sZERhdGEFFmdvdlN0YXR1c0lkeEltcGxTdGF0dXMFA25pbAUDU0VQARBFeGVjdXRpb25IaXN0b3J5BA11cGRhdGVWZXJzaW9uBXRpdGxlA3VybApwcm9wb3NhbElkBApnbnNidFRvdGFsCQCRAwIJARFnZXRFZmZlY3RpdmVHbnNidAECAAULSWR4RWZmVG90YWwEB3R1cm5vdXQAoMIeCQELU3RyaW5nRW50cnkCCQEPa2V5QXBwbHlIaXN0b3J5AQgFCWxhc3RCbG9jawl0aW1lc3RhbXAJALkJAgkAzAgCAgwlZCVkJWQlcyVzJWQJAMwIAgkApAMBBQ11cGRhdGVWZXJzaW9uCQDMCAIJAKQDAQUKZ25zYnRUb3RhbAkAzAgCCQCkAwEFB3R1cm5vdXQJAMwIAgUFdGl0bGUJAMwIAgUDdXJsCQDMCAIJAKQDAQUKcHJvcG9zYWxJZAUDbmlsBQNTRVAIAWkBDWNvbnN0cnVjdG9yVjEFC2NvbnRyb2xBZGRyDmdOc2J0UmVxVG9Jbml0DndhdmVzUmVxVG9Jbml0EXF1b3J1bVJlcVBlcmNJZGVhE3F1b3J1bVJlcVBlcmNVcGRhdGUDCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAAIBAhFQZXJtaXNzaW9uIGRlbmllZAkAzAgCCQELU3RyaW5nRW50cnkCCQERa2V5Q29udHJvbEFkZHJlc3MABQtjb250cm9sQWRkcgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBEGtleUduc2J0UmVxdWlyZWQABQ5nTnNidFJlcVRvSW5pdAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBEmtleVBheW1lbnRSZXF1aXJlZAAFDndhdmVzUmVxVG9Jbml0CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEYa2V5UXVvcnVtUmVxdWlyZWRQZXJjZW50AQIESURFQQURcXVvcnVtUmVxUGVyY0lkZWEJAMwIAgkBDEludGVnZXJFbnRyeQIJARhrZXlRdW9ydW1SZXF1aXJlZFBlcmNlbnQBAgZVUERBVEUFE3F1b3J1bVJlcVBlcmNVcGRhdGUFA25pbAFpAQhjYXN0Vm90ZQIKcHJvcG9zYWxJZAZjaG9pY2UEDnVzZXJBZGRyZXNzU3RyCQClCAEIBQFpBmNhbGxlcgQLZHluYW1pY0RhdGEJALUJAgkBD2dldFN0cmluZ09yRmFpbAIFBHRoaXMJARlrZXlQcm9wb3NhbFN0YXR1c0RhdGFCeUlkAQUKcHJvcG9zYWxJZAUDU0VQAwkAAAIJAJEDAgULZHluYW1pY0RhdGEFFmdvdlN0YXR1c0lkeElzQ2FuY2VsZWQCBHRydWUJAAIBAhpWb3RpbmcgaXMgY2FuY2VsZWQgYnkgdGVhbQQIcHJvcERhdGEJALUJAgkBD2dldFN0cmluZ09yRmFpbAIFBHRoaXMJARNrZXlQcm9wb3NhbERhdGFCeUlkAQUKcHJvcG9zYWxJZAUDU0VQBAVzdGFydAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCHByb3BEYXRhBQtnb3ZJZHhTdGFydAQDZW5kCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUIcHJvcERhdGEFCWdvdklkeEVuZAQDbm93CAUJbGFzdEJsb2NrCXRpbWVzdGFtcAMJAGYCBQVzdGFydAUDbm93CQACAQIWVm90aW5nIG5vdCBzdGFydGVkIHlldAMJAGcCBQNub3cFA2VuZAkAAgECF1ZvdGluZyBhbHJlYWR5IGZpbmlzaGVkBBBhdmFpbGFibGVPcHRpb25zCQC1CQIJAJEDAgUIcHJvcERhdGEFDWdvdklkeE9wdGlvbnMFB0xJU1RTRVAECm51bU9wdGlvbnMJAJADAQUQYXZhaWxhYmxlT3B0aW9ucwMJAGcCAAEFCm51bU9wdGlvbnMJAAIBAhdUb28gZmV3IGNob2ljZXMgdG8gdm90ZQMJAGcCBQZjaG9pY2UFCm51bU9wdGlvbnMJAAIBCQCsAgICG1Vua25vd24gY2hvaWNlISBNdXN0IGJlIDAuLgkApAMBCQBlAgUKbnVtT3B0aW9ucwABBANlZmYJARFnZXRFZmZlY3RpdmVHbnNidAEFDnVzZXJBZGRyZXNzU3RyBAhnbnNidEFtdAkAkQMCBQNlZmYFCklkeEVmZlVzZXIDCQBnAgAABQhnbnNidEFtdAkAAgECEG5vIGduc2J0IHRvIHZvdGUECmduc2J0VG90YWwJAJEDAgUDZWZmBQtJZHhFZmZUb3RhbAQJb2xkQ2hvaWNlCQCfCAEJARxrZXlQcm9wb3NhbENob2ljZUJ5SWRBbmRVc2VyAgUKcHJvcG9zYWxJZAUOdXNlckFkZHJlc3NTdHIEDG9sZFVzZXJWb3RlcwMJAQEhAQkBCWlzRGVmaW5lZAEFCW9sZENob2ljZQAACQEMZ2V0SW50T3JFbHNlAgkBG2tleVByb3Bvc2FsVm90ZXNCeUlkQW5kVXNlcgIFCnByb3Bvc2FsSWQFDnVzZXJBZGRyZXNzU3RyAAAEE29sZFRvdGFsQnlPbGRDaG9pY2UDCQEJaXNEZWZpbmVkAQUJb2xkQ2hvaWNlCQEMZ2V0SW50T3JFbHNlAgkBHWtleVByb3Bvc2FsVm90ZXNCeUlkQW5kT3B0aW9uAgUKcHJvcG9zYWxJZAkBBXZhbHVlAQUJb2xkQ2hvaWNlAAAAAAQTb2xkVG90YWxCeU5ld0Nob2ljZQkBDGdldEludE9yRWxzZQIJAR1rZXlQcm9wb3NhbFZvdGVzQnlJZEFuZE9wdGlvbgIFCnByb3Bvc2FsSWQFBmNob2ljZQAABAhvbGRUb3RhbAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFC2R5bmFtaWNEYXRhBRZnb3ZTdGF0dXNJZHhUb3RhbFZvdGVzBBNuZXdUb3RhbEJ5T2xkQ2hvaWNlAwkBASEBCQEJaXNEZWZpbmVkAQUJb2xkQ2hvaWNlAAAJAGQCCQBlAgUTb2xkVG90YWxCeU9sZENob2ljZQUMb2xkVXNlclZvdGVzAwkAAAIJAQV2YWx1ZQEFCW9sZENob2ljZQUGY2hvaWNlBQhnbnNidEFtdAAABBNuZXdUb3RhbEJ5TmV3Q2hvaWNlAwMJAQlpc0RlZmluZWQBBQlvbGRDaG9pY2UJAAACCQEFdmFsdWUBBQlvbGRDaG9pY2UFBmNob2ljZQcFE25ld1RvdGFsQnlPbGRDaG9pY2UJAGQCBRNvbGRUb3RhbEJ5TmV3Q2hvaWNlBQhnbnNidEFtdAQIbmV3VG90YWwJAGQCCQBlAgUIb2xkVG90YWwFDG9sZFVzZXJWb3RlcwUIZ25zYnRBbXQED2lzUXVvcnVtUmVhY2hlZAkAZwIFCG5ld1RvdGFsCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUIcHJvcERhdGEFDGdvdklkeFF1b3J1bQQVbnVtVm90ZXJzQnlQcm9wb3NhbElkCQEMZ2V0SW50T3JFbHNlAgkBHmtleU51bVVuaXF1ZVZvdGVyc0J5UHJvcG9zYWxJZAEFCnByb3Bvc2FsSWQAAAQUb2xkQXZlclVuaXF1ZVZvdGVyczYJAQxnZXRJbnRPckVsc2UCCQEYa2V5U3RhdHNBdmVyVW5pcXVlVm90ZXJzAAAABAxudW1Qcm9wb3NhbHMJAGQCCQBlAgkBEUBleHRyTmF0aXZlKDEwNTUpAQkBEWtleUxhc3RQcm9wb3NhbElkAAkBC3ZhbHVlT3JFbHNlAgkAnwgBCQESa2V5Rmlyc3RQcm9wb3NhbElkAAUUREVGQVVMVEZJUlNUUFJPUE9TQUwAAQQKdW5pcXVlRGlmZgMJAAACBQxvbGRVc2VyVm90ZXMAAAABAAAEFG5ld0F2ZXJVbmlxdWVWb3RlcnM2CQBkAgUUb2xkQXZlclVuaXF1ZVZvdGVyczYJAGsDBQp1bmlxdWVEaWZmBQVNVUxUNgUMbnVtUHJvcG9zYWxzBAxvbGRBdmVyR25zYnQJAQxnZXRJbnRPckVsc2UCCQEWa2V5U3RhdHNBdmVyR25zYnRWb3RlZAAAAAQMbmV3QXZlckduc2J0CQBkAgUMb2xkQXZlckduc2J0CQBpAgkAZQIFCGduc2J0QW10BQxvbGRVc2VyVm90ZXMFDG51bVByb3Bvc2FscwQOaXNQcmV2T3B0aW9uYWwDCQEBIQEJAQlpc0RlZmluZWQBBQlvbGRDaG9pY2UGCQAAAgkBBXZhbHVlAQUJb2xkQ2hvaWNlBQZjaG9pY2UEEG9wdGlvbmFsVG90YWxPbGQDBQ5pc1ByZXZPcHRpb25hbAUDbmlsCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEda2V5UHJvcG9zYWxWb3Rlc0J5SWRBbmRPcHRpb24CBQpwcm9wb3NhbElkCQEFdmFsdWUBBQlvbGRDaG9pY2UFE25ld1RvdGFsQnlPbGRDaG9pY2UFA25pbAQGd2luT3B0CQENY2FsY1dpbk9wdGlvbgcFCnByb3Bvc2FsSWQFEGF2YWlsYWJsZU9wdGlvbnMFDmlzUHJldk9wdGlvbmFsBQlvbGRDaG9pY2UFE25ld1RvdGFsQnlPbGRDaG9pY2UFBmNob2ljZQUTbmV3VG90YWxCeU5ld0Nob2ljZQQLcmVsZWFzZVRpbWUJAJYDAQkAzAgCBQNlbmQJAMwIAgkBDGdldEludE9yRWxzZQIJARdrZXlVc2VyR25zYnRSZWxlYXNlVGltZQEFDnVzZXJBZGRyZXNzU3RyAAAFA25pbAkAlAoCCQDOCAIJAMwIAgkBDEludGVnZXJFbnRyeQIJARxrZXlQcm9wb3NhbENob2ljZUJ5SWRBbmRVc2VyAgUKcHJvcG9zYWxJZAUOdXNlckFkZHJlc3NTdHIFBmNob2ljZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBG2tleVByb3Bvc2FsVm90ZXNCeUlkQW5kVXNlcgIFCnByb3Bvc2FsSWQFDnVzZXJBZGRyZXNzU3RyBQhnbnNidEFtdAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBHWtleVByb3Bvc2FsVm90ZXNCeUlkQW5kT3B0aW9uAgUKcHJvcG9zYWxJZAUGY2hvaWNlBRNuZXdUb3RhbEJ5TmV3Q2hvaWNlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEea2V5TnVtVW5pcXVlVm90ZXJzQnlQcm9wb3NhbElkAQUKcHJvcG9zYWxJZAkAZAIFFW51bVZvdGVyc0J5UHJvcG9zYWxJZAUKdW5pcXVlRGlmZgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBF2tleVVzZXJHbnNidFJlbGVhc2VUaW1lAQUOdXNlckFkZHJlc3NTdHIFC3JlbGVhc2VUaW1lCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEYa2V5U3RhdHNBdmVyVW5pcXVlVm90ZXJzAAUUbmV3QXZlclVuaXF1ZVZvdGVyczYJAMwIAgkBDEludGVnZXJFbnRyeQIJARZrZXlTdGF0c0F2ZXJHbnNidFZvdGVkAAUMbmV3QXZlckduc2J0CQDMCAIJAQtTdHJpbmdFbnRyeQIJARlrZXlQcm9wb3NhbFN0YXR1c0RhdGFCeUlkAQUKcHJvcG9zYWxJZAkBEHVwZGF0ZVN0YXR1c0RhdGEEBQtkeW5hbWljRGF0YQUPaXNRdW9ydW1SZWFjaGVkBQZ3aW5PcHQFCG5ld1RvdGFsBQNuaWwFEG9wdGlvbmFsVG90YWxPbGQFBHVuaXQBaQESaW5pdGlhdGVJZGVhVm90aW5nBQlmb3J1bUxpbmsFdGl0bGUPdm90aW5nU3RhcnRUaW1lDXZvdGluZ0VuZFRpbWULb3B0aW9uc0xpc3QDCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAEJAAIBAhxFeGFjdGx5IG9uZSBwYXltZW50IHJlcXVpcmVkAwkBAiE9AgkAkAMBBQtvcHRpb25zTGlzdAACCQACAQIrRXhhY3RseSAyIG9wdGlvbiBbJ05PJywgJ1lFUyddIGFyZSBleHBlY3RlZAMJAQIhPQIJAJEDAgULb3B0aW9uc0xpc3QAAAICTk8JAAIBAh1PcHRpb24gTk8gc2hvdWxkIGJlIHRoZSBmaXJzdAMJAQIhPQIJAJEDAgULb3B0aW9uc0xpc3QAAQIDWUVTCQACAQIfT3B0aW9uIFlFUyBzaG91bGQgYmUgdGhlIHNlY29uZAkBDmluaXRpYXRlVm90aW5nCwkBBXZhbHVlAQkAkQMCCAUBaQhwYXltZW50cwAACQDYBAEIBQFpDXRyYW5zYWN0aW9uSWQCBElERUEJAKUIAQgFAWkGY2FsbGVyBQlmb3J1bUxpbmsFBXRpdGxlBQ92b3RpbmdTdGFydFRpbWUFDXZvdGluZ0VuZFRpbWUCB1BFTkRJTkcFA25pbAULb3B0aW9uc0xpc3QBaQEUaW5pdGlhdGVVcGRhdGVWb3RpbmcFCWZvcnVtTGluawV0aXRsZQ92b3RpbmdTdGFydFRpbWUNdm90aW5nRW5kVGltZQZ0eExpc3QDCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAEJAAIBAhxFeGFjdGx5IG9uZSBwYXltZW50IHJlcXVpcmVkAwkAZgIAAQkAkAMBBQZ0eExpc3QJAAIBAhpUcmFuc2FjdGlvbnMgbGlzdCBpcyBlbXB0eQMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECDm5vdCBhdXRob3JpemVkCQEOaW5pdGlhdGVWb3RpbmcLCQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAAJANgEAQgFAWkNdHJhbnNhY3Rpb25JZAIGVVBEQVRFCQClCAEIBQFpBmNhbGxlcgUJZm9ydW1MaW5rBQV0aXRsZQUPdm90aW5nU3RhcnRUaW1lBQ12b3RpbmdFbmRUaW1lAgdQRU5ESU5HBQZ0eExpc3QJAMwIAgICTk8JAMwIAgIDWUVTBQNuaWwBaQEMY2FuY2VsVm90aW5nAQpwcm9wb3NhbElkAwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIObm90IGF1dGhvcml6ZWQEC2N1cnJlbnREYXRhCQEPZ2V0U3RyaW5nT3JGYWlsAgUEdGhpcwkBGWtleVByb3Bvc2FsU3RhdHVzRGF0YUJ5SWQBBQpwcm9wb3NhbElkBAt1cGRhdGVkRGF0YQkArAICCQCsAgIJAK8CAgULY3VycmVudERhdGEJAQV2YWx1ZQEJALcJAgULY3VycmVudERhdGEFA1NFUAUDU0VQAgR0cnVlCQCUCgIJAMwIAgkBC1N0cmluZ0VudHJ5AgkBGWtleVByb3Bvc2FsU3RhdHVzRGF0YUJ5SWQBBQpwcm9wb3NhbElkBQt1cGRhdGVkRGF0YQUDbmlsBQR1bml0AWkBC2FwcGx5VXBkYXRlAQpwcm9wb3NhbElkBAhwcm9wRGF0YQkAtQkCCQEPZ2V0U3RyaW5nT3JGYWlsAgUEdGhpcwkBE2tleVByb3Bvc2FsRGF0YUJ5SWQBBQpwcm9wb3NhbElkBQNTRVAEA2VuZAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCHByb3BEYXRhBQlnb3ZJZHhFbmQEA25vdwgFCWxhc3RCbG9jawl0aW1lc3RhbXADCQBmAgUDZW5kBQNub3cJAAIBAhpWb3RpbmcgaXMgbm90IGZpbmlzaGVkIHlldAMJAQIhPQICBlVQREFURQkAkQMCBQhwcm9wRGF0YQUKZ292SWR4VHlwZQkAAgECH09ubHkgVVBEQVRFIHR5cGUgY2FuIGJlIGFwcGxpZWQEC2R5bmFtaWNEYXRhCQC1CQIJAQ9nZXRTdHJpbmdPckZhaWwCBQR0aGlzCQEZa2V5UHJvcG9zYWxTdGF0dXNEYXRhQnlJZAEFCnByb3Bvc2FsSWQFA1NFUAMJAAACCQCRAwIFC2R5bmFtaWNEYXRhBRZnb3ZTdGF0dXNJZHhJc0NhbmNlbGVkAgR0cnVlCQACAQISVm90aW5nIGlzIGNhbmNlbGVkAwkBAiE9AgkAkQMCBQtkeW5hbWljRGF0YQUTZ292U3RhdHVzSWR4SXNWYWxpZAIEdHJ1ZQkAAgECFVZvdGluZyBzdGF0dXMgaW52YWxpZAMJAQIhPQIJAJEDAgULZHluYW1pY0RhdGEFEmdvdlN0YXR1c0lkeFdpbk9wdAIBMQkAAgECIVdpbm5lciBpcyAnTk8nIC0gbm90aGluZyB0byBhcHBseQMJAAACCQCRAwIFC2R5bmFtaWNEYXRhBRVnb3ZTdGF0dXNJZHhTY0FwcGxpZWQCBHRydWUJAAIBAhtTY3JpcHRzIGFyZSBhbHJlYWR5IGFwcGxpZWQECnNjcmlwdFRpbWUJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQtkeW5hbWljRGF0YQUSZ292U3RhdHVzSWR4U2NUaW1lAwkAZgIJAGUCBQNub3cFClBBU1RNQVJHSU4FCnNjcmlwdFRpbWUJAAIBCQCsAgIJAKwCAgISU2NyaXB0cyB0aW1lc3RhbXA9CQCkAwEFCnNjcmlwdFRpbWUCKiBpcyB0b28gZmFyIGluIHRoZSBwYXN0LCBtYXggMiBocnMgYWxsb3dlZAMJAGYCBQpzY3JpcHRUaW1lCQBkAgUDbm93BQxGVVRVUkVNQVJHSU4JAAIBCQCsAgIJAKwCAgISU2NyaXB0cyB0aW1lc3RhbXA9CQCkAwEFCnNjcmlwdFRpbWUCLiBpcyB0b28gZmFyIGluIHRoZSBmdXR1cmUsIG1heCAxLjUgaHJzIGFsbG93ZWQEDGluUHJvZ3Jlc3NJZAkBDGdldEludE9yRWxzZQIJARJrZXlBcHBseUluUHJvZ3Jlc3MAAP///////////wEDCQECIT0CBQxpblByb2dyZXNzSWQA////////////AQkAAgEJAKwCAgkArAICAgtwcm9wb3NhbElkPQkApAMBBQxpblByb2dyZXNzSWQCKyBpcyBhbHJlYWR5IGJlaW5nIGFwcGxpZWQuIEZpbmlzaCBpdCBmaXJzdCEECHNodXRkb3duCQD8BwQFD2NvbnRyb2xDb250cmFjdAIVY2FsbEVtZXJnZW5jeVNodXRkb3duCQDMCAICGkFwcGx5aW5nIEdvdmVybmFuY2UgVVBEQVRFBQNuaWwFA25pbAMJAAACBQhzaHV0ZG93bgUIc2h1dGRvd24JAJQKAgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBEmtleUFwcGx5SW5Qcm9ncmVzcwAFCnByb3Bvc2FsSWQFA25pbAUEdW5pdAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQtmaW5pc2hBcHBseQAECnByb3Bvc2FsSWQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnwgBCQESa2V5QXBwbHlJblByb2dyZXNzAAInTm8gYXBwbHkgaW4gcHJvZ3Jlc3MsIG5vdGhpbmcgdG8gZmluaXNoBAhwcm9wRGF0YQkAtQkCCQEPZ2V0U3RyaW5nT3JGYWlsAgUEdGhpcwkBE2tleVByb3Bvc2FsRGF0YUJ5SWQBBQpwcm9wb3NhbElkBQNTRVAEBnR4TGlzdAkAtQkCCQCRAwIFCHByb3BEYXRhBQtnb3ZJZHhUeElkcwUHTElTVFNFUAQLZHluYW1pY0RhdGEJALUJAgkBD2dldFN0cmluZ09yRmFpbAIFBHRoaXMJARlrZXlQcm9wb3NhbFN0YXR1c0RhdGFCeUlkAQUKcHJvcG9zYWxJZAUDU0VQAwkAAAIJAJEDAgULZHluYW1pY0RhdGEFFWdvdlN0YXR1c0lkeFNjQXBwbGllZAIEdHJ1ZQkAAgECG1NjcmlwdHMgYXJlIGFscmVhZHkgYXBwbGllZAoBB2NoZWNrZXICA2FjYwJ0eAMJAQEhAQkBCWlzRGVmaW5lZAEJAOkHAQkA2QQBBQJ0eAkAAgEJAKwCAgISTk9UIGFwcGxpZWQgdHhJZDogBQJ0eAUEdW5pdAQHaWdub3JlZAoAAiRsBQZ0eExpc3QKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQR1bml0CgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQdjaGVja2VyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAyMAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQEB3ZlcnNpb24JAGQCCQEMZ2V0SW50T3JFbHNlAgkBFGtleUxhc3RVcGRhdGVWZXJzaW9uAAAAAAEJAJQKAgkAzAgCCQELRGVsZXRlRW50cnkBCQESa2V5QXBwbHlJblByb2dyZXNzAAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBFGtleUxhc3RVcGRhdGVWZXJzaW9uAAUHdmVyc2lvbgkAzAgCCQELU3RyaW5nRW50cnkCCQEZa2V5UHJvcG9zYWxTdGF0dXNEYXRhQnlJZAEFCnByb3Bvc2FsSWQJARFzdGF0dXNBcHBseVNjcmlwdAEFC2R5bmFtaWNEYXRhCQDMCAIJARBFeGVjdXRpb25IaXN0b3J5BAUHdmVyc2lvbgkAkQMCBQhwcm9wRGF0YQULZ292SWR4VGl0bGUJAJEDAgUIcHJvcERhdGEFCWdvdklkeFVybAUKcHJvcG9zYWxJZAUDbmlsBQdpZ25vcmVkAWkBEGNoYW5nZUltcGxTdGF0dXMCCnByb3Bvc2FsSWQJbmV3U3RhdHVzAwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIObm90IGF1dGhvcml6ZWQDAwkBAiE9AgUJbmV3U3RhdHVzAgZBQ1RJVkUJAQIhPQIFCW5ld1N0YXR1cwIIT1VUREFURUQHCQACAQIdVW5rbm93biBpbXBsZW1lbnRhdGlvbiBzdGF0dXMEC2R5bmFtaWNEYXRhCQC1CQIJAQ9nZXRTdHJpbmdPckZhaWwCBQR0aGlzCQEZa2V5UHJvcG9zYWxTdGF0dXNEYXRhQnlJZAEFCnByb3Bvc2FsSWQFA1NFUAQHdXBkYXRlZAkAuQkCCQDMCAICECViJWQlZCVkJWIlZCViJXMJAMwIAgkAkQMCBQtkeW5hbWljRGF0YQUTZ292U3RhdHVzSWR4SXNWYWxpZAkAzAgCCQCRAwIFC2R5bmFtaWNEYXRhBRJnb3ZTdGF0dXNJZHhXaW5PcHQJAMwIAgkAkQMCBQtkeW5hbWljRGF0YQUUZ292U3RhdHVzSWR4V2luVm90ZXMJAMwIAgkAkQMCBQtkeW5hbWljRGF0YQUWZ292U3RhdHVzSWR4VG90YWxWb3RlcwkAzAgCCQCRAwIFC2R5bmFtaWNEYXRhBRVnb3ZTdGF0dXNJZHhTY0FwcGxpZWQJAMwIAgkAkQMCBQtkeW5hbWljRGF0YQUSZ292U3RhdHVzSWR4U2NUaW1lCQDMCAIJAJEDAgULZHluYW1pY0RhdGEFFmdvdlN0YXR1c0lkeElzQ2FuY2VsZWQJAMwIAgUJbmV3U3RhdHVzBQNuaWwFA1NFUAkAlAoCCQDMCAIJAQtTdHJpbmdFbnRyeQIJARlrZXlQcm9wb3NhbFN0YXR1c0RhdGFCeUlkAQUKcHJvcG9zYWxJZAUHdXBkYXRlZAUDbmlsBQR1bml0AArXuE8=", "height": 2564593, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 2x1A7Fhbat8D1mqPEkMks2CJitbPc9tTewpwXW2g1hgd Next: 5HhyJBJbgECjtjZWksCmRUaJKdPVFDAwJnEiL4qso1Ps Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let revisionNum = ""
55
66 let SEP = "__"
77
88 let LISTSEP = ":"
99
1010 let DEFAULTQUORUM = 500000
1111
1212 let URLPATTERN = "https://forum.neutrino.at/"
1313
1414 let MAXTITLE = 250
1515
1616 let MAXURL = 250
1717
1818 let MAXVOTINGTIME = 1209600000
1919
2020 let MULT6 = 1000000
2121
2222 let DEFAULTPAYMENT = 1000000000
2323
2424 let DEFAULTCREATIONGNSBT = 1000000000
2525
2626 let PASTMARGIN = 7200000
2727
2828 let FUTUREMARGIN = 5400000
2929
3030 let DEFAULTFIRSTPROPOSAL = 111
3131
3232 let govIdxProposalTxId = 1
3333
3434 let govIdxType = 2
3535
3636 let govIdxAuthor = 3
3737
3838 let govIdxUrl = 4
3939
4040 let govIdxTitle = 5
4141
4242 let govIdxCreationTime = 6
4343
4444 let govIdxStart = 7
4545
4646 let govIdxEnd = 8
4747
4848 let govIdxTxIds = 9
4949
5050 let govIdxQuorum = 10
5151
5252 let govIdxOptions = 11
5353
5454 let govStatusIdxIsValid = 1
5555
5656 let govStatusIdxWinOpt = 2
5757
5858 let govStatusIdxWinVotes = 3
5959
6060 let govStatusIdxTotalVotes = 4
6161
6262 let govStatusIdxScApplied = 5
6363
6464 let govStatusIdxScTime = 6
6565
6666 let govStatusIdxIsCanceled = 7
6767
6868 let govStatusIdxImplStatus = 8
6969
7070 func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], ""))
7171
7272
7373 func getIntOrElse (key,defaultVal) = valueOrElse(getInteger(this, key), defaultVal)
7474
7575
7676 let IdxControlCfgNeutrinoDapp = 1
7777
7878 let IdxControlCfgAuctionDapp = 2
7979
8080 let IdxControlCfgRpdDapp = 3
8181
8282 let IdxControlCfgMathDapp = 4
8383
8484 let IdxControlCfgLiquidationDapp = 5
8585
8686 let IdxControlCfgRestDapp = 6
8787
8888 let IdxControlCfgNodeRegistryDapp = 7
8989
9090 let IdxControlCfgNsbtStakingDapp = 8
9191
9292 let IdxControlCfgMediatorDapp = 9
9393
9494 let IdxControlCfgSurfStakingDapp = 10
9595
9696 let IdxControlCfgGnsbtControllerDapp = 11
9797
9898 let IdxControlCfgRestV2Dapp = 12
9999
100100 let IdxControlCfgGovernanceDapp = 13
101101
102102 func keyControlAddress () = "%s%s__config__controlAddress"
103103
104104
105105 func keyControlCfg () = "%s__controlConfig"
106106
107107
108108 func readControlCfgOrFail (control) = split_4C(getStringOrFail(control, keyControlCfg()), SEP)
109109
110110
111111 func getContractAddressOrFail (controlCfg,idx) = valueOrErrorMessage(addressFromString(controlCfg[idx]), ("Control cfg doesn't contain address at index " + toString(idx)))
112112
113113
114114 let controlContract = addressFromStringValue(valueOrElse(getString(this, keyControlAddress()), "3N4NS7d4Jo9a6F14LiFUKKYVdUkkf2eP4Zx"))
115115
116116 let controlCfg = readControlCfgOrFail(controlContract)
117117
118118 let neutrinoContract = getContractAddressOrFail(controlCfg, IdxControlCfgNeutrinoDapp)
119119
120120 let gnsbtControllerContract = getContractAddressOrFail(controlCfg, IdxControlCfgGnsbtControllerDapp)
121121
122122 let surfStakingContract = getContractAddressOrFail(controlCfg, IdxControlCfgSurfStakingDapp)
123123
124124 func keyLastBase58Proposal () = "%s__lastBase58Proposal"
125125
126126
127127 func keyQuorumRequiredPercent (type) = ("%s%s__quorumRequired__" + type)
128128
129129
130130 func keyPaymentRequired () = "%s__paymentRequired"
131131
132132
133133 func keyGnsbtRequired () = "%s__gNsbtRequired"
134134
135135
136136 func keyLastProposalId () = "%s__proposalId"
137137
138138
139139 func keyFirstProposalId () = "%s__firstProposalId"
140140
141141
142142 func keyLastUpdateVersion () = "%s__updateVersion"
143143
144144
145145 func keyProposalStatusDataById (proposalId) = ("%s%d__proposalStatusData__" + toString(proposalId))
146146
147147
148148 func keyProposalDataById (proposalId) = ("%s%d__proposalData__" + toString(proposalId))
149149
150150
151151 func keyProposalVotesByIdAndOption (proposalId,opt) = makeString(["%s%d%d", "votesByOpt", toString(proposalId), toString(opt)], SEP)
152152
153153
154154 func keyProposalVotesByIdAndUser (proposalId,userAddr) = makeString(["%s%d%s", "votesByUser", toString(proposalId), userAddr], SEP)
155155
156156
157157 func keyProposalChoiceByIdAndUser (proposalId,userAddr) = makeString(["%s%d%s", "optionByUser", toString(proposalId), userAddr], SEP)
158158
159159
160160 func keyApplyInProgress () = "%s__applyInProgress"
161161
162162
163163 func keyProposalIdByTopicId (topicId) = ("%s%d__proposalIdByTopicId__" + toString(topicId))
164164
165165
166166 func keyUserGnsbtReleaseTime (userAddr) = ("%s%s_userGnsbtReleaseTime__" + userAddr)
167167
168168
169169 func keyNumUniqueVotersByProposalId (proposalId) = ("%s%d__numVoters__" + toString(proposalId))
170170
171171
172172 func keyStatsAverUniqueVoters () = "%s%s%s__stats__avg__uniqueVoters"
173173
174174
175175 func keyStatsAverGnsbtVoted () = "%s%s%s__stats__avg__gnsbtVoted"
176176
177177
178178 func keyStatsUniqueAuthors () = "%s%s__stats__uniqueAuthors"
179179
180180
181181 func keyNumProposalsByAuthor (addressStr) = ("%s%s__numProposalsByAuthor__" + addressStr)
182182
183183
184184 func keyApplyHistory (timestamp) = ("%s%d__applyHistory__" + toString(timestamp))
185185
186186
187187 func asAnyList (v) = match v {
188188 case l: List[Any] =>
189189 l
190190 case _ =>
191191 throw("fail to cast into List[Any]")
192192 }
193193
194194
195195 func asInt (v) = match v {
196196 case i: Int =>
197197 i
198198 case _ =>
199199 throw("fail to cast into Int")
200200 }
201201
202202
203203 func statusData (isVotingValid,winOption,winOptionVotes,totalVotes,areScriptsApplied,scriptsTimestamp,canceledByTeam,implStatus) = makeString(["%b%d%d%d%b%d%b%s", toString(isVotingValid), toString(winOption), toString(winOptionVotes), toString(totalVotes), toString(areScriptsApplied), toString(scriptsTimestamp), toString(canceledByTeam), implStatus], SEP)
204204
205205
206206 func proposalData (proposalTxId,type,author,forumLink,title,proposalTime,votingStartTime,votingEndTime,txIds,quorumInGnsbt,options) = makeString(["%s%s%s%s%s%d%d%d%s%d%s", proposalTxId, type, author, forumLink, title, toString(proposalTime), toString(votingStartTime), toString(votingEndTime), txIds, toString(quorumInGnsbt), options], SEP)
207207
208208
209209 func checkTxList (txList) = if ((size(txList) > 20))
210210 then throw(("Too many transactions: " + toString(size(txList))))
211211 else {
212212 func combiner (acc,tx) = if ((size(fromBase58String(tx)) != 32))
213213 then throw(("Wrong txId: " + tx))
214214 else if ((acc == ""))
215215 then tx
216216 else ((acc + LISTSEP) + tx)
217217
218218 let $l = txList
219219 let $s = size($l)
220220 let $acc0 = ""
221221 func $f0_1 ($a,$i) = if (($i >= $s))
222222 then $a
223223 else combiner($a, $l[$i])
224224
225225 func $f0_2 ($a,$i) = if (($i >= $s))
226226 then $a
227227 else throw("List size exceeds 20")
228228
229229 $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)
230230 }
231231
232232
233233 let IdxEffTotal = 0
234234
235235 let IdxEffUser = 1
236236
237237 func getEffectiveGnsbt (userAddrStrOrEmpty) = {
238238 let upd = if (isDefined(addressFromString(userAddrStrOrEmpty)))
239239 then invoke(surfStakingContract, "updateVotingPower", [userAddrStrOrEmpty], nil)
240240 else unit
241241 if ((upd == upd))
242242 then {
243243 let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", [userAddrStrOrEmpty, 0, 0], nil))
244244 let nsbtData = asAnyList(gnsbtData[2])
245245 let userFromNsbt = asInt(nsbtData[2])
246246 let totalFromNsbt = asInt(nsbtData[3])
247247 let userMatureFromSurf = asInt(gnsbtData[9])
248248 let totalMatureFromSurf = asInt(gnsbtData[6])
249249 [(totalFromNsbt + totalMatureFromSurf), (userFromNsbt + userMatureFromSurf)]
250250 }
251251 else throw("Strict value is not equal to itself.")
252252 }
253253
254254
255255 func validateLink (url) = if ((value(indexOf(url, URLPATTERN)) != 0))
256256 then throw("Invalid url")
257257 else if ((size(url) > MAXURL))
258258 then throw("Url too long!")
259259 else {
260260 let topicId = valueOrErrorMessage(parseInt(drop(url, (value(lastIndexOf(url, "/")) + 1))), "Wrong topicId")
261261 let registeredId = getInteger(keyProposalIdByTopicId(topicId))
262262 if (isDefined(registeredId))
263263 then throw(("Voting with such forum link is already registered by id=" + toString(value(registeredId))))
264264 else topicId
265265 }
266266
267267
268268 func initiateVoting (payment,proposalTxId,type,author,forumLink,title,votingStartTime,votingEndTime,status,txList,optionsList) = if ((payment.assetId != unit))
269269 then throw("Allowed WAVES payment only!")
270270 else {
271271 let pmtReq = getIntOrElse(keyPaymentRequired(), DEFAULTPAYMENT)
272272 if ((pmtReq > payment.amount))
273273 then throw(("Payment attached should be at least " + toString(pmtReq)))
274274 else {
275275 let topicId = validateLink(forumLink)
276276 if ((title == ""))
277277 then throw("Title is empty")
278278 else if ((size(title) > MAXTITLE))
279279 then throw("Too long title")
280280 else {
281281 let proposalTime = lastBlock.timestamp
282282 if ((proposalTime > votingStartTime))
283283 then throw(((("votingStartTime=" + toString(votingStartTime)) + " < proposalTime=") + toString(proposalTime)))
284284 else if ((votingStartTime > votingEndTime))
285285 then throw(((("votingEndTime=" + toString(votingEndTime)) + " < votingStartTime=") + toString(votingStartTime)))
286286 else if (((votingEndTime - votingStartTime) > MAXVOTINGTIME))
287287 then throw(((("Voting period exceeds max: " + toString((votingEndTime - votingStartTime))) + " > ") + toString(MAXVOTINGTIME)))
288288 else {
289289 let txIds = if ((type == "IDEA"))
290290 then ""
291291 else checkTxList(txList)
292292 if ((1 >= size(optionsList)))
293293 then throw("Too few choices to vote")
294294 else {
295295 let eff = getEffectiveGnsbt(author)
296296 let gnsbtTotal = eff[IdxEffTotal]
297297 let gNsbtUser = eff[IdxEffUser]
298298 let gnsbtReq = getIntOrElse(keyGnsbtRequired(), DEFAULTCREATIONGNSBT)
299299 if ((gnsbtReq > gNsbtUser))
300300 then throw((("You need at least " + toString(gnsbtReq)) + " gNsbt to create voting"))
301301 else {
302302 let amountLeased = invoke(neutrinoContract, "acceptWaves", nil, [payment])
303303 if ((amountLeased == amountLeased))
304304 then {
305305 let quorum = getIntOrElse(keyQuorumRequiredPercent(type), DEFAULTQUORUM)
306306 let quorumInGnsbt = fraction(quorum, gnsbtTotal, MULT6)
307307 let proposalId = (getIntOrElse(keyLastProposalId(), 0) + 1)
308308 let numProposalsByAuthor = (getIntOrElse(keyNumProposalsByAuthor(author), 0) + 1)
309309 let uniqAuthors = (getIntOrElse(keyStatsUniqueAuthors(), 0) + (if ((numProposalsByAuthor == 1))
310310 then 1
311311 else 0))
312312 let optionsStr = makeString(optionsList, LISTSEP)
313313 let lastBase58Proposal = getInteger(keyLastBase58Proposal())
314314 let optionallastBase58Proposal = if ((lastBase58Proposal != unit))
315315 then nil
316316 else [IntegerEntry(keyLastBase58Proposal(), (proposalId - 1))]
317317 $Tuple2(([IntegerEntry(keyLastProposalId(), proposalId), IntegerEntry(keyProposalIdByTopicId(topicId), proposalId), StringEntry(keyProposalStatusDataById(proposalId), statusData(false, 0, 0, 0, false, votingEndTime, false, "ACTIVE")), StringEntry(keyProposalDataById(proposalId), proposalData(proposalTxId, type, author, toBase16String(toBytes(forumLink)), toBase16String(toBytes(title)), proposalTime, votingStartTime, votingEndTime, txIds, quorumInGnsbt, optionsStr)), IntegerEntry(keyNumProposalsByAuthor(author), numProposalsByAuthor), IntegerEntry(keyStatsUniqueAuthors(), uniqAuthors)] ++ optionallastBase58Proposal), proposalTxId)
318318 }
319319 else throw("Strict value is not equal to itself.")
320320 }
321321 }
322322 }
323323 }
324324 }
325325 }
326326
327327
328328 func calcWinOption (proposalId,optionsList,isPrevOptional,oldChoice,optionalTotalOld,newChoice,newTotalByNewChoice) = {
329329 func findBest (acc,elem) = {
330330 let idx = value(indexOf(optionsList, elem))
331331 let val = if (isPrevOptional)
332332 then if ((idx == newChoice))
333333 then newTotalByNewChoice
334334 else getIntOrElse(keyProposalVotesByIdAndOption(proposalId, idx), 0)
335335 else if ((idx == value(oldChoice)))
336336 then optionalTotalOld
337337 else if ((idx == newChoice))
338338 then newTotalByNewChoice
339339 else getIntOrElse(keyProposalVotesByIdAndOption(proposalId, idx), 0)
340340 if ((acc._2 > val))
341341 then acc
342342 else $Tuple2(idx, val)
343343 }
344344
345345 let $l = optionsList
346346 let $s = size($l)
347347 let $acc0 = $Tuple2(0, 0)
348348 func $f0_1 ($a,$i) = if (($i >= $s))
349349 then $a
350350 else findBest($a, $l[$i])
351351
352352 func $f0_2 ($a,$i) = if (($i >= $s))
353353 then $a
354354 else throw("List size exceeds 10")
355355
356356 $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)
357357 }
358358
359359
360360 func updateStatusData (oldData,isValid,newWinOpt,newTotalVotes) = makeString(["%b%d%d%d%b%d%b%s", toString(isValid), toString(newWinOpt._1), toString(newWinOpt._2), toString(newTotalVotes), oldData[govStatusIdxScApplied], oldData[govStatusIdxScTime], oldData[govStatusIdxIsCanceled], oldData[govStatusIdxImplStatus]], SEP)
361361
362362
363363 func statusApplyScript (oldData) = makeString(["%b%d%d%d%b%d%b%s", oldData[govStatusIdxIsValid], oldData[govStatusIdxWinOpt], oldData[govStatusIdxWinVotes], oldData[govStatusIdxTotalVotes], "true", oldData[govStatusIdxScTime], oldData[govStatusIdxIsCanceled], oldData[govStatusIdxImplStatus]], SEP)
364364
365365
366366 func ExecutionHistory (updateVersion,title,url,proposalId) = {
367367 let gnsbtTotal = getEffectiveGnsbt("")[IdxEffTotal]
368368 let turnout = 500000
369369 StringEntry(keyApplyHistory(lastBlock.timestamp), makeString(["%d%d%d%s%s%d", toString(updateVersion), toString(gnsbtTotal), toString(turnout), title, url, toString(proposalId)], SEP))
370370 }
371371
372372
373373 @Callable(i)
374374 func constructorV1 (controlAddr,gNsbtReqToInit,wavesReqToInit,quorumReqPercIdea,quorumReqPercUpdate) = if ((i.caller != this))
375375 then throw("Permission denied")
376376 else [StringEntry(keyControlAddress(), controlAddr), IntegerEntry(keyGnsbtRequired(), gNsbtReqToInit), IntegerEntry(keyPaymentRequired(), wavesReqToInit), IntegerEntry(keyQuorumRequiredPercent("IDEA"), quorumReqPercIdea), IntegerEntry(keyQuorumRequiredPercent("UPDATE"), quorumReqPercUpdate)]
377377
378378
379379
380380 @Callable(i)
381381 func castVote (proposalId,choice) = {
382382 let userAddressStr = toString(i.caller)
383383 let dynamicData = split(getStringOrFail(this, keyProposalStatusDataById(proposalId)), SEP)
384384 if ((dynamicData[govStatusIdxIsCanceled] == "true"))
385385 then throw("Voting is canceled by team")
386386 else {
387387 let propData = split(getStringOrFail(this, keyProposalDataById(proposalId)), SEP)
388388 let start = parseIntValue(propData[govIdxStart])
389389 let end = parseIntValue(propData[govIdxEnd])
390390 let now = lastBlock.timestamp
391391 if ((start > now))
392392 then throw("Voting not started yet")
393393 else if ((now >= end))
394394 then throw("Voting already finished")
395395 else {
396396 let availableOptions = split(propData[govIdxOptions], LISTSEP)
397397 let numOptions = size(availableOptions)
398398 if ((1 >= numOptions))
399399 then throw("Too few choices to vote")
400400 else if ((choice >= numOptions))
401401 then throw(("Unknown choice! Must be 0.." + toString((numOptions - 1))))
402402 else {
403403 let eff = getEffectiveGnsbt(userAddressStr)
404404 let gnsbtAmt = eff[IdxEffUser]
405405 if ((0 >= gnsbtAmt))
406406 then throw("no gnsbt to vote")
407407 else {
408408 let gnsbtTotal = eff[IdxEffTotal]
409409 let oldChoice = getInteger(keyProposalChoiceByIdAndUser(proposalId, userAddressStr))
410410 let oldUserVotes = if (!(isDefined(oldChoice)))
411411 then 0
412412 else getIntOrElse(keyProposalVotesByIdAndUser(proposalId, userAddressStr), 0)
413413 let oldTotalByOldChoice = if (isDefined(oldChoice))
414414 then getIntOrElse(keyProposalVotesByIdAndOption(proposalId, value(oldChoice)), 0)
415415 else 0
416416 let oldTotalByNewChoice = getIntOrElse(keyProposalVotesByIdAndOption(proposalId, choice), 0)
417417 let oldTotal = parseIntValue(dynamicData[govStatusIdxTotalVotes])
418418 let newTotalByOldChoice = if (!(isDefined(oldChoice)))
419419 then 0
420420 else ((oldTotalByOldChoice - oldUserVotes) + (if ((value(oldChoice) == choice))
421421 then gnsbtAmt
422422 else 0))
423423 let newTotalByNewChoice = if (if (isDefined(oldChoice))
424424 then (value(oldChoice) == choice)
425425 else false)
426426 then newTotalByOldChoice
427427 else (oldTotalByNewChoice + gnsbtAmt)
428428 let newTotal = ((oldTotal - oldUserVotes) + gnsbtAmt)
429429 let isQuorumReached = (newTotal >= parseIntValue(propData[govIdxQuorum]))
430430 let numVotersByProposalId = getIntOrElse(keyNumUniqueVotersByProposalId(proposalId), 0)
431431 let oldAverUniqueVoters6 = getIntOrElse(keyStatsAverUniqueVoters(), 0)
432432 let numProposals = ((getIntegerValue(keyLastProposalId()) - valueOrElse(getInteger(keyFirstProposalId()), DEFAULTFIRSTPROPOSAL)) + 1)
433433 let uniqueDiff = if ((oldUserVotes == 0))
434434 then 1
435435 else 0
436436 let newAverUniqueVoters6 = (oldAverUniqueVoters6 + fraction(uniqueDiff, MULT6, numProposals))
437437 let oldAverGnsbt = getIntOrElse(keyStatsAverGnsbtVoted(), 0)
438438 let newAverGnsbt = (oldAverGnsbt + ((gnsbtAmt - oldUserVotes) / numProposals))
439439 let isPrevOptional = if (!(isDefined(oldChoice)))
440440 then true
441441 else (value(oldChoice) == choice)
442442 let optionalTotalOld = if (isPrevOptional)
443443 then nil
444444 else [IntegerEntry(keyProposalVotesByIdAndOption(proposalId, value(oldChoice)), newTotalByOldChoice)]
445445 let winOpt = calcWinOption(proposalId, availableOptions, isPrevOptional, oldChoice, newTotalByOldChoice, choice, newTotalByNewChoice)
446446 let releaseTime = max([end, getIntOrElse(keyUserGnsbtReleaseTime(userAddressStr), 0)])
447447 $Tuple2(([IntegerEntry(keyProposalChoiceByIdAndUser(proposalId, userAddressStr), choice), IntegerEntry(keyProposalVotesByIdAndUser(proposalId, userAddressStr), gnsbtAmt), IntegerEntry(keyProposalVotesByIdAndOption(proposalId, choice), newTotalByNewChoice), IntegerEntry(keyNumUniqueVotersByProposalId(proposalId), (numVotersByProposalId + uniqueDiff)), IntegerEntry(keyUserGnsbtReleaseTime(userAddressStr), releaseTime), IntegerEntry(keyStatsAverUniqueVoters(), newAverUniqueVoters6), IntegerEntry(keyStatsAverGnsbtVoted(), newAverGnsbt), StringEntry(keyProposalStatusDataById(proposalId), updateStatusData(dynamicData, isQuorumReached, winOpt, newTotal))] ++ optionalTotalOld), unit)
448448 }
449449 }
450450 }
451451 }
452452 }
453453
454454
455455
456456 @Callable(i)
457457 func initiateIdeaVoting (forumLink,title,votingStartTime,votingEndTime,optionsList) = if ((size(i.payments) != 1))
458458 then throw("Exactly one payment required")
459459 else if ((size(optionsList) != 2))
460460 then throw("Exactly 2 option ['NO', 'YES'] are expected")
461461 else if ((optionsList[0] != "NO"))
462462 then throw("Option NO should be the first")
463463 else if ((optionsList[1] != "YES"))
464464 then throw("Option YES should be the second")
465465 else initiateVoting(value(i.payments[0]), toBase58String(i.transactionId), "IDEA", toString(i.caller), forumLink, title, votingStartTime, votingEndTime, "PENDING", nil, optionsList)
466466
467467
468468
469469 @Callable(i)
470470 func initiateUpdateVoting (forumLink,title,votingStartTime,votingEndTime,txList) = if ((size(i.payments) != 1))
471471 then throw("Exactly one payment required")
472472 else if ((1 > size(txList)))
473473 then throw("Transactions list is empty")
474474 else if ((i.caller != this))
475475 then throw("not authorized")
476476 else initiateVoting(value(i.payments[0]), toBase58String(i.transactionId), "UPDATE", toString(i.caller), forumLink, title, votingStartTime, votingEndTime, "PENDING", txList, ["NO", "YES"])
477477
478478
479479
480480 @Callable(i)
481481 func cancelVoting (proposalId) = if ((i.caller != this))
482482 then throw("not authorized")
483483 else {
484484 let currentData = getStringOrFail(this, keyProposalStatusDataById(proposalId))
485485 let updatedData = ((take(currentData, value(lastIndexOf(currentData, SEP))) + SEP) + "true")
486486 $Tuple2([StringEntry(keyProposalStatusDataById(proposalId), updatedData)], unit)
487487 }
488488
489489
490490
491491 @Callable(i)
492492 func applyUpdate (proposalId) = {
493493 let propData = split(getStringOrFail(this, keyProposalDataById(proposalId)), SEP)
494494 let end = parseIntValue(propData[govIdxEnd])
495495 let now = lastBlock.timestamp
496496 if ((end > now))
497497 then throw("Voting is not finished yet")
498498 else if (("UPDATE" != propData[govIdxType]))
499499 then throw("Only UPDATE type can be applied")
500500 else {
501501 let dynamicData = split(getStringOrFail(this, keyProposalStatusDataById(proposalId)), SEP)
502502 if ((dynamicData[govStatusIdxIsCanceled] == "true"))
503503 then throw("Voting is canceled")
504504 else if ((dynamicData[govStatusIdxIsValid] != "true"))
505505 then throw("Voting status invalid")
506506 else if ((dynamicData[govStatusIdxWinOpt] != "1"))
507507 then throw("Winner is 'NO' - nothing to apply")
508508 else if ((dynamicData[govStatusIdxScApplied] == "true"))
509509 then throw("Scripts are already applied")
510510 else {
511511 let scriptTime = parseIntValue(dynamicData[govStatusIdxScTime])
512512 if (((now - PASTMARGIN) > scriptTime))
513513 then throw((("Scripts timestamp=" + toString(scriptTime)) + " is too far in the past, max 2 hrs allowed"))
514514 else if ((scriptTime > (now + FUTUREMARGIN)))
515515 then throw((("Scripts timestamp=" + toString(scriptTime)) + " is too far in the future, max 1.5 hrs allowed"))
516516 else {
517517 let inProgressId = getIntOrElse(keyApplyInProgress(), -1)
518518 if ((inProgressId != -1))
519519 then throw((("proposalId=" + toString(inProgressId)) + " is already being applied. Finish it first!"))
520520 else {
521521 let shutdown = invoke(controlContract, "callEmergencyShutdown", ["Applying Governance UPDATE"], nil)
522522 if ((shutdown == shutdown))
523523 then $Tuple2([IntegerEntry(keyApplyInProgress(), proposalId)], unit)
524524 else throw("Strict value is not equal to itself.")
525525 }
526526 }
527527 }
528528 }
529529 }
530530
531531
532532
533533 @Callable(i)
534534 func finishApply () = {
535535 let proposalId = valueOrErrorMessage(getInteger(keyApplyInProgress()), "No apply in progress, nothing to finish")
536536 let propData = split(getStringOrFail(this, keyProposalDataById(proposalId)), SEP)
537537 let txList = split(propData[govIdxTxIds], LISTSEP)
538538 let dynamicData = split(getStringOrFail(this, keyProposalStatusDataById(proposalId)), SEP)
539539 if ((dynamicData[govStatusIdxScApplied] == "true"))
540540 then throw("Scripts are already applied")
541541 else {
542542 func checker (acc,tx) = if (!(isDefined(transactionHeightById(fromBase58String(tx)))))
543543 then throw(("NOT applied txId: " + tx))
544544 else unit
545545
546546 let ignored = {
547547 let $l = txList
548548 let $s = size($l)
549549 let $acc0 = unit
550550 func $f0_1 ($a,$i) = if (($i >= $s))
551551 then $a
552552 else checker($a, $l[$i])
553553
554554 func $f0_2 ($a,$i) = if (($i >= $s))
555555 then $a
556556 else throw("List size exceeds 20")
557557
558558 $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)
559559 }
560560 let version = (getIntOrElse(keyLastUpdateVersion(), 0) + 1)
561561 $Tuple2([DeleteEntry(keyApplyInProgress()), IntegerEntry(keyLastUpdateVersion(), version), StringEntry(keyProposalStatusDataById(proposalId), statusApplyScript(dynamicData)), ExecutionHistory(version, propData[govIdxTitle], propData[govIdxUrl], proposalId)], ignored)
562562 }
563563 }
564564
565565
566566
567567 @Callable(i)
568568 func changeImplStatus (proposalId,newStatus) = if ((i.caller != this))
569569 then throw("not authorized")
570570 else if (if ((newStatus != "ACTIVE"))
571571 then (newStatus != "OUTDATED")
572572 else false)
573573 then throw("Unknown implementation status")
574574 else {
575575 let dynamicData = split(getStringOrFail(this, keyProposalStatusDataById(proposalId)), SEP)
576576 let updated = makeString(["%b%d%d%d%b%d%b%s", dynamicData[govStatusIdxIsValid], dynamicData[govStatusIdxWinOpt], dynamicData[govStatusIdxWinVotes], dynamicData[govStatusIdxTotalVotes], dynamicData[govStatusIdxScApplied], dynamicData[govStatusIdxScTime], dynamicData[govStatusIdxIsCanceled], newStatus], SEP)
577577 $Tuple2([StringEntry(keyProposalStatusDataById(proposalId), updated)], unit)
578578 }
579579
580580

github/deemru/w8io/3ef1775 
76.71 ms