tx · HNJmBSHk97nTaoUTQXxd6zLHJHMRMsDekYngWvH9Zk8b

3Mu5kJR7ECoKqV4RjdtjBkeKaQoTgR1WBZc:  -0.01900000 Waves

2023.03.24 12:25 [2503899] smart account 3Mu5kJR7ECoKqV4RjdtjBkeKaQoTgR1WBZc > SELF 0.00000000 Waves

{ "type": 13, "id": "HNJmBSHk97nTaoUTQXxd6zLHJHMRMsDekYngWvH9Zk8b", "fee": 1900000, "feeAssetId": null, "timestamp": 1679649964165, "version": 2, "chainId": 84, "sender": "3Mu5kJR7ECoKqV4RjdtjBkeKaQoTgR1WBZc", "senderPublicKey": "242mibE5dTci8wD6vghuCGxjDZdnNJr88H7gcWWehpEX", "proofs": [ "2g26ggafwpGK5LSmHCxLHQ7G178D9sSp6B7SmbCszAoPheyHmPga579mFypqXHXPXagUPHdppg2yUn5JCiHzAef7" ], "script": "base64:BgI1CAISBwoFCAEBAQESBAoCAQESBwoFCAgBARgSBwoFCAgBARgSAwoBARIDCgEBEgASBAoCAQhbAAtyZXZpc2lvbk51bQIAAANTRVACAl9fAAdMSVNUU0VQAgE6AA1ERUZBVUxUUVVPUlVNAKDCHgAKVVJMUEFUVEVSTgIaaHR0cHM6Ly9mb3J1bS5uZXV0cmluby5hdC8ACE1BWFRJVExFAPoBAAZNQVhVUkwA+gEADU1BWFZPVElOR1RJTUUAgJDkwAQABU1VTFQ2AMCEPQAOREVGQVVMVFBBWU1FTlQAgJTr3AMAFERFRkFVTFRDUkVBVElPTkdOU0JUAICU69wDAApQQVNUTUFSR0lOAIC6twMADEZVVFVSRU1BUkdJTgDAy8kCABRERUZBVUxURklSU1RQUk9QT1NBTABvABJnb3ZJZHhQcm9wb3NhbFR4SWQAAQAKZ292SWR4VHlwZQACAAxnb3ZJZHhBdXRob3IAAwAJZ292SWR4VXJsAAQAC2dvdklkeFRpdGxlAAUAEmdvdklkeENyZWF0aW9uVGltZQAGAAtnb3ZJZHhTdGFydAAHAAlnb3ZJZHhFbmQACAALZ292SWR4VHhJZHMACQAMZ292SWR4UXVvcnVtAAoADWdvdklkeE9wdGlvbnMACwATZ292U3RhdHVzSWR4SXNWYWxpZAABABJnb3ZTdGF0dXNJZHhXaW5PcHQAAgAUZ292U3RhdHVzSWR4V2luVm90ZXMAAwAWZ292U3RhdHVzSWR4VG90YWxWb3RlcwAEABVnb3ZTdGF0dXNJZHhTY0FwcGxpZWQABQASZ292U3RhdHVzSWR4U2NUaW1lAAYAFmdvdlN0YXR1c0lkeElzQ2FuY2VsZWQABwAWZ292U3RhdHVzSWR4SW1wbFN0YXR1cwAIAQ9nZXRTdHJpbmdPckZhaWwCB2FkZHJlc3MDa2V5CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ0IAgUHYWRkcmVzcwUDa2V5CQC5CQIJAMwIAgIKbWFuZGF0b3J5IAkAzAgCCQClCAEFB2FkZHJlc3MJAMwIAgIBLgkAzAgCBQNrZXkJAMwIAgIPIGlzIG5vdCBkZWZpbmVkBQNuaWwCAAEMZ2V0SW50T3JFbHNlAgNrZXkKZGVmYXVsdFZhbAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQNrZXkFCmRlZmF1bHRWYWwAGUlkeENvbnRyb2xDZmdOZXV0cmlub0RhcHAAAQAYSWR4Q29udHJvbENmZ0F1Y3Rpb25EYXBwAAIAFElkeENvbnRyb2xDZmdScGREYXBwAAMAFUlkeENvbnRyb2xDZmdNYXRoRGFwcAAEABxJZHhDb250cm9sQ2ZnTGlxdWlkYXRpb25EYXBwAAUAFUlkeENvbnRyb2xDZmdSZXN0RGFwcAAGAB1JZHhDb250cm9sQ2ZnTm9kZVJlZ2lzdHJ5RGFwcAAHABxJZHhDb250cm9sQ2ZnTnNidFN0YWtpbmdEYXBwAAgAGUlkeENvbnRyb2xDZmdNZWRpYXRvckRhcHAACQAcSWR4Q29udHJvbENmZ1N1cmZTdGFraW5nRGFwcAAKACBJZHhDb250cm9sQ2ZnR25zYnRDb250cm9sbGVyRGFwcAALABdJZHhDb250cm9sQ2ZnUmVzdFYyRGFwcAAMABtJZHhDb250cm9sQ2ZnR292ZXJuYW5jZURhcHAADQERa2V5Q29udHJvbEFkZHJlc3MAAhwlcyVzX19jb25maWdfX2NvbnRyb2xBZGRyZXNzAQ1rZXlDb250cm9sQ2ZnAAIRJXNfX2NvbnRyb2xDb25maWcBFHJlYWRDb250cm9sQ2ZnT3JGYWlsAQdjb250cm9sCQC8CQIJAQ9nZXRTdHJpbmdPckZhaWwCBQdjb250cm9sCQENa2V5Q29udHJvbENmZwAFA1NFUAEYZ2V0Q29udHJhY3RBZGRyZXNzT3JGYWlsAgpjb250cm9sQ2ZnA2lkeAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJAJEDAgUKY29udHJvbENmZwUDaWR4CQCsAgICLUNvbnRyb2wgY2ZnIGRvZXNuJ3QgY29udGFpbiBhZGRyZXNzIGF0IGluZGV4IAkApAMBBQNpZHgAD2NvbnRyb2xDb250cmFjdAkBEUBleHRyTmF0aXZlKDEwNjIpAQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzCQERa2V5Q29udHJvbEFkZHJlc3MAAiMzUDVCZmQ1OFBQZk52Qk0ySHk4UWZiY0RxTWVOdHpnN0tmUAAKY29udHJvbENmZwkBFHJlYWRDb250cm9sQ2ZnT3JGYWlsAQUPY29udHJvbENvbnRyYWN0ABBuZXV0cmlub0NvbnRyYWN0CQEYZ2V0Q29udHJhY3RBZGRyZXNzT3JGYWlsAgUKY29udHJvbENmZwUZSWR4Q29udHJvbENmZ05ldXRyaW5vRGFwcAAXZ25zYnRDb250cm9sbGVyQ29udHJhY3QJARhnZXRDb250cmFjdEFkZHJlc3NPckZhaWwCBQpjb250cm9sQ2ZnBSBJZHhDb250cm9sQ2ZnR25zYnRDb250cm9sbGVyRGFwcAATc3VyZlN0YWtpbmdDb250cmFjdAkBGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAIFCmNvbnRyb2xDZmcFHElkeENvbnRyb2xDZmdTdXJmU3Rha2luZ0RhcHABGGtleVF1b3J1bVJlcXVpcmVkUGVyY2VudAEEdHlwZQkArAICAhYlcyVzX19xdW9ydW1SZXF1aXJlZF9fBQR0eXBlARJrZXlQYXltZW50UmVxdWlyZWQAAhMlc19fcGF5bWVudFJlcXVpcmVkARBrZXlHbnNidFJlcXVpcmVkAAIRJXNfX2dOc2J0UmVxdWlyZWQBEWtleUxhc3RQcm9wb3NhbElkAAIOJXNfX3Byb3Bvc2FsSWQBEmtleUZpcnN0UHJvcG9zYWxJZAACEyVzX19maXJzdFByb3Bvc2FsSWQBFGtleUxhc3RVcGRhdGVWZXJzaW9uAAIRJXNfX3VwZGF0ZVZlcnNpb24BGWtleVByb3Bvc2FsU3RhdHVzRGF0YUJ5SWQBCnByb3Bvc2FsSWQJAKwCAgIaJXMlZF9fcHJvcG9zYWxTdGF0dXNEYXRhX18JAKQDAQUKcHJvcG9zYWxJZAETa2V5UHJvcG9zYWxEYXRhQnlJZAEKcHJvcG9zYWxJZAkArAICAhQlcyVkX19wcm9wb3NhbERhdGFfXwkApAMBBQpwcm9wb3NhbElkAR1rZXlQcm9wb3NhbFZvdGVzQnlJZEFuZE9wdGlvbgIKcHJvcG9zYWxJZANvcHQJALkJAgkAzAgCAgYlcyVkJWQJAMwIAgIKdm90ZXNCeU9wdAkAzAgCCQCkAwEFCnByb3Bvc2FsSWQJAMwIAgkApAMBBQNvcHQFA25pbAUDU0VQARtrZXlQcm9wb3NhbFZvdGVzQnlJZEFuZFVzZXICCnByb3Bvc2FsSWQIdXNlckFkZHIJALkJAgkAzAgCAgYlcyVkJXMJAMwIAgILdm90ZXNCeVVzZXIJAMwIAgkApAMBBQpwcm9wb3NhbElkCQDMCAIFCHVzZXJBZGRyBQNuaWwFA1NFUAEca2V5UHJvcG9zYWxDaG9pY2VCeUlkQW5kVXNlcgIKcHJvcG9zYWxJZAh1c2VyQWRkcgkAuQkCCQDMCAICBiVzJWQlcwkAzAgCAgxvcHRpb25CeVVzZXIJAMwIAgkApAMBBQpwcm9wb3NhbElkCQDMCAIFCHVzZXJBZGRyBQNuaWwFA1NFUAESa2V5QXBwbHlJblByb2dyZXNzAAITJXNfX2FwcGx5SW5Qcm9ncmVzcwEWa2V5UHJvcG9zYWxJZEJ5VG9waWNJZAEHdG9waWNJZAkArAICAhslcyVkX19wcm9wb3NhbElkQnlUb3BpY0lkX18JAKQDAQUHdG9waWNJZAEXa2V5VXNlckduc2J0UmVsZWFzZVRpbWUBCHVzZXJBZGRyCQCsAgICGyVzJXNfdXNlckduc2J0UmVsZWFzZVRpbWVfXwUIdXNlckFkZHIBHmtleU51bVVuaXF1ZVZvdGVyc0J5UHJvcG9zYWxJZAEKcHJvcG9zYWxJZAkArAICAhElcyVkX19udW1Wb3RlcnNfXwkApAMBBQpwcm9wb3NhbElkARhrZXlTdGF0c0F2ZXJVbmlxdWVWb3RlcnMAAiAlcyVzJXNfX3N0YXRzX19hdmdfX3VuaXF1ZVZvdGVycwEWa2V5U3RhdHNBdmVyR25zYnRWb3RlZAACHiVzJXMlc19fc3RhdHNfX2F2Z19fZ25zYnRWb3RlZAEVa2V5U3RhdHNVbmlxdWVBdXRob3JzAAIaJXMlc19fc3RhdHNfX3VuaXF1ZUF1dGhvcnMBF2tleU51bVByb3Bvc2Fsc0J5QXV0aG9yAQphZGRyZXNzU3RyCQCsAgICHCVzJXNfX251bVByb3Bvc2Fsc0J5QXV0aG9yX18FCmFkZHJlc3NTdHIBD2tleUFwcGx5SGlzdG9yeQEJdGltZXN0YW1wCQCsAgICFCVzJWRfX2FwcGx5SGlzdG9yeV9fCQCkAwEFCXRpbWVzdGFtcAEJYXNBbnlMaXN0AQF2BAckbWF0Y2gwBQF2AwkAAQIFByRtYXRjaDACCUxpc3RbQW55XQQBbAUHJG1hdGNoMAUBbAkAAgECG2ZhaWwgdG8gY2FzdCBpbnRvIExpc3RbQW55XQEFYXNJbnQBAXYEByRtYXRjaDAFAXYDCQABAgUHJG1hdGNoMAIDSW50BAFpBQckbWF0Y2gwBQFpCQACAQIVZmFpbCB0byBjYXN0IGludG8gSW50AQpzdGF0dXNEYXRhCA1pc1ZvdGluZ1ZhbGlkCXdpbk9wdGlvbg53aW5PcHRpb25Wb3Rlcwp0b3RhbFZvdGVzEWFyZVNjcmlwdHNBcHBsaWVkEHNjcmlwdHNUaW1lc3RhbXAOY2FuY2VsZWRCeVRlYW0KaW1wbFN0YXR1cwkAuQkCCQDMCAICECViJWQlZCVkJWIlZCViJXMJAMwIAgkApQMBBQ1pc1ZvdGluZ1ZhbGlkCQDMCAIJAKQDAQUJd2luT3B0aW9uCQDMCAIJAKQDAQUOd2luT3B0aW9uVm90ZXMJAMwIAgkApAMBBQp0b3RhbFZvdGVzCQDMCAIJAKUDAQURYXJlU2NyaXB0c0FwcGxpZWQJAMwIAgkApAMBBRBzY3JpcHRzVGltZXN0YW1wCQDMCAIJAKUDAQUOY2FuY2VsZWRCeVRlYW0JAMwIAgUKaW1wbFN0YXR1cwUDbmlsBQNTRVABDHByb3Bvc2FsRGF0YQsMcHJvcG9zYWxUeElkBHR5cGUGYXV0aG9yCWZvcnVtTGluawV0aXRsZQxwcm9wb3NhbFRpbWUPdm90aW5nU3RhcnRUaW1lDXZvdGluZ0VuZFRpbWUFdHhJZHMNcXVvcnVtSW5HbnNidAdvcHRpb25zCQC5CQIJAMwIAgIWJXMlcyVzJXMlcyVkJWQlZCVzJWQlcwkAzAgCBQxwcm9wb3NhbFR4SWQJAMwIAgUEdHlwZQkAzAgCBQZhdXRob3IJAMwIAgUJZm9ydW1MaW5rCQDMCAIFBXRpdGxlCQDMCAIJAKQDAQUMcHJvcG9zYWxUaW1lCQDMCAIJAKQDAQUPdm90aW5nU3RhcnRUaW1lCQDMCAIJAKQDAQUNdm90aW5nRW5kVGltZQkAzAgCBQV0eElkcwkAzAgCCQCkAwEFDXF1b3J1bUluR25zYnQJAMwIAgUHb3B0aW9ucwUDbmlsBQNTRVABC2NoZWNrVHhMaXN0AQZ0eExpc3QDCQBmAgkAkAMBBQZ0eExpc3QAFAkAAgEJAKwCAgIXVG9vIG1hbnkgdHJhbnNhY3Rpb25zOiAJAKQDAQkAkAMBBQZ0eExpc3QKAQhjb21iaW5lcgIDYWNjAnR4AwkBAiE9AgkAyAEBCQDZBAEFAnR4ACAJAAIBCQCsAgICDFdyb25nIHR4SWQ6IAUCdHgDCQAAAgUDYWNjAgAFAnR4CQCsAgIJAKwCAgUDYWNjBQdMSVNUU0VQBQJ0eAoAAiRsBQZ0eExpc3QKAAIkcwkAkAMBBQIkbAoABSRhY2MwAgAKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBCGNvbWJpbmVyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAyMAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAC0lkeEVmZlRvdGFsAAAACklkeEVmZlVzZXIAAQERZ2V0RWZmZWN0aXZlR25zYnQBEnVzZXJBZGRyU3RyT3JFbXB0eQQDdXBkAwkBCWlzRGVmaW5lZAEJAKYIAQUSdXNlckFkZHJTdHJPckVtcHR5CQD8BwQFE3N1cmZTdGFraW5nQ29udHJhY3QCEXVwZGF0ZVZvdGluZ1Bvd2VyCQDMCAIFEnVzZXJBZGRyU3RyT3JFbXB0eQUDbmlsBQNuaWwFBHVuaXQDCQAAAgUDdXBkBQN1cGQECWduc2J0RGF0YQkBCWFzQW55TGlzdAEJAPwHBAUXZ25zYnRDb250cm9sbGVyQ29udHJhY3QCFGduc2J0SW5mb1NZU1JFQURPTkxZCQDMCAIFEnVzZXJBZGRyU3RyT3JFbXB0eQkAzAgCAAAJAMwIAgAABQNuaWwFA25pbAQIbnNidERhdGEJAQlhc0FueUxpc3QBCQCRAwIFCWduc2J0RGF0YQACBAx1c2VyRnJvbU5zYnQJAQVhc0ludAEJAJEDAgUIbnNidERhdGEAAgQNdG90YWxGcm9tTnNidAkBBWFzSW50AQkAkQMCBQhuc2J0RGF0YQADBBJ1c2VyTWF0dXJlRnJvbVN1cmYJAQVhc0ludAEJAJEDAgUJZ25zYnREYXRhAAkEE3RvdGFsTWF0dXJlRnJvbVN1cmYJAQVhc0ludAEJAJEDAgUJZ25zYnREYXRhAAYJAMwIAgkAZAIFDXRvdGFsRnJvbU5zYnQFE3RvdGFsTWF0dXJlRnJvbVN1cmYJAMwIAgkAZAIFDHVzZXJGcm9tTnNidAUSdXNlck1hdHVyZUZyb21TdXJmBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BDHZhbGlkYXRlTGluawEDdXJsAwkBAiE9AgkBBXZhbHVlAQkAswkCBQN1cmwFClVSTFBBVFRFUk4AAAkAAgECC0ludmFsaWQgdXJsAwkAZgIJALECAQUDdXJsBQZNQVhVUkwJAAIBAg1VcmwgdG9vIGxvbmchBAd0b3BpY0lkCQETdmFsdWVPckVycm9yTWVzc2FnZQIJALYJAQkAsAICBQN1cmwJAGQCCQEFdmFsdWUBCQC3CQIFA3VybAIBLwABAg1Xcm9uZyB0b3BpY0lkBAxyZWdpc3RlcmVkSWQJAJ8IAQkBFmtleVByb3Bvc2FsSWRCeVRvcGljSWQBBQd0b3BpY0lkAwkBCWlzRGVmaW5lZAEFDHJlZ2lzdGVyZWRJZAkAAgEJAKwCAgI4Vm90aW5nIHdpdGggc3VjaCBmb3J1bSBsaW5rIGlzIGFscmVhZHkgcmVnaXN0ZXJlZCBieSBpZD0JAKQDAQkBBXZhbHVlAQUMcmVnaXN0ZXJlZElkBQd0b3BpY0lkAQ5pbml0aWF0ZVZvdGluZwsHcGF5bWVudAxwcm9wb3NhbFR4SWQEdHlwZQZhdXRob3IJZm9ydW1MaW5rBXRpdGxlD3ZvdGluZ1N0YXJ0VGltZQ12b3RpbmdFbmRUaW1lBnN0YXR1cwZ0eExpc3QLb3B0aW9uc0xpc3QDCQECIT0CCAUHcGF5bWVudAdhc3NldElkBQR1bml0CQACAQIbQWxsb3dlZCBXQVZFUyBwYXltZW50IG9ubHkhBAZwbXRSZXEJAQxnZXRJbnRPckVsc2UCCQESa2V5UGF5bWVudFJlcXVpcmVkAAUOREVGQVVMVFBBWU1FTlQDCQBmAgUGcG10UmVxCAUHcGF5bWVudAZhbW91bnQJAAIBCQCsAgICJFBheW1lbnQgYXR0YWNoZWQgc2hvdWxkIGJlIGF0IGxlYXN0IAkApAMBBQZwbXRSZXEEB3RvcGljSWQJAQx2YWxpZGF0ZUxpbmsBBQlmb3J1bUxpbmsDCQAAAgUFdGl0bGUCAAkAAgECDlRpdGxlIGlzIGVtcHR5AwkAZgIJALECAQUFdGl0bGUFCE1BWFRJVExFCQACAQIOVG9vIGxvbmcgdGl0bGUEDHByb3Bvc2FsVGltZQgFCWxhc3RCbG9jawl0aW1lc3RhbXADCQBmAgUMcHJvcG9zYWxUaW1lBQ92b3RpbmdTdGFydFRpbWUJAAIBCQCsAgIJAKwCAgkArAICAhB2b3RpbmdTdGFydFRpbWU9CQCkAwEFD3ZvdGluZ1N0YXJ0VGltZQIQIDwgcHJvcG9zYWxUaW1lPQkApAMBBQxwcm9wb3NhbFRpbWUDCQBmAgUPdm90aW5nU3RhcnRUaW1lBQ12b3RpbmdFbmRUaW1lCQACAQkArAICCQCsAgIJAKwCAgIOdm90aW5nRW5kVGltZT0JAKQDAQUNdm90aW5nRW5kVGltZQITIDwgdm90aW5nU3RhcnRUaW1lPQkApAMBBQ92b3RpbmdTdGFydFRpbWUDCQBmAgkAZQIFDXZvdGluZ0VuZFRpbWUFD3ZvdGluZ1N0YXJ0VGltZQUNTUFYVk9USU5HVElNRQkAAgEJAKwCAgkArAICCQCsAgICG1ZvdGluZyBwZXJpb2QgZXhjZWVkcyBtYXg6IAkApAMBCQBlAgUNdm90aW5nRW5kVGltZQUPdm90aW5nU3RhcnRUaW1lAgMgPiAJAKQDAQUNTUFYVk9USU5HVElNRQQFdHhJZHMDCQAAAgUEdHlwZQIESURFQQIACQELY2hlY2tUeExpc3QBBQZ0eExpc3QDCQBnAgABCQCQAwEFC29wdGlvbnNMaXN0CQACAQIXVG9vIGZldyBjaG9pY2VzIHRvIHZvdGUEA2VmZgkBEWdldEVmZmVjdGl2ZUduc2J0AQUGYXV0aG9yBApnbnNidFRvdGFsCQCRAwIFA2VmZgULSWR4RWZmVG90YWwECWdOc2J0VXNlcgkAkQMCBQNlZmYFCklkeEVmZlVzZXIECGduc2J0UmVxCQEMZ2V0SW50T3JFbHNlAgkBEGtleUduc2J0UmVxdWlyZWQABRRERUZBVUxUQ1JFQVRJT05HTlNCVAMJAGYCBQhnbnNidFJlcQUJZ05zYnRVc2VyCQACAQkArAICCQCsAgICEllvdSBuZWVkIGF0IGxlYXN0IAkApAMBBQhnbnNidFJlcQIXIGdOc2J0IHRvIGNyZWF0ZSB2b3RpbmcEDGFtb3VudExlYXNlZAkA/AcEBRBuZXV0cmlub0NvbnRyYWN0AgthY2NlcHRXYXZlcwUDbmlsCQDMCAIFB3BheW1lbnQFA25pbAMJAAACBQxhbW91bnRMZWFzZWQFDGFtb3VudExlYXNlZAQGcXVvcnVtCQEMZ2V0SW50T3JFbHNlAgkBGGtleVF1b3J1bVJlcXVpcmVkUGVyY2VudAEFBHR5cGUFDURFRkFVTFRRVU9SVU0EDXF1b3J1bUluR25zYnQJAGsDBQZxdW9ydW0FCmduc2J0VG90YWwFBU1VTFQ2BApwcm9wb3NhbElkCQBkAgkBDGdldEludE9yRWxzZQIJARFrZXlMYXN0UHJvcG9zYWxJZAAAAAABBBRudW1Qcm9wb3NhbHNCeUF1dGhvcgkAZAIJAQxnZXRJbnRPckVsc2UCCQEXa2V5TnVtUHJvcG9zYWxzQnlBdXRob3IBBQZhdXRob3IAAAABBAt1bmlxQXV0aG9ycwkAZAIJAQxnZXRJbnRPckVsc2UCCQEVa2V5U3RhdHNVbmlxdWVBdXRob3JzAAAAAwkAAAIFFG51bVByb3Bvc2Fsc0J5QXV0aG9yAAEAAQAABApvcHRpb25zU3RyCQC5CQIFC29wdGlvbnNMaXN0BQdMSVNUU0VQCQCUCgIJAMwIAgkBDEludGVnZXJFbnRyeQIJARFrZXlMYXN0UHJvcG9zYWxJZAAFCnByb3Bvc2FsSWQJAMwIAgkBDEludGVnZXJFbnRyeQIJARZrZXlQcm9wb3NhbElkQnlUb3BpY0lkAQUHdG9waWNJZAUKcHJvcG9zYWxJZAkAzAgCCQELU3RyaW5nRW50cnkCCQEZa2V5UHJvcG9zYWxTdGF0dXNEYXRhQnlJZAEFCnByb3Bvc2FsSWQJAQpzdGF0dXNEYXRhCAcAAAAAAAAHBQ12b3RpbmdFbmRUaW1lBwIGQUNUSVZFCQDMCAIJAQtTdHJpbmdFbnRyeQIJARNrZXlQcm9wb3NhbERhdGFCeUlkAQUKcHJvcG9zYWxJZAkBDHByb3Bvc2FsRGF0YQsFDHByb3Bvc2FsVHhJZAUEdHlwZQUGYXV0aG9yCQDYBAEJAJsDAQUJZm9ydW1MaW5rCQDYBAEJAJsDAQUFdGl0bGUFDHByb3Bvc2FsVGltZQUPdm90aW5nU3RhcnRUaW1lBQ12b3RpbmdFbmRUaW1lBQV0eElkcwUNcXVvcnVtSW5HbnNidAUKb3B0aW9uc1N0cgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBF2tleU51bVByb3Bvc2Fsc0J5QXV0aG9yAQUGYXV0aG9yBRRudW1Qcm9wb3NhbHNCeUF1dGhvcgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBFWtleVN0YXRzVW5pcXVlQXV0aG9ycwAFC3VuaXFBdXRob3JzBQNuaWwFDHByb3Bvc2FsVHhJZAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgENY2FsY1dpbk9wdGlvbgcKcHJvcG9zYWxJZAtvcHRpb25zTGlzdA5pc1ByZXZPcHRpb25hbAlvbGRDaG9pY2UQb3B0aW9uYWxUb3RhbE9sZAluZXdDaG9pY2UTbmV3VG90YWxCeU5ld0Nob2ljZQoBCGZpbmRCZXN0AgNhY2MEZWxlbQQDaWR4CQEFdmFsdWUBCQDPCAIFC29wdGlvbnNMaXN0BQRlbGVtBAN2YWwDBQ5pc1ByZXZPcHRpb25hbAMJAAACBQNpZHgFCW5ld0Nob2ljZQUTbmV3VG90YWxCeU5ld0Nob2ljZQkBDGdldEludE9yRWxzZQIJAR1rZXlQcm9wb3NhbFZvdGVzQnlJZEFuZE9wdGlvbgIFCnByb3Bvc2FsSWQFA2lkeAAAAwkAAAIFA2lkeAkBBXZhbHVlAQUJb2xkQ2hvaWNlBRBvcHRpb25hbFRvdGFsT2xkAwkAAAIFA2lkeAUJbmV3Q2hvaWNlBRNuZXdUb3RhbEJ5TmV3Q2hvaWNlCQEMZ2V0SW50T3JFbHNlAgkBHWtleVByb3Bvc2FsVm90ZXNCeUlkQW5kT3B0aW9uAgUKcHJvcG9zYWxJZAUDaWR4AAADCQBmAggFA2FjYwJfMgUDdmFsBQNhY2MJAJQKAgUDaWR4BQN2YWwKAAIkbAULb3B0aW9uc0xpc3QKAAIkcwkAkAMBBQIkbAoABSRhY2MwCQCUCgIAAAAACgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQhmaW5kQmVzdAIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgEQdXBkYXRlU3RhdHVzRGF0YQQHb2xkRGF0YQdpc1ZhbGlkCW5ld1dpbk9wdA1uZXdUb3RhbFZvdGVzCQC5CQIJAMwIAgIQJWIlZCVkJWQlYiVkJWIlcwkAzAgCCQClAwEFB2lzVmFsaWQJAMwIAgkApAMBCAUJbmV3V2luT3B0Al8xCQDMCAIJAKQDAQgFCW5ld1dpbk9wdAJfMgkAzAgCCQCkAwEFDW5ld1RvdGFsVm90ZXMJAMwIAgkAkQMCBQdvbGREYXRhBRVnb3ZTdGF0dXNJZHhTY0FwcGxpZWQJAMwIAgkAkQMCBQdvbGREYXRhBRJnb3ZTdGF0dXNJZHhTY1RpbWUJAMwIAgkAkQMCBQdvbGREYXRhBRZnb3ZTdGF0dXNJZHhJc0NhbmNlbGVkCQDMCAIJAJEDAgUHb2xkRGF0YQUWZ292U3RhdHVzSWR4SW1wbFN0YXR1cwUDbmlsBQNTRVABEXN0YXR1c0FwcGx5U2NyaXB0AQdvbGREYXRhCQC5CQIJAMwIAgIQJWIlZCVkJWQlYiVkJWIlcwkAzAgCCQCRAwIFB29sZERhdGEFE2dvdlN0YXR1c0lkeElzVmFsaWQJAMwIAgkAkQMCBQdvbGREYXRhBRJnb3ZTdGF0dXNJZHhXaW5PcHQJAMwIAgkAkQMCBQdvbGREYXRhBRRnb3ZTdGF0dXNJZHhXaW5Wb3RlcwkAzAgCCQCRAwIFB29sZERhdGEFFmdvdlN0YXR1c0lkeFRvdGFsVm90ZXMJAMwIAgIEdHJ1ZQkAzAgCCQCRAwIFB29sZERhdGEFEmdvdlN0YXR1c0lkeFNjVGltZQkAzAgCCQCRAwIFB29sZERhdGEFFmdvdlN0YXR1c0lkeElzQ2FuY2VsZWQJAMwIAgkAkQMCBQdvbGREYXRhBRZnb3ZTdGF0dXNJZHhJbXBsU3RhdHVzBQNuaWwFA1NFUAEQRXhlY3V0aW9uSGlzdG9yeQQNdXBkYXRlVmVyc2lvbgV0aXRsZQN1cmwKcHJvcG9zYWxJZAQKZ25zYnRUb3RhbAkAkQMCCQERZ2V0RWZmZWN0aXZlR25zYnQBAgAFC0lkeEVmZlRvdGFsBAd0dXJub3V0AKDCHgkBC1N0cmluZ0VudHJ5AgkBD2tleUFwcGx5SGlzdG9yeQEIBQlsYXN0QmxvY2sJdGltZXN0YW1wCQC5CQIJAMwIAgIMJWQlZCVkJXMlcyVkCQDMCAIJAKQDAQUNdXBkYXRlVmVyc2lvbgkAzAgCCQCkAwEFCmduc2J0VG90YWwJAMwIAgkApAMBBQd0dXJub3V0CQDMCAIFBXRpdGxlCQDMCAIFA3VybAkAzAgCCQCkAwEFCnByb3Bvc2FsSWQFA25pbAUDU0VQCAFpAQ1jb25zdHJ1Y3RvclYxBQtjb250cm9sQWRkcg5nTnNidFJlcVRvSW5pdA53YXZlc1JlcVRvSW5pdBFxdW9ydW1SZXFQZXJjSWRlYRNxdW9ydW1SZXFQZXJjVXBkYXRlAwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIRUGVybWlzc2lvbiBkZW5pZWQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBEWtleUNvbnRyb2xBZGRyZXNzAAULY29udHJvbEFkZHIJAMwIAgkBDEludGVnZXJFbnRyeQIJARBrZXlHbnNidFJlcXVpcmVkAAUOZ05zYnRSZXFUb0luaXQJAMwIAgkBDEludGVnZXJFbnRyeQIJARJrZXlQYXltZW50UmVxdWlyZWQABQ53YXZlc1JlcVRvSW5pdAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBGGtleVF1b3J1bVJlcXVpcmVkUGVyY2VudAECBElERUEFEXF1b3J1bVJlcVBlcmNJZGVhCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEYa2V5UXVvcnVtUmVxdWlyZWRQZXJjZW50AQIGVVBEQVRFBRNxdW9ydW1SZXFQZXJjVXBkYXRlBQNuaWwBaQEIY2FzdFZvdGUCCnByb3Bvc2FsSWQGY2hvaWNlBA51c2VyQWRkcmVzc1N0cgkApQgBCAUBaQZjYWxsZXIEC2R5bmFtaWNEYXRhCQC1CQIJAQ9nZXRTdHJpbmdPckZhaWwCBQR0aGlzCQEZa2V5UHJvcG9zYWxTdGF0dXNEYXRhQnlJZAEFCnByb3Bvc2FsSWQFA1NFUAMJAAACCQCRAwIFC2R5bmFtaWNEYXRhBRZnb3ZTdGF0dXNJZHhJc0NhbmNlbGVkAgR0cnVlCQACAQIaVm90aW5nIGlzIGNhbmNlbGVkIGJ5IHRlYW0ECHByb3BEYXRhCQC1CQIJAQ9nZXRTdHJpbmdPckZhaWwCBQR0aGlzCQETa2V5UHJvcG9zYWxEYXRhQnlJZAEFCnByb3Bvc2FsSWQFA1NFUAQFc3RhcnQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQhwcm9wRGF0YQULZ292SWR4U3RhcnQEA2VuZAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCHByb3BEYXRhBQlnb3ZJZHhFbmQEA25vdwgFCWxhc3RCbG9jawl0aW1lc3RhbXADCQBmAgUFc3RhcnQFA25vdwkAAgECFlZvdGluZyBub3Qgc3RhcnRlZCB5ZXQDCQBnAgUDbm93BQNlbmQJAAIBAhdWb3RpbmcgYWxyZWFkeSBmaW5pc2hlZAQQYXZhaWxhYmxlT3B0aW9ucwkAtQkCCQCRAwIFCHByb3BEYXRhBQ1nb3ZJZHhPcHRpb25zBQdMSVNUU0VQBApudW1PcHRpb25zCQCQAwEFEGF2YWlsYWJsZU9wdGlvbnMDCQBnAgABBQpudW1PcHRpb25zCQACAQIXVG9vIGZldyBjaG9pY2VzIHRvIHZvdGUDCQBnAgUGY2hvaWNlBQpudW1PcHRpb25zCQACAQkArAICAhtVbmtub3duIGNob2ljZSEgTXVzdCBiZSAwLi4JAKQDAQkAZQIFCm51bU9wdGlvbnMAAQQDZWZmCQERZ2V0RWZmZWN0aXZlR25zYnQBBQ51c2VyQWRkcmVzc1N0cgQIZ25zYnRBbXQJAJEDAgUDZWZmBQpJZHhFZmZVc2VyAwkAZwIAAAUIZ25zYnRBbXQJAAIBAhBubyBnbnNidCB0byB2b3RlBApnbnNidFRvdGFsCQCRAwIFA2VmZgULSWR4RWZmVG90YWwECW9sZENob2ljZQkAnwgBCQEca2V5UHJvcG9zYWxDaG9pY2VCeUlkQW5kVXNlcgIFCnByb3Bvc2FsSWQFDnVzZXJBZGRyZXNzU3RyBAxvbGRVc2VyVm90ZXMDCQEBIQEJAQlpc0RlZmluZWQBBQlvbGRDaG9pY2UAAAkBDGdldEludE9yRWxzZQIJARtrZXlQcm9wb3NhbFZvdGVzQnlJZEFuZFVzZXICBQpwcm9wb3NhbElkBQ51c2VyQWRkcmVzc1N0cgAABBNvbGRUb3RhbEJ5T2xkQ2hvaWNlAwkBCWlzRGVmaW5lZAEFCW9sZENob2ljZQkBDGdldEludE9yRWxzZQIJAR1rZXlQcm9wb3NhbFZvdGVzQnlJZEFuZE9wdGlvbgIFCnByb3Bvc2FsSWQJAQV2YWx1ZQEFCW9sZENob2ljZQAAAAAEE29sZFRvdGFsQnlOZXdDaG9pY2UJAQxnZXRJbnRPckVsc2UCCQEda2V5UHJvcG9zYWxWb3Rlc0J5SWRBbmRPcHRpb24CBQpwcm9wb3NhbElkBQZjaG9pY2UAAAQIb2xkVG90YWwJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQtkeW5hbWljRGF0YQUWZ292U3RhdHVzSWR4VG90YWxWb3RlcwQTbmV3VG90YWxCeU9sZENob2ljZQMJAQEhAQkBCWlzRGVmaW5lZAEFCW9sZENob2ljZQAACQBkAgkAZQIFE29sZFRvdGFsQnlPbGRDaG9pY2UFDG9sZFVzZXJWb3RlcwMJAAACCQEFdmFsdWUBBQlvbGRDaG9pY2UFBmNob2ljZQUIZ25zYnRBbXQAAAQTbmV3VG90YWxCeU5ld0Nob2ljZQMDCQEJaXNEZWZpbmVkAQUJb2xkQ2hvaWNlCQAAAgkBBXZhbHVlAQUJb2xkQ2hvaWNlBQZjaG9pY2UHBRNuZXdUb3RhbEJ5T2xkQ2hvaWNlCQBkAgUTb2xkVG90YWxCeU5ld0Nob2ljZQUIZ25zYnRBbXQECG5ld1RvdGFsCQBkAgkAZQIFCG9sZFRvdGFsBQxvbGRVc2VyVm90ZXMFCGduc2J0QW10BA9pc1F1b3J1bVJlYWNoZWQJAGcCBQhuZXdUb3RhbAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCHByb3BEYXRhBQxnb3ZJZHhRdW9ydW0EFW51bVZvdGVyc0J5UHJvcG9zYWxJZAkBDGdldEludE9yRWxzZQIJAR5rZXlOdW1VbmlxdWVWb3RlcnNCeVByb3Bvc2FsSWQBBQpwcm9wb3NhbElkAAAEFG9sZEF2ZXJVbmlxdWVWb3RlcnM2CQEMZ2V0SW50T3JFbHNlAgkBGGtleVN0YXRzQXZlclVuaXF1ZVZvdGVycwAAAAQMbnVtUHJvcG9zYWxzCQBkAgkAZQIJARFAZXh0ck5hdGl2ZSgxMDU1KQEJARFrZXlMYXN0UHJvcG9zYWxJZAAJAQt2YWx1ZU9yRWxzZQIJAJ8IAQkBEmtleUZpcnN0UHJvcG9zYWxJZAAFFERFRkFVTFRGSVJTVFBST1BPU0FMAAEECnVuaXF1ZURpZmYDCQAAAgUMb2xkVXNlclZvdGVzAAAAAQAABBRuZXdBdmVyVW5pcXVlVm90ZXJzNgkAZAIFFG9sZEF2ZXJVbmlxdWVWb3RlcnM2CQBrAwUKdW5pcXVlRGlmZgUFTVVMVDYFDG51bVByb3Bvc2FscwQMb2xkQXZlckduc2J0CQEMZ2V0SW50T3JFbHNlAgkBFmtleVN0YXRzQXZlckduc2J0Vm90ZWQAAAAEDG5ld0F2ZXJHbnNidAkAZAIFDG9sZEF2ZXJHbnNidAkAaQIJAGUCBQhnbnNidEFtdAUMb2xkVXNlclZvdGVzBQxudW1Qcm9wb3NhbHMEDmlzUHJldk9wdGlvbmFsAwkBASEBCQEJaXNEZWZpbmVkAQUJb2xkQ2hvaWNlBgkAAAIJAQV2YWx1ZQEFCW9sZENob2ljZQUGY2hvaWNlBBBvcHRpb25hbFRvdGFsT2xkAwUOaXNQcmV2T3B0aW9uYWwFA25pbAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBHWtleVByb3Bvc2FsVm90ZXNCeUlkQW5kT3B0aW9uAgUKcHJvcG9zYWxJZAkBBXZhbHVlAQUJb2xkQ2hvaWNlBRNuZXdUb3RhbEJ5T2xkQ2hvaWNlBQNuaWwEBndpbk9wdAkBDWNhbGNXaW5PcHRpb24HBQpwcm9wb3NhbElkBRBhdmFpbGFibGVPcHRpb25zBQ5pc1ByZXZPcHRpb25hbAUJb2xkQ2hvaWNlBRNuZXdUb3RhbEJ5T2xkQ2hvaWNlBQZjaG9pY2UFE25ld1RvdGFsQnlOZXdDaG9pY2UEC3JlbGVhc2VUaW1lCQCWAwEJAMwIAgUDZW5kCQDMCAIJAQxnZXRJbnRPckVsc2UCCQEXa2V5VXNlckduc2J0UmVsZWFzZVRpbWUBBQ51c2VyQWRkcmVzc1N0cgAABQNuaWwJAJQKAgkAzggCCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEca2V5UHJvcG9zYWxDaG9pY2VCeUlkQW5kVXNlcgIFCnByb3Bvc2FsSWQFDnVzZXJBZGRyZXNzU3RyBQZjaG9pY2UJAMwIAgkBDEludGVnZXJFbnRyeQIJARtrZXlQcm9wb3NhbFZvdGVzQnlJZEFuZFVzZXICBQpwcm9wb3NhbElkBQ51c2VyQWRkcmVzc1N0cgUIZ25zYnRBbXQJAMwIAgkBDEludGVnZXJFbnRyeQIJAR1rZXlQcm9wb3NhbFZvdGVzQnlJZEFuZE9wdGlvbgIFCnByb3Bvc2FsSWQFBmNob2ljZQUTbmV3VG90YWxCeU5ld0Nob2ljZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBHmtleU51bVVuaXF1ZVZvdGVyc0J5UHJvcG9zYWxJZAEFCnByb3Bvc2FsSWQJAGQCBRVudW1Wb3RlcnNCeVByb3Bvc2FsSWQFCnVuaXF1ZURpZmYJAMwIAgkBDEludGVnZXJFbnRyeQIJARdrZXlVc2VyR25zYnRSZWxlYXNlVGltZQEFDnVzZXJBZGRyZXNzU3RyBQtyZWxlYXNlVGltZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBGGtleVN0YXRzQXZlclVuaXF1ZVZvdGVycwAFFG5ld0F2ZXJVbmlxdWVWb3RlcnM2CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEWa2V5U3RhdHNBdmVyR25zYnRWb3RlZAAFDG5ld0F2ZXJHbnNidAkAzAgCCQELU3RyaW5nRW50cnkCCQEZa2V5UHJvcG9zYWxTdGF0dXNEYXRhQnlJZAEFCnByb3Bvc2FsSWQJARB1cGRhdGVTdGF0dXNEYXRhBAULZHluYW1pY0RhdGEFD2lzUXVvcnVtUmVhY2hlZAUGd2luT3B0BQhuZXdUb3RhbAUDbmlsBRBvcHRpb25hbFRvdGFsT2xkBQR1bml0AWkBEmluaXRpYXRlSWRlYVZvdGluZwUJZm9ydW1MaW5rBXRpdGxlD3ZvdGluZ1N0YXJ0VGltZQ12b3RpbmdFbmRUaW1lC29wdGlvbnNMaXN0AwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwABCQACAQIcRXhhY3RseSBvbmUgcGF5bWVudCByZXF1aXJlZAMJAQIhPQIJAJADAQULb3B0aW9uc0xpc3QAAgkAAgECK0V4YWN0bHkgMiBvcHRpb24gWydOTycsICdZRVMnXSBhcmUgZXhwZWN0ZWQDCQECIT0CCQCRAwIFC29wdGlvbnNMaXN0AAACAk5PCQACAQIdT3B0aW9uIE5PIHNob3VsZCBiZSB0aGUgZmlyc3QDCQECIT0CCQCRAwIFC29wdGlvbnNMaXN0AAECA1lFUwkAAgECH09wdGlvbiBZRVMgc2hvdWxkIGJlIHRoZSBzZWNvbmQJAQ5pbml0aWF0ZVZvdGluZwsJAQV2YWx1ZQEJAJEDAggFAWkIcGF5bWVudHMAAAkA2AQBCAUBaQ10cmFuc2FjdGlvbklkAgRJREVBCQClCAEIBQFpBmNhbGxlcgUJZm9ydW1MaW5rBQV0aXRsZQUPdm90aW5nU3RhcnRUaW1lBQ12b3RpbmdFbmRUaW1lAgdQRU5ESU5HBQNuaWwFC29wdGlvbnNMaXN0AWkBFGluaXRpYXRlVXBkYXRlVm90aW5nBQlmb3J1bUxpbmsFdGl0bGUPdm90aW5nU3RhcnRUaW1lDXZvdGluZ0VuZFRpbWUGdHhMaXN0AwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwABCQACAQIcRXhhY3RseSBvbmUgcGF5bWVudCByZXF1aXJlZAMJAGYCAAEJAJADAQUGdHhMaXN0CQACAQIaVHJhbnNhY3Rpb25zIGxpc3QgaXMgZW1wdHkDCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAAIBAg5ub3QgYXV0aG9yaXplZAkBDmluaXRpYXRlVm90aW5nCwkBBXZhbHVlAQkAkQMCCAUBaQhwYXltZW50cwAACQDYBAEIBQFpDXRyYW5zYWN0aW9uSWQCBlVQREFURQkApQgBCAUBaQZjYWxsZXIFCWZvcnVtTGluawUFdGl0bGUFD3ZvdGluZ1N0YXJ0VGltZQUNdm90aW5nRW5kVGltZQIHUEVORElORwUGdHhMaXN0CQDMCAICAk5PCQDMCAICA1lFUwUDbmlsAWkBDGNhbmNlbFZvdGluZwEKcHJvcG9zYWxJZAMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECDm5vdCBhdXRob3JpemVkBAtjdXJyZW50RGF0YQkBD2dldFN0cmluZ09yRmFpbAIFBHRoaXMJARlrZXlQcm9wb3NhbFN0YXR1c0RhdGFCeUlkAQUKcHJvcG9zYWxJZAQLdXBkYXRlZERhdGEJAKwCAgkArAICCQCvAgIFC2N1cnJlbnREYXRhCQEFdmFsdWUBCQC3CQIFC2N1cnJlbnREYXRhBQNTRVAFA1NFUAIEdHJ1ZQkAlAoCCQDMCAIJAQtTdHJpbmdFbnRyeQIJARlrZXlQcm9wb3NhbFN0YXR1c0RhdGFCeUlkAQUKcHJvcG9zYWxJZAULdXBkYXRlZERhdGEFA25pbAUEdW5pdAFpAQthcHBseVVwZGF0ZQEKcHJvcG9zYWxJZAQIcHJvcERhdGEJALUJAgkBD2dldFN0cmluZ09yRmFpbAIFBHRoaXMJARNrZXlQcm9wb3NhbERhdGFCeUlkAQUKcHJvcG9zYWxJZAUDU0VQBANlbmQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQhwcm9wRGF0YQUJZ292SWR4RW5kBANub3cIBQlsYXN0QmxvY2sJdGltZXN0YW1wAwkAZgIFA2VuZAUDbm93CQACAQIaVm90aW5nIGlzIG5vdCBmaW5pc2hlZCB5ZXQDCQECIT0CAgZVUERBVEUJAJEDAgUIcHJvcERhdGEFCmdvdklkeFR5cGUJAAIBAh9Pbmx5IFVQREFURSB0eXBlIGNhbiBiZSBhcHBsaWVkBAtkeW5hbWljRGF0YQkAtQkCCQEPZ2V0U3RyaW5nT3JGYWlsAgUEdGhpcwkBGWtleVByb3Bvc2FsU3RhdHVzRGF0YUJ5SWQBBQpwcm9wb3NhbElkBQNTRVADCQAAAgkAkQMCBQtkeW5hbWljRGF0YQUWZ292U3RhdHVzSWR4SXNDYW5jZWxlZAIEdHJ1ZQkAAgECElZvdGluZyBpcyBjYW5jZWxlZAMJAQIhPQIJAJEDAgULZHluYW1pY0RhdGEFE2dvdlN0YXR1c0lkeElzVmFsaWQCBHRydWUJAAIBAhVWb3Rpbmcgc3RhdHVzIGludmFsaWQDCQECIT0CCQCRAwIFC2R5bmFtaWNEYXRhBRJnb3ZTdGF0dXNJZHhXaW5PcHQCATEJAAIBAiFXaW5uZXIgaXMgJ05PJyAtIG5vdGhpbmcgdG8gYXBwbHkDCQAAAgkAkQMCBQtkeW5hbWljRGF0YQUVZ292U3RhdHVzSWR4U2NBcHBsaWVkAgR0cnVlCQACAQIbU2NyaXB0cyBhcmUgYWxyZWFkeSBhcHBsaWVkBApzY3JpcHRUaW1lCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgULZHluYW1pY0RhdGEFEmdvdlN0YXR1c0lkeFNjVGltZQMJAGYCCQBlAgUDbm93BQpQQVNUTUFSR0lOBQpzY3JpcHRUaW1lCQACAQkArAICCQCsAgICElNjcmlwdHMgdGltZXN0YW1wPQkApAMBBQpzY3JpcHRUaW1lAiogaXMgdG9vIGZhciBpbiB0aGUgcGFzdCwgbWF4IDIgaHJzIGFsbG93ZWQDCQBmAgUKc2NyaXB0VGltZQkAZAIFA25vdwUMRlVUVVJFTUFSR0lOCQACAQkArAICCQCsAgICElNjcmlwdHMgdGltZXN0YW1wPQkApAMBBQpzY3JpcHRUaW1lAi4gaXMgdG9vIGZhciBpbiB0aGUgZnV0dXJlLCBtYXggMS41IGhycyBhbGxvd2VkBAxpblByb2dyZXNzSWQJAQxnZXRJbnRPckVsc2UCCQESa2V5QXBwbHlJblByb2dyZXNzAAD///////////8BAwkBAiE9AgUMaW5Qcm9ncmVzc0lkAP///////////wEJAAIBCQCsAgIJAKwCAgILcHJvcG9zYWxJZD0JAKQDAQUMaW5Qcm9ncmVzc0lkAisgaXMgYWxyZWFkeSBiZWluZyBhcHBsaWVkLiBGaW5pc2ggaXQgZmlyc3QhBAhzaHV0ZG93bgkA/AcEBQ9jb250cm9sQ29udHJhY3QCFWNhbGxFbWVyZ2VuY3lTaHV0ZG93bgkAzAgCAhpBcHBseWluZyBHb3Zlcm5hbmNlIFVQREFURQUDbmlsBQNuaWwDCQAAAgUIc2h1dGRvd24FCHNodXRkb3duCQCUCgIJAMwIAgkBDEludGVnZXJFbnRyeQIJARJrZXlBcHBseUluUHJvZ3Jlc3MABQpwcm9wb3NhbElkBQNuaWwFBHVuaXQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQELZmluaXNoQXBwbHkABApwcm9wb3NhbElkCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ8IAQkBEmtleUFwcGx5SW5Qcm9ncmVzcwACJ05vIGFwcGx5IGluIHByb2dyZXNzLCBub3RoaW5nIHRvIGZpbmlzaAQIcHJvcERhdGEJALUJAgkBD2dldFN0cmluZ09yRmFpbAIFBHRoaXMJARNrZXlQcm9wb3NhbERhdGFCeUlkAQUKcHJvcG9zYWxJZAUDU0VQBAZ0eExpc3QJALUJAgkAkQMCBQhwcm9wRGF0YQULZ292SWR4VHhJZHMFB0xJU1RTRVAEC2R5bmFtaWNEYXRhCQC1CQIJAQ9nZXRTdHJpbmdPckZhaWwCBQR0aGlzCQEZa2V5UHJvcG9zYWxTdGF0dXNEYXRhQnlJZAEFCnByb3Bvc2FsSWQFA1NFUAMJAAACCQCRAwIFC2R5bmFtaWNEYXRhBRVnb3ZTdGF0dXNJZHhTY0FwcGxpZWQCBHRydWUJAAIBAhtTY3JpcHRzIGFyZSBhbHJlYWR5IGFwcGxpZWQKAQdjaGVja2VyAgNhY2MCdHgDCQEBIQEJAQlpc0RlZmluZWQBCQDpBwEJANkEAQUCdHgJAAIBCQCsAgICEk5PVCBhcHBsaWVkIHR4SWQ6IAUCdHgFBHVuaXQEB2lnbm9yZWQKAAIkbAUGdHhMaXN0CgACJHMJAJADAQUCJGwKAAUkYWNjMAUEdW5pdAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEHY2hlY2tlcgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMjAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgALAAwADQAOAA8AEAARABIAEwAUBAd2ZXJzaW9uCQBkAgkBDGdldEludE9yRWxzZQIJARRrZXlMYXN0VXBkYXRlVmVyc2lvbgAAAAABCQCUCgIJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBEmtleUFwcGx5SW5Qcm9ncmVzcwAJAMwIAgkBDEludGVnZXJFbnRyeQIJARRrZXlMYXN0VXBkYXRlVmVyc2lvbgAFB3ZlcnNpb24JAMwIAgkBC1N0cmluZ0VudHJ5AgkBGWtleVByb3Bvc2FsU3RhdHVzRGF0YUJ5SWQBBQpwcm9wb3NhbElkCQERc3RhdHVzQXBwbHlTY3JpcHQBBQtkeW5hbWljRGF0YQkAzAgCCQEQRXhlY3V0aW9uSGlzdG9yeQQFB3ZlcnNpb24JAJEDAgUIcHJvcERhdGEFC2dvdklkeFRpdGxlCQCRAwIFCHByb3BEYXRhBQlnb3ZJZHhVcmwFCnByb3Bvc2FsSWQFA25pbAUHaWdub3JlZAFpARBjaGFuZ2VJbXBsU3RhdHVzAgpwcm9wb3NhbElkCW5ld1N0YXR1cwMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECDm5vdCBhdXRob3JpemVkAwMJAQIhPQIFCW5ld1N0YXR1cwIGQUNUSVZFCQECIT0CBQluZXdTdGF0dXMCCE9VVERBVEVEBwkAAgECHVVua25vd24gaW1wbGVtZW50YXRpb24gc3RhdHVzBAtkeW5hbWljRGF0YQkAtQkCCQEPZ2V0U3RyaW5nT3JGYWlsAgUEdGhpcwkBGWtleVByb3Bvc2FsU3RhdHVzRGF0YUJ5SWQBBQpwcm9wb3NhbElkBQNTRVAEB3VwZGF0ZWQJALkJAgkAzAgCAhAlYiVkJWQlZCViJWQlYiVzCQDMCAIJAJEDAgULZHluYW1pY0RhdGEFE2dvdlN0YXR1c0lkeElzVmFsaWQJAMwIAgkAkQMCBQtkeW5hbWljRGF0YQUSZ292U3RhdHVzSWR4V2luT3B0CQDMCAIJAJEDAgULZHluYW1pY0RhdGEFFGdvdlN0YXR1c0lkeFdpblZvdGVzCQDMCAIJAJEDAgULZHluYW1pY0RhdGEFFmdvdlN0YXR1c0lkeFRvdGFsVm90ZXMJAMwIAgkAkQMCBQtkeW5hbWljRGF0YQUVZ292U3RhdHVzSWR4U2NBcHBsaWVkCQDMCAIJAJEDAgULZHluYW1pY0RhdGEFEmdvdlN0YXR1c0lkeFNjVGltZQkAzAgCCQCRAwIFC2R5bmFtaWNEYXRhBRZnb3ZTdGF0dXNJZHhJc0NhbmNlbGVkCQDMCAIFCW5ld1N0YXR1cwUDbmlsBQNTRVAJAJQKAgkAzAgCCQELU3RyaW5nRW50cnkCCQEZa2V5UHJvcG9zYWxTdGF0dXNEYXRhQnlJZAEFCnByb3Bvc2FsSWQFB3VwZGF0ZWQFA25pbAUEdW5pdABqXyjU", "height": 2503899, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: DW9RSgESNKPWvggQuVyw7ci1bA8vVh28CPrmWgQyt6wL Next: 2x1A7Fhbat8D1mqPEkMks2CJitbPc9tTewpwXW2g1hgd Diff:
OldNewDifferences
6565
6666 let govStatusIdxIsCanceled = 7
6767
68+let govStatusIdxImplStatus = 8
69+
6870 func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], ""))
6971
7072
116118 let neutrinoContract = getContractAddressOrFail(controlCfg, IdxControlCfgNeutrinoDapp)
117119
118120 let gnsbtControllerContract = getContractAddressOrFail(controlCfg, IdxControlCfgGnsbtControllerDapp)
121+
122+let surfStakingContract = getContractAddressOrFail(controlCfg, IdxControlCfgSurfStakingDapp)
119123
120124 func keyQuorumRequiredPercent (type) = ("%s%s__quorumRequired__" + type)
121125
193197 }
194198
195199
196-func statusData (isVotingValid,winOption,winOptionVotes,totalVotes,areScriptsApplied,scriptsTimestamp,canceledByTeam) = makeString(["%b%d%d%d%b%d%b", toString(isVotingValid), toString(winOption), toString(winOptionVotes), toString(totalVotes), toString(areScriptsApplied), toString(scriptsTimestamp), toString(canceledByTeam)], SEP)
200+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)
197201
198202
199203 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)
228232 let IdxEffUser = 1
229233
230234 func getEffectiveGnsbt (userAddrStrOrEmpty) = {
231- let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", [userAddrStrOrEmpty, 0, 0], nil))
232- let nsbtData = asAnyList(gnsbtData[2])
233- let userFromNsbt = asInt(nsbtData[2])
234- let totalFromNsbt = asInt(nsbtData[3])
235- let userMatureFromSurf = asInt(gnsbtData[9])
236- let totalMatureFromSurf = asInt(gnsbtData[6])
235+ let upd = if (isDefined(addressFromString(userAddrStrOrEmpty)))
236+ then invoke(surfStakingContract, "updateVotingPower", [userAddrStrOrEmpty], nil)
237+ else unit
238+ if ((upd == upd))
239+ then {
240+ let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", [userAddrStrOrEmpty, 0, 0], nil))
241+ let nsbtData = asAnyList(gnsbtData[2])
242+ let userFromNsbt = asInt(nsbtData[2])
243+ let totalFromNsbt = asInt(nsbtData[3])
244+ let userMatureFromSurf = asInt(gnsbtData[9])
245+ let totalMatureFromSurf = asInt(gnsbtData[6])
237246 [(totalFromNsbt + totalMatureFromSurf), (userFromNsbt + userMatureFromSurf)]
247+ }
248+ else throw("Strict value is not equal to itself.")
238249 }
239250
240251
296307 then 1
297308 else 0))
298309 let optionsStr = makeString(optionsList, LISTSEP)
299- $Tuple2([IntegerEntry(keyLastProposalId(), proposalId), IntegerEntry(keyProposalIdByTopicId(topicId), proposalId), StringEntry(keyProposalStatusDataById(proposalId), statusData(false, 0, 0, 0, false, 0, false)), StringEntry(keyProposalDataById(proposalId), proposalData(proposalTxId, type, author, toBase58String(toBytes(forumLink)), toBase58String(toBytes(title)), proposalTime, votingStartTime, votingEndTime, txIds, quorumInGnsbt, optionsStr)), IntegerEntry(keyNumProposalsByAuthor(author), numProposalsByAuthor), IntegerEntry(keyStatsUniqueAuthors(), uniqAuthors)], proposalTxId)
310+ $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, toBase58String(toBytes(forumLink)), toBase58String(toBytes(title)), proposalTime, votingStartTime, votingEndTime, txIds, quorumInGnsbt, optionsStr)), IntegerEntry(keyNumProposalsByAuthor(author), numProposalsByAuthor), IntegerEntry(keyStatsUniqueAuthors(), uniqAuthors)], proposalTxId)
300311 }
301312 else throw("Strict value is not equal to itself.")
302313 }
339350 }
340351
341352
342-func updateStatusData (oldData,isValid,newWinOpt,newTotalVotes) = makeString(["%b%d%d%d%b%d%b", toString(isValid), toString(newWinOpt._1), toString(newWinOpt._2), toString(newTotalVotes), oldData[govStatusIdxScApplied], oldData[govStatusIdxScTime], oldData[govStatusIdxIsCanceled]], SEP)
353+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)
343354
344355
345-func statusApplyScript (oldData) = makeString(["%b%d%d%d%b%d%b", oldData[govStatusIdxIsValid], oldData[govStatusIdxWinOpt], oldData[govStatusIdxWinVotes], oldData[govStatusIdxTotalVotes], "true", oldData[govStatusIdxScTime], oldData[govStatusIdxIsCanceled]], SEP)
356+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)
346357
347358
348359 func ExecutionHistory (updateVersion,title,url,proposalId) = {
453464 then throw("Exactly one payment required")
454465 else if ((1 > size(txList)))
455466 then throw("Transactions list is empty")
456- else initiateVoting(value(i.payments[0]), toBase58String(i.transactionId), "UPDATE", toString(i.caller), forumLink, title, votingStartTime, votingEndTime, "PENDING", txList, ["NO", "YES"])
467+ else if ((i.caller != this))
468+ then throw("not authorized")
469+ else initiateVoting(value(i.payments[0]), toBase58String(i.transactionId), "UPDATE", toString(i.caller), forumLink, title, votingStartTime, votingEndTime, "PENDING", txList, ["NO", "YES"])
457470
458471
459472
543556 }
544557
545558
559+
560+@Callable(i)
561+func changeImplStatus (proposalId,newStatus) = if ((i.caller != this))
562+ then throw("not authorized")
563+ else if (if ((newStatus != "ACTIVE"))
564+ then (newStatus != "OUTDATED")
565+ else false)
566+ then throw("Unknown implementation status")
567+ else {
568+ let dynamicData = split(getStringOrFail(this, keyProposalStatusDataById(proposalId)), SEP)
569+ 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)
570+ $Tuple2([StringEntry(keyProposalStatusDataById(proposalId), updated)], unit)
571+ }
572+
573+
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
68+let govStatusIdxImplStatus = 8
69+
6870 func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], ""))
6971
7072
7173 func getIntOrElse (key,defaultVal) = valueOrElse(getInteger(this, key), defaultVal)
7274
7375
7476 let IdxControlCfgNeutrinoDapp = 1
7577
7678 let IdxControlCfgAuctionDapp = 2
7779
7880 let IdxControlCfgRpdDapp = 3
7981
8082 let IdxControlCfgMathDapp = 4
8183
8284 let IdxControlCfgLiquidationDapp = 5
8385
8486 let IdxControlCfgRestDapp = 6
8587
8688 let IdxControlCfgNodeRegistryDapp = 7
8789
8890 let IdxControlCfgNsbtStakingDapp = 8
8991
9092 let IdxControlCfgMediatorDapp = 9
9193
9294 let IdxControlCfgSurfStakingDapp = 10
9395
9496 let IdxControlCfgGnsbtControllerDapp = 11
9597
9698 let IdxControlCfgRestV2Dapp = 12
9799
98100 let IdxControlCfgGovernanceDapp = 13
99101
100102 func keyControlAddress () = "%s%s__config__controlAddress"
101103
102104
103105 func keyControlCfg () = "%s__controlConfig"
104106
105107
106108 func readControlCfgOrFail (control) = split_4C(getStringOrFail(control, keyControlCfg()), SEP)
107109
108110
109111 func getContractAddressOrFail (controlCfg,idx) = valueOrErrorMessage(addressFromString(controlCfg[idx]), ("Control cfg doesn't contain address at index " + toString(idx)))
110112
111113
112114 let controlContract = addressFromStringValue(valueOrElse(getString(this, keyControlAddress()), "3P5Bfd58PPfNvBM2Hy8QfbcDqMeNtzg7KfP"))
113115
114116 let controlCfg = readControlCfgOrFail(controlContract)
115117
116118 let neutrinoContract = getContractAddressOrFail(controlCfg, IdxControlCfgNeutrinoDapp)
117119
118120 let gnsbtControllerContract = getContractAddressOrFail(controlCfg, IdxControlCfgGnsbtControllerDapp)
121+
122+let surfStakingContract = getContractAddressOrFail(controlCfg, IdxControlCfgSurfStakingDapp)
119123
120124 func keyQuorumRequiredPercent (type) = ("%s%s__quorumRequired__" + type)
121125
122126
123127 func keyPaymentRequired () = "%s__paymentRequired"
124128
125129
126130 func keyGnsbtRequired () = "%s__gNsbtRequired"
127131
128132
129133 func keyLastProposalId () = "%s__proposalId"
130134
131135
132136 func keyFirstProposalId () = "%s__firstProposalId"
133137
134138
135139 func keyLastUpdateVersion () = "%s__updateVersion"
136140
137141
138142 func keyProposalStatusDataById (proposalId) = ("%s%d__proposalStatusData__" + toString(proposalId))
139143
140144
141145 func keyProposalDataById (proposalId) = ("%s%d__proposalData__" + toString(proposalId))
142146
143147
144148 func keyProposalVotesByIdAndOption (proposalId,opt) = makeString(["%s%d%d", "votesByOpt", toString(proposalId), toString(opt)], SEP)
145149
146150
147151 func keyProposalVotesByIdAndUser (proposalId,userAddr) = makeString(["%s%d%s", "votesByUser", toString(proposalId), userAddr], SEP)
148152
149153
150154 func keyProposalChoiceByIdAndUser (proposalId,userAddr) = makeString(["%s%d%s", "optionByUser", toString(proposalId), userAddr], SEP)
151155
152156
153157 func keyApplyInProgress () = "%s__applyInProgress"
154158
155159
156160 func keyProposalIdByTopicId (topicId) = ("%s%d__proposalIdByTopicId__" + toString(topicId))
157161
158162
159163 func keyUserGnsbtReleaseTime (userAddr) = ("%s%s_userGnsbtReleaseTime__" + userAddr)
160164
161165
162166 func keyNumUniqueVotersByProposalId (proposalId) = ("%s%d__numVoters__" + toString(proposalId))
163167
164168
165169 func keyStatsAverUniqueVoters () = "%s%s%s__stats__avg__uniqueVoters"
166170
167171
168172 func keyStatsAverGnsbtVoted () = "%s%s%s__stats__avg__gnsbtVoted"
169173
170174
171175 func keyStatsUniqueAuthors () = "%s%s__stats__uniqueAuthors"
172176
173177
174178 func keyNumProposalsByAuthor (addressStr) = ("%s%s__numProposalsByAuthor__" + addressStr)
175179
176180
177181 func keyApplyHistory (timestamp) = ("%s%d__applyHistory__" + toString(timestamp))
178182
179183
180184 func asAnyList (v) = match v {
181185 case l: List[Any] =>
182186 l
183187 case _ =>
184188 throw("fail to cast into List[Any]")
185189 }
186190
187191
188192 func asInt (v) = match v {
189193 case i: Int =>
190194 i
191195 case _ =>
192196 throw("fail to cast into Int")
193197 }
194198
195199
196-func statusData (isVotingValid,winOption,winOptionVotes,totalVotes,areScriptsApplied,scriptsTimestamp,canceledByTeam) = makeString(["%b%d%d%d%b%d%b", toString(isVotingValid), toString(winOption), toString(winOptionVotes), toString(totalVotes), toString(areScriptsApplied), toString(scriptsTimestamp), toString(canceledByTeam)], SEP)
200+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)
197201
198202
199203 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)
200204
201205
202206 func checkTxList (txList) = if ((size(txList) > 20))
203207 then throw(("Too many transactions: " + toString(size(txList))))
204208 else {
205209 func combiner (acc,tx) = if ((size(fromBase58String(tx)) != 32))
206210 then throw(("Wrong txId: " + tx))
207211 else if ((acc == ""))
208212 then tx
209213 else ((acc + LISTSEP) + tx)
210214
211215 let $l = txList
212216 let $s = size($l)
213217 let $acc0 = ""
214218 func $f0_1 ($a,$i) = if (($i >= $s))
215219 then $a
216220 else combiner($a, $l[$i])
217221
218222 func $f0_2 ($a,$i) = if (($i >= $s))
219223 then $a
220224 else throw("List size exceeds 20")
221225
222226 $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)
223227 }
224228
225229
226230 let IdxEffTotal = 0
227231
228232 let IdxEffUser = 1
229233
230234 func getEffectiveGnsbt (userAddrStrOrEmpty) = {
231- let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", [userAddrStrOrEmpty, 0, 0], nil))
232- let nsbtData = asAnyList(gnsbtData[2])
233- let userFromNsbt = asInt(nsbtData[2])
234- let totalFromNsbt = asInt(nsbtData[3])
235- let userMatureFromSurf = asInt(gnsbtData[9])
236- let totalMatureFromSurf = asInt(gnsbtData[6])
235+ let upd = if (isDefined(addressFromString(userAddrStrOrEmpty)))
236+ then invoke(surfStakingContract, "updateVotingPower", [userAddrStrOrEmpty], nil)
237+ else unit
238+ if ((upd == upd))
239+ then {
240+ let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", [userAddrStrOrEmpty, 0, 0], nil))
241+ let nsbtData = asAnyList(gnsbtData[2])
242+ let userFromNsbt = asInt(nsbtData[2])
243+ let totalFromNsbt = asInt(nsbtData[3])
244+ let userMatureFromSurf = asInt(gnsbtData[9])
245+ let totalMatureFromSurf = asInt(gnsbtData[6])
237246 [(totalFromNsbt + totalMatureFromSurf), (userFromNsbt + userMatureFromSurf)]
247+ }
248+ else throw("Strict value is not equal to itself.")
238249 }
239250
240251
241252 func validateLink (url) = if ((value(indexOf(url, URLPATTERN)) != 0))
242253 then throw("Invalid url")
243254 else if ((size(url) > MAXURL))
244255 then throw("Url too long!")
245256 else {
246257 let topicId = valueOrErrorMessage(parseInt(drop(url, (value(lastIndexOf(url, "/")) + 1))), "Wrong topicId")
247258 let registeredId = getInteger(keyProposalIdByTopicId(topicId))
248259 if (isDefined(registeredId))
249260 then throw(("Voting with such forum link is already registered by id=" + toString(value(registeredId))))
250261 else topicId
251262 }
252263
253264
254265 func initiateVoting (payment,proposalTxId,type,author,forumLink,title,votingStartTime,votingEndTime,status,txList,optionsList) = if ((payment.assetId != unit))
255266 then throw("Allowed WAVES payment only!")
256267 else {
257268 let pmtReq = getIntOrElse(keyPaymentRequired(), DEFAULTPAYMENT)
258269 if ((pmtReq > payment.amount))
259270 then throw(("Payment attached should be at least " + toString(pmtReq)))
260271 else {
261272 let topicId = validateLink(forumLink)
262273 if ((title == ""))
263274 then throw("Title is empty")
264275 else if ((size(title) > MAXTITLE))
265276 then throw("Too long title")
266277 else {
267278 let proposalTime = lastBlock.timestamp
268279 if ((proposalTime > votingStartTime))
269280 then throw(((("votingStartTime=" + toString(votingStartTime)) + " < proposalTime=") + toString(proposalTime)))
270281 else if ((votingStartTime > votingEndTime))
271282 then throw(((("votingEndTime=" + toString(votingEndTime)) + " < votingStartTime=") + toString(votingStartTime)))
272283 else if (((votingEndTime - votingStartTime) > MAXVOTINGTIME))
273284 then throw(((("Voting period exceeds max: " + toString((votingEndTime - votingStartTime))) + " > ") + toString(MAXVOTINGTIME)))
274285 else {
275286 let txIds = if ((type == "IDEA"))
276287 then ""
277288 else checkTxList(txList)
278289 if ((1 >= size(optionsList)))
279290 then throw("Too few choices to vote")
280291 else {
281292 let eff = getEffectiveGnsbt(author)
282293 let gnsbtTotal = eff[IdxEffTotal]
283294 let gNsbtUser = eff[IdxEffUser]
284295 let gnsbtReq = getIntOrElse(keyGnsbtRequired(), DEFAULTCREATIONGNSBT)
285296 if ((gnsbtReq > gNsbtUser))
286297 then throw((("You need at least " + toString(gnsbtReq)) + " gNsbt to create voting"))
287298 else {
288299 let amountLeased = invoke(neutrinoContract, "acceptWaves", nil, [payment])
289300 if ((amountLeased == amountLeased))
290301 then {
291302 let quorum = getIntOrElse(keyQuorumRequiredPercent(type), DEFAULTQUORUM)
292303 let quorumInGnsbt = fraction(quorum, gnsbtTotal, MULT6)
293304 let proposalId = (getIntOrElse(keyLastProposalId(), 0) + 1)
294305 let numProposalsByAuthor = (getIntOrElse(keyNumProposalsByAuthor(author), 0) + 1)
295306 let uniqAuthors = (getIntOrElse(keyStatsUniqueAuthors(), 0) + (if ((numProposalsByAuthor == 1))
296307 then 1
297308 else 0))
298309 let optionsStr = makeString(optionsList, LISTSEP)
299- $Tuple2([IntegerEntry(keyLastProposalId(), proposalId), IntegerEntry(keyProposalIdByTopicId(topicId), proposalId), StringEntry(keyProposalStatusDataById(proposalId), statusData(false, 0, 0, 0, false, 0, false)), StringEntry(keyProposalDataById(proposalId), proposalData(proposalTxId, type, author, toBase58String(toBytes(forumLink)), toBase58String(toBytes(title)), proposalTime, votingStartTime, votingEndTime, txIds, quorumInGnsbt, optionsStr)), IntegerEntry(keyNumProposalsByAuthor(author), numProposalsByAuthor), IntegerEntry(keyStatsUniqueAuthors(), uniqAuthors)], proposalTxId)
310+ $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, toBase58String(toBytes(forumLink)), toBase58String(toBytes(title)), proposalTime, votingStartTime, votingEndTime, txIds, quorumInGnsbt, optionsStr)), IntegerEntry(keyNumProposalsByAuthor(author), numProposalsByAuthor), IntegerEntry(keyStatsUniqueAuthors(), uniqAuthors)], proposalTxId)
300311 }
301312 else throw("Strict value is not equal to itself.")
302313 }
303314 }
304315 }
305316 }
306317 }
307318 }
308319
309320
310321 func calcWinOption (proposalId,optionsList,isPrevOptional,oldChoice,optionalTotalOld,newChoice,newTotalByNewChoice) = {
311322 func findBest (acc,elem) = {
312323 let idx = value(indexOf(optionsList, elem))
313324 let val = if (isPrevOptional)
314325 then if ((idx == newChoice))
315326 then newTotalByNewChoice
316327 else getIntOrElse(keyProposalVotesByIdAndOption(proposalId, idx), 0)
317328 else if ((idx == value(oldChoice)))
318329 then optionalTotalOld
319330 else if ((idx == newChoice))
320331 then newTotalByNewChoice
321332 else getIntOrElse(keyProposalVotesByIdAndOption(proposalId, idx), 0)
322333 if ((acc._2 > val))
323334 then acc
324335 else $Tuple2(idx, val)
325336 }
326337
327338 let $l = optionsList
328339 let $s = size($l)
329340 let $acc0 = $Tuple2(0, 0)
330341 func $f0_1 ($a,$i) = if (($i >= $s))
331342 then $a
332343 else findBest($a, $l[$i])
333344
334345 func $f0_2 ($a,$i) = if (($i >= $s))
335346 then $a
336347 else throw("List size exceeds 10")
337348
338349 $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)
339350 }
340351
341352
342-func updateStatusData (oldData,isValid,newWinOpt,newTotalVotes) = makeString(["%b%d%d%d%b%d%b", toString(isValid), toString(newWinOpt._1), toString(newWinOpt._2), toString(newTotalVotes), oldData[govStatusIdxScApplied], oldData[govStatusIdxScTime], oldData[govStatusIdxIsCanceled]], SEP)
353+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)
343354
344355
345-func statusApplyScript (oldData) = makeString(["%b%d%d%d%b%d%b", oldData[govStatusIdxIsValid], oldData[govStatusIdxWinOpt], oldData[govStatusIdxWinVotes], oldData[govStatusIdxTotalVotes], "true", oldData[govStatusIdxScTime], oldData[govStatusIdxIsCanceled]], SEP)
356+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)
346357
347358
348359 func ExecutionHistory (updateVersion,title,url,proposalId) = {
349360 let gnsbtTotal = getEffectiveGnsbt("")[IdxEffTotal]
350361 let turnout = 500000
351362 StringEntry(keyApplyHistory(lastBlock.timestamp), makeString(["%d%d%d%s%s%d", toString(updateVersion), toString(gnsbtTotal), toString(turnout), title, url, toString(proposalId)], SEP))
352363 }
353364
354365
355366 @Callable(i)
356367 func constructorV1 (controlAddr,gNsbtReqToInit,wavesReqToInit,quorumReqPercIdea,quorumReqPercUpdate) = if ((i.caller != this))
357368 then throw("Permission denied")
358369 else [StringEntry(keyControlAddress(), controlAddr), IntegerEntry(keyGnsbtRequired(), gNsbtReqToInit), IntegerEntry(keyPaymentRequired(), wavesReqToInit), IntegerEntry(keyQuorumRequiredPercent("IDEA"), quorumReqPercIdea), IntegerEntry(keyQuorumRequiredPercent("UPDATE"), quorumReqPercUpdate)]
359370
360371
361372
362373 @Callable(i)
363374 func castVote (proposalId,choice) = {
364375 let userAddressStr = toString(i.caller)
365376 let dynamicData = split(getStringOrFail(this, keyProposalStatusDataById(proposalId)), SEP)
366377 if ((dynamicData[govStatusIdxIsCanceled] == "true"))
367378 then throw("Voting is canceled by team")
368379 else {
369380 let propData = split(getStringOrFail(this, keyProposalDataById(proposalId)), SEP)
370381 let start = parseIntValue(propData[govIdxStart])
371382 let end = parseIntValue(propData[govIdxEnd])
372383 let now = lastBlock.timestamp
373384 if ((start > now))
374385 then throw("Voting not started yet")
375386 else if ((now >= end))
376387 then throw("Voting already finished")
377388 else {
378389 let availableOptions = split(propData[govIdxOptions], LISTSEP)
379390 let numOptions = size(availableOptions)
380391 if ((1 >= numOptions))
381392 then throw("Too few choices to vote")
382393 else if ((choice >= numOptions))
383394 then throw(("Unknown choice! Must be 0.." + toString((numOptions - 1))))
384395 else {
385396 let eff = getEffectiveGnsbt(userAddressStr)
386397 let gnsbtAmt = eff[IdxEffUser]
387398 if ((0 >= gnsbtAmt))
388399 then throw("no gnsbt to vote")
389400 else {
390401 let gnsbtTotal = eff[IdxEffTotal]
391402 let oldChoice = getInteger(keyProposalChoiceByIdAndUser(proposalId, userAddressStr))
392403 let oldUserVotes = if (!(isDefined(oldChoice)))
393404 then 0
394405 else getIntOrElse(keyProposalVotesByIdAndUser(proposalId, userAddressStr), 0)
395406 let oldTotalByOldChoice = if (isDefined(oldChoice))
396407 then getIntOrElse(keyProposalVotesByIdAndOption(proposalId, value(oldChoice)), 0)
397408 else 0
398409 let oldTotalByNewChoice = getIntOrElse(keyProposalVotesByIdAndOption(proposalId, choice), 0)
399410 let oldTotal = parseIntValue(dynamicData[govStatusIdxTotalVotes])
400411 let newTotalByOldChoice = if (!(isDefined(oldChoice)))
401412 then 0
402413 else ((oldTotalByOldChoice - oldUserVotes) + (if ((value(oldChoice) == choice))
403414 then gnsbtAmt
404415 else 0))
405416 let newTotalByNewChoice = if (if (isDefined(oldChoice))
406417 then (value(oldChoice) == choice)
407418 else false)
408419 then newTotalByOldChoice
409420 else (oldTotalByNewChoice + gnsbtAmt)
410421 let newTotal = ((oldTotal - oldUserVotes) + gnsbtAmt)
411422 let isQuorumReached = (newTotal >= parseIntValue(propData[govIdxQuorum]))
412423 let numVotersByProposalId = getIntOrElse(keyNumUniqueVotersByProposalId(proposalId), 0)
413424 let oldAverUniqueVoters6 = getIntOrElse(keyStatsAverUniqueVoters(), 0)
414425 let numProposals = ((getIntegerValue(keyLastProposalId()) - valueOrElse(getInteger(keyFirstProposalId()), DEFAULTFIRSTPROPOSAL)) + 1)
415426 let uniqueDiff = if ((oldUserVotes == 0))
416427 then 1
417428 else 0
418429 let newAverUniqueVoters6 = (oldAverUniqueVoters6 + fraction(uniqueDiff, MULT6, numProposals))
419430 let oldAverGnsbt = getIntOrElse(keyStatsAverGnsbtVoted(), 0)
420431 let newAverGnsbt = (oldAverGnsbt + ((gnsbtAmt - oldUserVotes) / numProposals))
421432 let isPrevOptional = if (!(isDefined(oldChoice)))
422433 then true
423434 else (value(oldChoice) == choice)
424435 let optionalTotalOld = if (isPrevOptional)
425436 then nil
426437 else [IntegerEntry(keyProposalVotesByIdAndOption(proposalId, value(oldChoice)), newTotalByOldChoice)]
427438 let winOpt = calcWinOption(proposalId, availableOptions, isPrevOptional, oldChoice, newTotalByOldChoice, choice, newTotalByNewChoice)
428439 let releaseTime = max([end, getIntOrElse(keyUserGnsbtReleaseTime(userAddressStr), 0)])
429440 $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)
430441 }
431442 }
432443 }
433444 }
434445 }
435446
436447
437448
438449 @Callable(i)
439450 func initiateIdeaVoting (forumLink,title,votingStartTime,votingEndTime,optionsList) = if ((size(i.payments) != 1))
440451 then throw("Exactly one payment required")
441452 else if ((size(optionsList) != 2))
442453 then throw("Exactly 2 option ['NO', 'YES'] are expected")
443454 else if ((optionsList[0] != "NO"))
444455 then throw("Option NO should be the first")
445456 else if ((optionsList[1] != "YES"))
446457 then throw("Option YES should be the second")
447458 else initiateVoting(value(i.payments[0]), toBase58String(i.transactionId), "IDEA", toString(i.caller), forumLink, title, votingStartTime, votingEndTime, "PENDING", nil, optionsList)
448459
449460
450461
451462 @Callable(i)
452463 func initiateUpdateVoting (forumLink,title,votingStartTime,votingEndTime,txList) = if ((size(i.payments) != 1))
453464 then throw("Exactly one payment required")
454465 else if ((1 > size(txList)))
455466 then throw("Transactions list is empty")
456- else initiateVoting(value(i.payments[0]), toBase58String(i.transactionId), "UPDATE", toString(i.caller), forumLink, title, votingStartTime, votingEndTime, "PENDING", txList, ["NO", "YES"])
467+ else if ((i.caller != this))
468+ then throw("not authorized")
469+ else initiateVoting(value(i.payments[0]), toBase58String(i.transactionId), "UPDATE", toString(i.caller), forumLink, title, votingStartTime, votingEndTime, "PENDING", txList, ["NO", "YES"])
457470
458471
459472
460473 @Callable(i)
461474 func cancelVoting (proposalId) = if ((i.caller != this))
462475 then throw("not authorized")
463476 else {
464477 let currentData = getStringOrFail(this, keyProposalStatusDataById(proposalId))
465478 let updatedData = ((take(currentData, value(lastIndexOf(currentData, SEP))) + SEP) + "true")
466479 $Tuple2([StringEntry(keyProposalStatusDataById(proposalId), updatedData)], unit)
467480 }
468481
469482
470483
471484 @Callable(i)
472485 func applyUpdate (proposalId) = {
473486 let propData = split(getStringOrFail(this, keyProposalDataById(proposalId)), SEP)
474487 let end = parseIntValue(propData[govIdxEnd])
475488 let now = lastBlock.timestamp
476489 if ((end > now))
477490 then throw("Voting is not finished yet")
478491 else if (("UPDATE" != propData[govIdxType]))
479492 then throw("Only UPDATE type can be applied")
480493 else {
481494 let dynamicData = split(getStringOrFail(this, keyProposalStatusDataById(proposalId)), SEP)
482495 if ((dynamicData[govStatusIdxIsCanceled] == "true"))
483496 then throw("Voting is canceled")
484497 else if ((dynamicData[govStatusIdxIsValid] != "true"))
485498 then throw("Voting status invalid")
486499 else if ((dynamicData[govStatusIdxWinOpt] != "1"))
487500 then throw("Winner is 'NO' - nothing to apply")
488501 else if ((dynamicData[govStatusIdxScApplied] == "true"))
489502 then throw("Scripts are already applied")
490503 else {
491504 let scriptTime = parseIntValue(dynamicData[govStatusIdxScTime])
492505 if (((now - PASTMARGIN) > scriptTime))
493506 then throw((("Scripts timestamp=" + toString(scriptTime)) + " is too far in the past, max 2 hrs allowed"))
494507 else if ((scriptTime > (now + FUTUREMARGIN)))
495508 then throw((("Scripts timestamp=" + toString(scriptTime)) + " is too far in the future, max 1.5 hrs allowed"))
496509 else {
497510 let inProgressId = getIntOrElse(keyApplyInProgress(), -1)
498511 if ((inProgressId != -1))
499512 then throw((("proposalId=" + toString(inProgressId)) + " is already being applied. Finish it first!"))
500513 else {
501514 let shutdown = invoke(controlContract, "callEmergencyShutdown", ["Applying Governance UPDATE"], nil)
502515 if ((shutdown == shutdown))
503516 then $Tuple2([IntegerEntry(keyApplyInProgress(), proposalId)], unit)
504517 else throw("Strict value is not equal to itself.")
505518 }
506519 }
507520 }
508521 }
509522 }
510523
511524
512525
513526 @Callable(i)
514527 func finishApply () = {
515528 let proposalId = valueOrErrorMessage(getInteger(keyApplyInProgress()), "No apply in progress, nothing to finish")
516529 let propData = split(getStringOrFail(this, keyProposalDataById(proposalId)), SEP)
517530 let txList = split(propData[govIdxTxIds], LISTSEP)
518531 let dynamicData = split(getStringOrFail(this, keyProposalStatusDataById(proposalId)), SEP)
519532 if ((dynamicData[govStatusIdxScApplied] == "true"))
520533 then throw("Scripts are already applied")
521534 else {
522535 func checker (acc,tx) = if (!(isDefined(transactionHeightById(fromBase58String(tx)))))
523536 then throw(("NOT applied txId: " + tx))
524537 else unit
525538
526539 let ignored = {
527540 let $l = txList
528541 let $s = size($l)
529542 let $acc0 = unit
530543 func $f0_1 ($a,$i) = if (($i >= $s))
531544 then $a
532545 else checker($a, $l[$i])
533546
534547 func $f0_2 ($a,$i) = if (($i >= $s))
535548 then $a
536549 else throw("List size exceeds 20")
537550
538551 $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)
539552 }
540553 let version = (getIntOrElse(keyLastUpdateVersion(), 0) + 1)
541554 $Tuple2([DeleteEntry(keyApplyInProgress()), IntegerEntry(keyLastUpdateVersion(), version), StringEntry(keyProposalStatusDataById(proposalId), statusApplyScript(dynamicData)), ExecutionHistory(version, propData[govIdxTitle], propData[govIdxUrl], proposalId)], ignored)
542555 }
543556 }
544557
545558
559+
560+@Callable(i)
561+func changeImplStatus (proposalId,newStatus) = if ((i.caller != this))
562+ then throw("not authorized")
563+ else if (if ((newStatus != "ACTIVE"))
564+ then (newStatus != "OUTDATED")
565+ else false)
566+ then throw("Unknown implementation status")
567+ else {
568+ let dynamicData = split(getStringOrFail(this, keyProposalStatusDataById(proposalId)), SEP)
569+ 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)
570+ $Tuple2([StringEntry(keyProposalStatusDataById(proposalId), updated)], unit)
571+ }
572+
573+

github/deemru/w8io/873ac7e 
82.43 ms