tx · 4ey9kFvkF3YadfYHJ9QfATr3LvnvKiRUxjhrd3tcswrH

3MuS6qVvhBR6wSynFRdcE3fVqmGBjoc7Hhx:  -0.02200000 Waves

2023.07.27 13:55 [2684165] smart account 3MuS6qVvhBR6wSynFRdcE3fVqmGBjoc7Hhx > SELF 0.00000000 Waves

{ "type": 13, "id": "4ey9kFvkF3YadfYHJ9QfATr3LvnvKiRUxjhrd3tcswrH", "fee": 2200000, "feeAssetId": null, "timestamp": 1690455453311, "version": 2, "chainId": 84, "sender": "3MuS6qVvhBR6wSynFRdcE3fVqmGBjoc7Hhx", "senderPublicKey": "62CHk4MqTdq3LqeUycy7TPnpvwrjgerSa2FqAY2EafXn", "proofs": [ "2g8ou1AmcFzwcKhQuYVtQ8kqjkz3gGzx6zQ6dtfE21xfhKpEMhqy6uJKsEAAzKGJ28bvp2Bg9oYtT9zsYhe7Jpb9" ], "script": "base64:BgIrCAISBQoDCAEIEgMKAQgSBAoCCAQSAwoBCBIDCgEIEgUKAwgBCBIECgIIATAACXNlcGFyYXRvcgICX18ABU1VTFQ4AIDC1y8BB3dyYXBFcnIBA21zZwkAuQkCCQDMCAICGHZvdGluZ192ZXJpZmllZF92Mi5yaWRlOgkAzAgCBQNtc2cFA25pbAIBIAEIdGhyb3dFcnIBA21zZwkAAgEJAQd3cmFwRXJyAQUDbXNnAQVhc0ludAEDdmFsBAckbWF0Y2gwBQN2YWwDCQABAgUHJG1hdGNoMAIDSW50BAZ2YWxJbnQFByRtYXRjaDAFBnZhbEludAkAAgECG0ZhaWxlZCB0byBjYXN0IGludG8gSW50ZWdlcgEQZ2V0SW50ZWdlck9yWmVybwIHYWRkcmVzcwNrZXkJAQt2YWx1ZU9yRWxzZQIJAJoIAgUHYWRkcmVzcwUDa2V5AAABEGdldEludGVnZXJPckZhaWwCB2FkZHJlc3MDa2V5CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUHYWRkcmVzcwUDa2V5CQEHd3JhcEVycgEJAKwCAgUDa2V5Ag8gaXMgbm90IGRlZmluZWQBEGdldFN0cmluZ09yRW1wdHkCB2FkZHJlc3MDa2V5CQELdmFsdWVPckVsc2UCCQCdCAIFB2FkZHJlc3MFA2tleQIAAQ9nZXRTdHJpbmdPckZhaWwCB2FkZHJlc3MDa2V5CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ0IAgUHYWRkcmVzcwUDa2V5CQEHd3JhcEVycgEJAKwCAgUDa2V5Ag8gaXMgbm90IGRlZmluZWQAE2tleUJvb3N0aW5nQ29udHJhY3QJALkJAgkAzAgCAgIlcwkAzAgCAhBib29zdGluZ0NvbnRyYWN0BQNuaWwFCXNlcGFyYXRvcgATa2V5RW1pc3Npb25Db250cmFjdAkAuQkCCQDMCAICAiVzCQDMCAICEGVtaXNzaW9uQ29udHJhY3QFA25pbAUJc2VwYXJhdG9yABZrZXlBc3NldHNTdG9yZUNvbnRyYWN0CQC5CQIJAMwIAgICJXMJAMwIAgITYXNzZXRzU3RvcmVDb250cmFjdAUDbmlsBQlzZXBhcmF0b3IAEGJvb3N0aW5nQ29udHJhY3QJARFAZXh0ck5hdGl2ZSgxMDYyKQEJARFAZXh0ck5hdGl2ZSgxMDU4KQEFE2tleUJvb3N0aW5nQ29udHJhY3QAEGVtaXNzaW9uQ29udHJhY3QJARFAZXh0ck5hdGl2ZSgxMDYyKQEJARFAZXh0ck5hdGl2ZSgxMDU4KQEFE2tleUVtaXNzaW9uQ29udHJhY3QAE2Fzc2V0c1N0b3JlQ29udHJhY3QJARFAZXh0ck5hdGl2ZSgxMDYyKQEJARFAZXh0ck5hdGl2ZSgxMDU4KQEFFmtleUFzc2V0c1N0b3JlQ29udHJhY3QAEWtleUVtaXNzaW9uQ29uZmlnCQC5CQIJAMwIAgICJXMJAMwIAgIGY29uZmlnBQNuaWwFCXNlcGFyYXRvcgAMd3hBc3NldElkU3RyCQCRAwIJALUJAgkBD2dldFN0cmluZ09yRmFpbAIFEGVtaXNzaW9uQ29udHJhY3QFEWtleUVtaXNzaW9uQ29uZmlnBQlzZXBhcmF0b3IAAQAJd3hBc3NldElkCQDZBAEFDHd4QXNzZXRJZFN0cgAVa2V5Vm90aW5nVGhyZXNob2xkQWRkCQC5CQIJAMwIAgIEJXMlcwkAzAgCAg92b3RpbmdUaHJlc2hvbGQJAMwIAgIDYWRkBQNuaWwFCXNlcGFyYXRvcgAYa2V5Vm90aW5nVGhyZXNob2xkUmVtb3ZlCQC5CQIJAMwIAgIEJXMlcwkAzAgCAg92b3RpbmdUaHJlc2hvbGQJAMwIAgIGcmVtb3ZlBQNuaWwFCXNlcGFyYXRvcgAVa2V5UGVyaW9kTGVuZ3RoUmVtb3ZlCQC5CQIJAMwIAgICJXMJAMwIAgIScGVyaW9kTGVuZ3RoUmVtb3ZlBQNuaWwFCXNlcGFyYXRvcgASa2V5TWF4UGVyaW9kTGVuZ3RoCQC5CQIJAMwIAgICJXMJAMwIAgIPbWF4UGVyaW9kTGVuZ3RoBQNuaWwFCXNlcGFyYXRvcgASa2V5TWluUGVyaW9kTGVuZ3RoCQC5CQIJAMwIAgICJXMJAMwIAgIPbWluUGVyaW9kTGVuZ3RoBQNuaWwFCXNlcGFyYXRvcgEWa2V5Vm90aW5nUmV3YXJkQXNzZXRJZAIHYXNzZXRJZAVpbmRleAkAuQkCCQDMCAICBiVzJXMlZAkAzAgCAhN2b3RpbmdSZXdhcmRBc3NldElkCQDMCAIFB2Fzc2V0SWQJAMwIAgkApAMBBQVpbmRleAUDbmlsBQlzZXBhcmF0b3IBD2tleVZvdGluZ1Jld2FyZAMLdXNlckFkZHJlc3MHYXNzZXRJZAVpbmRleAkAuQkCCQDMCAICCCVzJXMlcyVkCQDMCAICDHZvdGluZ1Jld2FyZAkAzAgCCQClCAEFC3VzZXJBZGRyZXNzCQDMCAIFB2Fzc2V0SWQJAMwIAgkApAMBBQVpbmRleAUDbmlsBQlzZXBhcmF0b3IBFGtleVRvdGFsVm90aW5nUmV3YXJkAgdhc3NldElkBWluZGV4CQC5CQIJAMwIAgIGJXMlcyVkCQDMCAICEXRvdGFsVm90aW5nUmV3YXJkCQDMCAIFB2Fzc2V0SWQJAMwIAgkApAMBBQVpbmRleAUDbmlsBQlzZXBhcmF0b3IAG2tleUZpbmFsaXplQ2FsbFJld2FyZEFtb3VudAkAuQkCCQDMCAICAiVzCQDMCAICGGZpbmFsaXplQ2FsbFJld2FyZEFtb3VudAUDbmlsBQlzZXBhcmF0b3IAGmtleU1pblN1Z2dlc3RSZW1vdmVCYWxhbmNlCQC5CQIJAMwIAgICJXMJAMwIAgIXbWluU3VnZ2VzdFJlbW92ZUJhbGFuY2UFA25pbAUJc2VwYXJhdG9yAQ9rZXlDdXJyZW50SW5kZXgBB2Fzc2V0SWQJALkJAgkAzAgCAgQlcyVzCQDMCAICDGN1cnJlbnRJbmRleAkAzAgCBQdhc3NldElkBQNuaWwFCXNlcGFyYXRvcgEHa2V5Vm90ZQMHYXNzZXRJZAVpbmRleAZjYWxsZXIJALkJAgkAzAgCAgglcyVzJWQlcwkAzAgCAgR2b3RlCQDMCAIFB2Fzc2V0SWQJAMwIAgkApAMBBQVpbmRleAkAzAgCCQClCAEFBmNhbGxlcgUDbmlsBQlzZXBhcmF0b3IBCXZvdGVWYWx1ZQIHaW5GYXZvcglnd3hBbW91bnQJALkJAgkAzAgCAgQlcyVkCQDMCAIJAKUDAQUHaW5GYXZvcgkAzAgCCQCkAwEFCWd3eEFtb3VudAUDbmlsBQlzZXBhcmF0b3IBEGtleVN1Z2dlc3RJc3N1ZXICB2Fzc2V0SWQFaW5kZXgJALkJAgkAzAgCAgYlcyVzJWQJAMwIAgINc3VnZ2VzdElzc3VlcgkAzAgCBQdhc3NldElkCQDMCAIJAKQDAQUFaW5kZXgFA25pbAUJc2VwYXJhdG9yAQ9rZXlDbGFpbUhpc3RvcnkDC3VzZXJBZGRyZXNzB2Fzc2V0SWQFaW5kZXgJALkJAgkAzAgCAgglcyVzJXMlZAkAzAgCAgdoaXN0b3J5CQDMCAIJAKUIAQULdXNlckFkZHJlc3MJAMwIAgUHYXNzZXRJZAkAzAgCCQCkAwEFBWluZGV4BQNuaWwFCXNlcGFyYXRvcgAOa2V5RmVlUGVyQmxvY2sJALkJAgkAzAgCAgIlcwkAzAgCAgtmZWVQZXJCbG9jawUDbmlsBQlzZXBhcmF0b3IAC2ZlZVBlckJsb2NrCQEQZ2V0SW50ZWdlck9yRmFpbAIFBHRoaXMFDmtleUZlZVBlckJsb2NrACZrZXlNaW5XeE1pbkZvclN1Z2dlc3RBZGRBbW91bnRSZXF1aXJlZAkAuQkCCQDMCAICAiVzCQDMCAICIHd4TWluRm9yU3VnZ2VzdEFkZEFtb3VudFJlcXVpcmVkBQNuaWwFCXNlcGFyYXRvcgAja2V5V3hGb3JTdWdnZXN0UmVtb3ZlQW1vdW50UmVxdWlyZWQJALkJAgkAzAgCAgIlcwkAzAgCAiB3eEZvclN1Z2dlc3RSZW1vdmVBbW91bnRSZXF1aXJlZAUDbmlsBQlzZXBhcmF0b3IBDWtleVZvdGluZ0luZm8CB2Fzc2V0SWQFaW5kZXgJALkJAgkAzAgCAgYlcyVzJWQJAMwIAgIKdm90aW5nSW5mbwkAzAgCBQdhc3NldElkCQDMCAIJAKQDAQUFaW5kZXgFA25pbAUJc2VwYXJhdG9yAQ92b3RpbmdJbmZvVmFsdWUKDWlzUmV3YXJkRXhpc3QNcmV3YXJkQXNzZXRJZAxyZXdhcmRBbW91bnQKdm90aW5nVHlwZQZzdGF0dXMRdm90aW5nU3RhcnRIZWlnaHQPdm90aW5nRW5kSGVpZ2h0C3ZvdGVzUXVvcnVtCHZvdGVzRm9yDHZvdGVzQWdhaW5zdAkAuQkCCQDMCAICFCVzJXMlZCVzJXMlZCVkJWQlZCVkCQDMCAIJAKUDAQUNaXNSZXdhcmRFeGlzdAkAzAgCBQ1yZXdhcmRBc3NldElkCQDMCAIJAKQDAQUMcmV3YXJkQW1vdW50CQDMCAIFCnZvdGluZ1R5cGUJAMwIAgUGc3RhdHVzCQDMCAIJAKQDAQURdm90aW5nU3RhcnRIZWlnaHQJAMwIAgkApAMBBQ92b3RpbmdFbmRIZWlnaHQJAMwIAgkApAMBBQt2b3Rlc1F1b3J1bQkAzAgCCQCkAwEFCHZvdGVzRm9yCQDMCAIJAKQDAQUMdm90ZXNBZ2FpbnN0BQNuaWwFCXNlcGFyYXRvcgENa2V5QXNzZXRJbWFnZQEHYXNzZXRJZAkAuQkCCQDMCAICBCVzJXMJAMwIAgIKYXNzZXRJbWFnZQkAzAgCBQdhc3NldElkBQNuaWwFCXNlcGFyYXRvcgEYZ2V0VXNlckd3eEFtb3VudEF0SGVpZ2h0Agt1c2VyQWRkcmVzcwx0YXJnZXRIZWlnaHQECWd3eEFtb3VudAkA/AcEBRBib29zdGluZ0NvbnRyYWN0AiBnZXRVc2VyR3d4QW1vdW50QXRIZWlnaHRSRUFET05MWQkAzAgCBQt1c2VyQWRkcmVzcwkAzAgCBQx0YXJnZXRIZWlnaHQFA25pbAUDbmlsCQEFYXNJbnQBBQlnd3hBbW91bnQBFmtleU1hbmFnZXJWYXVsdEFkZHJlc3MAAhclc19fbWFuYWdlclZhdWx0QWRkcmVzcwETa2V5TWFuYWdlclB1YmxpY0tleQACFCVzX19tYW5hZ2VyUHVibGljS2V5ARxnZXRNYW5hZ2VyVmF1bHRBZGRyZXNzT3JUaGlzAAQHJG1hdGNoMAkAoggBCQEWa2V5TWFuYWdlclZhdWx0QWRkcmVzcwADCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFzBQckbWF0Y2gwCQERQGV4dHJOYXRpdmUoMTA2MikBBQFzBQR0aGlzARZtYW5hZ2VyUHVibGljS2V5T3JVbml0AAQTbWFuYWdlclZhdWx0QWRkcmVzcwkBHGdldE1hbmFnZXJWYXVsdEFkZHJlc3NPclRoaXMABAckbWF0Y2gwCQCdCAIFE21hbmFnZXJWYXVsdEFkZHJlc3MJARNrZXlNYW5hZ2VyUHVibGljS2V5AAMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAXMFByRtYXRjaDAJANkEAQUBcwMJAAECBQckbWF0Y2gwAgRVbml0BQR1bml0CQACAQILTWF0Y2ggZXJyb3IBEmdldFZvdGluZ0luZm9QYXJ0cwEKdm90aW5nSW5mbwQPdm90aW5nSW5mb1BhcnRzCQC1CQIFCnZvdGluZ0luZm8FCXNlcGFyYXRvcgQQaXNSZXdhcmRFeGlzdFN0cgkAkQMCBQ92b3RpbmdJbmZvUGFydHMAAQQNaXNSZXdhcmRFeGlzdAMJAAACBRBpc1Jld2FyZEV4aXN0U3RyAgR0cnVlBgcEDXJld2FyZEFzc2V0SWQJAJEDAgUPdm90aW5nSW5mb1BhcnRzAAIEDHJld2FyZEFtb3VudAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFD3ZvdGluZ0luZm9QYXJ0cwADBAp2b3RpbmdUeXBlCQCRAwIFD3ZvdGluZ0luZm9QYXJ0cwAEBAZzdGF0dXMJAJEDAgUPdm90aW5nSW5mb1BhcnRzAAUEEXZvdGluZ1N0YXJ0SGVpZ2h0CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUPdm90aW5nSW5mb1BhcnRzAAYED3ZvdGluZ0VuZEhlaWdodAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFD3ZvdGluZ0luZm9QYXJ0cwAHBAt2b3Rlc1F1b3J1bQkBDXBhcnNlSW50VmFsdWUBCQCRAwIFD3ZvdGluZ0luZm9QYXJ0cwAIBAh2b3Rlc0ZvcgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFD3ZvdGluZ0luZm9QYXJ0cwAJBAx2b3Rlc0FnYWluc3QJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQ92b3RpbmdJbmZvUGFydHMACgkAnAoKBQ1pc1Jld2FyZEV4aXN0BQ1yZXdhcmRBc3NldElkBQxyZXdhcmRBbW91bnQFCnZvdGluZ1R5cGUFBnN0YXR1cwURdm90aW5nU3RhcnRIZWlnaHQFD3ZvdGluZ0VuZEhlaWdodAULdm90ZXNRdW9ydW0FCHZvdGVzRm9yBQx2b3Rlc0FnYWluc3QBEXZvdGluZ0V4aXN0Q2hlY2tzAgdhc3NldElkDGN1cnJlbnRJbmRleAQKdm90aW5nSW5mbwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCiCAEJAQ1rZXlWb3RpbmdJbmZvAgUHYXNzZXRJZAUMY3VycmVudEluZGV4CQEHd3JhcEVycgECFXZvdGluZyBpbmZvIG5vdCBmb3VuZAQPdm90aW5nSW5mb0FycmF5CQC1CQIFCnZvdGluZ0luZm8FCXNlcGFyYXRvcgQGc3RhdHVzCQCRAwIFD3ZvdGluZ0luZm9BcnJheQAFBA92b3RpbmdFbmRIZWlnaHQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFD3ZvdGluZ0luZm9BcnJheQAHCQEHd3JhcEVycgECHXZvdGluZyBzdGFydCBoZWlnaHQgbm90IGZvdW5kBA1zdWdnZXN0SXNzdWVyCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKIIAQkBEGtleVN1Z2dlc3RJc3N1ZXICBQdhc3NldElkBQxjdXJyZW50SW5kZXgJAQd3cmFwRXJyAQIXdm90aW5nIGlzc3VlciBub3QgZm91bmQEBmNoZWNrcwkAzAgCAwkAAAIFBnN0YXR1cwIKaW5Qcm9ncmVzcwYJAQh0aHJvd0VycgECFW5vIHZvdGluZyBpbiBwcm9ncmVzcwkAzAgCAwkAZgIFD3ZvdGluZ0VuZEhlaWdodAUGaGVpZ2h0BgkBCHRocm93RXJyAQIOdm90aW5nIGV4cGlyZWQFA25pbAMJAAACBQZjaGVja3MFBmNoZWNrcwkAlQoDBQZzdGF0dXMFD3ZvdGluZ0VuZEhlaWdodAUNc3VnZ2VzdElzc3VlcgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgEPY2FsY3VsYXRlUmV3YXJkAwV2b3Rlcgdhc3NldElkBWluZGV4BAd2b3RlS2V5CQEHa2V5Vm90ZQMFB2Fzc2V0SWQFBWluZGV4BQV2b3RlcgQIbGFzdFZvdGUJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBBQd2b3RlS2V5CQEHd3JhcEVycgECEnlvdSBoYXZlIG5vdCB2b3RlZAQNbGFzdFZvdGVQYXJ0cwkAtQkCBQhsYXN0Vm90ZQUJc2VwYXJhdG9yBAlnd3hBbW91bnQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQ1sYXN0Vm90ZVBhcnRzAAIEDXZvdGluZ0luZm9TdHIJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQENa2V5Vm90aW5nSW5mbwIFB2Fzc2V0SWQFBWluZGV4CQEHd3JhcEVycgECFXZvdGluZyBpbmZvIG5vdCBmb3VuZAQLdm90aW5nUGFydHMJARJnZXRWb3RpbmdJbmZvUGFydHMBBQ12b3RpbmdJbmZvU3RyBAh2b3Rlc0ZvcggFC3ZvdGluZ1BhcnRzAl85BAx2b3Rlc0FnYWluc3QIBQt2b3RpbmdQYXJ0cwNfMTAEFXBhcnRPZlRoZVRvdGFsVm90ZXNYOAkAawMFCWd3eEFtb3VudAUFTVVMVDgJAGQCBQh2b3Rlc0ZvcgUMdm90ZXNBZ2FpbnN0BBF0b3RhbFZvdGluZ1Jld2FyZAkBC3ZhbHVlT3JFbHNlAgkAnwgBCQEUa2V5VG90YWxWb3RpbmdSZXdhcmQCBQdhc3NldElkBQVpbmRleAAABBF2b3RlclJld2FyZEFtb3VudAkAbgQFFXBhcnRPZlRoZVRvdGFsVm90ZXNYOAURdG90YWxWb3RpbmdSZXdhcmQFBU1VTFQ4BQVGTE9PUgURdm90ZXJSZXdhcmRBbW91bnQHAWkBCnN1Z2dlc3RBZGQDB2Fzc2V0SWQMcGVyaW9kTGVuZ3RoCmFzc2V0SW1hZ2UECXd4UGF5bWVudAkAkQMCCAUBaQhwYXltZW50cwAABBB3eFBheW1lbnRBc3NldElkCQEFdmFsdWUBCAUJd3hQYXltZW50B2Fzc2V0SWQED3d4UGF5bWVudEFtb3VudAkBBXZhbHVlAQgFCXd4UGF5bWVudAZhbW91bnQED21pblBlcmlvZExlbmd0aAkBEUBleHRyTmF0aXZlKDEwNTUpAQUSa2V5TWluUGVyaW9kTGVuZ3RoBA9tYXhQZXJpb2RMZW5ndGgJARFAZXh0ck5hdGl2ZSgxMDU1KQEFEmtleU1heFBlcmlvZExlbmd0aAQPdG9rZW5Jc1ZlcmlmaWVkCgABQAkA/AcEBRNhc3NldHNTdG9yZUNvbnRyYWN0AhJpc1ZlcmlmaWVkUkVBRE9OTFkJAMwIAgUHYXNzZXRJZAUDbmlsBQNuaWwDCQABAgUBQAIHQm9vbGVhbgUBQAkAAgEJAKwCAgkAAwEFAUACHCBjb3VsZG4ndCBiZSBjYXN0IHRvIEJvb2xlYW4EBmNoZWNrcwkAzAgCAwMJAGcCBQxwZXJpb2RMZW5ndGgFD21pblBlcmlvZExlbmd0aAkAZwIFD21heFBlcmlvZExlbmd0aAUMcGVyaW9kTGVuZ3RoBwYJAQh0aHJvd0VycgECFGludmFsaWQgcGVyaW9kTGVuZ3RoCQDMCAIDCQAAAgUPdG9rZW5Jc1ZlcmlmaWVkBwYJAQh0aHJvd0VycgECFnRva2VuIGFscmVhZHkgdmVyaWZpZWQJAMwIAgMJAGYCBQ93eFBheW1lbnRBbW91bnQJAGgCBQxwZXJpb2RMZW5ndGgFC2ZlZVBlckJsb2NrBgkBCHRocm93RXJyAQIebm90IGVub3VnaCB3eCBmb3IgZ2l2ZW4gcGVyaW9kCQDMCAIDCQBnAgUPd3hQYXltZW50QW1vdW50CQERQGV4dHJOYXRpdmUoMTA1NSkBBSZrZXlNaW5XeE1pbkZvclN1Z2dlc3RBZGRBbW91bnRSZXF1aXJlZAYJAQh0aHJvd0VycgECIXBheW1lbnQgbGVzcyB0aGVuIG1pbiBmb3Igc3VnZ2VzdAUDbmlsAwkAAAIFBmNoZWNrcwUGY2hlY2tzBA9jdXJyZW50SW5kZXhLZXkJAQ9rZXlDdXJyZW50SW5kZXgBBQdhc3NldElkBAxjdXJyZW50SW5kZXgJAJ8IAQUPY3VycmVudEluZGV4S2V5BAhuZXdJbmRleAMJAQlpc0RlZmluZWQBBQxjdXJyZW50SW5kZXgJAGQCCQEFdmFsdWUBBQxjdXJyZW50SW5kZXgAAQAABAskdDA4Nzg0OTQyNAMJAGYCCQCQAwEIBQFpCHBheW1lbnRzAAEEE3ZvdGluZ1Jld2FyZFBheW1lbnQJAJEDAggFAWkIcGF5bWVudHMAAQQadm90aW5nUmV3YXJkUGF5bWVudEFzc2V0SWQJANgEAQkBBXZhbHVlAQgFE3ZvdGluZ1Jld2FyZFBheW1lbnQHYXNzZXRJZAQZdm90aW5nUmV3YXJkUGF5bWVudEFtb3VudAkBBXZhbHVlAQgFE3ZvdGluZ1Jld2FyZFBheW1lbnQGYW1vdW50CQCWCgQGBRp2b3RpbmdSZXdhcmRQYXltZW50QXNzZXRJZAUZdm90aW5nUmV3YXJkUGF5bWVudEFtb3VudAkAzAgCCQELU3RyaW5nRW50cnkCCQEWa2V5Vm90aW5nUmV3YXJkQXNzZXRJZAIFB2Fzc2V0SWQFCG5ld0luZGV4BRp2b3RpbmdSZXdhcmRQYXltZW50QXNzZXRJZAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBFGtleVRvdGFsVm90aW5nUmV3YXJkAgUHYXNzZXRJZAUIbmV3SW5kZXgFGXZvdGluZ1Jld2FyZFBheW1lbnRBbW91bnQFA25pbAkAlgoEBwIFRU1QVFkAAAUDbmlsBA1pc1Jld2FyZEV4aXN0CAULJHQwODc4NDk0MjQCXzEEDXJld2FyZEFzc2V0SWQIBQskdDA4Nzg0OTQyNAJfMgQMcmV3YXJkQW1vdW50CAULJHQwODc4NDk0MjQCXzMEE3ZvdGluZ1Jld2FyZEFjdGlvbnMIBQskdDA4Nzg0OTQyNAJfNAQLdm90ZXNRdW9ydW0JARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnwgBBRVrZXlWb3RpbmdUaHJlc2hvbGRBZGQJAQd3cmFwRXJyAQIadm90aW5nVGhyZXNob2xkQWRkIG5vdCBzZXQECnZvdGluZ0luZm8JAQ92b3RpbmdJbmZvVmFsdWUKBQ1pc1Jld2FyZEV4aXN0BQ1yZXdhcmRBc3NldElkBQxyZXdhcmRBbW91bnQCDHZlcmlmaWNhdGlvbgIKaW5Qcm9ncmVzcwUGaGVpZ2h0CQBkAgUGaGVpZ2h0BQxwZXJpb2RMZW5ndGgFC3ZvdGVzUXVvcnVtAAAAAAQYZmluYWxpemVDYWxsUmV3YXJkQW1vdW50CQERQGV4dHJOYXRpdmUoMTA1NSkBBRtrZXlGaW5hbGl6ZUNhbGxSZXdhcmRBbW91bnQEDGJ1cm5XeEFtb3VudAkAZQIFD3d4UGF5bWVudEFtb3VudAUYZmluYWxpemVDYWxsUmV3YXJkQW1vdW50CQDOCAIJAMwIAgkBDEludGVnZXJFbnRyeQIFD2N1cnJlbnRJbmRleEtleQUIbmV3SW5kZXgJAMwIAgkBC1N0cmluZ0VudHJ5AgkBEGtleVN1Z2dlc3RJc3N1ZXICBQdhc3NldElkBQhuZXdJbmRleAkApQgBCAUBaQZjYWxsZXIJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDWtleVZvdGluZ0luZm8CBQdhc3NldElkBQhuZXdJbmRleAUKdm90aW5nSW5mbwkAzAgCCQELU3RyaW5nRW50cnkCCQENa2V5QXNzZXRJbWFnZQEFB2Fzc2V0SWQFCmFzc2V0SW1hZ2UJAMwIAgkBBEJ1cm4CBRB3eFBheW1lbnRBc3NldElkBQxidXJuV3hBbW91bnQFA25pbAUTdm90aW5nUmV3YXJkQWN0aW9ucwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ1zdWdnZXN0UmVtb3ZlAQdhc3NldElkBA5nd3hBbW91bnRBdE5vdwkBGGdldFVzZXJHd3hBbW91bnRBdEhlaWdodAIJAKUIAQgFAWkGY2FsbGVyBQZoZWlnaHQEF21pblN1Z2dlc3RSZW1vdmVCYWxhbmNlCQERQGV4dHJOYXRpdmUoMTA1NSkBBRprZXlNaW5TdWdnZXN0UmVtb3ZlQmFsYW5jZQQJd3hQYXltZW50CQCRAwIIBQFpCHBheW1lbnRzAAAEEHd4UGF5bWVudEFzc2V0SWQJAQV2YWx1ZQEIBQl3eFBheW1lbnQHYXNzZXRJZAQPd3hQYXltZW50QW1vdW50CQEFdmFsdWUBCAUJd3hQYXltZW50BmFtb3VudAQPdG9rZW5Jc1ZlcmlmaWVkCgABQAkA/AcEBRNhc3NldHNTdG9yZUNvbnRyYWN0AhJpc1ZlcmlmaWVkUkVBRE9OTFkJAMwIAgUHYXNzZXRJZAUDbmlsBQNuaWwDCQABAgUBQAIHQm9vbGVhbgUBQAkAAgEJAKwCAgkAAwEFAUACHCBjb3VsZG4ndCBiZSBjYXN0IHRvIEJvb2xlYW4EBmNoZWNrcwkAzAgCAwUPdG9rZW5Jc1ZlcmlmaWVkBgkBCHRocm93RXJyAQISdG9rZW4gbm90IHZlcmlmaWVkCQDMCAIDCQBnAgUOZ3d4QW1vdW50QXROb3cFF21pblN1Z2dlc3RSZW1vdmVCYWxhbmNlBgkBCHRocm93RXJyAQIQbm90IGVub3VnaCBnV1hlcwkAzAgCAwkAZwIFD3d4UGF5bWVudEFtb3VudAkBEUBleHRyTmF0aXZlKDEwNTUpAQUja2V5V3hGb3JTdWdnZXN0UmVtb3ZlQW1vdW50UmVxdWlyZWQGCQEIdGhyb3dFcnIBAiFwYXltZW50IGxlc3MgdGhlbiBtaW4gZm9yIHN1Z2dlc3QFA25pbAMJAAACBQZjaGVja3MFBmNoZWNrcwQPY3VycmVudEluZGV4S2V5CQEPa2V5Q3VycmVudEluZGV4AQUHYXNzZXRJZAQMY3VycmVudEluZGV4CQCfCAEFD2N1cnJlbnRJbmRleEtleQQIbmV3SW5kZXgDCQEJaXNEZWZpbmVkAQUMY3VycmVudEluZGV4CQBkAgkBBXZhbHVlAQUMY3VycmVudEluZGV4AAEAAAQMcGVyaW9kTGVuZ3RoCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ8IAQUVa2V5UGVyaW9kTGVuZ3RoUmVtb3ZlCQEHd3JhcEVycgECGnBlcmlvZExlbmd0aFJlbW92ZSBub3Qgc2V0BA92b3RpbmdFbmRIZWlnaHQJAGQCBQZoZWlnaHQFDHBlcmlvZExlbmd0aAQLdm90ZXNRdW9ydW0JARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnwgBBRhrZXlWb3RpbmdUaHJlc2hvbGRSZW1vdmUJAQd3cmFwRXJyAQIddm90aW5nVGhyZXNob2xkUmVtb3ZlIG5vdCBzZXQECnZvdGluZ0luZm8JAQ92b3RpbmdJbmZvVmFsdWUKBwIFRU1QVFkAAAIOZGV2ZXJpZmljYXRpb24CCmluUHJvZ3Jlc3MFBmhlaWdodAkAZAIFBmhlaWdodAUMcGVyaW9kTGVuZ3RoBQt2b3Rlc1F1b3J1bQAAAAAJAMwIAgkBDEludGVnZXJFbnRyeQIFD2N1cnJlbnRJbmRleEtleQUIbmV3SW5kZXgJAMwIAgkBC1N0cmluZ0VudHJ5AgkBEGtleVN1Z2dlc3RJc3N1ZXICBQdhc3NldElkBQhuZXdJbmRleAkApQgBCAUBaQZjYWxsZXIJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDWtleVZvdGluZ0luZm8CBQdhc3NldElkBQhuZXdJbmRleAUKdm90aW5nSW5mbwUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBBHZvdGUCB2Fzc2V0SWQHaW5GYXZvcgQPY3VycmVudEluZGV4S2V5CQEPa2V5Q3VycmVudEluZGV4AQUHYXNzZXRJZAQMY3VycmVudEluZGV4CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ8IAQUPY3VycmVudEluZGV4S2V5CQEHd3JhcEVycgECFXZvdGluZyBkb2VzIG5vdCBleGlzdAQKdm90aW5nSW5mbwkBEXZvdGluZ0V4aXN0Q2hlY2tzAgUHYXNzZXRJZAUMY3VycmVudEluZGV4AwkAAAIFCnZvdGluZ0luZm8FCnZvdGluZ0luZm8EFmN1cnJlbnRWb3RpbmdFbmRIZWlnaHQIBQp2b3RpbmdJbmZvAl8yBA5nd3hBbW91bnRBdEVuZAkBGGdldFVzZXJHd3hBbW91bnRBdEhlaWdodAIJAKUIAQgFAWkGY2FsbGVyBRZjdXJyZW50Vm90aW5nRW5kSGVpZ2h0BAd2b3RlS2V5CQEHa2V5Vm90ZQMFB2Fzc2V0SWQFDGN1cnJlbnRJbmRleAgFAWkGY2FsbGVyBAZjaGVja3MJAMwIAgMJAAACCQCiCAEFB3ZvdGVLZXkFBHVuaXQGCQEIdGhyb3dFcnIBAhZZb3UgaGF2ZSBhbHJlYWR5IHZvdGVkCQDMCAIDCQBmAgUOZ3d4QW1vdW50QXRFbmQAAAYJAAIBAihZb3UnbGwgbm90IGhhdmUgZ1dYIGF0IHRoZSBlbmQgb2Ygdm90aW5nBQNuaWwDCQAAAgUGY2hlY2tzBQZjaGVja3MEDXZvdGluZ0luZm9TdHIJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQENa2V5Vm90aW5nSW5mbwIFB2Fzc2V0SWQFDGN1cnJlbnRJbmRleAkBB3dyYXBFcnIBAhV2b3RpbmcgaW5mbyBub3QgZm91bmQED3ZvdGluZ0luZm9QYXJ0cwkBEmdldFZvdGluZ0luZm9QYXJ0cwEFDXZvdGluZ0luZm9TdHIECHZvdGVzRm9yCAUPdm90aW5nSW5mb1BhcnRzAl85BAx2b3Rlc0FnYWluc3QIBQ92b3RpbmdJbmZvUGFydHMDXzEwBA0kdDAxMjc0NTEyOTA2AwUHaW5GYXZvcgkAlAoCCQBkAgUIdm90ZXNGb3IFDmd3eEFtb3VudEF0RW5kBQx2b3Rlc0FnYWluc3QJAJQKAgUIdm90ZXNGb3IJAGQCBQx2b3Rlc0FnYWluc3QFDmd3eEFtb3VudEF0RW5kBAtuZXdWb3Rlc0ZvcggFDSR0MDEyNzQ1MTI5MDYCXzEED25ld1ZvdGVzQWdhaW5zdAgFDSR0MDEyNzQ1MTI5MDYCXzIEEm5ld1ZvdGluZ0luZm9WYWx1ZQkBD3ZvdGluZ0luZm9WYWx1ZQoIBQ92b3RpbmdJbmZvUGFydHMCXzEIBQ92b3RpbmdJbmZvUGFydHMCXzIIBQ92b3RpbmdJbmZvUGFydHMCXzMIBQ92b3RpbmdJbmZvUGFydHMCXzQIBQ92b3RpbmdJbmZvUGFydHMCXzUIBQ92b3RpbmdJbmZvUGFydHMCXzYIBQ92b3RpbmdJbmZvUGFydHMCXzcIBQ92b3RpbmdJbmZvUGFydHMCXzgFC25ld1ZvdGVzRm9yBQ9uZXdWb3Rlc0FnYWluc3QEEnZvdGluZ1Jld2FyZEFjdGlvbgQHJG1hdGNoMAkAoggBCQEWa2V5Vm90aW5nUmV3YXJkQXNzZXRJZAIFB2Fzc2V0SWQFDGN1cnJlbnRJbmRleAMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAnBrBQckbWF0Y2gwCQDMCAIJAQtTdHJpbmdFbnRyeQIJAQ9rZXlWb3RpbmdSZXdhcmQDCAUBaQZjYWxsZXIFB2Fzc2V0SWQFDGN1cnJlbnRJbmRleAkBCXZvdGVWYWx1ZQIFB2luRmF2b3IFDmd3eEFtb3VudEF0RW5kBQNuaWwDCQABAgUHJG1hdGNoMAIEVW5pdAUDbmlsCQACAQILTWF0Y2ggZXJyb3IJAM4IAgkAzAgCCQELU3RyaW5nRW50cnkCBQd2b3RlS2V5CQEJdm90ZVZhbHVlAgUHaW5GYXZvcgUOZ3d4QW1vdW50QXRFbmQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDWtleVZvdGluZ0luZm8CBQdhc3NldElkBQxjdXJyZW50SW5kZXgFEm5ld1ZvdGluZ0luZm9WYWx1ZQUDbmlsBRJ2b3RpbmdSZXdhcmRBY3Rpb24JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEKY2FuY2VsVm90ZQEHYXNzZXRJZAQPY3VycmVudEluZGV4S2V5CQEPa2V5Q3VycmVudEluZGV4AQUHYXNzZXRJZAQMY3VycmVudEluZGV4CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ8IAQUPY3VycmVudEluZGV4S2V5CQEHd3JhcEVycgECFXZvdGluZyBkb2VzIG5vdCBleGlzdAQHdm90ZUtleQkBB2tleVZvdGUDBQdhc3NldElkBQxjdXJyZW50SW5kZXgIBQFpBmNhbGxlcgQIbGFzdFZvdGUJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBBQd2b3RlS2V5CQEHd3JhcEVycgECEnlvdSBoYXZlIG5vdCB2b3RlZAQNbGFzdFZvdGVQYXJ0cwkAtQkCBQhsYXN0Vm90ZQUJc2VwYXJhdG9yBAdpbkZhdm9yCQCRAwIFDWxhc3RWb3RlUGFydHMAAQQJZ3d4QW1vdW50CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUNbGFzdFZvdGVQYXJ0cwACBAp2b3RpbmdJbmZvCQERdm90aW5nRXhpc3RDaGVja3MCBQdhc3NldElkBQxjdXJyZW50SW5kZXgDCQAAAgUKdm90aW5nSW5mbwUKdm90aW5nSW5mbwQGY2hlY2tzCQDMCAIDAwkAAAIFB2luRmF2b3ICBHRydWUGCQAAAgUHaW5GYXZvcgIFZmFsc2UGCQEIdGhyb3dFcnIBAgxpbnZhbGlkIHZvdGUFA25pbAMJAAACBQZjaGVja3MFBmNoZWNrcwQNdm90aW5nSW5mb1N0cgkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCiCAEJAQ1rZXlWb3RpbmdJbmZvAgUHYXNzZXRJZAUMY3VycmVudEluZGV4CQEHd3JhcEVycgECFXZvdGluZyBpbmZvIG5vdCBmb3VuZAQPdm90aW5nSW5mb1BhcnRzCQESZ2V0Vm90aW5nSW5mb1BhcnRzAQUNdm90aW5nSW5mb1N0cgQIdm90ZXNGb3IIBQ92b3RpbmdJbmZvUGFydHMCXzkEDHZvdGVzQWdhaW5zdAgFD3ZvdGluZ0luZm9QYXJ0cwNfMTAEDSR0MDE0NTMxMTQ2OTIDCQAAAgUHaW5GYXZvcgIEdHJ1ZQkAlAoCCQBlAgUIdm90ZXNGb3IFCWd3eEFtb3VudAUMdm90ZXNBZ2FpbnN0CQCUCgIFCHZvdGVzRm9yCQBlAgUMdm90ZXNBZ2FpbnN0BQlnd3hBbW91bnQEC25ld1ZvdGVzRm9yCAUNJHQwMTQ1MzExNDY5MgJfMQQPbmV3Vm90ZXNBZ2FpbnN0CAUNJHQwMTQ1MzExNDY5MgJfMgQSbmV3Vm90aW5nSW5mb1ZhbHVlCQEPdm90aW5nSW5mb1ZhbHVlCggFD3ZvdGluZ0luZm9QYXJ0cwJfMQgFD3ZvdGluZ0luZm9QYXJ0cwJfMggFD3ZvdGluZ0luZm9QYXJ0cwJfMwgFD3ZvdGluZ0luZm9QYXJ0cwJfNAgFD3ZvdGluZ0luZm9QYXJ0cwJfNQgFD3ZvdGluZ0luZm9QYXJ0cwJfNggFD3ZvdGluZ0luZm9QYXJ0cwJfNwgFD3ZvdGluZ0luZm9QYXJ0cwJfOAULbmV3Vm90ZXNGb3IFD25ld1ZvdGVzQWdhaW5zdAkAzAgCCQELU3RyaW5nRW50cnkCCQENa2V5Vm90aW5nSW5mbwIFB2Fzc2V0SWQFDGN1cnJlbnRJbmRleAUSbmV3Vm90aW5nSW5mb1ZhbHVlCQDMCAIJAQtEZWxldGVFbnRyeQEFB3ZvdGVLZXkJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBD2tleVZvdGluZ1Jld2FyZAMIBQFpBmNhbGxlcgUHYXNzZXRJZAUMY3VycmVudEluZGV4BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEIZmluYWxpemUBB2Fzc2V0SWQED2N1cnJlbnRJbmRleEtleQkBD2tleUN1cnJlbnRJbmRleAEFB2Fzc2V0SWQEDGN1cnJlbnRJbmRleAkBC3ZhbHVlT3JFbHNlAgkAnwgBBQ9jdXJyZW50SW5kZXhLZXkAAAQSdm90aW5nVGhyZXNob2xkQWRkCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ8IAQUVa2V5Vm90aW5nVGhyZXNob2xkQWRkCQEHd3JhcEVycgECGnZvdGluZ1RocmVzaG9sZEFkZCBub3Qgc2V0BBV2b3RpbmdUaHJlc2hvbGRSZW1vdmUJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnwgBBRhrZXlWb3RpbmdUaHJlc2hvbGRSZW1vdmUJAQd3cmFwRXJyAQIddm90aW5nVGhyZXNob2xkUmVtb3ZlIG5vdCBzZXQEDXZvdGluZ0luZm9TdHIJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQENa2V5Vm90aW5nSW5mbwIFB2Fzc2V0SWQFDGN1cnJlbnRJbmRleAkBB3dyYXBFcnIBAhV2b3RpbmcgaW5mbyBub3QgZm91bmQED3ZvdGluZ0luZm9QYXJ0cwkBEmdldFZvdGluZ0luZm9QYXJ0cwEFDXZvdGluZ0luZm9TdHIECnZvdGluZ1R5cGUIBQ92b3RpbmdJbmZvUGFydHMCXzQEBnN0YXR1cwgFD3ZvdGluZ0luZm9QYXJ0cwJfNQQPdm90aW5nRW5kSGVpZ2h0CAUPdm90aW5nSW5mb1BhcnRzAl83BAx2b3RpbmdRdW9ydW0IBQ92b3RpbmdJbmZvUGFydHMCXzgECHZvdGVzRm9yCAUPdm90aW5nSW5mb1BhcnRzAl85BAx2b3Rlc0FnYWluc3QIBQ92b3RpbmdJbmZvUGFydHMDXzEwBAZjaGVja3MJAMwIAgMJAAACBQZzdGF0dXMCCmluUHJvZ3Jlc3MGCQEIdGhyb3dFcnIBAhZ2b3Rpbmcgbm90IGluIHByb2dyZXNzCQDMCAIDCQBnAgUGaGVpZ2h0BQ92b3RpbmdFbmRIZWlnaHQGCQEIdGhyb3dFcnIBAhN2b3Rpbmcgbm90IGZpbmlzaGVkCQDMCAIDCQEJaXNEZWZpbmVkAQkAoggBCQENa2V5QXNzZXRJbWFnZQEFB2Fzc2V0SWQGCQEIdGhyb3dFcnIBAhNhc3NldCBpbWFnZSBub3Qgc2V0BQNuaWwDCQAAAgUGY2hlY2tzBQZjaGVja3MEDnZvdGluZ0FjY2VwdGVkAwMJAGcCCQBkAgUIdm90ZXNGb3IFDHZvdGVzQWdhaW5zdAUMdm90aW5nUXVvcnVtCQBmAgUIdm90ZXNGb3IFDHZvdGVzQWdhaW5zdAcGBwQJbmV3U3RhdHVzAwUOdm90aW5nQWNjZXB0ZWQCCGFjY2VwdGVkAghyZWplY3RlZAQKYXNzZXRJbWFnZQkBEUBleHRyTmF0aXZlKDEwNTgpAQkBDWtleUFzc2V0SW1hZ2UBBQdhc3NldElkBBBpc1ZvdGluZ0FjY2VwdGVkAwUOdm90aW5nQWNjZXB0ZWQEFXZvdGluZ0FjY2VwdGVkSW52b2tlcwMJAAACBQp2b3RpbmdUeXBlAgx2ZXJpZmljYXRpb24JAPwHBAUTYXNzZXRzU3RvcmVDb250cmFjdAIOY3JlYXRlT3JVcGRhdGUJAMwIAgUHYXNzZXRJZAkAzAgCBQphc3NldEltYWdlCQDMCAIGBQNuaWwFA25pbAkA/AcEBRNhc3NldHNTdG9yZUNvbnRyYWN0AgtzZXRWZXJpZmllZAkAzAgCBQdhc3NldElkCQDMCAIHBQNuaWwFA25pbAUVdm90aW5nQWNjZXB0ZWRJbnZva2VzBQNuaWwDCQAAAgUQaXNWb3RpbmdBY2NlcHRlZAUQaXNWb3RpbmdBY2NlcHRlZAQSbmV3Vm90aW5nSW5mb1ZhbHVlCQEPdm90aW5nSW5mb1ZhbHVlCggFD3ZvdGluZ0luZm9QYXJ0cwJfMQgFD3ZvdGluZ0luZm9QYXJ0cwJfMggFD3ZvdGluZ0luZm9QYXJ0cwJfMwgFD3ZvdGluZ0luZm9QYXJ0cwJfNAUJbmV3U3RhdHVzCAUPdm90aW5nSW5mb1BhcnRzAl82CAUPdm90aW5nSW5mb1BhcnRzAl83CAUPdm90aW5nSW5mb1BhcnRzAl84CAUPdm90aW5nSW5mb1BhcnRzAl85CAUPdm90aW5nSW5mb1BhcnRzA18xMAQYZmluYWxpemVDYWxsUmV3YXJkQW1vdW50CQERQGV4dHJOYXRpdmUoMTA1NSkBBRtrZXlGaW5hbGl6ZUNhbGxSZXdhcmRBbW91bnQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDWtleVZvdGluZ0luZm8CBQdhc3NldElkBQxjdXJyZW50SW5kZXgFEm5ld1ZvdGluZ0luZm9WYWx1ZQkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCAUBaQZjYWxsZXIFGGZpbmFsaXplQ2FsbFJld2FyZEFtb3VudAUJd3hBc3NldElkBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQENY2xhaW1SRUFET05MWQMHYXNzZXRJZAVpbmRleA51c2VyQWRkcmVzc1N0cgQLdXNlckFkZHJlc3MJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBBQ51c2VyQWRkcmVzc1N0cgkBB3dyYXBFcnIBAg9pbnZhbGlkIGFkZHJlc3MEFnZvdGluZ1Jld2FyZEFzc2V0SWRTdHIJAKIIAQkBFmtleVZvdGluZ1Jld2FyZEFzc2V0SWQCBQdhc3NldElkBQVpbmRleAQMcmV3YXJkQW1vdW50AwkBCWlzRGVmaW5lZAEFFnZvdGluZ1Jld2FyZEFzc2V0SWRTdHIJAQ9jYWxjdWxhdGVSZXdhcmQDBQt1c2VyQWRkcmVzcwUHYXNzZXRJZAUFaW5kZXgAAAkAlAoCBQNuaWwFDHJld2FyZEFtb3VudAFpAQVjbGFpbQIHYXNzZXRJZAVpbmRleAQNY2FsbGVyQWRkcmVzcwgFAWkGY2FsbGVyBA9jbGFpbUhpc3RvcnlLZXkJAQ9rZXlDbGFpbUhpc3RvcnkDBQ1jYWxsZXJBZGRyZXNzBQdhc3NldElkBQVpbmRleAQMY2xhaW1IaXN0b3J5CQCfCAEFD2NsYWltSGlzdG9yeUtleQQGY2hlY2tzCQDMCAIDCQAAAgUMY2xhaW1IaXN0b3J5BQR1bml0BgkBCHRocm93RXJyAQIPYWxyZWFkeSBjbGFpbWVkBQNuaWwDCQAAAgUGY2hlY2tzBQZjaGVja3MEDHJld2FyZEFtb3VudAMJAGYCCQEPY2FsY3VsYXRlUmV3YXJkAwUNY2FsbGVyQWRkcmVzcwUHYXNzZXRJZAUFaW5kZXgAAAkBD2NhbGN1bGF0ZVJld2FyZAMFDWNhbGxlckFkZHJlc3MFB2Fzc2V0SWQFBWluZGV4CQEIdGhyb3dFcnIBAhBub3RoaW5nIHRvIGNsYWltBBZ2b3RpbmdSZXdhcmRBc3NldElkU3RyCQCiCAEJARZrZXlWb3RpbmdSZXdhcmRBc3NldElkAgUHYXNzZXRJZAUFaW5kZXgEDHJld2FyZEFjdGlvbgMJAQlpc0RlZmluZWQBBRZ2b3RpbmdSZXdhcmRBc3NldElkU3RyBBN2b3RpbmdSZXdhcmRBc3NldElkCQDZBAEJAQV2YWx1ZQEFFnZvdGluZ1Jld2FyZEFzc2V0SWRTdHIJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwUNY2FsbGVyQWRkcmVzcwUMcmV3YXJkQW1vdW50BRN2b3RpbmdSZXdhcmRBc3NldElkCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ9jbGFpbUhpc3RvcnlLZXkFDHJld2FyZEFtb3VudAkAzAgCCQELRGVsZXRlRW50cnkBCQEPa2V5Vm90aW5nUmV3YXJkAwUNY2FsbGVyQWRkcmVzcwUHYXNzZXRJZAUFaW5kZXgFA25pbAkBCHRocm93RXJyAQIQbm90aGluZyB0byBjbGFpbQUMcmV3YXJkQWN0aW9uCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAQJ0eAEGdmVyaWZ5AAQPdGFyZ2V0UHVibGljS2V5BAckbWF0Y2gwCQEWbWFuYWdlclB1YmxpY0tleU9yVW5pdAADCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQCcGsFByRtYXRjaDAFAnBrAwkAAQIFByRtYXRjaDACBFVuaXQIBQJ0eA9zZW5kZXJQdWJsaWNLZXkJAAIBAgtNYXRjaCBlcnJvcgkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAAUPdGFyZ2V0UHVibGljS2V53B5nmw==", "height": 2684165, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: CtTHQp6sU4V41BKz7F6wTwNPUnRDPqMu21ybf9aumc6o Next: FnjdA9Rj9FxjWAKpa45AtPk5xfNBPzmKCN2dqmAzu8xx Full:
OldNewDifferences
1-{-# STDLIB_VERSION 7 #-}
1+{-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let SEP = "__"
4+let separator = "__"
55
6-let contractFilename = "factory.ride"
6+let MULT8 = 100000000
77
8-func wrapErr (s) = ((contractFilename + ": ") + s)
8+func wrapErr (msg) = makeString(["voting_verified_v2.ride:", msg], " ")
99
1010
11-func throwErr (s) = throw(wrapErr(s))
11+func throwErr (msg) = throw(wrapErr(msg))
1212
1313
14-let ADMIN_LIST_SIZE = 5
15-
16-let QUORUM = 3
17-
18-let TXID_BYTES_LENGTH = 32
19-
20-func keyAllowedTxIdVotePrefix (txId) = makeString(["%s%s%s", "allowTxId", txId], SEP)
14+func asInt (val) = match val {
15+ case valInt: Int =>
16+ valInt
17+ case _ =>
18+ throw("Failed to cast into Integer")
19+}
2120
2221
23-func keyFullAdminVote (prefix,adminAddress) = makeString([prefix, adminAddress], SEP)
22+func getIntegerOrZero (address,key) = valueOrElse(getInteger(address, key), 0)
2423
2524
26-func keyAdminAddressList () = makeString(["%s", "adminAddressList"], SEP)
25+func getIntegerOrFail (address,key) = valueOrErrorMessage(getInteger(address, key), wrapErr((key + " is not defined")))
2726
2827
29-func keyAllowedTxId () = makeString(["%s", "txId"], SEP)
28+func getStringOrEmpty (address,key) = valueOrElse(getString(address, key), "")
3029
3130
32-func getAdminVote (prefix,admin) = {
33- let voteKey = keyFullAdminVote(prefix, admin)
34- valueOrElse(getInteger(voteKey), 0)
31+func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), wrapErr((key + " is not defined")))
32+
33+
34+let keyBoostingContract = makeString(["%s", "boostingContract"], separator)
35+
36+let keyEmissionContract = makeString(["%s", "emissionContract"], separator)
37+
38+let keyAssetsStoreContract = makeString(["%s", "assetsStoreContract"], separator)
39+
40+let boostingContract = addressFromStringValue(getStringValue(keyBoostingContract))
41+
42+let emissionContract = addressFromStringValue(getStringValue(keyEmissionContract))
43+
44+let assetsStoreContract = addressFromStringValue(getStringValue(keyAssetsStoreContract))
45+
46+let keyEmissionConfig = makeString(["%s", "config"], separator)
47+
48+let wxAssetIdStr = split(getStringOrFail(emissionContract, keyEmissionConfig), separator)[1]
49+
50+let wxAssetId = fromBase58String(wxAssetIdStr)
51+
52+let keyVotingThresholdAdd = makeString(["%s%s", "votingThreshold", "add"], separator)
53+
54+let keyVotingThresholdRemove = makeString(["%s%s", "votingThreshold", "remove"], separator)
55+
56+let keyPeriodLengthRemove = makeString(["%s", "periodLengthRemove"], separator)
57+
58+let keyMaxPeriodLength = makeString(["%s", "maxPeriodLength"], separator)
59+
60+let keyMinPeriodLength = makeString(["%s", "minPeriodLength"], separator)
61+
62+func keyVotingRewardAssetId (assetId,index) = makeString(["%s%s%d", "votingRewardAssetId", assetId, toString(index)], separator)
63+
64+
65+func keyVotingReward (userAddress,assetId,index) = makeString(["%s%s%s%d", "votingReward", toString(userAddress), assetId, toString(index)], separator)
66+
67+
68+func keyTotalVotingReward (assetId,index) = makeString(["%s%s%d", "totalVotingReward", assetId, toString(index)], separator)
69+
70+
71+let keyFinalizeCallRewardAmount = makeString(["%s", "finalizeCallRewardAmount"], separator)
72+
73+let keyMinSuggestRemoveBalance = makeString(["%s", "minSuggestRemoveBalance"], separator)
74+
75+func keyCurrentIndex (assetId) = makeString(["%s%s", "currentIndex", assetId], separator)
76+
77+
78+func keyVote (assetId,index,caller) = makeString(["%s%s%d%s", "vote", assetId, toString(index), toString(caller)], separator)
79+
80+
81+func voteValue (inFavor,gwxAmount) = makeString(["%s%d", toString(inFavor), toString(gwxAmount)], separator)
82+
83+
84+func keySuggestIssuer (assetId,index) = makeString(["%s%s%d", "suggestIssuer", assetId, toString(index)], separator)
85+
86+
87+func keyClaimHistory (userAddress,assetId,index) = makeString(["%s%s%s%d", "history", toString(userAddress), assetId, toString(index)], separator)
88+
89+
90+let keyFeePerBlock = makeString(["%s", "feePerBlock"], separator)
91+
92+let feePerBlock = getIntegerOrFail(this, keyFeePerBlock)
93+
94+let keyMinWxMinForSuggestAddAmountRequired = makeString(["%s", "wxMinForSuggestAddAmountRequired"], separator)
95+
96+let keyWxForSuggestRemoveAmountRequired = makeString(["%s", "wxForSuggestRemoveAmountRequired"], separator)
97+
98+func keyVotingInfo (assetId,index) = makeString(["%s%s%d", "votingInfo", assetId, toString(index)], separator)
99+
100+
101+func votingInfoValue (isRewardExist,rewardAssetId,rewardAmount,votingType,status,votingStartHeight,votingEndHeight,votesQuorum,votesFor,votesAgainst) = makeString(["%s%s%d%s%s%d%d%d%d%d", toString(isRewardExist), rewardAssetId, toString(rewardAmount), votingType, status, toString(votingStartHeight), toString(votingEndHeight), toString(votesQuorum), toString(votesFor), toString(votesAgainst)], separator)
102+
103+
104+func keyAssetImage (assetId) = makeString(["%s%s", "assetImage", assetId], separator)
105+
106+
107+func getUserGwxAmountAtHeight (userAddress,targetHeight) = {
108+ let gwxAmount = invoke(boostingContract, "getUserGwxAmountAtHeightREADONLY", [userAddress, targetHeight], nil)
109+ asInt(gwxAmount)
35110 }
36111
37112
38-func getAdminsList () = match getString(this, keyAdminAddressList()) {
113+func keyManagerVaultAddress () = "%s__managerVaultAddress"
114+
115+
116+func keyManagerPublicKey () = "%s__managerPublicKey"
117+
118+
119+func getManagerVaultAddressOrThis () = match getString(keyManagerVaultAddress()) {
39120 case s: String =>
40- split(s, SEP)
121+ addressFromStringValue(s)
41122 case _ =>
42- nil
123+ this
43124 }
44125
45126
46-func isInAdminList (address) = containsElement(getAdminsList(), address)
47-
48-
49-func genVotesKeysHelper (a,adminAddress) = {
50- let $t012621286 = a
51- let result = $t012621286._1
52- let prefix = $t012621286._2
53- $Tuple2((result :+ keyFullAdminVote(prefix, adminAddress)), prefix)
127+func managerPublicKeyOrUnit () = {
128+ let managerVaultAddress = getManagerVaultAddressOrThis()
129+ match getString(managerVaultAddress, keyManagerPublicKey()) {
130+ case s: String =>
131+ fromBase58String(s)
132+ case _: Unit =>
133+ unit
134+ case _ =>
135+ throw("Match error")
136+ }
54137 }
55138
56139
57-func genVotesKeys (keyPrefix) = {
58- let adminList = keyAdminAddressList()
59- let $t014331517 = {
60- let $l = getAdminsList()
61- let $s = size($l)
62- let $acc0 = $Tuple2(nil, keyPrefix)
63- func $f0_1 ($a,$i) = if (($i >= $s))
64- then $a
65- else genVotesKeysHelper($a, $l[$i])
66-
67- func $f0_2 ($a,$i) = if (($i >= $s))
68- then $a
69- else throw("List size exceeds 5")
70-
71- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5)
72- }
73- let result = $t014331517._1
74- let prefix = $t014331517._2
75- result
140+func getVotingInfoParts (votingInfo) = {
141+ let votingInfoParts = split(votingInfo, separator)
142+ let isRewardExistStr = votingInfoParts[1]
143+ let isRewardExist = if ((isRewardExistStr == "true"))
144+ then true
145+ else false
146+ let rewardAssetId = votingInfoParts[2]
147+ let rewardAmount = parseIntValue(votingInfoParts[3])
148+ let votingType = votingInfoParts[4]
149+ let status = votingInfoParts[5]
150+ let votingStartHeight = parseIntValue(votingInfoParts[6])
151+ let votingEndHeight = parseIntValue(votingInfoParts[7])
152+ let votesQuorum = parseIntValue(votingInfoParts[8])
153+ let votesFor = parseIntValue(votingInfoParts[9])
154+ let votesAgainst = parseIntValue(votingInfoParts[10])
155+ $Tuple10(isRewardExist, rewardAssetId, rewardAmount, votingType, status, votingStartHeight, votingEndHeight, votesQuorum, votesFor, votesAgainst)
76156 }
77157
78158
79-func countVotesHelper (result,voteKey) = (result + valueOrElse(getInteger(voteKey), 0))
80-
81-
82-func countVotes (prefix) = {
83- let votes = genVotesKeys(prefix)
84- let $l = votes
85- let $s = size($l)
86- let $acc0 = 0
87- func $f0_1 ($a,$i) = if (($i >= $s))
88- then $a
89- else countVotesHelper($a, $l[$i])
90-
91- func $f0_2 ($a,$i) = if (($i >= $s))
92- then $a
93- else throw("List size exceeds 5")
94-
95- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5)
159+func votingExistChecks (assetId,currentIndex) = {
160+ let votingInfo = valueOrErrorMessage(getString(keyVotingInfo(assetId, currentIndex)), wrapErr("voting info not found"))
161+ let votingInfoArray = split(votingInfo, separator)
162+ let status = votingInfoArray[5]
163+ let votingEndHeight = valueOrErrorMessage(parseIntValue(votingInfoArray[7]), wrapErr("voting start height not found"))
164+ let suggestIssuer = valueOrErrorMessage(getString(keySuggestIssuer(assetId, currentIndex)), wrapErr("voting issuer not found"))
165+ let checks = [if ((status == "inProgress"))
166+ then true
167+ else throwErr("no voting in progress"), if ((votingEndHeight > height))
168+ then true
169+ else throwErr("voting expired")]
170+ if ((checks == checks))
171+ then $Tuple3(status, votingEndHeight, suggestIssuer)
172+ else throw("Strict value is not equal to itself.")
96173 }
97174
98175
99-func clearVotesHelper (result,key) = (result :+ DeleteEntry(key))
100-
101-
102-func getClearVoteEntries (prefix) = {
103- let votes = genVotesKeys(prefix)
104- let $l = votes
105- let $s = size($l)
106- let $acc0 = nil
107- func $f0_1 ($a,$i) = if (($i >= $s))
108- then $a
109- else clearVotesHelper($a, $l[$i])
110-
111- func $f0_2 ($a,$i) = if (($i >= $s))
112- then $a
113- else throw("List size exceeds 5")
114-
115- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5)
176+func calculateReward (voter,assetId,index) = {
177+ let voteKey = keyVote(assetId, index, voter)
178+ let lastVote = valueOrErrorMessage(getString(voteKey), wrapErr("you have not voted"))
179+ let lastVoteParts = split(lastVote, separator)
180+ let gwxAmount = parseIntValue(lastVoteParts[2])
181+ let votingInfoStr = valueOrErrorMessage(getString(keyVotingInfo(assetId, index)), wrapErr("voting info not found"))
182+ let votingParts = getVotingInfoParts(votingInfoStr)
183+ let votesFor = votingParts._9
184+ let votesAgainst = votingParts._10
185+ let partOfTheTotalVotesX8 = fraction(gwxAmount, MULT8, (votesFor + votesAgainst))
186+ let totalVotingReward = valueOrElse(getInteger(keyTotalVotingReward(assetId, index)), 0)
187+ let voterRewardAmount = fraction(partOfTheTotalVotesX8, totalVotingReward, MULT8, FLOOR)
188+ voterRewardAmount
116189 }
117190
118191
119-func voteINTERNAL (callerAddressString,keyPrefix,minVotes,voteResult) = {
120- let voteKey = keyFullAdminVote(keyPrefix, callerAddressString)
121- let adminCurrentVote = getAdminVote(keyPrefix, callerAddressString)
122- let err = if (!(isInAdminList(callerAddressString)))
123- then throwErr((("Address: " + callerAddressString) + " not in Admin list"))
124- else if ((adminCurrentVote == 1))
125- then throwErr((voteKey + " you already voted"))
126- else unit
127- if ((err == err))
192+@Callable(i)
193+func suggestAdd (assetId,periodLength,assetImage) = {
194+ let wxPayment = i.payments[0]
195+ let wxPaymentAssetId = value(wxPayment.assetId)
196+ let wxPaymentAmount = value(wxPayment.amount)
197+ let minPeriodLength = getIntegerValue(keyMinPeriodLength)
198+ let maxPeriodLength = getIntegerValue(keyMaxPeriodLength)
199+ let tokenIsVerified = {
200+ let @ = invoke(assetsStoreContract, "isVerifiedREADONLY", [assetId], nil)
201+ if ($isInstanceOf(@, "Boolean"))
202+ then @
203+ else throw(($getType(@) + " couldn't be cast to Boolean"))
204+ }
205+ let checks = [if (if ((periodLength >= minPeriodLength))
206+ then (maxPeriodLength >= periodLength)
207+ else false)
208+ then true
209+ else throwErr("invalid periodLength"), if ((tokenIsVerified == false))
210+ then true
211+ else throwErr("token already verified"), if ((wxPaymentAmount > (periodLength * feePerBlock)))
212+ then true
213+ else throwErr("not enough wx for given period"), if ((wxPaymentAmount >= getIntegerValue(keyMinWxMinForSuggestAddAmountRequired)))
214+ then true
215+ else throwErr("payment less then min for suggest")]
216+ if ((checks == checks))
128217 then {
129- let votes = countVotes(keyPrefix)
130- if (((votes + 1) >= minVotes))
218+ let currentIndexKey = keyCurrentIndex(assetId)
219+ let currentIndex = getInteger(currentIndexKey)
220+ let newIndex = if (isDefined(currentIndex))
221+ then (value(currentIndex) + 1)
222+ else 0
223+ let $t087849424 = if ((size(i.payments) > 1))
131224 then {
132- let clearVoteEntries = getClearVoteEntries(keyPrefix)
133- (clearVoteEntries ++ voteResult)
225+ let votingRewardPayment = i.payments[1]
226+ let votingRewardPaymentAssetId = toBase58String(value(votingRewardPayment.assetId))
227+ let votingRewardPaymentAmount = value(votingRewardPayment.amount)
228+ $Tuple4(true, votingRewardPaymentAssetId, votingRewardPaymentAmount, [StringEntry(keyVotingRewardAssetId(assetId, newIndex), votingRewardPaymentAssetId), IntegerEntry(keyTotalVotingReward(assetId, newIndex), votingRewardPaymentAmount)])
134229 }
135- else [IntegerEntry(voteKey, 1)]
230+ else $Tuple4(false, "EMPTY", 0, nil)
231+ let isRewardExist = $t087849424._1
232+ let rewardAssetId = $t087849424._2
233+ let rewardAmount = $t087849424._3
234+ let votingRewardActions = $t087849424._4
235+ let votesQuorum = valueOrErrorMessage(getInteger(keyVotingThresholdAdd), wrapErr("votingThresholdAdd not set"))
236+ let votingInfo = votingInfoValue(isRewardExist, rewardAssetId, rewardAmount, "verification", "inProgress", height, (height + periodLength), votesQuorum, 0, 0)
237+ let finalizeCallRewardAmount = getIntegerValue(keyFinalizeCallRewardAmount)
238+ let burnWxAmount = (wxPaymentAmount - finalizeCallRewardAmount)
239+ ([IntegerEntry(currentIndexKey, newIndex), StringEntry(keySuggestIssuer(assetId, newIndex), toString(i.caller)), StringEntry(keyVotingInfo(assetId, newIndex), votingInfo), StringEntry(keyAssetImage(assetId), assetImage), Burn(wxPaymentAssetId, burnWxAmount)] ++ votingRewardActions)
136240 }
137241 else throw("Strict value is not equal to itself.")
138242 }
139243
140244
141-func keyCalculatorAddress () = "%s__calculator"
142-
143-
144-func keyProxyTreasuryAddress () = "%s__proxyTreasury"
145-
146-
147-func keyChildAddress () = "%s__child"
148-
149-
150-func keyBlockProcessingReward () = "%s__blockProcessingReward"
151-
152-
153-func keyNextBlockToProcess () = "%s__nextBlockToProcess"
154-
155-
156-func keyLpAssetId () = "%s__lpAssetId"
157-
158-
159-let calculatorAddressOption = match getString(this, keyCalculatorAddress()) {
160- case s: String =>
161- addressFromString(s)
162- case _: Unit =>
163- unit
164- case _ =>
165- throw("Match error")
166-}
167-
168-let calculatorAddressOrFail = valueOrErrorMessage(calculatorAddressOption, wrapErr("invalid calculator address"))
169-
170-let proxyTreasuryAddressOption = match getString(this, keyProxyTreasuryAddress()) {
171- case s: String =>
172- addressFromString(s)
173- case _: Unit =>
174- unit
175- case _ =>
176- throw("Match error")
177-}
178-
179-let proxyTreasuryAddressOrFail = valueOrErrorMessage(proxyTreasuryAddressOption, wrapErr("invalid proxy treasury address"))
180-
181-func keyConfigAddress () = "%s__config"
182-
183-
184-func keyChildrenAddress () = "contract_children"
185-
186-
187-func keyVotingResultAddress () = "contract_voting_result"
188-
189-
190-func keyProposalAllowBroadcast (address,txId) = ((("proposal_allow_broadcast_" + toString(address)) + "_") + toBase58String(txId))
191-
192-
193-func keyInvestedByUser (childAddress,userAddress) = makeString(["investor", toString(childAddress), toString(userAddress)], "_")
194-
195-
196-let configAddressOption = match getString(this, keyConfigAddress()) {
197- case s: String =>
198- addressFromString(s)
199- case _: Unit =>
200- unit
201- case _ =>
202- throw("Match error")
203-}
204-
205-let configAddressOrFail = valueOrErrorMessage(configAddressOption, wrapErr("invalid config address"))
206-
207-let votingResultAddressOption = match configAddressOption {
208- case a: Address =>
209- match getString(a, keyVotingResultAddress()) {
210- case s: String =>
211- addressFromString(s)
212- case _: Unit =>
213- unit
214- case _ =>
215- throw("Match error")
216- }
217- case _: Unit =>
218- unit
219- case _ =>
220- throw("Match error")
221-}
222-
223-let votingResultAddressOrFail = valueOrErrorMessage(votingResultAddressOption, wrapErr("invalid voting result address"))
224-
225-let childrenAddressOption = match configAddressOption {
226- case a: Address =>
227- match getString(a, keyChildrenAddress()) {
228- case s: String =>
229- addressFromString(s)
230- case _: Unit =>
231- unit
232- case _ =>
233- throw("Match error")
234- }
235- case _: Unit =>
236- unit
237- case _ =>
238- throw("Match error")
239-}
240-
241-let childrenAddressOrFail = valueOrErrorMessage(childrenAddressOption, wrapErr("invalid children address"))
242-
243-let lpAssetIdOption = match getString(this, keyLpAssetId()) {
244- case s: String =>
245- fromBase58String(s)
246- case _: Unit =>
247- unit
248- case _ =>
249- throw("Match error")
250-}
251-
252-let lpAssetIdOrFail = valueOrErrorMessage(lpAssetIdOption, wrapErr("invalid lpAssetId"))
253-
254-func onlyAddress (i,address) = if ((i.caller == address))
255- then true
256- else throwErr("permission denied")
257-
258-
259-func onlyThis (i) = onlyAddress(i, this)
260-
261-
262-func onlyCalculator (i) = onlyAddress(i, calculatorAddressOrFail)
263-
264245
265246 @Callable(i)
266-func stringEntry (key,val) = if (onlyCalculator(i))
267- then $Tuple2([StringEntry(key, val)], key)
268- else $Tuple2(nil, unit)
247+func suggestRemove (assetId) = {
248+ let gwxAmountAtNow = getUserGwxAmountAtHeight(toString(i.caller), height)
249+ let minSuggestRemoveBalance = getIntegerValue(keyMinSuggestRemoveBalance)
250+ let wxPayment = i.payments[0]
251+ let wxPaymentAssetId = value(wxPayment.assetId)
252+ let wxPaymentAmount = value(wxPayment.amount)
253+ let tokenIsVerified = {
254+ let @ = invoke(assetsStoreContract, "isVerifiedREADONLY", [assetId], nil)
255+ if ($isInstanceOf(@, "Boolean"))
256+ then @
257+ else throw(($getType(@) + " couldn't be cast to Boolean"))
258+ }
259+ let checks = [if (tokenIsVerified)
260+ then true
261+ else throwErr("token not verified"), if ((gwxAmountAtNow >= minSuggestRemoveBalance))
262+ then true
263+ else throwErr("not enough gWXes"), if ((wxPaymentAmount >= getIntegerValue(keyWxForSuggestRemoveAmountRequired)))
264+ then true
265+ else throwErr("payment less then min for suggest")]
266+ if ((checks == checks))
267+ then {
268+ let currentIndexKey = keyCurrentIndex(assetId)
269+ let currentIndex = getInteger(currentIndexKey)
270+ let newIndex = if (isDefined(currentIndex))
271+ then (value(currentIndex) + 1)
272+ else 0
273+ let periodLength = valueOrErrorMessage(getInteger(keyPeriodLengthRemove), wrapErr("periodLengthRemove not set"))
274+ let votingEndHeight = (height + periodLength)
275+ let votesQuorum = valueOrErrorMessage(getInteger(keyVotingThresholdRemove), wrapErr("votingThresholdRemove not set"))
276+ let votingInfo = votingInfoValue(false, "EMPTY", 0, "deverification", "inProgress", height, (height + periodLength), votesQuorum, 0, 0)
277+[IntegerEntry(currentIndexKey, newIndex), StringEntry(keySuggestIssuer(assetId, newIndex), toString(i.caller)), StringEntry(keyVotingInfo(assetId, newIndex), votingInfo)]
278+ }
279+ else throw("Strict value is not equal to itself.")
280+ }
269281
270282
271283
272284 @Callable(i)
273-func integerEntry (key,val) = if (onlyCalculator(i))
274- then $Tuple2([IntegerEntry(key, val)], key)
275- else $Tuple2(nil, unit)
285+func vote (assetId,inFavor) = {
286+ let currentIndexKey = keyCurrentIndex(assetId)
287+ let currentIndex = valueOrErrorMessage(getInteger(currentIndexKey), wrapErr("voting does not exist"))
288+ let votingInfo = votingExistChecks(assetId, currentIndex)
289+ if ((votingInfo == votingInfo))
290+ then {
291+ let currentVotingEndHeight = votingInfo._2
292+ let gwxAmountAtEnd = getUserGwxAmountAtHeight(toString(i.caller), currentVotingEndHeight)
293+ let voteKey = keyVote(assetId, currentIndex, i.caller)
294+ let checks = [if ((getString(voteKey) == unit))
295+ then true
296+ else throwErr("You have already voted"), if ((gwxAmountAtEnd > 0))
297+ then true
298+ else throw("You'll not have gWX at the end of voting")]
299+ if ((checks == checks))
300+ then {
301+ let votingInfoStr = valueOrErrorMessage(getString(keyVotingInfo(assetId, currentIndex)), wrapErr("voting info not found"))
302+ let votingInfoParts = getVotingInfoParts(votingInfoStr)
303+ let votesFor = votingInfoParts._9
304+ let votesAgainst = votingInfoParts._10
305+ let $t01274512906 = if (inFavor)
306+ then $Tuple2((votesFor + gwxAmountAtEnd), votesAgainst)
307+ else $Tuple2(votesFor, (votesAgainst + gwxAmountAtEnd))
308+ let newVotesFor = $t01274512906._1
309+ let newVotesAgainst = $t01274512906._2
310+ let newVotingInfoValue = votingInfoValue(votingInfoParts._1, votingInfoParts._2, votingInfoParts._3, votingInfoParts._4, votingInfoParts._5, votingInfoParts._6, votingInfoParts._7, votingInfoParts._8, newVotesFor, newVotesAgainst)
311+ let votingRewardAction = match getString(keyVotingRewardAssetId(assetId, currentIndex)) {
312+ case pk: String =>
313+[StringEntry(keyVotingReward(i.caller, assetId, currentIndex), voteValue(inFavor, gwxAmountAtEnd))]
314+ case _: Unit =>
315+ nil
316+ case _ =>
317+ throw("Match error")
318+ }
319+ ([StringEntry(voteKey, voteValue(inFavor, gwxAmountAtEnd)), StringEntry(keyVotingInfo(assetId, currentIndex), newVotingInfoValue)] ++ votingRewardAction)
320+ }
321+ else throw("Strict value is not equal to itself.")
322+ }
323+ else throw("Strict value is not equal to itself.")
324+ }
276325
277326
278327
279328 @Callable(i)
280-func booleanEntry (key,val) = if (onlyCalculator(i))
281- then $Tuple2([BooleanEntry(key, val)], key)
282- else $Tuple2(nil, unit)
329+func cancelVote (assetId) = {
330+ let currentIndexKey = keyCurrentIndex(assetId)
331+ let currentIndex = valueOrErrorMessage(getInteger(currentIndexKey), wrapErr("voting does not exist"))
332+ let voteKey = keyVote(assetId, currentIndex, i.caller)
333+ let lastVote = valueOrErrorMessage(getString(voteKey), wrapErr("you have not voted"))
334+ let lastVoteParts = split(lastVote, separator)
335+ let inFavor = lastVoteParts[1]
336+ let gwxAmount = parseIntValue(lastVoteParts[2])
337+ let votingInfo = votingExistChecks(assetId, currentIndex)
338+ if ((votingInfo == votingInfo))
339+ then {
340+ let checks = [if (if ((inFavor == "true"))
341+ then true
342+ else (inFavor == "false"))
343+ then true
344+ else throwErr("invalid vote")]
345+ if ((checks == checks))
346+ then {
347+ let votingInfoStr = valueOrErrorMessage(getString(keyVotingInfo(assetId, currentIndex)), wrapErr("voting info not found"))
348+ let votingInfoParts = getVotingInfoParts(votingInfoStr)
349+ let votesFor = votingInfoParts._9
350+ let votesAgainst = votingInfoParts._10
351+ let $t01453114692 = if ((inFavor == "true"))
352+ then $Tuple2((votesFor - gwxAmount), votesAgainst)
353+ else $Tuple2(votesFor, (votesAgainst - gwxAmount))
354+ let newVotesFor = $t01453114692._1
355+ let newVotesAgainst = $t01453114692._2
356+ let newVotingInfoValue = votingInfoValue(votingInfoParts._1, votingInfoParts._2, votingInfoParts._3, votingInfoParts._4, votingInfoParts._5, votingInfoParts._6, votingInfoParts._7, votingInfoParts._8, newVotesFor, newVotesAgainst)
357+[StringEntry(keyVotingInfo(assetId, currentIndex), newVotingInfoValue), DeleteEntry(voteKey), DeleteEntry(keyVotingReward(i.caller, assetId, currentIndex))]
358+ }
359+ else throw("Strict value is not equal to itself.")
360+ }
361+ else throw("Strict value is not equal to itself.")
362+ }
283363
284364
285365
286366 @Callable(i)
287-func binaryEntry (key,val) = if (onlyCalculator(i))
288- then $Tuple2([BinaryEntry(key, val)], key)
289- else $Tuple2(nil, unit)
367+func finalize (assetId) = {
368+ let currentIndexKey = keyCurrentIndex(assetId)
369+ let currentIndex = valueOrElse(getInteger(currentIndexKey), 0)
370+ let votingThresholdAdd = valueOrErrorMessage(getInteger(keyVotingThresholdAdd), wrapErr("votingThresholdAdd not set"))
371+ let votingThresholdRemove = valueOrErrorMessage(getInteger(keyVotingThresholdRemove), wrapErr("votingThresholdRemove not set"))
372+ let votingInfoStr = valueOrErrorMessage(getString(keyVotingInfo(assetId, currentIndex)), wrapErr("voting info not found"))
373+ let votingInfoParts = getVotingInfoParts(votingInfoStr)
374+ let votingType = votingInfoParts._4
375+ let status = votingInfoParts._5
376+ let votingEndHeight = votingInfoParts._7
377+ let votingQuorum = votingInfoParts._8
378+ let votesFor = votingInfoParts._9
379+ let votesAgainst = votingInfoParts._10
380+ let checks = [if ((status == "inProgress"))
381+ then true
382+ else throwErr("voting not in progress"), if ((height >= votingEndHeight))
383+ then true
384+ else throwErr("voting not finished"), if (isDefined(getString(keyAssetImage(assetId))))
385+ then true
386+ else throwErr("asset image not set")]
387+ if ((checks == checks))
388+ then {
389+ let votingAccepted = if (if (((votesFor + votesAgainst) >= votingQuorum))
390+ then (votesFor > votesAgainst)
391+ else false)
392+ then true
393+ else false
394+ let newStatus = if (votingAccepted)
395+ then "accepted"
396+ else "rejected"
397+ let assetImage = getStringValue(keyAssetImage(assetId))
398+ let isVotingAccepted = if (votingAccepted)
399+ then {
400+ let votingAcceptedInvokes = if ((votingType == "verification"))
401+ then invoke(assetsStoreContract, "createOrUpdate", [assetId, assetImage, true], nil)
402+ else invoke(assetsStoreContract, "setVerified", [assetId, false], nil)
403+ votingAcceptedInvokes
404+ }
405+ else nil
406+ if ((isVotingAccepted == isVotingAccepted))
407+ then {
408+ let newVotingInfoValue = votingInfoValue(votingInfoParts._1, votingInfoParts._2, votingInfoParts._3, votingInfoParts._4, newStatus, votingInfoParts._6, votingInfoParts._7, votingInfoParts._8, votingInfoParts._9, votingInfoParts._10)
409+ let finalizeCallRewardAmount = getIntegerValue(keyFinalizeCallRewardAmount)
410+[StringEntry(keyVotingInfo(assetId, currentIndex), newVotingInfoValue), ScriptTransfer(i.caller, finalizeCallRewardAmount, wxAssetId)]
411+ }
412+ else throw("Strict value is not equal to itself.")
413+ }
414+ else throw("Strict value is not equal to itself.")
415+ }
290416
291417
292418
293419 @Callable(i)
294-func deleteEntry (key) = if (onlyCalculator(i))
295- then $Tuple2([DeleteEntry(key)], key)
296- else $Tuple2(nil, unit)
420+func claimREADONLY (assetId,index,userAddressStr) = {
421+ let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid address"))
422+ let votingRewardAssetIdStr = getString(keyVotingRewardAssetId(assetId, index))
423+ let rewardAmount = if (isDefined(votingRewardAssetIdStr))
424+ then calculateReward(userAddress, assetId, index)
425+ else 0
426+ $Tuple2(nil, rewardAmount)
427+ }
297428
298429
299430
300431 @Callable(i)
301-func reissue (amount) = if (onlyCalculator(i))
302- then $Tuple2([Reissue(lpAssetIdOrFail, amount, true)], amount)
303- else $Tuple2(nil, unit)
304-
305-
306-
307-@Callable(i)
308-func burn (amount) = if (onlyCalculator(i))
309- then $Tuple2([Burn(lpAssetIdOrFail, amount)], amount)
310- else $Tuple2(nil, unit)
311-
312-
313-
314-@Callable(i)
315-func transferAsset (recepientBytes,amount,assetId) = if (onlyCalculator(i))
316- then $Tuple2([ScriptTransfer(Address(recepientBytes), amount, assetId)], amount)
317- else $Tuple2(nil, unit)
318-
319-
320-
321-@Callable(i)
322-func transferWaves (recepientBytes,amount) = if (onlyCalculator(i))
323- then $Tuple2([ScriptTransfer(Address(recepientBytes), amount, unit)], amount)
324- else $Tuple2(nil, unit)
325-
326-
327-
328-@Callable(i)
329-func transferFromProxyTreasury (recipientBytes,rewardsAmount) = if (onlyCalculator(i))
330- then $Tuple2(nil, invoke(proxyTreasuryAddressOrFail, "transferWaves", [recipientBytes, rewardsAmount], nil))
331- else $Tuple2(nil, unit)
332-
333-
334-
335-@Callable(i)
336-func finalize (newTreasuryVolumeInWaves,pwrManagersBonusInWaves,treasuryVolumeDiffAllocationCoef) = $Tuple2(nil, reentrantInvoke(calculatorAddressOrFail, "finalize", [i.caller.bytes, newTreasuryVolumeInWaves, pwrManagersBonusInWaves, treasuryVolumeDiffAllocationCoef], i.payments))
337-
338-
339-
340-@Callable(i)
341-func finalizeREADONLY (newTreasuryVolumeInWaves,pwrManagersBonusInWaves,treasuryVolumeDiffAllocationCoef) = $Tuple2(nil, reentrantInvoke(calculatorAddressOrFail, "finalizeREADONLY", [newTreasuryVolumeInWaves, pwrManagersBonusInWaves, treasuryVolumeDiffAllocationCoef], nil))
342-
343-
344-
345-@Callable(i)
346-func claimLP () = $Tuple2(nil, reentrantInvoke(calculatorAddressOrFail, "claimLP", [i.caller.bytes], i.payments))
347-
348-
349-
350-@Callable(i)
351-func claimWaves (txIdStr) = $Tuple2(nil, reentrantInvoke(calculatorAddressOrFail, "claimWaves", [i.caller.bytes, fromBase58String(txIdStr)], i.payments))
352-
353-
354-
355-@Callable(i)
356-func invest () = $Tuple2(nil, reentrantInvoke(calculatorAddressOrFail, "invest", [i.caller.bytes], i.payments))
357-
358-
359-
360-@Callable(i)
361-func withdraw () = $Tuple2(nil, reentrantInvoke(calculatorAddressOrFail, "withdraw", [i.caller.bytes], i.payments))
362-
363-
364-
365-@Callable(i)
366-func cancelWithdraw (txIdStr) = $Tuple2(nil, reentrantInvoke(calculatorAddressOrFail, "cancelWithdraw", [i.caller.bytes, fromBase58String(txIdStr)], i.payments))
367-
368-
369-
370-@Callable(i)
371-func processBlocks () = $Tuple2(nil, reentrantInvoke(calculatorAddressOrFail, "processBlocks", [i.caller.bytes], i.payments))
372-
373-
374-
375-@Callable(i)
376-func voteForTxId (txId) = {
377- let callerAddressString = toBase58String(i.caller.bytes)
378- let keyPrefix = keyAllowedTxIdVotePrefix(txId)
379- let result = [StringEntry(keyAllowedTxId(), txId)]
380- let allowedTxIdOption = getString(this, keyAllowedTxId())
381- let err = [if ((size(fromBase58String(txId)) == TXID_BYTES_LENGTH))
432+func claim (assetId,index) = {
433+ let callerAddress = i.caller
434+ let claimHistoryKey = keyClaimHistory(callerAddress, assetId, index)
435+ let claimHistory = getInteger(claimHistoryKey)
436+ let checks = [if ((claimHistory == unit))
382437 then true
383- else throwErr((txId + " is not valid txId")), if (if ((allowedTxIdOption == unit))
384- then true
385- else (value(allowedTxIdOption) != txId))
386- then true
387- else throwErr((txId + " is already allowed"))]
388- if ((err == err))
389- then voteINTERNAL(callerAddressString, keyPrefix, QUORUM, result)
438+ else throwErr("already claimed")]
439+ if ((checks == checks))
440+ then {
441+ let rewardAmount = if ((calculateReward(callerAddress, assetId, index) > 0))
442+ then calculateReward(callerAddress, assetId, index)
443+ else throwErr("nothing to claim")
444+ let votingRewardAssetIdStr = getString(keyVotingRewardAssetId(assetId, index))
445+ let rewardAction = if (isDefined(votingRewardAssetIdStr))
446+ then {
447+ let votingRewardAssetId = fromBase58String(value(votingRewardAssetIdStr))
448+[ScriptTransfer(callerAddress, rewardAmount, votingRewardAssetId), IntegerEntry(claimHistoryKey, rewardAmount), DeleteEntry(keyVotingReward(callerAddress, assetId, index))]
449+ }
450+ else throwErr("nothing to claim")
451+ rewardAction
452+ }
390453 else throw("Strict value is not equal to itself.")
391454 }
392455
393456
394457 @Verifier(tx)
395458 func verify () = {
396- let byProposal = match votingResultAddressOption {
397- case proposalAddress: Address =>
398- valueOrElse(getBoolean(proposalAddress, keyProposalAllowBroadcast(this, tx.id)), false)
459+ let targetPublicKey = match managerPublicKeyOrUnit() {
460+ case pk: ByteVector =>
461+ pk
462+ case _: Unit =>
463+ tx.senderPublicKey
399464 case _ =>
400- false
465+ throw("Match error")
401466 }
402- let byAdmins = (tx.id == fromBase58String(valueOrElse(getString(this, keyAllowedTxId()), "")))
403- let byOwner = if ((size(getAdminsList()) >= QUORUM))
404- then false
405- else sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
406- if (if (byProposal)
407- then true
408- else byAdmins)
409- then true
410- else byOwner
467+ sigVerify(tx.bodyBytes, tx.proofs[0], targetPublicKey)
411468 }
412469

github/deemru/w8io/169f3d6 
64.95 ms