tx · 2Aizk9BvQhe4hE4fKr7ESsrye6nc7wiqJMWSHWinh8fb 3MsU936briqQ2XZMpkhWdrV8EsNwm5iCuRY: -0.02100000 Waves 2023.05.11 12:59 [2573068] smart account 3MsU936briqQ2XZMpkhWdrV8EsNwm5iCuRY > SELF 0.00000000 Waves
{ "type": 13, "id": "2Aizk9BvQhe4hE4fKr7ESsrye6nc7wiqJMWSHWinh8fb", "fee": 2100000, "feeAssetId": null, "timestamp": 1683799210059, "version": 2, "chainId": 84, "sender": "3MsU936briqQ2XZMpkhWdrV8EsNwm5iCuRY", "senderPublicKey": "F471QhzucRgQCSkZK5opBNc55AoNgiibCabvTp6GZ9nq", "proofs": [ "5CuF1ASA512qJSUJ241ozu9msKtLpBihHxmq438j1vpQ2sfGDthHeC1MCoUKKnouibgxZQTtFSUQ2srKR6NPCqkN" ], "script": "base64:BgI6CAISBwoFAQgIAQESBQoDCAgIEgASAwoBCBIDCgEIEgYKBAgIAQESAwoBCBIGCgQBAQgIEgUKAwgICEoAA1NFUAICX18ABU1VTFQ2AMCEPQAFTVVMVDgAgMLXLwAKV0FWRVNJRFNUUgIFV0FWRVMAB1dBVkVTSUQJANkEAQUKV0FWRVNJRFNUUgEMZ2V0SW50T3JGYWlsAQNrZXkJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBQR0aGlzBQNrZXkJAKwCAgkArAICAg9NYW5kYXRvcnkgdGhpcy4FA2tleQIPIGlzIG5vdCBkZWZpbmVkAQxnZXRJbnRPckVsc2UCA2tleQN2YWwJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwUDa2V5BQN2YWwBDGdldFN0ck9yRWxzZQMHYWRkcmVzcwNrZXkKZGVmYXVsdFZhbAkBC3ZhbHVlT3JFbHNlAgkAnQgCBQdhZGRyZXNzBQNrZXkFCmRlZmF1bHRWYWwBD2dldFN0cmluZ09yRmFpbAIHYWRkcmVzcwNrZXkJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBQdhZGRyZXNzBQNrZXkJAKwCAgkArAICAg9NYW5kYXRvcnkgdGhpcy4FA2tleQIPIGlzIG5vdCBkZWZpbmVkARBnZXRBZGRyZXNzT3JGYWlsAQNrZXkJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQEPZ2V0U3RyaW5nT3JGYWlsAgUEdGhpcwUDa2V5CQCsAgIJAKwCAgIVRmFpbCB0byBjb252ZXJ0IHRoaXMuBQNrZXkCEyB2YWx1ZSBpbnRvIEFkZHJlc3MBCWFzQW55TGlzdAEDdmFsBAckbWF0Y2gwBQN2YWwDCQABAgUHJG1hdGNoMAIJTGlzdFtBbnldBAp2YWxBbnlMaXN0BQckbWF0Y2gwBQp2YWxBbnlMaXN0CQACAQIbZmFpbCB0byBjYXN0IGludG8gTGlzdFtBbnldAQVhc0ludAEBdgQHJG1hdGNoMAUBdgMJAAECBQckbWF0Y2gwAgNJbnQEAWkFByRtYXRjaDAFAWkJAAIBAhVmYWlsIHRvIGNhc3QgaW50byBJbnQBC2FzQnl0ZVZlY290AQF2BAckbWF0Y2gwBQF2AwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEAWkFByRtYXRjaDAFAWkJAAIBAhxmYWlsIHRvIGNhc3QgaW50byBCeXRlVmVjdG9yARV2YWxpZGF0ZUFkZHJlc3NPckZhaWwBCmFkZHJlc3NTdHIEB2FkZHJlc3MJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBBQphZGRyZXNzU3RyCQCsAgICHWZhaWwgdG8gY29udmVydCBpbnRvIGFkZHJlc3MgBQphZGRyZXNzU3RyAwkAZgIAAAgJAO8HAQUHYWRkcmVzcwlhdmFpbGFibGUJAQV0aHJvdwAFCmFkZHJlc3NTdHIBD2tleU5vZGVSZWdpc3RyeQEHYWRkcmVzcwkArAICAgQlc19fBQdhZGRyZXNzARRrZXlOb2RlUmV3YXJkc1RvdGFscwEHYWRkcmVzcwkArAICAg4lcyVzX190b3RhbHNfXwUHYWRkcmVzcwETa2V5QXBwcm92ZWROb2RlTGlzdAACFCVzX19hcHByb3ZlZE5vZGVMaXN0ARBrZXlEZXBvc2l0QW1vdW50AAIYJXMlc19fY2ZnX19kZXBvc2l0QW1vdW50ARVrZXlOZXV0cmlub0FkZHJlc3NTdHIAAholcyVzX19jZmdfX25ldXRyaW5vQWRkcmVzcwEXa2V5TWFzdGVyTm9kZUFkZHJlc3NTdHIAAiIlcyVzX19jZmdfX21haW5OZXV0cmlub05vZGVBZGRyZXNzARFrZXlQcm90b2NvbFBhcnRYNgACGSVzJXNfX2NmZ19fcHJvdG9jb2xQYXJ0WDYBE2tleUJlbmlmaWNhcnlQYXJ0WDYAAhslcyVzX19jZmdfX2JlbmlmaWNhcnlQYXJ0WDYBFmtleU1pbkRpc3RyaWJ1dGVBbW91bnQAAh4lcyVzX19jZmdfX21pbkRpc3RyaWJ1dGVBbW91bnQBHGtleVN3b3BmaVVzZHRVc2RuUG9vbEFkZHJlc3MAAiQlcyVzX19jZmdfX3N3b3BmaVVzZHRVc2RuUG9vbEFkZHJlc3MBEGtleVd4U3dhcEFkZHJlc3MAAhglcyVzX19jZmdfX3d4U3dhcEFkZHJlc3MBEWtleVNhdmluZ3NBZGRyZXNzAAIZJXMlc19fY2ZnX19zYXZpbmdzQWRkcmVzcwEVa2V5QmVuZWZpY2lhcnlBZGRyZXNzAAIdJXMlc19fY2ZnX19iZW5lZmljaWFyeUFkZHJlc3MBFWtleU5vZGVzVm90aW5nTmV4dE51bQACIyVzJXNfX25vZGVzVm90aW5nQ2ZnX19uZXh0Vm90aW5nTnVtARdrZXlOb2Rlc1ZvdGluZ09wdGlvbktleQIJdm90aW5nTnVtCW9wdGlvbk51bQkAuQkCCQDMCAICFiVzJWQlc19fbm9kZXNWb3RpbmdDZmcJAMwIAgUJdm90aW5nTnVtCQDMCAIFCW9wdGlvbk51bQUDbmlsBQNTRVABEmtleU5vZGVzVm90aW5nRGVzYwEJdm90aW5nTnVtCQC5CQIJAMwIAgIWJXMlZCVzX19ub2Rlc1ZvdGluZ0NmZwkAzAgCBQl2b3RpbmdOdW0JAMwIAgILZGVzY3JpcHRpb24FA25pbAUDU0VQARlrZXlOb2Rlc1ZvdGluZ1N0YXJ0SGVpZ2h0AQl2b3RpbmdOdW0JALkJAgkAzAgCAhYlcyVkJXNfX25vZGVzVm90aW5nQ2ZnCQDMCAIFCXZvdGluZ051bQkAzAgCAhF2b3RpbmdTdGFydEhlaWdodAUDbmlsBQNTRVABF2tleU5vZGVzVm90aW5nRW5kSGVpZ2h0AQl2b3RpbmdOdW0JALkJAgkAzAgCAhYlcyVkJXNfX25vZGVzVm90aW5nQ2ZnCQDMCAIFCXZvdGluZ051bQkAzAgCAg92b3RpbmdFbmRIZWlnaHQFA25pbAUDU0VQAR5rZXlOb2Rlc1ZvdGluZ09wdGlvblRvdGFsVm90ZXMCCXZvdGluZ051bQlvcHRpb25OdW0JALkJAgkAzAgCAhklcyVkJXMlc19fbm9kZXNWb3RpbmdEYXRhCQDMCAIFCXZvdGluZ051bQkAzAgCAhBvcHRpb25Ub3RhbFZvdGVzCQDMCAIFCW9wdGlvbk51bQUDbmlsBQNTRVABGGtleU5vZGVzVm90aW5nTm9kZUNob2ljZQIJdm90aW5nTnVtDm5vZGVBZGRyZXNzU3RyCQC5CQIJAMwIAgIZJXMlZCVzJXNfX25vZGVzVm90aW5nRGF0YQkAzAgCBQl2b3RpbmdOdW0JAMwIAgIKbm9kZUNob2ljZQkAzAgCBQ5ub2RlQWRkcmVzc1N0cgUDbmlsBQNTRVAAGUlkeENvbnRyb2xDZmdOZXV0cmlub0RhcHAAAQAYSWR4Q29udHJvbENmZ0F1Y3Rpb25EYXBwAAIAFElkeENvbnRyb2xDZmdScGREYXBwAAMAFUlkeENvbnRyb2xDZmdNYXRoRGFwcAAEABxJZHhDb250cm9sQ2ZnTGlxdWlkYXRpb25EYXBwAAUAFUlkeENvbnRyb2xDZmdSZXN0RGFwcAAGAB1JZHhDb250cm9sQ2ZnTm9kZVJlZ2lzdHJ5RGFwcAAHABxJZHhDb250cm9sQ2ZnTnNidFN0YWtpbmdEYXBwAAgAGUlkeENvbnRyb2xDZmdNZWRpYXRvckRhcHAACQAcSWR4Q29udHJvbENmZ1N1cmZTdGFraW5nRGFwcAAKACBJZHhDb250cm9sQ2ZnR25zYnRDb250cm9sbGVyRGFwcAALABdJZHhDb250cm9sQ2ZnUmVzdFYyRGFwcAAMABtJZHhDb250cm9sQ2ZnR292ZXJuYW5jZURhcHAADQERa2V5Q29udHJvbEFkZHJlc3MAAhwlcyVzX19jb25maWdfX2NvbnRyb2xBZGRyZXNzAQ1rZXlDb250cm9sQ2ZnAAIRJXNfX2NvbnRyb2xDb25maWcBDmtleVVzZG5Bc3NldElkAAIRbmV1dHJpbm9fYXNzZXRfaWQBFHJlYWRDb250cm9sQ2ZnT3JGYWlsAQdjb250cm9sCQC8CQIJAQ9nZXRTdHJpbmdPckZhaWwCBQdjb250cm9sCQENa2V5Q29udHJvbENmZwAFA1NFUAEYZ2V0Q29udHJhY3RBZGRyZXNzT3JGYWlsAgpjb250cm9sQ2ZnA2lkeAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJAJEDAgUKY29udHJvbENmZwUDaWR4CQCsAgICLUNvbnRyb2wgY2ZnIGRvZXNuJ3QgY29udGFpbiBhZGRyZXNzIGF0IGluZGV4IAkApAMBBQNpZHgAD2NvbnRyb2xDb250cmFjdAkBEUBleHRyTmF0aXZlKDEwNjIpAQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzCQERa2V5Q29udHJvbEFkZHJlc3MAAiMzTjROUzdkNEpvOWE2RjE0TGlGVUtLWVZkVWtrZjJlUDRaeAAKY29udHJvbENmZwkBFHJlYWRDb250cm9sQ2ZnT3JGYWlsAQUPY29udHJvbENvbnRyYWN0ABBuZXV0cmlub0NvbnRyYWN0CQEYZ2V0Q29udHJhY3RBZGRyZXNzT3JGYWlsAgUKY29udHJvbENmZwUZSWR4Q29udHJvbENmZ05ldXRyaW5vRGFwcAAOdXNkbkFzc2V0SWRTdHIJAQxnZXRTdHJPckVsc2UDBRBuZXV0cmlub0NvbnRyYWN0CQEOa2V5VXNkbkFzc2V0SWQAAixIZXpzZFF1UkR0emtzQVlVeTk3Z2ZoS3k3WjFOVzJ1WFlTSEEzYmdxZW5OWgALdXNkbkFzc2V0SWQJANkEAQUOdXNkbkFzc2V0SWRTdHIADG5SZWdJZHhUeEFkZAABABBuUmVnSWR4SGVpZ2h0QWRkAAIADm5SZWdJZHhUaW1lQWRkAAMADm5SZWdJZHhEZXBvQW10AAQAEm5SZWdJZHhEZXBvQW10TGVmdAAFAA1uUmVnSWR4U3RhdHVzAAYAGW5SZWdJZHhTdGF0dXNDaGFuZ2VIZWlnaHQABwAXblJlZ0lkeFN0YXR1c0NoYW5nZVRpbWUACAEQZm9ybWF0RGVwb3NpdEFkZAQHdHhJZFN0cg1kZXBvc2l0QW1vdW50FnJlbWFpbmluZ0RlcG9zaXRBbW91bnQGc3RhdHVzCQC5CQIJAMwIAgIQJXMlZCVkJWQlZCVzJWQlZAkAzAgCBQd0eElkU3RyCQDMCAIJAKQDAQgFCWxhc3RCbG9jawZoZWlnaHQJAMwIAgkApAMBCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAkAzAgCCQCkAwEFDWRlcG9zaXRBbW91bnQJAMwIAgkApAMBBRZyZW1haW5pbmdEZXBvc2l0QW1vdW50CQDMCAIFBnN0YXR1cwkAzAgCAgEwCQDMCAICATAFA25pbAUDU0VQARlmb3JtYXREZXBvc2l0Q2hhbmdlU3RhdHVzAgVvcmlnUwluZXdTdGF0dXMEBG9yaWcJALUJAgUFb3JpZ1MFA1NFUAkAuQkCCQDMCAICECVzJWQlZCVkJWQlcyVkJWQJAMwIAgkAkQMCBQRvcmlnBQxuUmVnSWR4VHhBZGQJAMwIAgkAkQMCBQRvcmlnBRBuUmVnSWR4SGVpZ2h0QWRkCQDMCAIJAJEDAgUEb3JpZwUOblJlZ0lkeFRpbWVBZGQJAMwIAgkAkQMCBQRvcmlnBQ5uUmVnSWR4RGVwb0FtdAkAzAgCCQCRAwIFBG9yaWcFEm5SZWdJZHhEZXBvQW10TGVmdAkAzAgCBQluZXdTdGF0dXMJAMwIAgkApAMBCAUJbGFzdEJsb2NrBmhlaWdodAkAzAgCCQCkAwEIBQlsYXN0QmxvY2sJdGltZXN0YW1wBQNuaWwFA1NFUAEQa2V5UmV3YXJkSGlzdG9yeQILbm9kZUFkZHJlc3MEdHhJZAkAuQkCCQDMCAICBiVzJXMlcwkAzAgCAgdoaXN0b3J5CQDMCAIJAKUIAQULbm9kZUFkZHJlc3MJAMwIAgkA2AQBBQR0eElkBQNuaWwFA1NFUAERZGF0YVJld2FyZEhpc3RvcnkFEHdhdmVzQW1vdW50VG90YWwOYmVuZWZpY2lhcnlBbXQLcHJvdG9jb2xBbXQQcHJvdG9jb2xBbXRQYXJ0MRBwcm90b2NvbEFtdFBhcnQyCQC5CQIJAMwIAgIOJWQlZCVkJWQlZCVkJWQJAMwIAgkApAMBCAUJbGFzdEJsb2NrBmhlaWdodAkAzAgCCQCkAwEIBQlsYXN0QmxvY2sJdGltZXN0YW1wCQDMCAIJAKQDAQUQd2F2ZXNBbW91bnRUb3RhbAkAzAgCCQCkAwEFDmJlbmVmaWNpYXJ5QW10CQDMCAIJAKQDAQULcHJvdG9jb2xBbXQJAMwIAgkApAMBBRBwcm90b2NvbEFtdFBhcnQxCQDMCAIJAKQDAQUQcHJvdG9jb2xBbXRQYXJ0MgUDbmlsBQNTRVABElJld2FyZEhpc3RvcnlFbnRyeQcLbm9kZUFkZHJlc3MEdHhJZAhtaW5lZEFtdA5iZW5lZmljaWFyeUFtdAtwcm90b2NvbEFtdAxwcm90b2NvbEFtdDEMcHJvdG9jb2xBbXQyCQELU3RyaW5nRW50cnkCCQEQa2V5UmV3YXJkSGlzdG9yeQIFC25vZGVBZGRyZXNzBQR0eElkCQERZGF0YVJld2FyZEhpc3RvcnkFBQhtaW5lZEFtdAUOYmVuZWZpY2lhcnlBbXQFC3Byb3RvY29sQW10BQxwcm90b2NvbEFtdDEFDHByb3RvY29sQW10MgEQZGF0YVJld2FyZFRvdGFscwUIbWluZWRBbXQOYmVuZWZpY2lhcnlBbXQLcHJvdG9jb2xBbXQQcHJvdG9jb2xBbXRQYXJ0MRBwcm90b2NvbEFtdFBhcnQyCQC5CQIJAMwIAgIKJWQlZCVkJWQlZAkAzAgCCQCkAwEFCG1pbmVkQW10CQDMCAIJAKQDAQUOYmVuZWZpY2lhcnlBbXQJAMwIAgkApAMBBQtwcm90b2NvbEFtdAkAzAgCCQCkAwEFEHByb3RvY29sQW10UGFydDEJAMwIAgkApAMBBRBwcm90b2NvbEFtdFBhcnQyBQNuaWwFA1NFUAERUmV3YXJkVG90YWxzRW50cnkGBW1pbmVyCG1pbmVkQW10DmJlbmVmaWNpYXJ5QW10C3Byb3RvY29sQW10EHByb3RvY29sQW10UGFydDEQcHJvdG9jb2xBbXRQYXJ0MgQUbm9kZVJld2FyZHNUb3RhbHNLRVkJARRrZXlOb2RlUmV3YXJkc1RvdGFscwEJAKUIAQUFbWluZXIEEG5vZGVSZXdhcmRzQXJyYXkJALUJAgkBDGdldFN0ck9yRWxzZQMFBHRoaXMFFG5vZGVSZXdhcmRzVG90YWxzS0VZCQEQZGF0YVJld2FyZFRvdGFscwUAAAAAAAAAAAAABQNTRVAEC25ld01pbmVkQW10CQBkAgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFEG5vZGVSZXdhcmRzQXJyYXkAAQUIbWluZWRBbXQEEW5ld0JlbmVmaWNpYXJ5QW10CQBkAgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFEG5vZGVSZXdhcmRzQXJyYXkAAgUOYmVuZWZpY2lhcnlBbXQEDm5ld1Byb3RvY29sQW10CQBkAgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFEG5vZGVSZXdhcmRzQXJyYXkAAwULcHJvdG9jb2xBbXQEE25ld1Byb3RvY29sQW10UGFydDEJAGQCCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUQbm9kZVJld2FyZHNBcnJheQAEBRBwcm90b2NvbEFtdFBhcnQxBBNuZXdQcm90b2NvbEFtdFBhcnQyCQBkAgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFEG5vZGVSZXdhcmRzQXJyYXkABQUQcHJvdG9jb2xBbXRQYXJ0MgkBC1N0cmluZ0VudHJ5AgUUbm9kZVJld2FyZHNUb3RhbHNLRVkJARBkYXRhUmV3YXJkVG90YWxzBQULbmV3TWluZWRBbXQFEW5ld0JlbmVmaWNpYXJ5QW10BQ5uZXdQcm90b2NvbEFtdAUTbmV3UHJvdG9jb2xBbXRQYXJ0MQUTbmV3UHJvdG9jb2xBbXRQYXJ0MgEUcmVzb2x2ZUJlbmVmaWNpYXJpZXMCDG1pbmVyQWRkcmVzcxRiZW5lZmljaWFyeUZyb21QYXJhbQQZYmVuZWZpY2lhcnlGcm9tTWluZXJTdGF0ZQkBEUBleHRyTmF0aXZlKDEwNjIpAQkBD2dldFN0cmluZ09yRmFpbAIFDG1pbmVyQWRkcmVzcwkBFWtleUJlbmVmaWNpYXJ5QWRkcmVzcwADCQAAAgkA8QcBBQxtaW5lckFkZHJlc3MFBHVuaXQFFGJlbmVmaWNpYXJ5RnJvbVBhcmFtBRliZW5lZmljaWFyeUZyb21NaW5lclN0YXRlAR1yZWFkTm9kZURhdGFBbmRWYWxpZGF0ZVN0YXR1cwIIbm9kZUFkZHIOZXhwZWN0ZWRTdGF0dXMEC25vZGVEYXRhT3B0CQCiCAEJAQ9rZXlOb2RlUmVnaXN0cnkBBQhub2RlQWRkcgMJAQEhAQkBCWlzRGVmaW5lZAEFC25vZGVEYXRhT3B0CQACAQkArAICAg1Vbmtub3duIE5vZGUgBQhub2RlQWRkcgQLbm9kZURhdGFTdHIJAQV2YWx1ZQEFC25vZGVEYXRhT3B0BAhub2RlRGF0YQkAtQkCBQtub2RlRGF0YVN0cgUDU0VQBApub2RlU3RhdHVzAwkAZwIJAJADAQUIbm9kZURhdGEACQkAkQMCBQhub2RlRGF0YQUNblJlZ0lkeFN0YXR1cwIHUEVORElORwMJAQIhPQIFCm5vZGVTdGF0dXMFDmV4cGVjdGVkU3RhdHVzCQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgICBU5vZGUgBQhub2RlQWRkcgISIHN0YXR1cyBzaG91bGQgYmUgBQ5leHBlY3RlZFN0YXR1cwIPLCBidXQgYWN0dWFsbHkgBQpub2RlU3RhdHVzBQtub2RlRGF0YVN0cgkBaQENY29uc3RydWN0b3JWMQUNZGVwb3NpdEFtb3VudBJuZXV0cmlub0FkZHJlc3NTdHIUbWFzdGVyTm9kZUFkZHJlc3NTdHIOcHJvdG9jb2xQYXJ0WDYQYmVuaWZpY2FyeVBhcnRYNgMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECEnBlcm1pc3Npb25zIGRlbmllZAMJAGYCAAAFDWRlcG9zaXRBbW91bnQJAAIBAhxkZXBvc2l0QW1vdW50IGxlc3MgdGhlbiB6ZXJvAwkAZgIAAAUOcHJvdG9jb2xQYXJ0WDYJAAIBAh1wcm90b2NvbFBhcnRYNiBsZXNzIHRoZW4gemVybwMJAGYCAAAFEGJlbmlmaWNhcnlQYXJ0WDYJAAIBAh9iZW5pZmljYXJ5UGFydFg2IGxlc3MgdGhlbiB6ZXJvAwkBAiE9AgkAZAIFDnByb3RvY29sUGFydFg2BRBiZW5pZmljYXJ5UGFydFg2BQVNVUxUNgkAAgECE3BhcnRzIHN1bSBtdXN0IGJlIDEJAMwIAgkBDEludGVnZXJFbnRyeQIJARBrZXlEZXBvc2l0QW1vdW50AAUNZGVwb3NpdEFtb3VudAkAzAgCCQELU3RyaW5nRW50cnkCCQEVa2V5TmV1dHJpbm9BZGRyZXNzU3RyAAkBFXZhbGlkYXRlQWRkcmVzc09yRmFpbAEFEm5ldXRyaW5vQWRkcmVzc1N0cgkAzAgCCQELU3RyaW5nRW50cnkCCQEXa2V5TWFzdGVyTm9kZUFkZHJlc3NTdHIACQEVdmFsaWRhdGVBZGRyZXNzT3JGYWlsAQUUbWFzdGVyTm9kZUFkZHJlc3NTdHIJAMwIAgkBDEludGVnZXJFbnRyeQIJARFrZXlQcm90b2NvbFBhcnRYNgAFDnByb3RvY29sUGFydFg2CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQETa2V5QmVuaWZpY2FyeVBhcnRYNgAFEGJlbmlmaWNhcnlQYXJ0WDYFA25pbAFpAQ1jb25zdHJ1Y3RvclYyAxBzd29wZmlBZGRyZXNzU3RyEWNvbnRyb2xBZGRyZXNzU3RyEXNhdmluZ3NBZGRyZXNzU3RyAwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIScGVybWlzc2lvbnMgZGVuaWVkCQDMCAIJAQtTdHJpbmdFbnRyeQIJARxrZXlTd29wZmlVc2R0VXNkblBvb2xBZGRyZXNzAAkBFXZhbGlkYXRlQWRkcmVzc09yRmFpbAEFEHN3b3BmaUFkZHJlc3NTdHIJAMwIAgkBC1N0cmluZ0VudHJ5AgkBEWtleUNvbnRyb2xBZGRyZXNzAAkBFXZhbGlkYXRlQWRkcmVzc09yRmFpbAEFEWNvbnRyb2xBZGRyZXNzU3RyCQDMCAIJAQtTdHJpbmdFbnRyeQIJARFrZXlTYXZpbmdzQWRkcmVzcwAJARV2YWxpZGF0ZUFkZHJlc3NPckZhaWwBBRFzYXZpbmdzQWRkcmVzc1N0cgUDbmlsAWkBEXN1bWJpdEFwcGxpY2F0aW9uAAMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAQkAAgECIGV4YWN0IDEgcGF5bWVudCBtdXN0IGJlIGF0dGFjaGVkAwkBAiE9AggFAWkGY2FsbGVyCAUBaQxvcmlnaW5DYWxsZXIJAAIBAiJkYXBwIHRvIGRhcHAgY2FsbHMgYXJlIG5vdCBhbGxvd2VkBANwbXQJAJEDAggFAWkIcGF5bWVudHMAAAQHZGVwb3NpdAgFA3BtdAZhbW91bnQECnBtdEFzc2V0SWQJAQt2YWx1ZU9yRWxzZQIIBQNwbXQHYXNzZXRJZAUHV0FWRVNJRAQVZXhwZWN0ZWREZXBvc2l0QW1vdW50CQEMZ2V0SW50T3JGYWlsAQkBEGtleURlcG9zaXRBbW91bnQABAR0eElkCQDYBAEIBQFpDXRyYW5zYWN0aW9uSWQEC25vZGVBZGRyZXNzCQClCAEIBQFpBmNhbGxlcgQPbm9kZVJlZ2lzdHJ5S0VZCQEPa2V5Tm9kZVJlZ2lzdHJ5AQULbm9kZUFkZHJlc3MDCQECIT0CBQpwbXRBc3NldElkBQdXQVZFU0lECQACAQIib25seSBXYXZlcyBjYW4gYmUgdXNlZCBmb3IgZGVwb3NpdAMJAQIhPQIFB2RlcG9zaXQFFWV4cGVjdGVkRGVwb3NpdEFtb3VudAkAAgEJAKwCAgkArAICAghleGFjdGx5IAkApAMBBRVleHBlY3RlZERlcG9zaXRBbW91bnQCFiBXYXZlbGV0cyBhcmUgZXhwZWN0ZWQDCQECIT0CCQEMZ2V0U3RyT3JFbHNlAwUEdGhpcwUPbm9kZVJlZ2lzdHJ5S0VZAgACAAkAAgECHHlvdXIgbm9kZSBhbHJlYWR5IHJlZ2lzdGVyZWQJAMwIAgkBC1N0cmluZ0VudHJ5AgUPbm9kZVJlZ2lzdHJ5S0VZCQEQZm9ybWF0RGVwb3NpdEFkZAQFBHR4SWQFB2RlcG9zaXQFB2RlcG9zaXQCB1BFTkRJTkcFA25pbAFpARVkaXN0cmlidXRlTWluZXJSZXdhcmQBFWJlbmVmaWNpYXJ5QWRkcmVzc1N0cgQTbWluRGlzdHJpYnV0ZUFtb3VudAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEWa2V5TWluRGlzdHJpYnV0ZUFtb3VudAAJAGgCABgFBU1VTFQ4AwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwABCQACAQIgZXhhY3QgMSBwYXltZW50IG11c3QgYmUgYXR0YWNoZWQDCQECIT0CCAUBaQZjYWxsZXIIBQFpDG9yaWdpbkNhbGxlcgkAAgECImRhcHAgdG8gZGFwcCBjYWxscyBhcmUgbm90IGFsbG93ZWQEA3BtdAkAkQMCCAUBaQhwYXltZW50cwAABApwbXRBc3NldElkCQELdmFsdWVPckVsc2UCCAUDcG10B2Fzc2V0SWQFB1dBVkVTSUQEBmZlZUFtdAgFAWkDZmVlBApmZWVBc3NldElkCQELdmFsdWVPckVsc2UCCAUBaQpmZWVBc3NldElkBQdXQVZFU0lEBApjYWxsUmV3YXJkCQBoAgUGZmVlQW10AAMECG1pbmVkQW10CQBlAggFA3BtdAZhbW91bnQFCmNhbGxSZXdhcmQDCQECIT0CCAUDcG10BmFtb3VudAUTbWluRGlzdHJpYnV0ZUFtb3VudAkAAgEJAKwCAgkArAICAh9hdHRhY2hlZCBwYXltZW50IG11c3QgYmUgZXhhY3QgCQCkAwEFE21pbkRpc3RyaWJ1dGVBbW91bnQCCSBXYXZlbGV0cwMJAQIhPQIFCnBtdEFzc2V0SWQFB1dBVkVTSUQJAAIBAiFvbmx5IFdhdmVzIGNhbiBiZSB1c2VkIGluIHBheW1lbnQDCQECIT0CBQpmZWVBc3NldElkBQdXQVZFU0lECQACAQIeb25seSBXYXZlcyBjYW4gYmUgdXNlZCBpbiBmZWVzAwkBAiE9AgUGZmVlQW10CQBpAgkAaAIABQUFTVVMVDgA6AcJAAIBAiBmZWUgYW1vdW50IGNvdWxkbid0IGV4Y2VlZCAwLjAwNQQPbmV1dHJpbm9BZGRyZXNzCQEQZ2V0QWRkcmVzc09yRmFpbAEJARVrZXlOZXV0cmlub0FkZHJlc3NTdHIABBFtYXN0ZXJOb2RlQWRkcmVzcwkBEGdldEFkZHJlc3NPckZhaWwBCQEXa2V5TWFzdGVyTm9kZUFkZHJlc3NTdHIABAxtaW5lckFkZHJlc3MIBQFpBmNhbGxlcgQUYmVuZWZpY2lhcnlGcm9tUGFyYW0JARFAZXh0ck5hdGl2ZSgxMDYyKQEFFWJlbmVmaWNpYXJ5QWRkcmVzc1N0cgQSYmVuZWZpY2lhcnlBZGRyZXNzCQEUcmVzb2x2ZUJlbmVmaWNpYXJpZXMCBQxtaW5lckFkZHJlc3MFFGJlbmVmaWNpYXJ5RnJvbVBhcmFtBBB0eFJld2FyZFJlY2VpdmVyBRRiZW5lZmljaWFyeUZyb21QYXJhbQQMcHJvdG9jb2xQYXJ0CQEMZ2V0SW50T3JGYWlsAQkBEWtleVByb3RvY29sUGFydFg2AAQPYmVuZWZpY2lhcnlQYXJ0CQEMZ2V0SW50T3JGYWlsAQkBE2tleUJlbmlmaWNhcnlQYXJ0WDYABA5iZW5lZmljaWFyeUFtdAkAawMFCG1pbmVkQW10BQ9iZW5lZmljaWFyeVBhcnQFBU1VTFQ2BAtwcm90b2NvbEFtdAkAZQIFCG1pbmVkQW10BQ5iZW5lZmljaWFyeUFtdAQKYnV5QmFja0FtdAkAaAIAeAUFTVVMVDgEDnNhdmluZ3NBZGRyZXNzCQERQGV4dHJOYXRpdmUoMTA2MikBCQEMZ2V0U3RyT3JFbHNlAwUEdGhpcwkBEWtleVNhdmluZ3NBZGRyZXNzAAIjM1BDN0RCaW1hdXlLeXR4OHRYaEtvNXUyRUNiNkZzbmRZS0gECnNhdmluZ3NBbXQJAQVhc0ludAEJAPwHBAUOc2F2aW5nc0FkZHJlc3MCCHdpdGhkcmF3CQDMCAIFCmJ1eUJhY2tBbXQFA25pbAUDbmlsBAx3eEFzc2V0SWRTdHICLEF0cXY1OUVZempGR3VpdEtWbk1SazZIOEZ1a2pvVjNrdFBvcmJFeXMyNW9uBA13eFN3YXBBZGRyZXNzCQERQGV4dHJOYXRpdmUoMTA2MikBCQEMZ2V0U3RyT3JFbHNlAwUEdGhpcwkBEGtleVd4U3dhcEFkZHJlc3MAAiMzUDY4ek5pdWZzdTF2aVpwdTFhWTNjZGFoUlJLY3ZWNU45MwQKc3dhcFJlc3VsdAkA/AcEBQ13eFN3YXBBZGRyZXNzAgRzd2FwCQDMCAIAAQkAzAgCBQx3eEFzc2V0SWRTdHIJAMwIAgkApQgBBRBuZXV0cmlub0NvbnRyYWN0BQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIFBHVuaXQFCnNhdmluZ3NBbXQFA25pbAMJAAACBQpzd2FwUmVzdWx0BQpzd2FwUmVzdWx0CQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMFEmJlbmVmaWNpYXJ5QWRkcmVzcwUOYmVuZWZpY2lhcnlBbXQFBHVuaXQJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwUQbmV1dHJpbm9Db250cmFjdAULcHJvdG9jb2xBbXQFBHVuaXQJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwUQdHhSZXdhcmRSZWNlaXZlcgUKY2FsbFJld2FyZAUEdW5pdAkAzAgCCQESUmV3YXJkSGlzdG9yeUVudHJ5BwUMbWluZXJBZGRyZXNzCAUBaQ10cmFuc2FjdGlvbklkBQhtaW5lZEFtdAUOYmVuZWZpY2lhcnlBbXQFC3Byb3RvY29sQW10BQtwcm90b2NvbEFtdAAACQDMCAIJARFSZXdhcmRUb3RhbHNFbnRyeQYFDG1pbmVyQWRkcmVzcwUIbWluZWRBbXQFDmJlbmVmaWNpYXJ5QW10BQtwcm90b2NvbEFtdAULcHJvdG9jb2xBbXQAAAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBGnZhbGlkYXRlQW5kQXBwcm92ZUxlYXNpbmdzAQZuTGlzdFMEBW5JZHhzCQDMCAIAAAkAzAgCAAEJAMwIAgACCQDMCAIAAwkAzAgCAAQJAMwIAgAFCQDMCAIABgkAzAgCAAcFA25pbAQFbkxpc3QJALUJAgUGbkxpc3RTBQNTRVAEDWV4cGVjdGVkQ291bnQJAJADAQUFbklkeHMED25ldXRyaW5vQWRkcmVzcwkBEGdldEFkZHJlc3NPckZhaWwBCQEVa2V5TmV1dHJpbm9BZGRyZXNzU3RyAAMJAQIhPQIIBQFpBmNhbGxlcgUPbmV1dHJpbm9BZGRyZXNzCQACAQIpdmFsaWRhdGVBbmRBcHByb3ZlTGVhc2luZ3Mgbm90IGF1dGhvcml6ZWQDCQECIT0CCQBqAgkAkAMBBQVuTGlzdAACAAAJAAIBAiRPbmx5IGV2ZW4gbnVtYmVyIG9mIG5vZGVzIGlzIGFsbG93ZWQDCQECIT0CCQCQAwEFBW5MaXN0BQ1leHBlY3RlZENvdW50CQACAQkArAICCQCsAgICBU9ubHkgCQCkAwEFDWV4cGVjdGVkQ291bnQCIiBvZiBub2RlcycgYWRkcmVzc2VzIGNhbiBiZSBwYXNzZWQKARdmb3JFYWNoTm9kZUNoYW5nZVN0YXR1cwIDYWNjAWkECG5vZGVBZGRyCQCRAwIFBW5MaXN0BQFpBAtub2RlRGF0YVN0cgkBHXJlYWROb2RlRGF0YUFuZFZhbGlkYXRlU3RhdHVzAgUIbm9kZUFkZHICB1BFTkRJTkcJAM0IAgUDYWNjCQELU3RyaW5nRW50cnkCCQEPa2V5Tm9kZVJlZ2lzdHJ5AQUIbm9kZUFkZHIJARlmb3JtYXREZXBvc2l0Q2hhbmdlU3RhdHVzAgULbm9kZURhdGFTdHICCEFQUFJPVkVEBBFhcHByb3ZlZE5vZGVzRGF0YQoAAiRsBQVuSWR4cwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEXZm9yRWFjaE5vZGVDaGFuZ2VTdGF0dXMCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECE0xpc3Qgc2l6ZSBleGNlZWRzIDgJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAICQCUCgIFEWFwcHJvdmVkTm9kZXNEYXRhBQNuaWwBaQETcmVwbGFjZUFwcHJvdmVkTm9kZQQOb2xkTm9kZUFkZHJTdHIObmV3Tm9kZUFkZHJTdHIIZ3JvdXBOdW0NcGVuYWx0eUFtb3VudAMJAQIhPQIIBQFpBmNhbGxlcgUQbmV1dHJpbm9Db250cmFjdAkAAgECEnBlcm1pc3Npb25zIGRlbmllZAQKb2xkRGF0YVN0cgkBHXJlYWROb2RlRGF0YUFuZFZhbGlkYXRlU3RhdHVzAgUOb2xkTm9kZUFkZHJTdHICCEFQUFJPVkVEBApuZXdEYXRhU3RyCQEdcmVhZE5vZGVEYXRhQW5kVmFsaWRhdGVTdGF0dXMCBQ5uZXdOb2RlQWRkclN0cgIHUEVORElORwQRYXBwcm92ZWROb2RlTGlzdFMJAQ9nZXRTdHJpbmdPckZhaWwCBQR0aGlzCQETa2V5QXBwcm92ZWROb2RlTGlzdAADCQEBIQEJAQhjb250YWlucwIFEWFwcHJvdmVkTm9kZUxpc3RTBQ5vbGROb2RlQWRkclN0cgkAAgEJAKwCAgIiYXBwcm92ZWROb2RlTGlzdCBkb2VzIG5vdCBjb250YWluIAUOb2xkTm9kZUFkZHJTdHIEEHVwZGF0ZWROb2RlTGlzdFMJALoJAgkAvAkCBRFhcHByb3ZlZE5vZGVMaXN0UwUOb2xkTm9kZUFkZHJTdHIFDm5ld05vZGVBZGRyU3RyBAtvbGROb2RlQWRkcgkBEUBleHRyTmF0aXZlKDEwNjIpAQUOb2xkTm9kZUFkZHJTdHIEEmJlbmVmaWNpYXJ5QWRkcmVzcwkBFHJlc29sdmVCZW5lZmljaWFyaWVzAgULb2xkTm9kZUFkZHIFC29sZE5vZGVBZGRyBApkZXBvQW1vdW50CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgkAtQkCBQpvbGREYXRhU3RyBQNTRVAFDm5SZWdJZHhEZXBvQW10BAdhY3Rpb25zCQDMCAIJAQtTdHJpbmdFbnRyeQIJARNrZXlBcHByb3ZlZE5vZGVMaXN0AAUQdXBkYXRlZE5vZGVMaXN0UwkAzAgCCQELRGVsZXRlRW50cnkBCQEPa2V5Tm9kZVJlZ2lzdHJ5AQUOb2xkTm9kZUFkZHJTdHIJAMwIAgkBC1N0cmluZ0VudHJ5AgkBD2tleU5vZGVSZWdpc3RyeQEFDm5ld05vZGVBZGRyU3RyCQEZZm9ybWF0RGVwb3NpdENoYW5nZVN0YXR1cwIFCm5ld0RhdGFTdHICCEFQUFJPVkVEBQNuaWwJAJQKAgMJAGYCBQpkZXBvQW1vdW50BQ1wZW5hbHR5QW1vdW50CQDNCAIFB2FjdGlvbnMJAQ5TY3JpcHRUcmFuc2ZlcgMFEmJlbmVmaWNpYXJ5QWRkcmVzcwkAZQIFCmRlcG9BbW91bnQFDXBlbmFsdHlBbW91bnQFBHVuaXQFB2FjdGlvbnMFBHVuaXQBaQENcmV0dXJuRGVwb3NpdAEObm9kZUFkZHJlc3NTdHIDCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAAJAAIBAhNObyBwYXltZW50cyBhbGxvd2VkBA1jYWxsZXJBZGRyZXNzCAUBaQZjYWxsZXIED25vZGVSZWdpc3RyeUtFWQkBD2tleU5vZGVSZWdpc3RyeQEFDm5vZGVBZGRyZXNzU3RyBAtub2RlRGF0YU9wdAkAnQgCBQR0aGlzBQ9ub2RlUmVnaXN0cnlLRVkDCQEBIQEJAQlpc0RlZmluZWQBBQtub2RlRGF0YU9wdAkAAgEJAKwCAgIpQWRkcmVzcyBpcyBub3QgYXBwbGllZCBhcyBuZXV0cmlubyBub2RlOiAFDm5vZGVBZGRyZXNzU3RyBBBhcHByb3ZlZE5vZGVMaXN0CQEPZ2V0U3RyaW5nT3JGYWlsAgUEdGhpcwkBE2tleUFwcHJvdmVkTm9kZUxpc3QAAwkBCGNvbnRhaW5zAgUQYXBwcm92ZWROb2RlTGlzdAUObm9kZUFkZHJlc3NTdHIJAAIBAkxJbXBvc3NpYmxlIHRvIHJldHVybiBkZXBvc2l0IGZyb20gYXBwcm92ZWQgTm9kZSwgcGxlYXNlIGNvbnRhY3Qgc3VwcG9ydCB0ZWFtBAhub2RlRGF0YQkAtQkCCQEFdmFsdWUBBQtub2RlRGF0YU9wdAUDU0VQBAZzdGF0dXMDCQBnAgkAkAMBBQhub2RlRGF0YQAJCQCRAwIFCG5vZGVEYXRhBQ1uUmVnSWR4U3RhdHVzAgdQRU5ESU5HAwkBAiE9AgUGc3RhdHVzAgdQRU5ESU5HCQACAQIiQXBwbGljYXRpb24gc3RhdHVzIGlzIG5vdCBQRU5ESU5HIQQKZGVwb0Ftb3VudAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCG5vZGVEYXRhBQ5uUmVnSWR4RGVwb0FtdAQLbm9kZUFkZHJlc3MJARFAZXh0ck5hdGl2ZSgxMDYyKQEFDm5vZGVBZGRyZXNzU3RyBBJiZW5lZmljaWFyeUFkZHJlc3MJARRyZXNvbHZlQmVuZWZpY2lhcmllcwIFC25vZGVBZGRyZXNzBQtub2RlQWRkcmVzcwMJAQEhAQMDCQAAAgUNY2FsbGVyQWRkcmVzcwUEdGhpcwYDCQECIT0CBRJiZW5lZmljaWFyeUFkZHJlc3MFC25vZGVBZGRyZXNzCQAAAgUNY2FsbGVyQWRkcmVzcwUSYmVuZWZpY2lhcnlBZGRyZXNzBwYDCQAAAgUSYmVuZWZpY2lhcnlBZGRyZXNzBQtub2RlQWRkcmVzcwkAAAIFDWNhbGxlckFkZHJlc3MFC25vZGVBZGRyZXNzBwkAAgECIHJldHVybkRlcG9zaXQgcGVybWlzc2lvbnMgZGVuaWVkCQDMCAIJAQtEZWxldGVFbnRyeQEFD25vZGVSZWdpc3RyeUtFWQkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDBRJiZW5lZmljaWFyeUFkZHJlc3MFCmRlcG9BbW91bnQFBHVuaXQFA25pbAFpAQ9pbml0Tm9kZXNWb3RpbmcEC3N0YXJ0SGVpZ2h0CWVuZEhlaWdodAdvcHRpb25zC2Rlc2NyaXB0aW9uAwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIScGVybWlzc2lvbnMgZGVuaWVkBAxvcHRpb25zQXJyYXkJALUJAgUHb3B0aW9ucwICX18DCQECIT0CCQBqAgkAkAMBBQxvcHRpb25zQXJyYXkAAgAACQACAQIaTm90IGV2ZW4gbnVtYmVyIG9mIG9wdGlvbnMDCQBmAgkAaQIJAJADAQUMb3B0aW9uc0FycmF5AAIACgkAAgECH01heCAxMCBvcHRpb25zIGNhbiBiZSBzcGVjaWZpZWQEEW5vZGVzVm90aW5nTnVtS0VZCQEVa2V5Tm9kZXNWb3RpbmdOZXh0TnVtAAQJdm90aW5nTnVtCQEMZ2V0SW50T3JFbHNlAgURbm9kZXNWb3RpbmdOdW1LRVkAAAQMdm90aW5nTnVtU3RyCQCkAwEFCXZvdGluZ051bQoBEHRyYW5zZm9ybU9wdGlvbnMCBWFjY3VtB25leHRPcHQEB29wdERhdGEJALUJAgUHbmV4dE9wdAIBOgQDb3B0CQCRAwIFB29wdERhdGEAAAQGb3B0S0VZCQEXa2V5Tm9kZXNWb3RpbmdPcHRpb25LZXkCBQx2b3RpbmdOdW1TdHIFA29wdAQIb3B0RGVzY3IJAJEDAgUHb3B0RGF0YQABBBBvcHRUb3RhbFZvdGVzS0VZCQEea2V5Tm9kZXNWb3RpbmdPcHRpb25Ub3RhbFZvdGVzAgUMdm90aW5nTnVtU3RyBQNvcHQJAM0IAgkAzQgCBQVhY2N1bQkBC1N0cmluZ0VudHJ5AgUGb3B0S0VZBQhvcHREZXNjcgkBDEludGVnZXJFbnRyeQIFEG9wdFRvdGFsVm90ZXNLRVkAAAkAzQgCCQDNCAIJAM0IAgkAzQgCCgACJGwFDG9wdGlvbnNBcnJheQoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEQdHJhbnNmb3JtT3B0aW9ucwIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgkBDEludGVnZXJFbnRyeQIFEW5vZGVzVm90aW5nTnVtS0VZCQBkAgUJdm90aW5nTnVtAAEJAQtTdHJpbmdFbnRyeQIJARJrZXlOb2Rlc1ZvdGluZ0Rlc2MBBQx2b3RpbmdOdW1TdHIFC2Rlc2NyaXB0aW9uCQEMSW50ZWdlckVudHJ5AgkBGWtleU5vZGVzVm90aW5nU3RhcnRIZWlnaHQBBQx2b3RpbmdOdW1TdHIFC3N0YXJ0SGVpZ2h0CQEMSW50ZWdlckVudHJ5AgkBF2tleU5vZGVzVm90aW5nRW5kSGVpZ2h0AQUMdm90aW5nTnVtU3RyBQllbmRIZWlnaHQBaQEKdm90ZUJ5Tm9kZQMObm9kZUFkZHJlc3NTdHIJdm90aW5nTnVtCW9wdGlvbk51bQQMdmFsaWRhdGVOb2RlCQEdcmVhZE5vZGVEYXRhQW5kVmFsaWRhdGVTdGF0dXMCBQ5ub2RlQWRkcmVzc1N0cgIIQVBQUk9WRUQDCQAAAgUMdmFsaWRhdGVOb2RlBQx2YWxpZGF0ZU5vZGUEC25vZGVBZGRyZXNzCQERQGV4dHJOYXRpdmUoMTA2MikBBQ5ub2RlQWRkcmVzc1N0cgQPbm9kZUJlbmVmaWNpYXJ5CQEPZ2V0U3RyaW5nT3JGYWlsAgULbm9kZUFkZHJlc3MJARVrZXlCZW5lZmljaWFyeUFkZHJlc3MABA92b3RlckFkZHJlc3NTdHIJAKUIAQgFAWkGY2FsbGVyAwkBAiE9AgUPdm90ZXJBZGRyZXNzU3RyBQ9ub2RlQmVuZWZpY2lhcnkJAAIBAiVPbmx5IE5vZGUncyBiZW5lZmljaWFyeSBjYW4gZG8gdm90aW5nBAtzdGFydEhlaWdodAkBDGdldEludE9yRmFpbAEJARlrZXlOb2Rlc1ZvdGluZ1N0YXJ0SGVpZ2h0AQUJdm90aW5nTnVtBAllbmRIZWlnaHQJAQxnZXRJbnRPckZhaWwBCQEXa2V5Tm9kZXNWb3RpbmdFbmRIZWlnaHQBBQl2b3RpbmdOdW0DCQBmAgULc3RhcnRIZWlnaHQFBmhlaWdodAkAAgECH1ZvdGluZyBoYXMgbm90IGJlZW4gc3RhcnRlZCB5ZXQDCQBmAgUGaGVpZ2h0BQllbmRIZWlnaHQJAAIBAg9Wb3RpbmcgZmluaXNoZWQEDW5vZGVDaG9pY2VLRVkJARhrZXlOb2Rlc1ZvdGluZ05vZGVDaG9pY2UCBQl2b3RpbmdOdW0FDm5vZGVBZGRyZXNzU3RyBApub2RlQ2hvaWNlCQEMZ2V0U3RyT3JFbHNlAwUEdGhpcwUNbm9kZUNob2ljZUtFWQIAAwkBAiE9AgUKbm9kZUNob2ljZQIACQACAQI3Tm9kZSBoYXMgYWxyZWFkeSB2b3RlZC4gSXQgaXMgYWxsb3dlZCB0byB2b3RlIG9ubHkgb25jZQQTb3B0aW9uVG90YWxWb3Rlc0tFWQkBHmtleU5vZGVzVm90aW5nT3B0aW9uVG90YWxWb3RlcwIFCXZvdGluZ051bQUJb3B0aW9uTnVtBBBvcHRpb25Ub3RhbFZvdGVzCQEMZ2V0SW50T3JGYWlsAQUTb3B0aW9uVG90YWxWb3Rlc0tFWQkAzAgCCQEMSW50ZWdlckVudHJ5AgUTb3B0aW9uVG90YWxWb3Rlc0tFWQkAZAIFEG9wdGlvblRvdGFsVm90ZXMAAQkAzAgCCQELU3RyaW5nRW50cnkCBQ1ub2RlQ2hvaWNlS0VZBQlvcHRpb25OdW0FA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgBabYzJ", "height": 2573068, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 3nbSEye8VP72T52daNthsvn6YuU9XHG9nss2faA4RAxE Next: 4wR9QRnwzw4fxLsSD92ah6jp8NKGNACNKtAd5Jnb2FfZ Diff:
Old | New | Differences | |
---|---|---|---|
12 | 12 | let WAVESID = fromBase58String(WAVESIDSTR) | |
13 | 13 | ||
14 | 14 | func getIntOrFail (key) = valueOrErrorMessage(getInteger(this, key), (("Mandatory this." + key) + " is not defined")) | |
15 | + | ||
16 | + | ||
17 | + | func getIntOrElse (key,val) = valueOrElse(getInteger(this, key), val) | |
15 | 18 | ||
16 | 19 | ||
17 | 20 | func getStrOrElse (address,key,defaultVal) = valueOrElse(getString(address, key), defaultVal) | |
85 | 88 | func keySwopfiUsdtUsdnPoolAddress () = "%s%s__cfg__swopfiUsdtUsdnPoolAddress" | |
86 | 89 | ||
87 | 90 | ||
91 | + | func keyWxSwapAddress () = "%s%s__cfg__wxSwapAddress" | |
92 | + | ||
93 | + | ||
88 | 94 | func keySavingsAddress () = "%s%s__cfg__savingsAddress" | |
89 | 95 | ||
90 | 96 | ||
91 | 97 | func keyBeneficiaryAddress () = "%s%s__cfg__beneficiaryAddress" | |
98 | + | ||
99 | + | ||
100 | + | func keyNodesVotingNextNum () = "%s%s__nodesVotingCfg__nextVotingNum" | |
101 | + | ||
102 | + | ||
103 | + | func keyNodesVotingOptionKey (votingNum,optionNum) = makeString(["%s%d%s__nodesVotingCfg", votingNum, optionNum], SEP) | |
104 | + | ||
105 | + | ||
106 | + | func keyNodesVotingDesc (votingNum) = makeString(["%s%d%s__nodesVotingCfg", votingNum, "description"], SEP) | |
107 | + | ||
108 | + | ||
109 | + | func keyNodesVotingStartHeight (votingNum) = makeString(["%s%d%s__nodesVotingCfg", votingNum, "votingStartHeight"], SEP) | |
110 | + | ||
111 | + | ||
112 | + | func keyNodesVotingEndHeight (votingNum) = makeString(["%s%d%s__nodesVotingCfg", votingNum, "votingEndHeight"], SEP) | |
113 | + | ||
114 | + | ||
115 | + | func keyNodesVotingOptionTotalVotes (votingNum,optionNum) = makeString(["%s%d%s%s__nodesVotingData", votingNum, "optionTotalVotes", optionNum], SEP) | |
116 | + | ||
117 | + | ||
118 | + | func keyNodesVotingNodeChoice (votingNum,nodeAddressStr) = makeString(["%s%d%s%s__nodesVotingData", votingNum, "nodeChoice", nodeAddressStr], SEP) | |
92 | 119 | ||
93 | 120 | ||
94 | 121 | let IdxControlCfgNeutrinoDapp = 1 | |
295 | 322 | let beneficiaryPart = getIntOrFail(keyBenificaryPartX6()) | |
296 | 323 | let beneficiaryAmt = fraction(minedAmt, beneficiaryPart, MULT6) | |
297 | 324 | let protocolAmt = (minedAmt - beneficiaryAmt) | |
298 | - | [ScriptTransfer(beneficiaryAddress, beneficiaryAmt, unit), ScriptTransfer(neutrinoContract, protocolAmt, unit), ScriptTransfer(txRewardReceiver, callReward, unit), RewardHistoryEntry(minerAddress, i.transactionId, minedAmt, beneficiaryAmt, protocolAmt, protocolAmt, 0), RewardTotalsEntry(minerAddress, minedAmt, beneficiaryAmt, protocolAmt, protocolAmt, 0)] | |
325 | + | let buyBackAmt = (120 * MULT8) | |
326 | + | let savingsAddress = addressFromStringValue(getStrOrElse(this, keySavingsAddress(), "3PC7DBimauyKytx8tXhKo5u2ECb6FsndYKH")) | |
327 | + | let savingsAmt = asInt(invoke(savingsAddress, "withdraw", [buyBackAmt], nil)) | |
328 | + | let wxAssetIdStr = "Atqv59EYzjFGuitKVnMRk6H8FukjoV3ktPorbEys25on" | |
329 | + | let wxSwapAddress = addressFromStringValue(getStrOrElse(this, keyWxSwapAddress(), "3P68zNiufsu1viZpu1aY3cdahRRKcvV5N93")) | |
330 | + | let swapResult = invoke(wxSwapAddress, "swap", [1, wxAssetIdStr, toString(neutrinoContract)], [AttachedPayment(unit, savingsAmt)]) | |
331 | + | if ((swapResult == swapResult)) | |
332 | + | then [ScriptTransfer(beneficiaryAddress, beneficiaryAmt, unit), ScriptTransfer(neutrinoContract, protocolAmt, unit), ScriptTransfer(txRewardReceiver, callReward, unit), RewardHistoryEntry(minerAddress, i.transactionId, minedAmt, beneficiaryAmt, protocolAmt, protocolAmt, 0), RewardTotalsEntry(minerAddress, minedAmt, beneficiaryAmt, protocolAmt, protocolAmt, 0)] | |
333 | + | else throw("Strict value is not equal to itself.") | |
299 | 334 | } | |
300 | 335 | } | |
301 | 336 | } | |
405 | 440 | } | |
406 | 441 | ||
407 | 442 | ||
443 | + | ||
444 | + | @Callable(i) | |
445 | + | func initNodesVoting (startHeight,endHeight,options,description) = if ((i.caller != this)) | |
446 | + | then throw("permissions denied") | |
447 | + | else { | |
448 | + | let optionsArray = split(options, "__") | |
449 | + | if (((size(optionsArray) % 2) != 0)) | |
450 | + | then throw("Not even number of options") | |
451 | + | else if (((size(optionsArray) / 2) > 10)) | |
452 | + | then throw("Max 10 options can be specified") | |
453 | + | else { | |
454 | + | let nodesVotingNumKEY = keyNodesVotingNextNum() | |
455 | + | let votingNum = getIntOrElse(nodesVotingNumKEY, 0) | |
456 | + | let votingNumStr = toString(votingNum) | |
457 | + | func transformOptions (accum,nextOpt) = { | |
458 | + | let optData = split(nextOpt, ":") | |
459 | + | let opt = optData[0] | |
460 | + | let optKEY = keyNodesVotingOptionKey(votingNumStr, opt) | |
461 | + | let optDescr = optData[1] | |
462 | + | let optTotalVotesKEY = keyNodesVotingOptionTotalVotes(votingNumStr, opt) | |
463 | + | ((accum :+ StringEntry(optKEY, optDescr)) :+ IntegerEntry(optTotalVotesKEY, 0)) | |
464 | + | } | |
465 | + | ||
466 | + | (((({ | |
467 | + | let $l = optionsArray | |
468 | + | let $s = size($l) | |
469 | + | let $acc0 = nil | |
470 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
471 | + | then $a | |
472 | + | else transformOptions($a, $l[$i]) | |
473 | + | ||
474 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
475 | + | then $a | |
476 | + | else throw("List size exceeds 10") | |
477 | + | ||
478 | + | $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) | |
479 | + | } :+ IntegerEntry(nodesVotingNumKEY, (votingNum + 1))) :+ StringEntry(keyNodesVotingDesc(votingNumStr), description)) :+ IntegerEntry(keyNodesVotingStartHeight(votingNumStr), startHeight)) :+ IntegerEntry(keyNodesVotingEndHeight(votingNumStr), endHeight)) | |
480 | + | } | |
481 | + | } | |
482 | + | ||
483 | + | ||
484 | + | ||
485 | + | @Callable(i) | |
486 | + | func voteByNode (nodeAddressStr,votingNum,optionNum) = { | |
487 | + | let validateNode = readNodeDataAndValidateStatus(nodeAddressStr, "APPROVED") | |
488 | + | if ((validateNode == validateNode)) | |
489 | + | then { | |
490 | + | let nodeAddress = addressFromStringValue(nodeAddressStr) | |
491 | + | let nodeBeneficiary = getStringOrFail(nodeAddress, keyBeneficiaryAddress()) | |
492 | + | let voterAddressStr = toString(i.caller) | |
493 | + | if ((voterAddressStr != nodeBeneficiary)) | |
494 | + | then throw("Only Node's beneficiary can do voting") | |
495 | + | else { | |
496 | + | let startHeight = getIntOrFail(keyNodesVotingStartHeight(votingNum)) | |
497 | + | let endHeight = getIntOrFail(keyNodesVotingEndHeight(votingNum)) | |
498 | + | if ((startHeight > height)) | |
499 | + | then throw("Voting has not been started yet") | |
500 | + | else if ((height > endHeight)) | |
501 | + | then throw("Voting finished") | |
502 | + | else { | |
503 | + | let nodeChoiceKEY = keyNodesVotingNodeChoice(votingNum, nodeAddressStr) | |
504 | + | let nodeChoice = getStrOrElse(this, nodeChoiceKEY, "") | |
505 | + | if ((nodeChoice != "")) | |
506 | + | then throw("Node has already voted. It is allowed to vote only once") | |
507 | + | else { | |
508 | + | let optionTotalVotesKEY = keyNodesVotingOptionTotalVotes(votingNum, optionNum) | |
509 | + | let optionTotalVotes = getIntOrFail(optionTotalVotesKEY) | |
510 | + | [IntegerEntry(optionTotalVotesKEY, (optionTotalVotes + 1)), StringEntry(nodeChoiceKEY, optionNum)] | |
511 | + | } | |
512 | + | } | |
513 | + | } | |
514 | + | } | |
515 | + | else throw("Strict value is not equal to itself.") | |
516 | + | } | |
517 | + | ||
518 | + |
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 6 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | 4 | let SEP = "__" | |
5 | 5 | ||
6 | 6 | let MULT6 = 1000000 | |
7 | 7 | ||
8 | 8 | let MULT8 = 100000000 | |
9 | 9 | ||
10 | 10 | let WAVESIDSTR = "WAVES" | |
11 | 11 | ||
12 | 12 | let WAVESID = fromBase58String(WAVESIDSTR) | |
13 | 13 | ||
14 | 14 | func getIntOrFail (key) = valueOrErrorMessage(getInteger(this, key), (("Mandatory this." + key) + " is not defined")) | |
15 | + | ||
16 | + | ||
17 | + | func getIntOrElse (key,val) = valueOrElse(getInteger(this, key), val) | |
15 | 18 | ||
16 | 19 | ||
17 | 20 | func getStrOrElse (address,key,defaultVal) = valueOrElse(getString(address, key), defaultVal) | |
18 | 21 | ||
19 | 22 | ||
20 | 23 | func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), (("Mandatory this." + key) + " is not defined")) | |
21 | 24 | ||
22 | 25 | ||
23 | 26 | func getAddressOrFail (key) = valueOrErrorMessage(addressFromString(getStringOrFail(this, key)), (("Fail to convert this." + key) + " value into Address")) | |
24 | 27 | ||
25 | 28 | ||
26 | 29 | func asAnyList (val) = match val { | |
27 | 30 | case valAnyList: List[Any] => | |
28 | 31 | valAnyList | |
29 | 32 | case _ => | |
30 | 33 | throw("fail to cast into List[Any]") | |
31 | 34 | } | |
32 | 35 | ||
33 | 36 | ||
34 | 37 | func asInt (v) = match v { | |
35 | 38 | case i: Int => | |
36 | 39 | i | |
37 | 40 | case _ => | |
38 | 41 | throw("fail to cast into Int") | |
39 | 42 | } | |
40 | 43 | ||
41 | 44 | ||
42 | 45 | func asByteVecot (v) = match v { | |
43 | 46 | case i: ByteVector => | |
44 | 47 | i | |
45 | 48 | case _ => | |
46 | 49 | throw("fail to cast into ByteVector") | |
47 | 50 | } | |
48 | 51 | ||
49 | 52 | ||
50 | 53 | func validateAddressOrFail (addressStr) = { | |
51 | 54 | let address = valueOrErrorMessage(addressFromString(addressStr), ("fail to convert into address " + addressStr)) | |
52 | 55 | if ((0 > wavesBalance(address).available)) | |
53 | 56 | then throw() | |
54 | 57 | else addressStr | |
55 | 58 | } | |
56 | 59 | ||
57 | 60 | ||
58 | 61 | func keyNodeRegistry (address) = ("%s__" + address) | |
59 | 62 | ||
60 | 63 | ||
61 | 64 | func keyNodeRewardsTotals (address) = ("%s%s__totals__" + address) | |
62 | 65 | ||
63 | 66 | ||
64 | 67 | func keyApprovedNodeList () = "%s__approvedNodeList" | |
65 | 68 | ||
66 | 69 | ||
67 | 70 | func keyDepositAmount () = "%s%s__cfg__depositAmount" | |
68 | 71 | ||
69 | 72 | ||
70 | 73 | func keyNeutrinoAddressStr () = "%s%s__cfg__neutrinoAddress" | |
71 | 74 | ||
72 | 75 | ||
73 | 76 | func keyMasterNodeAddressStr () = "%s%s__cfg__mainNeutrinoNodeAddress" | |
74 | 77 | ||
75 | 78 | ||
76 | 79 | func keyProtocolPartX6 () = "%s%s__cfg__protocolPartX6" | |
77 | 80 | ||
78 | 81 | ||
79 | 82 | func keyBenificaryPartX6 () = "%s%s__cfg__benificaryPartX6" | |
80 | 83 | ||
81 | 84 | ||
82 | 85 | func keyMinDistributeAmount () = "%s%s__cfg__minDistributeAmount" | |
83 | 86 | ||
84 | 87 | ||
85 | 88 | func keySwopfiUsdtUsdnPoolAddress () = "%s%s__cfg__swopfiUsdtUsdnPoolAddress" | |
86 | 89 | ||
87 | 90 | ||
91 | + | func keyWxSwapAddress () = "%s%s__cfg__wxSwapAddress" | |
92 | + | ||
93 | + | ||
88 | 94 | func keySavingsAddress () = "%s%s__cfg__savingsAddress" | |
89 | 95 | ||
90 | 96 | ||
91 | 97 | func keyBeneficiaryAddress () = "%s%s__cfg__beneficiaryAddress" | |
98 | + | ||
99 | + | ||
100 | + | func keyNodesVotingNextNum () = "%s%s__nodesVotingCfg__nextVotingNum" | |
101 | + | ||
102 | + | ||
103 | + | func keyNodesVotingOptionKey (votingNum,optionNum) = makeString(["%s%d%s__nodesVotingCfg", votingNum, optionNum], SEP) | |
104 | + | ||
105 | + | ||
106 | + | func keyNodesVotingDesc (votingNum) = makeString(["%s%d%s__nodesVotingCfg", votingNum, "description"], SEP) | |
107 | + | ||
108 | + | ||
109 | + | func keyNodesVotingStartHeight (votingNum) = makeString(["%s%d%s__nodesVotingCfg", votingNum, "votingStartHeight"], SEP) | |
110 | + | ||
111 | + | ||
112 | + | func keyNodesVotingEndHeight (votingNum) = makeString(["%s%d%s__nodesVotingCfg", votingNum, "votingEndHeight"], SEP) | |
113 | + | ||
114 | + | ||
115 | + | func keyNodesVotingOptionTotalVotes (votingNum,optionNum) = makeString(["%s%d%s%s__nodesVotingData", votingNum, "optionTotalVotes", optionNum], SEP) | |
116 | + | ||
117 | + | ||
118 | + | func keyNodesVotingNodeChoice (votingNum,nodeAddressStr) = makeString(["%s%d%s%s__nodesVotingData", votingNum, "nodeChoice", nodeAddressStr], SEP) | |
92 | 119 | ||
93 | 120 | ||
94 | 121 | let IdxControlCfgNeutrinoDapp = 1 | |
95 | 122 | ||
96 | 123 | let IdxControlCfgAuctionDapp = 2 | |
97 | 124 | ||
98 | 125 | let IdxControlCfgRpdDapp = 3 | |
99 | 126 | ||
100 | 127 | let IdxControlCfgMathDapp = 4 | |
101 | 128 | ||
102 | 129 | let IdxControlCfgLiquidationDapp = 5 | |
103 | 130 | ||
104 | 131 | let IdxControlCfgRestDapp = 6 | |
105 | 132 | ||
106 | 133 | let IdxControlCfgNodeRegistryDapp = 7 | |
107 | 134 | ||
108 | 135 | let IdxControlCfgNsbtStakingDapp = 8 | |
109 | 136 | ||
110 | 137 | let IdxControlCfgMediatorDapp = 9 | |
111 | 138 | ||
112 | 139 | let IdxControlCfgSurfStakingDapp = 10 | |
113 | 140 | ||
114 | 141 | let IdxControlCfgGnsbtControllerDapp = 11 | |
115 | 142 | ||
116 | 143 | let IdxControlCfgRestV2Dapp = 12 | |
117 | 144 | ||
118 | 145 | let IdxControlCfgGovernanceDapp = 13 | |
119 | 146 | ||
120 | 147 | func keyControlAddress () = "%s%s__config__controlAddress" | |
121 | 148 | ||
122 | 149 | ||
123 | 150 | func keyControlCfg () = "%s__controlConfig" | |
124 | 151 | ||
125 | 152 | ||
126 | 153 | func keyUsdnAssetId () = "neutrino_asset_id" | |
127 | 154 | ||
128 | 155 | ||
129 | 156 | func readControlCfgOrFail (control) = split_4C(getStringOrFail(control, keyControlCfg()), SEP) | |
130 | 157 | ||
131 | 158 | ||
132 | 159 | func getContractAddressOrFail (controlCfg,idx) = valueOrErrorMessage(addressFromString(controlCfg[idx]), ("Control cfg doesn't contain address at index " + toString(idx))) | |
133 | 160 | ||
134 | 161 | ||
135 | 162 | let controlContract = addressFromStringValue(valueOrElse(getString(this, keyControlAddress()), "3N4NS7d4Jo9a6F14LiFUKKYVdUkkf2eP4Zx")) | |
136 | 163 | ||
137 | 164 | let controlCfg = readControlCfgOrFail(controlContract) | |
138 | 165 | ||
139 | 166 | let neutrinoContract = getContractAddressOrFail(controlCfg, IdxControlCfgNeutrinoDapp) | |
140 | 167 | ||
141 | 168 | let usdnAssetIdStr = getStrOrElse(neutrinoContract, keyUsdnAssetId(), "HezsdQuRDtzksAYUy97gfhKy7Z1NW2uXYSHA3bgqenNZ") | |
142 | 169 | ||
143 | 170 | let usdnAssetId = fromBase58String(usdnAssetIdStr) | |
144 | 171 | ||
145 | 172 | let nRegIdxTxAdd = 1 | |
146 | 173 | ||
147 | 174 | let nRegIdxHeightAdd = 2 | |
148 | 175 | ||
149 | 176 | let nRegIdxTimeAdd = 3 | |
150 | 177 | ||
151 | 178 | let nRegIdxDepoAmt = 4 | |
152 | 179 | ||
153 | 180 | let nRegIdxDepoAmtLeft = 5 | |
154 | 181 | ||
155 | 182 | let nRegIdxStatus = 6 | |
156 | 183 | ||
157 | 184 | let nRegIdxStatusChangeHeight = 7 | |
158 | 185 | ||
159 | 186 | let nRegIdxStatusChangeTime = 8 | |
160 | 187 | ||
161 | 188 | func formatDepositAdd (txIdStr,depositAmount,remainingDepositAmount,status) = makeString(["%s%d%d%d%d%s%d%d", txIdStr, toString(lastBlock.height), toString(lastBlock.timestamp), toString(depositAmount), toString(remainingDepositAmount), status, "0", "0"], SEP) | |
162 | 189 | ||
163 | 190 | ||
164 | 191 | func formatDepositChangeStatus (origS,newStatus) = { | |
165 | 192 | let orig = split(origS, SEP) | |
166 | 193 | makeString(["%s%d%d%d%d%s%d%d", orig[nRegIdxTxAdd], orig[nRegIdxHeightAdd], orig[nRegIdxTimeAdd], orig[nRegIdxDepoAmt], orig[nRegIdxDepoAmtLeft], newStatus, toString(lastBlock.height), toString(lastBlock.timestamp)], SEP) | |
167 | 194 | } | |
168 | 195 | ||
169 | 196 | ||
170 | 197 | func keyRewardHistory (nodeAddress,txId) = makeString(["%s%s%s", "history", toString(nodeAddress), toBase58String(txId)], SEP) | |
171 | 198 | ||
172 | 199 | ||
173 | 200 | func dataRewardHistory (wavesAmountTotal,beneficiaryAmt,protocolAmt,protocolAmtPart1,protocolAmtPart2) = makeString(["%d%d%d%d%d%d%d", toString(lastBlock.height), toString(lastBlock.timestamp), toString(wavesAmountTotal), toString(beneficiaryAmt), toString(protocolAmt), toString(protocolAmtPart1), toString(protocolAmtPart2)], SEP) | |
174 | 201 | ||
175 | 202 | ||
176 | 203 | func RewardHistoryEntry (nodeAddress,txId,minedAmt,beneficiaryAmt,protocolAmt,protocolAmt1,protocolAmt2) = StringEntry(keyRewardHistory(nodeAddress, txId), dataRewardHistory(minedAmt, beneficiaryAmt, protocolAmt, protocolAmt1, protocolAmt2)) | |
177 | 204 | ||
178 | 205 | ||
179 | 206 | func dataRewardTotals (minedAmt,beneficiaryAmt,protocolAmt,protocolAmtPart1,protocolAmtPart2) = makeString(["%d%d%d%d%d", toString(minedAmt), toString(beneficiaryAmt), toString(protocolAmt), toString(protocolAmtPart1), toString(protocolAmtPart2)], SEP) | |
180 | 207 | ||
181 | 208 | ||
182 | 209 | func RewardTotalsEntry (miner,minedAmt,beneficiaryAmt,protocolAmt,protocolAmtPart1,protocolAmtPart2) = { | |
183 | 210 | let nodeRewardsTotalsKEY = keyNodeRewardsTotals(toString(miner)) | |
184 | 211 | let nodeRewardsArray = split(getStrOrElse(this, nodeRewardsTotalsKEY, dataRewardTotals(0, 0, 0, 0, 0)), SEP) | |
185 | 212 | let newMinedAmt = (parseIntValue(nodeRewardsArray[1]) + minedAmt) | |
186 | 213 | let newBeneficiaryAmt = (parseIntValue(nodeRewardsArray[2]) + beneficiaryAmt) | |
187 | 214 | let newProtocolAmt = (parseIntValue(nodeRewardsArray[3]) + protocolAmt) | |
188 | 215 | let newProtocolAmtPart1 = (parseIntValue(nodeRewardsArray[4]) + protocolAmtPart1) | |
189 | 216 | let newProtocolAmtPart2 = (parseIntValue(nodeRewardsArray[5]) + protocolAmtPart2) | |
190 | 217 | StringEntry(nodeRewardsTotalsKEY, dataRewardTotals(newMinedAmt, newBeneficiaryAmt, newProtocolAmt, newProtocolAmtPart1, newProtocolAmtPart2)) | |
191 | 218 | } | |
192 | 219 | ||
193 | 220 | ||
194 | 221 | func resolveBeneficiaries (minerAddress,beneficiaryFromParam) = { | |
195 | 222 | let beneficiaryFromMinerState = addressFromStringValue(getStringOrFail(minerAddress, keyBeneficiaryAddress())) | |
196 | 223 | if ((scriptHash(minerAddress) == unit)) | |
197 | 224 | then beneficiaryFromParam | |
198 | 225 | else beneficiaryFromMinerState | |
199 | 226 | } | |
200 | 227 | ||
201 | 228 | ||
202 | 229 | func readNodeDataAndValidateStatus (nodeAddr,expectedStatus) = { | |
203 | 230 | let nodeDataOpt = getString(keyNodeRegistry(nodeAddr)) | |
204 | 231 | if (!(isDefined(nodeDataOpt))) | |
205 | 232 | then throw(("Unknown Node " + nodeAddr)) | |
206 | 233 | else { | |
207 | 234 | let nodeDataStr = value(nodeDataOpt) | |
208 | 235 | let nodeData = split(nodeDataStr, SEP) | |
209 | 236 | let nodeStatus = if ((size(nodeData) >= 9)) | |
210 | 237 | then nodeData[nRegIdxStatus] | |
211 | 238 | else "PENDING" | |
212 | 239 | if ((nodeStatus != expectedStatus)) | |
213 | 240 | then throw(((((("Node " + nodeAddr) + " status should be ") + expectedStatus) + ", but actually ") + nodeStatus)) | |
214 | 241 | else nodeDataStr | |
215 | 242 | } | |
216 | 243 | } | |
217 | 244 | ||
218 | 245 | ||
219 | 246 | @Callable(i) | |
220 | 247 | func constructorV1 (depositAmount,neutrinoAddressStr,masterNodeAddressStr,protocolPartX6,benificaryPartX6) = if ((i.caller != this)) | |
221 | 248 | then throw("permissions denied") | |
222 | 249 | else if ((0 > depositAmount)) | |
223 | 250 | then throw("depositAmount less then zero") | |
224 | 251 | else if ((0 > protocolPartX6)) | |
225 | 252 | then throw("protocolPartX6 less then zero") | |
226 | 253 | else if ((0 > benificaryPartX6)) | |
227 | 254 | then throw("benificaryPartX6 less then zero") | |
228 | 255 | else if (((protocolPartX6 + benificaryPartX6) != MULT6)) | |
229 | 256 | then throw("parts sum must be 1") | |
230 | 257 | else [IntegerEntry(keyDepositAmount(), depositAmount), StringEntry(keyNeutrinoAddressStr(), validateAddressOrFail(neutrinoAddressStr)), StringEntry(keyMasterNodeAddressStr(), validateAddressOrFail(masterNodeAddressStr)), IntegerEntry(keyProtocolPartX6(), protocolPartX6), IntegerEntry(keyBenificaryPartX6(), benificaryPartX6)] | |
231 | 258 | ||
232 | 259 | ||
233 | 260 | ||
234 | 261 | @Callable(i) | |
235 | 262 | func constructorV2 (swopfiAddressStr,controlAddressStr,savingsAddressStr) = if ((i.caller != this)) | |
236 | 263 | then throw("permissions denied") | |
237 | 264 | else [StringEntry(keySwopfiUsdtUsdnPoolAddress(), validateAddressOrFail(swopfiAddressStr)), StringEntry(keyControlAddress(), validateAddressOrFail(controlAddressStr)), StringEntry(keySavingsAddress(), validateAddressOrFail(savingsAddressStr))] | |
238 | 265 | ||
239 | 266 | ||
240 | 267 | ||
241 | 268 | @Callable(i) | |
242 | 269 | func sumbitApplication () = if ((size(i.payments) != 1)) | |
243 | 270 | then throw("exact 1 payment must be attached") | |
244 | 271 | else if ((i.caller != i.originCaller)) | |
245 | 272 | then throw("dapp to dapp calls are not allowed") | |
246 | 273 | else { | |
247 | 274 | let pmt = i.payments[0] | |
248 | 275 | let deposit = pmt.amount | |
249 | 276 | let pmtAssetId = valueOrElse(pmt.assetId, WAVESID) | |
250 | 277 | let expectedDepositAmount = getIntOrFail(keyDepositAmount()) | |
251 | 278 | let txId = toBase58String(i.transactionId) | |
252 | 279 | let nodeAddress = toString(i.caller) | |
253 | 280 | let nodeRegistryKEY = keyNodeRegistry(nodeAddress) | |
254 | 281 | if ((pmtAssetId != WAVESID)) | |
255 | 282 | then throw("only Waves can be used for deposit") | |
256 | 283 | else if ((deposit != expectedDepositAmount)) | |
257 | 284 | then throw((("exactly " + toString(expectedDepositAmount)) + " Wavelets are expected")) | |
258 | 285 | else if ((getStrOrElse(this, nodeRegistryKEY, "") != "")) | |
259 | 286 | then throw("your node already registered") | |
260 | 287 | else [StringEntry(nodeRegistryKEY, formatDepositAdd(txId, deposit, deposit, "PENDING"))] | |
261 | 288 | } | |
262 | 289 | ||
263 | 290 | ||
264 | 291 | ||
265 | 292 | @Callable(i) | |
266 | 293 | func distributeMinerReward (beneficiaryAddressStr) = { | |
267 | 294 | let minDistributeAmount = valueOrElse(getInteger(this, keyMinDistributeAmount()), (24 * MULT8)) | |
268 | 295 | if ((size(i.payments) != 1)) | |
269 | 296 | then throw("exact 1 payment must be attached") | |
270 | 297 | else if ((i.caller != i.originCaller)) | |
271 | 298 | then throw("dapp to dapp calls are not allowed") | |
272 | 299 | else { | |
273 | 300 | let pmt = i.payments[0] | |
274 | 301 | let pmtAssetId = valueOrElse(pmt.assetId, WAVESID) | |
275 | 302 | let feeAmt = i.fee | |
276 | 303 | let feeAssetId = valueOrElse(i.feeAssetId, WAVESID) | |
277 | 304 | let callReward = (feeAmt * 3) | |
278 | 305 | let minedAmt = (pmt.amount - callReward) | |
279 | 306 | if ((pmt.amount != minDistributeAmount)) | |
280 | 307 | then throw((("attached payment must be exact " + toString(minDistributeAmount)) + " Wavelets")) | |
281 | 308 | else if ((pmtAssetId != WAVESID)) | |
282 | 309 | then throw("only Waves can be used in payment") | |
283 | 310 | else if ((feeAssetId != WAVESID)) | |
284 | 311 | then throw("only Waves can be used in fees") | |
285 | 312 | else if ((feeAmt != ((5 * MULT8) / 1000))) | |
286 | 313 | then throw("fee amount couldn't exceed 0.005") | |
287 | 314 | else { | |
288 | 315 | let neutrinoAddress = getAddressOrFail(keyNeutrinoAddressStr()) | |
289 | 316 | let masterNodeAddress = getAddressOrFail(keyMasterNodeAddressStr()) | |
290 | 317 | let minerAddress = i.caller | |
291 | 318 | let beneficiaryFromParam = addressFromStringValue(beneficiaryAddressStr) | |
292 | 319 | let beneficiaryAddress = resolveBeneficiaries(minerAddress, beneficiaryFromParam) | |
293 | 320 | let txRewardReceiver = beneficiaryFromParam | |
294 | 321 | let protocolPart = getIntOrFail(keyProtocolPartX6()) | |
295 | 322 | let beneficiaryPart = getIntOrFail(keyBenificaryPartX6()) | |
296 | 323 | let beneficiaryAmt = fraction(minedAmt, beneficiaryPart, MULT6) | |
297 | 324 | let protocolAmt = (minedAmt - beneficiaryAmt) | |
298 | - | [ScriptTransfer(beneficiaryAddress, beneficiaryAmt, unit), ScriptTransfer(neutrinoContract, protocolAmt, unit), ScriptTransfer(txRewardReceiver, callReward, unit), RewardHistoryEntry(minerAddress, i.transactionId, minedAmt, beneficiaryAmt, protocolAmt, protocolAmt, 0), RewardTotalsEntry(minerAddress, minedAmt, beneficiaryAmt, protocolAmt, protocolAmt, 0)] | |
325 | + | let buyBackAmt = (120 * MULT8) | |
326 | + | let savingsAddress = addressFromStringValue(getStrOrElse(this, keySavingsAddress(), "3PC7DBimauyKytx8tXhKo5u2ECb6FsndYKH")) | |
327 | + | let savingsAmt = asInt(invoke(savingsAddress, "withdraw", [buyBackAmt], nil)) | |
328 | + | let wxAssetIdStr = "Atqv59EYzjFGuitKVnMRk6H8FukjoV3ktPorbEys25on" | |
329 | + | let wxSwapAddress = addressFromStringValue(getStrOrElse(this, keyWxSwapAddress(), "3P68zNiufsu1viZpu1aY3cdahRRKcvV5N93")) | |
330 | + | let swapResult = invoke(wxSwapAddress, "swap", [1, wxAssetIdStr, toString(neutrinoContract)], [AttachedPayment(unit, savingsAmt)]) | |
331 | + | if ((swapResult == swapResult)) | |
332 | + | then [ScriptTransfer(beneficiaryAddress, beneficiaryAmt, unit), ScriptTransfer(neutrinoContract, protocolAmt, unit), ScriptTransfer(txRewardReceiver, callReward, unit), RewardHistoryEntry(minerAddress, i.transactionId, minedAmt, beneficiaryAmt, protocolAmt, protocolAmt, 0), RewardTotalsEntry(minerAddress, minedAmt, beneficiaryAmt, protocolAmt, protocolAmt, 0)] | |
333 | + | else throw("Strict value is not equal to itself.") | |
299 | 334 | } | |
300 | 335 | } | |
301 | 336 | } | |
302 | 337 | ||
303 | 338 | ||
304 | 339 | ||
305 | 340 | @Callable(i) | |
306 | 341 | func validateAndApproveLeasings (nListS) = { | |
307 | 342 | let nIdxs = [0, 1, 2, 3, 4, 5, 6, 7] | |
308 | 343 | let nList = split(nListS, SEP) | |
309 | 344 | let expectedCount = size(nIdxs) | |
310 | 345 | let neutrinoAddress = getAddressOrFail(keyNeutrinoAddressStr()) | |
311 | 346 | if ((i.caller != neutrinoAddress)) | |
312 | 347 | then throw("validateAndApproveLeasings not authorized") | |
313 | 348 | else if (((size(nList) % 2) != 0)) | |
314 | 349 | then throw("Only even number of nodes is allowed") | |
315 | 350 | else if ((size(nList) != expectedCount)) | |
316 | 351 | then throw((("Only " + toString(expectedCount)) + " of nodes' addresses can be passed")) | |
317 | 352 | else { | |
318 | 353 | func forEachNodeChangeStatus (acc,i) = { | |
319 | 354 | let nodeAddr = nList[i] | |
320 | 355 | let nodeDataStr = readNodeDataAndValidateStatus(nodeAddr, "PENDING") | |
321 | 356 | (acc :+ StringEntry(keyNodeRegistry(nodeAddr), formatDepositChangeStatus(nodeDataStr, "APPROVED"))) | |
322 | 357 | } | |
323 | 358 | ||
324 | 359 | let approvedNodesData = { | |
325 | 360 | let $l = nIdxs | |
326 | 361 | let $s = size($l) | |
327 | 362 | let $acc0 = nil | |
328 | 363 | func $f0_1 ($a,$i) = if (($i >= $s)) | |
329 | 364 | then $a | |
330 | 365 | else forEachNodeChangeStatus($a, $l[$i]) | |
331 | 366 | ||
332 | 367 | func $f0_2 ($a,$i) = if (($i >= $s)) | |
333 | 368 | then $a | |
334 | 369 | else throw("List size exceeds 8") | |
335 | 370 | ||
336 | 371 | $f0_2($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) | |
337 | 372 | } | |
338 | 373 | $Tuple2(approvedNodesData, nil) | |
339 | 374 | } | |
340 | 375 | } | |
341 | 376 | ||
342 | 377 | ||
343 | 378 | ||
344 | 379 | @Callable(i) | |
345 | 380 | func replaceApprovedNode (oldNodeAddrStr,newNodeAddrStr,groupNum,penaltyAmount) = if ((i.caller != neutrinoContract)) | |
346 | 381 | then throw("permissions denied") | |
347 | 382 | else { | |
348 | 383 | let oldDataStr = readNodeDataAndValidateStatus(oldNodeAddrStr, "APPROVED") | |
349 | 384 | let newDataStr = readNodeDataAndValidateStatus(newNodeAddrStr, "PENDING") | |
350 | 385 | let approvedNodeListS = getStringOrFail(this, keyApprovedNodeList()) | |
351 | 386 | if (!(contains(approvedNodeListS, oldNodeAddrStr))) | |
352 | 387 | then throw(("approvedNodeList does not contain " + oldNodeAddrStr)) | |
353 | 388 | else { | |
354 | 389 | let updatedNodeListS = makeString_2C(split_4C(approvedNodeListS, oldNodeAddrStr), newNodeAddrStr) | |
355 | 390 | let oldNodeAddr = addressFromStringValue(oldNodeAddrStr) | |
356 | 391 | let beneficiaryAddress = resolveBeneficiaries(oldNodeAddr, oldNodeAddr) | |
357 | 392 | let depoAmount = parseIntValue(split(oldDataStr, SEP)[nRegIdxDepoAmt]) | |
358 | 393 | let actions = [StringEntry(keyApprovedNodeList(), updatedNodeListS), DeleteEntry(keyNodeRegistry(oldNodeAddrStr)), StringEntry(keyNodeRegistry(newNodeAddrStr), formatDepositChangeStatus(newDataStr, "APPROVED"))] | |
359 | 394 | $Tuple2(if ((depoAmount > penaltyAmount)) | |
360 | 395 | then (actions :+ ScriptTransfer(beneficiaryAddress, (depoAmount - penaltyAmount), unit)) | |
361 | 396 | else actions, unit) | |
362 | 397 | } | |
363 | 398 | } | |
364 | 399 | ||
365 | 400 | ||
366 | 401 | ||
367 | 402 | @Callable(i) | |
368 | 403 | func returnDeposit (nodeAddressStr) = if ((size(i.payments) != 0)) | |
369 | 404 | then throw("No payments allowed") | |
370 | 405 | else { | |
371 | 406 | let callerAddress = i.caller | |
372 | 407 | let nodeRegistryKEY = keyNodeRegistry(nodeAddressStr) | |
373 | 408 | let nodeDataOpt = getString(this, nodeRegistryKEY) | |
374 | 409 | if (!(isDefined(nodeDataOpt))) | |
375 | 410 | then throw(("Address is not applied as neutrino node: " + nodeAddressStr)) | |
376 | 411 | else { | |
377 | 412 | let approvedNodeList = getStringOrFail(this, keyApprovedNodeList()) | |
378 | 413 | if (contains(approvedNodeList, nodeAddressStr)) | |
379 | 414 | then throw("Impossible to return deposit from approved Node, please contact support team") | |
380 | 415 | else { | |
381 | 416 | let nodeData = split(value(nodeDataOpt), SEP) | |
382 | 417 | let status = if ((size(nodeData) >= 9)) | |
383 | 418 | then nodeData[nRegIdxStatus] | |
384 | 419 | else "PENDING" | |
385 | 420 | if ((status != "PENDING")) | |
386 | 421 | then throw("Application status is not PENDING!") | |
387 | 422 | else { | |
388 | 423 | let depoAmount = parseIntValue(nodeData[nRegIdxDepoAmt]) | |
389 | 424 | let nodeAddress = addressFromStringValue(nodeAddressStr) | |
390 | 425 | let beneficiaryAddress = resolveBeneficiaries(nodeAddress, nodeAddress) | |
391 | 426 | if (!(if (if ((callerAddress == this)) | |
392 | 427 | then true | |
393 | 428 | else if ((beneficiaryAddress != nodeAddress)) | |
394 | 429 | then (callerAddress == beneficiaryAddress) | |
395 | 430 | else false) | |
396 | 431 | then true | |
397 | 432 | else if ((beneficiaryAddress == nodeAddress)) | |
398 | 433 | then (callerAddress == nodeAddress) | |
399 | 434 | else false)) | |
400 | 435 | then throw("returnDeposit permissions denied") | |
401 | 436 | else [DeleteEntry(nodeRegistryKEY), ScriptTransfer(beneficiaryAddress, depoAmount, unit)] | |
402 | 437 | } | |
403 | 438 | } | |
404 | 439 | } | |
405 | 440 | } | |
406 | 441 | ||
407 | 442 | ||
443 | + | ||
444 | + | @Callable(i) | |
445 | + | func initNodesVoting (startHeight,endHeight,options,description) = if ((i.caller != this)) | |
446 | + | then throw("permissions denied") | |
447 | + | else { | |
448 | + | let optionsArray = split(options, "__") | |
449 | + | if (((size(optionsArray) % 2) != 0)) | |
450 | + | then throw("Not even number of options") | |
451 | + | else if (((size(optionsArray) / 2) > 10)) | |
452 | + | then throw("Max 10 options can be specified") | |
453 | + | else { | |
454 | + | let nodesVotingNumKEY = keyNodesVotingNextNum() | |
455 | + | let votingNum = getIntOrElse(nodesVotingNumKEY, 0) | |
456 | + | let votingNumStr = toString(votingNum) | |
457 | + | func transformOptions (accum,nextOpt) = { | |
458 | + | let optData = split(nextOpt, ":") | |
459 | + | let opt = optData[0] | |
460 | + | let optKEY = keyNodesVotingOptionKey(votingNumStr, opt) | |
461 | + | let optDescr = optData[1] | |
462 | + | let optTotalVotesKEY = keyNodesVotingOptionTotalVotes(votingNumStr, opt) | |
463 | + | ((accum :+ StringEntry(optKEY, optDescr)) :+ IntegerEntry(optTotalVotesKEY, 0)) | |
464 | + | } | |
465 | + | ||
466 | + | (((({ | |
467 | + | let $l = optionsArray | |
468 | + | let $s = size($l) | |
469 | + | let $acc0 = nil | |
470 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
471 | + | then $a | |
472 | + | else transformOptions($a, $l[$i]) | |
473 | + | ||
474 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
475 | + | then $a | |
476 | + | else throw("List size exceeds 10") | |
477 | + | ||
478 | + | $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) | |
479 | + | } :+ IntegerEntry(nodesVotingNumKEY, (votingNum + 1))) :+ StringEntry(keyNodesVotingDesc(votingNumStr), description)) :+ IntegerEntry(keyNodesVotingStartHeight(votingNumStr), startHeight)) :+ IntegerEntry(keyNodesVotingEndHeight(votingNumStr), endHeight)) | |
480 | + | } | |
481 | + | } | |
482 | + | ||
483 | + | ||
484 | + | ||
485 | + | @Callable(i) | |
486 | + | func voteByNode (nodeAddressStr,votingNum,optionNum) = { | |
487 | + | let validateNode = readNodeDataAndValidateStatus(nodeAddressStr, "APPROVED") | |
488 | + | if ((validateNode == validateNode)) | |
489 | + | then { | |
490 | + | let nodeAddress = addressFromStringValue(nodeAddressStr) | |
491 | + | let nodeBeneficiary = getStringOrFail(nodeAddress, keyBeneficiaryAddress()) | |
492 | + | let voterAddressStr = toString(i.caller) | |
493 | + | if ((voterAddressStr != nodeBeneficiary)) | |
494 | + | then throw("Only Node's beneficiary can do voting") | |
495 | + | else { | |
496 | + | let startHeight = getIntOrFail(keyNodesVotingStartHeight(votingNum)) | |
497 | + | let endHeight = getIntOrFail(keyNodesVotingEndHeight(votingNum)) | |
498 | + | if ((startHeight > height)) | |
499 | + | then throw("Voting has not been started yet") | |
500 | + | else if ((height > endHeight)) | |
501 | + | then throw("Voting finished") | |
502 | + | else { | |
503 | + | let nodeChoiceKEY = keyNodesVotingNodeChoice(votingNum, nodeAddressStr) | |
504 | + | let nodeChoice = getStrOrElse(this, nodeChoiceKEY, "") | |
505 | + | if ((nodeChoice != "")) | |
506 | + | then throw("Node has already voted. It is allowed to vote only once") | |
507 | + | else { | |
508 | + | let optionTotalVotesKEY = keyNodesVotingOptionTotalVotes(votingNum, optionNum) | |
509 | + | let optionTotalVotes = getIntOrFail(optionTotalVotesKEY) | |
510 | + | [IntegerEntry(optionTotalVotesKEY, (optionTotalVotes + 1)), StringEntry(nodeChoiceKEY, optionNum)] | |
511 | + | } | |
512 | + | } | |
513 | + | } | |
514 | + | } | |
515 | + | else throw("Strict value is not equal to itself.") | |
516 | + | } | |
517 | + | ||
518 | + |
github/deemru/w8io/169f3d6 119.43 ms ◑![]()