tx · 3J844DxTN85g5x4pS4GGiLe9GDJxn2MXCNpPs45BeoMq

3N9wLKKtDBphos7U3xzsPqgvJJ5zPQEU6pV:  -0.02400000 Waves

2023.07.04 16:29 [2651218] smart account 3N9wLKKtDBphos7U3xzsPqgvJJ5zPQEU6pV > SELF 0.00000000 Waves

{ "type": 13, "id": "3J844DxTN85g5x4pS4GGiLe9GDJxn2MXCNpPs45BeoMq", "fee": 2400000, "feeAssetId": null, "timestamp": 1688477344386, "version": 1, "sender": "3N9wLKKtDBphos7U3xzsPqgvJJ5zPQEU6pV", "senderPublicKey": "GKX7DbVJVEtTB6ak3PXWHNPUhC3jym3ozbtZ7a36rGu6", "proofs": [ "4LVbhTPXqRrRAUcZp5QGpHkLwMUJHHdH9kM9agt4brZihrZ5bzemUBiwWVPaSmddpYMG3r6xUag4LRf8hQkdhT6S" ], "script": "base64:BwIqCAISAwoBAhIGCgQCAQEBEgMKAQISAwoBAhIECgICAhIECgICAhIDCgECKgADU0VQAgJfXwANQ09OVFJBQ1RfTkFNRQIPY2FsY3VsYXRvci5yaWRlAAZTQ0FMRTgAgMLXLwAHUEVORElORwIHUEVORElORwAIRklOSVNIRUQCCEZJTklTSEVEAAVXQVZFUwIFV0FWRVMBB3dyYXBFcnIBAXMJAKwCAgkArAICBQ1DT05UUkFDVF9OQU1FAgI6IAUBcwEIdGhyb3dFcnIBAXMJAAIBCQEHd3JhcEVycgEFAXMBD2Fzc2V0SWRUb1N0cmluZwEHYXNzZXRJZAQHJG1hdGNoMAUHYXNzZXRJZAMJAAECBQckbWF0Y2gwAgpCeXRlVmVjdG9yBAFiBQckbWF0Y2gwCQDYBAEFAWIDCQABAgUHJG1hdGNoMAIEVW5pdAUFV0FWRVMJAAIBAgtNYXRjaCBlcnJvcgEDYWJzAQFuAwkAZgIAAAUBbgkBAS0BBQFuBQFuARFrZXlGYWN0b3J5QWRkcmVzcwAJALkJAgkAzAgCAgIlcwkAzAgCAgdmYWN0b3J5BQNuaWwFA1NFUAETa2V5TWFuYWdlclB1YmxpY0tleQAJALkJAgkAzAgCAgIlcwkAzAgCAhBtYW5hZ2VyUHVibGljS2V5BQNuaWwFA1NFUAEMa2V5THBBc3NldElkAAkAuQkCCQDMCAICAiVzCQDMCAICCWxwQXNzZXRJZAUDbmlsBQNTRVABF2tleVByb3h5VHJlYXN1cnlBZGRyZXNzAAkAuQkCCQDMCAICAiVzCQDMCAICDXByb3h5VHJlYXN1cnkFA25pbAUDU0VQARZrZXlNYWluVHJlYXN1cnlBZGRyZXNzAAkAuQkCCQDMCAICAiVzCQDMCAICDG1haW5UcmVhc3VyeQUDbmlsBQNTRVABC2tleUludmVzdGVkAQdhc3NldElkCQC5CQIJAMwIAgIEJXMlcwkAzAgCAghpbnZlc3RlZAkAzAgCCQEPYXNzZXRJZFRvU3RyaW5nAQUHYXNzZXRJZAUDbmlsBQNTRVABCmtleURvbmF0ZWQBB2Fzc2V0SWQJALkJAgkAzAgCAgQlcyVzCQDMCAICB2RvbmF0ZWQJAMwIAgkBD2Fzc2V0SWRUb1N0cmluZwEFB2Fzc2V0SWQFA25pbAUDU0VQAQxrZXlBdmFpbGFibGUBC3VzZXJBZGRyZXNzCQC5CQIJAMwIAgIEJXMlcwkAzAgCAglhdmFpbGFibGUJAMwIAgkApQgBBQt1c2VyQWRkcmVzcwUDbmlsBQNTRVABCmtleUNsYWltZWQBC3VzZXJBZGRyZXNzCQC5CQIJAMwIAgIEJXMlcwkAzAgCAgdjbGFpbWVkCQDMCAIJAKUIAQULdXNlckFkZHJlc3MFA25pbAUDU0VQARBrZXlDdXJyZW50UGVyaW9kAAkAuQkCCQDMCAICAiVzCQDMCAICDWN1cnJlbnRQZXJpb2QFA25pbAUDU0VQARFrZXlQcmljZUZvclBlcmlvZAEGcGVyaW9kCQC5CQIJAMwIAgIEJXMlZAkAzAgCAgVwcmljZQkAzAgCCQCkAwEFBnBlcmlvZAUDbmlsBQNTRVABDmtleVN0YXJ0SGVpZ2h0AQZwZXJpb2QJALkJAgkAzAgCAgQlcyVkCQDMCAICC3N0YXJ0SGVpZ2h0CQDMCAIJAKQDAQUGcGVyaW9kBQNuaWwFA1NFUAEPa2V5UGVyaW9kTGVuZ3RoAAIQJXNfX3BlcmlvZExlbmd0aAEYa2V5QmxvY2tQcm9jZXNzaW5nUmV3YXJkAAIZJXNfX2Jsb2NrUHJvY2Vzc2luZ1Jld2FyZAEVa2V5TmV4dEJsb2NrVG9Qcm9jZXNzAAIWJXNfX25leHRCbG9ja1RvUHJvY2VzcwERa2V5QmxvY2tQcm9jZXNzZWQBBmhlaWdodAkAuQkCCQDMCAICBCVzJWQJAMwIAgIOYmxvY2tQcm9jZXNzZWQJAMwIAgkApAMBBQZoZWlnaHQFA25pbAUDU0VQAQ1rZXlXaXRoZHJhd2FsAAIOJXNfX3dpdGhkcmF3YWwBFGtleVdpdGhkcmF3YWxSZXF1ZXN0Agt1c2VyQWRkcmVzcwR0eElkCQC5CQIJAMwIAgIGJXMlcyVzCQDMCAICCndpdGhkcmF3YWwJAMwIAgkApQgBBQt1c2VyQWRkcmVzcwkAzAgCCQDYBAEFBHR4SWQFA25pbAUDU0VQARZ2YWx1ZVdpdGhkcmF3YWxSZXF1ZXN0BAZzdGF0dXMNbHBBc3NldEFtb3VudAx0YXJnZXRQZXJpb2QJY2xhaW1UeElkBAxjbGFpbVR4SWRTdHIEByRtYXRjaDAFCWNsYWltVHhJZAMJAAECBQckbWF0Y2gwAgpCeXRlVmVjdG9yBAFiBQckbWF0Y2gwCQDYBAEFAWIDCQABAgUHJG1hdGNoMAIEVW5pdAIEU09PTgkAAgECC01hdGNoIGVycm9yCQC5CQIJAMwIAgIIJXMlZCVkJXMJAMwIAgUGc3RhdHVzCQDMCAIJAKQDAQUNbHBBc3NldEFtb3VudAkAzAgCCQCkAwEFDHRhcmdldFBlcmlvZAkAzAgCBQxjbGFpbVR4SWRTdHIFA25pbAUDU0VQASFwYXJzZVdpdGhkcmF3YWxSZXF1ZXN0VmFsdWVPckZhaWwBAXMEBXBhcnRzCQC1CQIFAXMFA1NFUAMJAAACCQCQAwEFBXBhcnRzAAUEBnN0YXR1cwkAkQMCBQVwYXJ0cwABBA1scEFzc2V0QW1vdW50CQETdmFsdWVPckVycm9yTWVzc2FnZQIJALYJAQkAkQMCBQVwYXJ0cwACCQEHd3JhcEVycgECFWludmFsaWQgbHBBc3NldEFtb3VudAQMdGFyZ2V0UGVyaW9kCQETdmFsdWVPckVycm9yTWVzc2FnZQIJALYJAQkAkQMCBQVwYXJ0cwADCQEHd3JhcEVycgECFGludmFsaWQgdGFyZ2V0UGVyaW9kBAljbGFpbVR4SWQJAJEDAgUFcGFydHMABAkAlgoEBQZzdGF0dXMFDWxwQXNzZXRBbW91bnQFDHRhcmdldFBlcmlvZAUJY2xhaW1UeElkCQEIdGhyb3dFcnIBAiBpbnZhbGlkIHdpdGhkcmF3YWwgcmVxdWVzdCB2YWx1ZQAUZmFjdG9yeUFkZHJlc3NPcHRpb24EByRtYXRjaDAJAJ0IAgUEdGhpcwkBEWtleUZhY3RvcnlBZGRyZXNzAAMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAXMFByRtYXRjaDAJAKYIAQUBcwMJAAECBQckbWF0Y2gwAgRVbml0BQR1bml0CQACAQILTWF0Y2ggZXJyb3IAFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQETdmFsdWVPckVycm9yTWVzc2FnZQIFFGZhY3RvcnlBZGRyZXNzT3B0aW9uCQEHd3JhcEVycgECF2ludmFsaWQgZmFjdG9yeSBhZGRyZXNzAA9scEFzc2V0SWRPcHRpb24EByRtYXRjaDAFFGZhY3RvcnlBZGRyZXNzT3B0aW9uAwkAAQIFByRtYXRjaDACB0FkZHJlc3MEAWEFByRtYXRjaDAEByRtYXRjaDEJAJ0IAgUBYQkBDGtleUxwQXNzZXRJZAADCQABAgUHJG1hdGNoMQIGU3RyaW5nBAFzBQckbWF0Y2gxCQDZBAEFAXMDCQABAgUHJG1hdGNoMQIEVW5pdAUEdW5pdAkAAgECC01hdGNoIGVycm9yAwkAAQIFByRtYXRjaDACBFVuaXQFBHVuaXQJAAIBAgtNYXRjaCBlcnJvcgAPbHBBc3NldElkT3JGYWlsCQETdmFsdWVPckVycm9yTWVzc2FnZQIFD2xwQXNzZXRJZE9wdGlvbgkBB3dyYXBFcnIBAhFpbnZhbGlkIGxwQXNzZXRJZAAacHJveHlUcmVhc3VyeUFkZHJlc3NPcHRpb24EByRtYXRjaDAFFGZhY3RvcnlBZGRyZXNzT3B0aW9uAwkAAQIFByRtYXRjaDACB0FkZHJlc3MEAWEFByRtYXRjaDAEByRtYXRjaDEJAJ0IAgUBYQkBF2tleVByb3h5VHJlYXN1cnlBZGRyZXNzAAMJAAECBQckbWF0Y2gxAgZTdHJpbmcEAXMFByRtYXRjaDEJAKYIAQUBcwMJAAECBQckbWF0Y2gxAgRVbml0BQR1bml0CQACAQILTWF0Y2ggZXJyb3IDCQABAgUHJG1hdGNoMAIEVW5pdAUEdW5pdAkAAgECC01hdGNoIGVycm9yABpwcm94eVRyZWFzdXJ5QWRkcmVzc09yRmFpbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCBRpwcm94eVRyZWFzdXJ5QWRkcmVzc09wdGlvbgkBB3dyYXBFcnIBAh5pbnZhbGlkIHByb3h5IHRyZWFzdXJ5IGFkZHJlc3MAHGZlYXR1cmVUcmVhc3VyeUFkZHJlc3NPcHRpb24EByRtYXRjaDAFFGZhY3RvcnlBZGRyZXNzT3B0aW9uAwkAAQIFByRtYXRjaDACB0FkZHJlc3MEAWEFByRtYXRjaDAEByRtYXRjaDEJAJ0IAgUBYQkBFmtleU1haW5UcmVhc3VyeUFkZHJlc3MAAwkAAQIFByRtYXRjaDECBlN0cmluZwQBcwUHJG1hdGNoMQkApggBBQFzAwkAAQIFByRtYXRjaDECBFVuaXQFBHVuaXQJAAIBAgtNYXRjaCBlcnJvcgMJAAECBQckbWF0Y2gwAgRVbml0BQR1bml0CQACAQILTWF0Y2ggZXJyb3IAHGZlYXR1cmVUcmVhc3VyeUFkZHJlc3NPckZhaWwJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgUcZmVhdHVyZVRyZWFzdXJ5QWRkcmVzc09wdGlvbgkBB3dyYXBFcnIBAiBpbnZhbGlkIGZlYXR1cmUgdHJlYXN1cnkgYWRkcmVzcwEZZ2V0TWFuYWdlclB1YmxpY0tleU9yVW5pdAAEByRtYXRjaDAFFGZhY3RvcnlBZGRyZXNzT3B0aW9uAwkAAQIFByRtYXRjaDACB0FkZHJlc3MEAmZhBQckbWF0Y2gwBAckbWF0Y2gxCQCdCAIFAmZhCQETa2V5TWFuYWdlclB1YmxpY0tleQADCQABAgUHJG1hdGNoMQIGU3RyaW5nBANwdWIFByRtYXRjaDEJANkEAQUDcHViBQR1bml0BQR1bml0AQtvbmx5QWRkcmVzcwIBaQdhZGRyZXNzAwkAAAIIBQFpBmNhbGxlcgUHYWRkcmVzcwYJAQh0aHJvd0VycgECEXBlcm1pc3Npb24gZGVuaWVkAQtvbmx5RmFjdG9yeQEBaQkBC29ubHlBZGRyZXNzAgUBaQUUZmFjdG9yeUFkZHJlc3NPckZhaWwBD3Jld2FyZEZvck9wdGlvbgIHcmV3YXJkcwZ0YXJnZXQEAXMJAJADAQUHcmV3YXJkcwQLJHQwNDY0MTQ2NjYJAJEDAgUHcmV3YXJkcwAABAJhMAgFCyR0MDQ2NDE0NjY2Al8xBAJyMAgFCyR0MDQ2NDE0NjY2Al8yBAskdDA0NjY5NDY5NAkAkQMCBQdyZXdhcmRzAAEEAmExCAULJHQwNDY2OTQ2OTQCXzEEAnIxCAULJHQwNDY2OTQ2OTQCXzIECyR0MDQ2OTc0NzIyCQCRAwIFB3Jld2FyZHMAAgQCYTIIBQskdDA0Njk3NDcyMgJfMQQCcjIIBQskdDA0Njk3NDcyMgJfMgMDCQBmAgUBcwAACQAAAgUCYTAFBnRhcmdldAcFAnIwAwMJAGYCBQFzAAEJAAACBQJhMQUGdGFyZ2V0BwUCcjEDAwkAZgIFAXMAAgkAAAIFAmEyBQZ0YXJnZXQHBQJyMgUEdW5pdAcBaQEHY2xhaW1MUAEQdXNlckFkZHJlc3NCeXRlcwQLY2hlY2tDYWxsZXIJAQtvbmx5RmFjdG9yeQEFAWkDCQAAAgULY2hlY2tDYWxsZXIFC2NoZWNrQ2FsbGVyBAt1c2VyQWRkcmVzcwkBB0FkZHJlc3MBBRB1c2VyQWRkcmVzc0J5dGVzBAlhdmFpbGFibGUJAQt2YWx1ZU9yRWxzZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJAQxrZXlBdmFpbGFibGUBBQt1c2VyQWRkcmVzcwAABAdjbGFpbWVkCQELdmFsdWVPckVsc2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQEKa2V5Q2xhaW1lZAEFC3VzZXJBZGRyZXNzAAAEDmZhY3RvcnlBY3Rpb25zAwkAZgIFCWF2YWlsYWJsZQAACQDMCAIJAPwHBAUUZmFjdG9yeUFkZHJlc3NPckZhaWwCDXRyYW5zZmVyQXNzZXQJAMwIAgUQdXNlckFkZHJlc3NCeXRlcwkAzAgCBQlhdmFpbGFibGUJAMwIAgUPbHBBc3NldElkT3JGYWlsBQNuaWwFA25pbAkAzAgCCQD8BwQFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAgxpbnRlZ2VyRW50cnkJAMwIAgkBDGtleUF2YWlsYWJsZQEFC3VzZXJBZGRyZXNzCQDMCAIAAAUDbmlsBQNuaWwJAMwIAgkA/AcEBRRmYWN0b3J5QWRkcmVzc09yRmFpbAIMaW50ZWdlckVudHJ5CQDMCAIJAQprZXlDbGFpbWVkAQULdXNlckFkZHJlc3MJAMwIAgkAZAIFB2NsYWltZWQFCWF2YWlsYWJsZQUDbmlsBQNuaWwFA25pbAkBCHRocm93RXJyAQIQbm90aGluZyB0byBjbGFpbQkAlAoCBQNuaWwFDmZhY3RvcnlBY3Rpb25zCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCGZpbmFsaXplBBB1c2VyQWRkcmVzc0J5dGVzGG5ld1RyZWFzdXJ5Vm9sdW1lSW5XYXZlcxdwd3JNYW5hZ2Vyc0JvbnVzSW5XYXZlcyB0cmVhc3VyeVZvbHVtZURpZmZBbGxvY2F0aW9uQ29lZgQLY2hlY2tDYWxsZXIJAQtvbmx5RmFjdG9yeQEFAWkDCQAAAgULY2hlY2tDYWxsZXIFC2NoZWNrQ2FsbGVyBBNjdXJyZW50UGVyaW9kT3JGYWlsCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJARBrZXlDdXJyZW50UGVyaW9kAAkBB3dyYXBFcnIBAg5pbnZhbGlkIHBlcmlvZAQMcGVyaW9kTGVuZ3RoCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJAQ9rZXlQZXJpb2RMZW5ndGgACQEHd3JhcEVycgECFWludmFsaWQgcGVyaW9kIGxlbmd0aAQSY3VycmVudFN0YXJ0SGVpZ2h0CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJAQ5rZXlTdGFydEhlaWdodAEFE2N1cnJlbnRQZXJpb2RPckZhaWwJAQd3cmFwRXJyAQIUaW52YWxpZCBzdGFydCBoZWlnaHQEEmN1cnJlbnRQcmljZU9yRmFpbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQERa2V5UHJpY2VGb3JQZXJpb2QBBRNjdXJyZW50UGVyaW9kT3JGYWlsCQEHd3JhcEVycgECDWludmFsaWQgcHJpY2UEEm5leHRCbG9ja1RvUHJvY2VzcwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQEVa2V5TmV4dEJsb2NrVG9Qcm9jZXNzAAkBB3dyYXBFcnIBAh1pbnZhbGlkIG5leHQgYmxvY2sgdG8gcHJvY2VzcwQPcGVyaW9kRW5kSGVpZ2h0CQBlAgkAZAIFEmN1cnJlbnRTdGFydEhlaWdodAUMcGVyaW9kTGVuZ3RoAAEEBmNoZWNrcwkAzAgCAwkAAAIIBQFpDG9yaWdpbkNhbGxlcgUcZmVhdHVyZVRyZWFzdXJ5QWRkcmVzc09yRmFpbAYJAQh0aHJvd0VycgECEXBlcm1pc3Npb24gZGVuaWVkCQDMCAIDCQBmAgUSbmV4dEJsb2NrVG9Qcm9jZXNzBQ9wZXJpb2RFbmRIZWlnaHQGCQEIdGhyb3dFcnIBAhJ1bnByb2Nlc3NlZCBibG9ja3MJAMwIAgMJAGcCBRhuZXdUcmVhc3VyeVZvbHVtZUluV2F2ZXMAAAYJAQh0aHJvd0VycgECG2ludmFsaWQgbmV3IHRyZWFzdXJ5IHZvbHVtZQkAzAgCAwkAZwIFF3B3ck1hbmFnZXJzQm9udXNJbldhdmVzAAAGCQEIdGhyb3dFcnIBAhppbnZhbGlkIFBXUiBtYW5hZ2VycyBib251cwkAzAgCAwMJAGcCBSB0cmVhc3VyeVZvbHVtZURpZmZBbGxvY2F0aW9uQ29lZgkBAS0BBQZTQ0FMRTgJAGcCBQZTQ0FMRTgFIHRyZWFzdXJ5Vm9sdW1lRGlmZkFsbG9jYXRpb25Db2VmBwYJAQh0aHJvd0VycgECM2ludmFsaWQgdHJlYXN1cnkgdm9sdW1lIGRpZmYgYWxsb2NhdGlvbiBjb2VmZmljaWVudAUDbmlsAwkAAAIFBmNoZWNrcwUGY2hlY2tzBBJkb25hdGVkV2F2ZXNBbW91bnQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJAQprZXlEb25hdGVkAQUEdW5pdAAABBNpbnZlc3RlZFdhdmVzQW1vdW50CQELdmFsdWVPckVsc2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQELa2V5SW52ZXN0ZWQBBQR1bml0AAAEHGN1cnJlbnRUcmVhc3VyeVZvbHVtZUluV2F2ZXMJAGQCBRJkb25hdGVkV2F2ZXNBbW91bnQFE2ludmVzdGVkV2F2ZXNBbW91bnQECXByb2ZpdFJhdwkAZQIFGG5ld1RyZWFzdXJ5Vm9sdW1lSW5XYXZlcwUcY3VycmVudFRyZWFzdXJ5Vm9sdW1lSW5XYXZlcwQWcHdyTWFuYWdlcnNCb251c0Ftb3VudAMDCQBmAgUJcHJvZml0UmF3AAAJAGcCBQlwcm9maXRSYXcFF3B3ck1hbmFnZXJzQm9udXNJbldhdmVzBwUXcHdyTWFuYWdlcnNCb251c0luV2F2ZXMAAAQGcHJvZml0CQBlAgUJcHJvZml0UmF3BRZwd3JNYW5hZ2Vyc0JvbnVzQW1vdW50BAxkb25hdGlvblBhcnQDCQBmAgUcY3VycmVudFRyZWFzdXJ5Vm9sdW1lSW5XYXZlcwAACQBrAwUSZG9uYXRlZFdhdmVzQW1vdW50BQZTQ0FMRTgFHGN1cnJlbnRUcmVhc3VyeVZvbHVtZUluV2F2ZXMAAAQVZG9uYXRpb25Qcm9maXRQYXJ0UmF3CQBrAwUGcHJvZml0BQxkb25hdGlvblBhcnQFBlNDQUxFOAQXaW52ZXN0bWVudFByb2ZpdFBhcnRSYXcJAGUCBQZwcm9maXQFFWRvbmF0aW9uUHJvZml0UGFydFJhdwQjdHJlYXN1cnlWb2x1bWVEaWZmQWxsb2NhdGlvbkNvZWZBYnMJAQNhYnMBBSB0cmVhc3VyeVZvbHVtZURpZmZBbGxvY2F0aW9uQ29lZgQQYW1vdW50VG9Eb25hdGlvbgkAawMFF2ludmVzdG1lbnRQcm9maXRQYXJ0UmF3AwkAZgIAAAUgdHJlYXN1cnlWb2x1bWVEaWZmQWxsb2NhdGlvbkNvZWYFI3RyZWFzdXJ5Vm9sdW1lRGlmZkFsbG9jYXRpb25Db2VmQWJzAAAFBlNDQUxFOAQSYW1vdW50VG9JbnZlc3RtZW50CQBrAwUVZG9uYXRpb25Qcm9maXRQYXJ0UmF3AwkAZgIFIHRyZWFzdXJ5Vm9sdW1lRGlmZkFsbG9jYXRpb25Db2VmAAAFI3RyZWFzdXJ5Vm9sdW1lRGlmZkFsbG9jYXRpb25Db2VmQWJzAAAFBlNDQUxFOAQSZG9uYXRpb25Qcm9maXRQYXJ0CQBkAgkAZQIFFWRvbmF0aW9uUHJvZml0UGFydFJhdwUSYW1vdW50VG9JbnZlc3RtZW50BRBhbW91bnRUb0RvbmF0aW9uBBRpbnZlc3RtZW50UHJvZml0UGFydAkAZAIJAGUCBRdpbnZlc3RtZW50UHJvZml0UGFydFJhdwUQYW1vdW50VG9Eb25hdGlvbgUSYW1vdW50VG9JbnZlc3RtZW50BBZpbnZlc3RlZFdhdmVzQW1vdW50TmV3CQBkAgUTaW52ZXN0ZWRXYXZlc0Ftb3VudAUUaW52ZXN0bWVudFByb2ZpdFBhcnQECW5ld1BlcmlvZAkAZAIFE2N1cnJlbnRQZXJpb2RPckZhaWwAAQQPbHBBc3NldFF1YW50aXR5CAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQDsBwEFD2xwQXNzZXRJZE9yRmFpbAkBB3dyYXBFcnIBAhRpbnZhbGlkIGxwQXNzZXQgaW5mbwhxdWFudGl0eQQIbmV3UHJpY2UJAGsDBRZpbnZlc3RlZFdhdmVzQW1vdW50TmV3BQZTQ0FMRTgFD2xwQXNzZXRRdWFudGl0eQQTbHBBc3NldEFtb3VudFRvQnVybgkBC3ZhbHVlT3JFbHNlAgkAmggCBRRmYWN0b3J5QWRkcmVzc09yRmFpbAkBDWtleVdpdGhkcmF3YWwAAAAEC25ld0xwQW1vdW50CQBlAgUPbHBBc3NldFF1YW50aXR5BRNscEFzc2V0QW1vdW50VG9CdXJuBA9uZXdJbnZlc3RBbW91bnQJAJYDAQkAzAgCAAAJAMwIAgkAawMFC25ld0xwQW1vdW50BQhuZXdQcmljZQUGU0NBTEU4BQNuaWwEEHBheW1lbnRBbW91bnRNaW4JAJYDAQkAzAgCAAAJAMwIAgkAawMFE2xwQXNzZXRBbW91bnRUb0J1cm4FCG5ld1ByaWNlBQZTQ0FMRTgFA25pbAQNcGF5bWVudE9wdGlvbgMJAGYCCQCQAwEIBQFpCHBheW1lbnRzAAAJAJEDAggFAWkIcGF5bWVudHMAAAUEdW5pdAQNcGF5bWVudEFtb3VudAgJAQV2YWx1ZQEFDXBheW1lbnRPcHRpb24GYW1vdW50BA5wYXltZW50QXNzZXRJZAgJAQV2YWx1ZQEFDXBheW1lbnRPcHRpb24HYXNzZXRJZAQMY2hlY2tQYXltZW50AwMJAAACBRBwYXltZW50QW1vdW50TWluAAAGAwMJAQIhPQIFDXBheW1lbnRPcHRpb24FBHVuaXQJAAACBQ5wYXltZW50QXNzZXRJZAUEdW5pdAcJAGcCBQ1wYXltZW50QW1vdW50BRBwYXltZW50QW1vdW50TWluBwYJAQh0aHJvd0VycgEJAKwCAgImaW52YWxpZCBwYXltZW50cywgcGF5bWVudCBhbW91bnQgbWluOiAJAKQDAQUQcGF5bWVudEFtb3VudE1pbgMJAAACBQxjaGVja1BheW1lbnQFDGNoZWNrUGF5bWVudAQHYWN0aW9ucwMJAQIhPQIFDXBheW1lbnRPcHRpb24FBHVuaXQJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwUUZmFjdG9yeUFkZHJlc3NPckZhaWwFDXBheW1lbnRBbW91bnQFDnBheW1lbnRBc3NldElkBQNuaWwFA25pbAQOZmFjdG9yeUFjdGlvbnMJAMwIAgkA/AcEBRRmYWN0b3J5QWRkcmVzc09yRmFpbAIMaW50ZWdlckVudHJ5CQDMCAIJARBrZXlDdXJyZW50UGVyaW9kAAkAzAgCBQluZXdQZXJpb2QFA25pbAUDbmlsCQDMCAIJAPwHBAUUZmFjdG9yeUFkZHJlc3NPckZhaWwCDGludGVnZXJFbnRyeQkAzAgCCQERa2V5UHJpY2VGb3JQZXJpb2QBBQluZXdQZXJpb2QJAMwIAgUIbmV3UHJpY2UFA25pbAUDbmlsCQDMCAIJAPwHBAUUZmFjdG9yeUFkZHJlc3NPckZhaWwCDGludGVnZXJFbnRyeQkAzAgCCQEOa2V5U3RhcnRIZWlnaHQBBQluZXdQZXJpb2QJAMwIAgkAZAIFD3BlcmlvZEVuZEhlaWdodAABBQNuaWwFA25pbAkAzAgCCQD8BwQFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAgRidXJuCQDMCAIFE2xwQXNzZXRBbW91bnRUb0J1cm4FA25pbAUDbmlsCQDMCAIJAPwHBAUUZmFjdG9yeUFkZHJlc3NPckZhaWwCDGludGVnZXJFbnRyeQkAzAgCCQENa2V5V2l0aGRyYXdhbAAJAMwIAgAABQNuaWwFA25pbAkAzAgCCQD8BwQFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAgxpbnRlZ2VyRW50cnkJAMwIAgkBC2tleUludmVzdGVkAQUEdW5pdAkAzAgCBQ9uZXdJbnZlc3RBbW91bnQFA25pbAUDbmlsBQNuaWwJAJQKAgUHYWN0aW9ucwUOZmFjdG9yeUFjdGlvbnMJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEGaW52ZXN0ARB1c2VyQWRkcmVzc0J5dGVzBAtjaGVja0NhbGxlcgkBC29ubHlGYWN0b3J5AQUBaQMJAAACBQtjaGVja0NhbGxlcgULY2hlY2tDYWxsZXIEC3VzZXJBZGRyZXNzCQEHQWRkcmVzcwEFEHVzZXJBZGRyZXNzQnl0ZXMEE2N1cnJlbnRQZXJpb2RPckZhaWwJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBRRmYWN0b3J5QWRkcmVzc09yRmFpbAkBEGtleUN1cnJlbnRQZXJpb2QACQEHd3JhcEVycgECDmludmFsaWQgcGVyaW9kBBJjdXJyZW50UHJpY2VPckZhaWwJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBRRmYWN0b3J5QWRkcmVzc09yRmFpbAkBEWtleVByaWNlRm9yUGVyaW9kAQUTY3VycmVudFBlcmlvZE9yRmFpbAkBB3dyYXBFcnIBAg1pbnZhbGlkIHByaWNlBAdwYXltZW50AwkAAAIJAJADAQgFAWkIcGF5bWVudHMAAQkAkQMCCAUBaQhwYXltZW50cwAACQEIdGhyb3dFcnIBAhBpbnZhbGlkIHBheW1lbnRzBA0kdDAxMTI0NjExNDIzAwMJAAACCAUHcGF5bWVudAdhc3NldElkBQR1bml0CQBmAggFB3BheW1lbnQGYW1vdW50AAAHCQCUCgIIBQdwYXltZW50BmFtb3VudAgFB3BheW1lbnQHYXNzZXRJZAkBCHRocm93RXJyAQIWaW52YWxpZCBwYXltZW50IGFtb3VudAQNcGF5bWVudEFtb3VudAgFDSR0MDExMjQ2MTE0MjMCXzEEDnBheW1lbnRBc3NldElkCAUNJHQwMTEyNDYxMTQyMwJfMgQNbHBBc3NldEFtb3VudAMJAGYCBRJjdXJyZW50UHJpY2VPckZhaWwAAAkAawMFDXBheW1lbnRBbW91bnQFBlNDQUxFOAUSY3VycmVudFByaWNlT3JGYWlsAAAECGludmVzdGVkCQELdmFsdWVPckVsc2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQELa2V5SW52ZXN0ZWQBBQR1bml0AAAEB2FjdGlvbnMJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwUcZmVhdHVyZVRyZWFzdXJ5QWRkcmVzc09yRmFpbAUNcGF5bWVudEFtb3VudAUOcGF5bWVudEFzc2V0SWQFA25pbAQOZmFjdG9yeUFjdGlvbnMJAMwIAgkA/AcEBRRmYWN0b3J5QWRkcmVzc09yRmFpbAIMaW50ZWdlckVudHJ5CQDMCAIJAQtrZXlJbnZlc3RlZAEFBHVuaXQJAMwIAgkAZAIFCGludmVzdGVkBQ1wYXltZW50QW1vdW50BQNuaWwFA25pbAkAzAgCCQD8BwQFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAgdyZWlzc3VlCQDMCAIFDWxwQXNzZXRBbW91bnQFA25pbAUDbmlsCQDMCAIJAPwHBAUUZmFjdG9yeUFkZHJlc3NPckZhaWwCDXRyYW5zZmVyQXNzZXQJAMwIAgUQdXNlckFkZHJlc3NCeXRlcwkAzAgCBQ1scEFzc2V0QW1vdW50CQDMCAIFD2xwQXNzZXRJZE9yRmFpbAUDbmlsBQNuaWwFA25pbAkAlAoCBQdhY3Rpb25zBQ5mYWN0b3J5QWN0aW9ucwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQh3aXRoZHJhdwEQdXNlckFkZHJlc3NCeXRlcwQLY2hlY2tDYWxsZXIJAQtvbmx5RmFjdG9yeQEFAWkDCQAAAgULY2hlY2tDYWxsZXIFC2NoZWNrQ2FsbGVyBAt1c2VyQWRkcmVzcwkBB0FkZHJlc3MBBRB1c2VyQWRkcmVzc0J5dGVzBBNjdXJyZW50UGVyaW9kT3JGYWlsCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJARBrZXlDdXJyZW50UGVyaW9kAAkBB3dyYXBFcnIBAg5pbnZhbGlkIHBlcmlvZAQHcGF5bWVudAMJAAACCQCQAwEIBQFpCHBheW1lbnRzAAEJAJEDAggFAWkIcGF5bWVudHMAAAkBCHRocm93RXJyAQkBB3dyYXBFcnIBAhBpbnZhbGlkIHBheW1lbnRzBA5wYXltZW50QXNzZXRJZAMJAAACCAUHcGF5bWVudAdhc3NldElkBQ9scEFzc2V0SWRPckZhaWwFD2xwQXNzZXRJZE9yRmFpbAkBCHRocm93RXJyAQIVaW52YWxpZCBwYXltZW50IGFzc2V0BA1wYXltZW50QW1vdW50AwkAZgIIBQdwYXltZW50BmFtb3VudAAACAUHcGF5bWVudAZhbW91bnQJAQh0aHJvd0VycgECFmludmFsaWQgcGF5bWVudCBhbW91bnQECndpdGhkcmF3YWwJAQt2YWx1ZU9yRWxzZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJAQ1rZXlXaXRoZHJhd2FsAAAABAdhY3Rpb25zCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMFFGZhY3RvcnlBZGRyZXNzT3JGYWlsBQ1wYXltZW50QW1vdW50BQ5wYXltZW50QXNzZXRJZAUDbmlsBA5mYWN0b3J5QWN0aW9ucwkAzAgCCQD8BwQFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAgxpbnRlZ2VyRW50cnkJAMwIAgkBDWtleVdpdGhkcmF3YWwACQDMCAIJAGQCBQp3aXRoZHJhd2FsBQ1wYXltZW50QW1vdW50BQNuaWwFA25pbAkAzAgCCQD8BwQFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAgtzdHJpbmdFbnRyeQkAzAgCCQEUa2V5V2l0aGRyYXdhbFJlcXVlc3QCBQt1c2VyQWRkcmVzcwgFAWkNdHJhbnNhY3Rpb25JZAkAzAgCCQEWdmFsdWVXaXRoZHJhd2FsUmVxdWVzdAQFB1BFTkRJTkcFDXBheW1lbnRBbW91bnQJAGQCBRNjdXJyZW50UGVyaW9kT3JGYWlsAAEFBHVuaXQFA25pbAUDbmlsBQNuaWwDCQAAAgUOZmFjdG9yeUFjdGlvbnMFDmZhY3RvcnlBY3Rpb25zCQCUCgIFB2FjdGlvbnMFDmZhY3RvcnlBY3Rpb25zCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDmNhbmNlbFdpdGhkcmF3AhB1c2VyQWRkcmVzc0J5dGVzBHR4SWQEC2NoZWNrQ2FsbGVyCQELb25seUZhY3RvcnkBBQFpAwkAAAIFC2NoZWNrQ2FsbGVyBQtjaGVja0NhbGxlcgQLdXNlckFkZHJlc3MJAQdBZGRyZXNzAQUQdXNlckFkZHJlc3NCeXRlcwQXd2l0aGRyYXdhbFJlcXVlc3RPcHRpb24JARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBRRmYWN0b3J5QWRkcmVzc09yRmFpbAkBFGtleVdpdGhkcmF3YWxSZXF1ZXN0AgULdXNlckFkZHJlc3MFBHR4SWQJAQd3cmFwRXJyAQIaaW52YWxpZCB3aXRoZHJhd2FsIHJlcXVlc3QEE2N1cnJlbnRQZXJpb2RPckZhaWwJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBRRmYWN0b3J5QWRkcmVzc09yRmFpbAkBEGtleUN1cnJlbnRQZXJpb2QACQEHd3JhcEVycgECDmludmFsaWQgcGVyaW9kBA0kdDAxMzgzMzEzOTQ2CQEhcGFyc2VXaXRoZHJhd2FsUmVxdWVzdFZhbHVlT3JGYWlsAQUXd2l0aGRyYXdhbFJlcXVlc3RPcHRpb24EBnN0YXR1cwgFDSR0MDEzODMzMTM5NDYCXzEEDWxwQXNzZXRBbW91bnQIBQ0kdDAxMzgzMzEzOTQ2Al8yBAx0YXJnZXRQZXJpb2QIBQ0kdDAxMzgzMzEzOTQ2Al8zBAljbGFpbVR4SWQIBQ0kdDAxMzgzMzEzOTQ2Al80BAZjaGVja3MJAMwIAgMJAAACBQZzdGF0dXMFB1BFTkRJTkcGCQEIdGhyb3dFcnIBAiFpbnZhbGlkIHdpdGhkcmF3YWwgcmVxdWVzdCBzdGF0dXMJAMwIAgMJAGYCBQx0YXJnZXRQZXJpb2QFE2N1cnJlbnRQZXJpb2RPckZhaWwGCQEIdGhyb3dFcnIBAiFpbnZhbGlkIHdpdGhkcmF3YWwgcmVxdWVzdCBwZXJpb2QFA25pbAMJAAACBQZjaGVja3MFBmNoZWNrcwQKd2l0aGRyYXdhbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQENa2V5V2l0aGRyYXdhbAAJAQd3cmFwRXJyAQIfaW52YWxpZCB0b3RhbCB3aXRoZHJhd2FsIGFtb3VudAQOZmFjdG9yeUFjdGlvbnMJAMwIAgkA/AcEBRRmYWN0b3J5QWRkcmVzc09yRmFpbAIMaW50ZWdlckVudHJ5CQDMCAIJAQ1rZXlXaXRoZHJhd2FsAAkAzAgCAwkAZwIFCndpdGhkcmF3YWwFDWxwQXNzZXRBbW91bnQJAGUCBQp3aXRoZHJhd2FsBQ1scEFzc2V0QW1vdW50CQEIdGhyb3dFcnIBAhlpbnZhbGlkIHdpdGhkcmF3YWwgYW1vdW50BQNuaWwFA25pbAkAzAgCCQD8BwQFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAgtkZWxldGVFbnRyeQkAzAgCCQEUa2V5V2l0aGRyYXdhbFJlcXVlc3QCBQt1c2VyQWRkcmVzcwUEdHhJZAUDbmlsBQNuaWwJAMwIAgkA/AcEBRRmYWN0b3J5QWRkcmVzc09yRmFpbAINdHJhbnNmZXJBc3NldAkAzAgCBRB1c2VyQWRkcmVzc0J5dGVzCQDMCAIFDWxwQXNzZXRBbW91bnQJAMwIAgUPbHBBc3NldElkT3JGYWlsBQNuaWwFA25pbAUDbmlsAwkAAAIFDmZhY3RvcnlBY3Rpb25zBQ5mYWN0b3J5QWN0aW9ucwkAlAoCBQNuaWwFDmZhY3RvcnlBY3Rpb25zCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCmNsYWltV2F2ZXMCEHVzZXJBZGRyZXNzQnl0ZXMEdHhJZAQLY2hlY2tDYWxsZXIJAQtvbmx5RmFjdG9yeQEFAWkDCQAAAgULY2hlY2tDYWxsZXIFC2NoZWNrQ2FsbGVyBAt1c2VyQWRkcmVzcwkBB0FkZHJlc3MBBRB1c2VyQWRkcmVzc0J5dGVzBBNjdXJyZW50UGVyaW9kT3JGYWlsCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJARBrZXlDdXJyZW50UGVyaW9kAAkBB3dyYXBFcnIBAg5pbnZhbGlkIHBlcmlvZAQXd2l0aGRyYXdhbFJlcXVlc3RPcHRpb24JARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBRRmYWN0b3J5QWRkcmVzc09yRmFpbAkBFGtleVdpdGhkcmF3YWxSZXF1ZXN0AgULdXNlckFkZHJlc3MFBHR4SWQJAQd3cmFwRXJyAQIaaW52YWxpZCB3aXRoZHJhd2FsIHJlcXVlc3QEDSR0MDE1Mjc4MTUzOTEJASFwYXJzZVdpdGhkcmF3YWxSZXF1ZXN0VmFsdWVPckZhaWwBBRd3aXRoZHJhd2FsUmVxdWVzdE9wdGlvbgQGc3RhdHVzCAUNJHQwMTUyNzgxNTM5MQJfMQQNbHBBc3NldEFtb3VudAgFDSR0MDE1Mjc4MTUzOTECXzIEDHRhcmdldFBlcmlvZAgFDSR0MDE1Mjc4MTUzOTECXzMECWNsYWltVHhJZAgFDSR0MDE1Mjc4MTUzOTECXzQDCQAAAgUGc3RhdHVzBQhGSU5JU0hFRAkBCHRocm93RXJyAQIhaW52YWxpZCB3aXRoZHJhd2FsIHJlcXVlc3Qgc3RhdHVzAwkAZgIFDHRhcmdldFBlcmlvZAUTY3VycmVudFBlcmlvZE9yRmFpbAkBCHRocm93RXJyAQIhaW52YWxpZCB3aXRoZHJhd2FsIHJlcXVlc3QgcGVyaW9kBAtwcmljZU9yRmFpbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQERa2V5UHJpY2VGb3JQZXJpb2QBBQx0YXJnZXRQZXJpb2QJAQd3cmFwRXJyAQINaW52YWxpZCBwcmljZQQGYW1vdW50AwkAZgIFC3ByaWNlT3JGYWlsAAAJAGsDBQ1scEFzc2V0QW1vdW50BQtwcmljZU9yRmFpbAUGU0NBTEU4AAAEDmZhY3RvcnlBY3Rpb25zCQDMCAIJAPwHBAUUZmFjdG9yeUFkZHJlc3NPckZhaWwCC3N0cmluZ0VudHJ5CQDMCAIJARRrZXlXaXRoZHJhd2FsUmVxdWVzdAIFC3VzZXJBZGRyZXNzBQR0eElkCQDMCAIJARZ2YWx1ZVdpdGhkcmF3YWxSZXF1ZXN0BAUIRklOSVNIRUQFDWxwQXNzZXRBbW91bnQFDHRhcmdldFBlcmlvZAgFAWkNdHJhbnNhY3Rpb25JZAUDbmlsBQNuaWwJAMwIAgkA/AcEBRRmYWN0b3J5QWRkcmVzc09yRmFpbAINdHJhbnNmZXJXYXZlcwkAzAgCBRB1c2VyQWRkcmVzc0J5dGVzCQDMCAIFBmFtb3VudAUDbmlsBQNuaWwFA25pbAkAlAoCBQNuaWwFDmZhY3RvcnlBY3Rpb25zCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDXByb2Nlc3NCbG9ja3MBEHVzZXJBZGRyZXNzQnl0ZXMEC2NoZWNrQ2FsbGVyCQELb25seUZhY3RvcnkBBQFpAwkAAAIFC2NoZWNrQ2FsbGVyBQtjaGVja0NhbGxlcgQLdXNlckFkZHJlc3MJAQdBZGRyZXNzAQUQdXNlckFkZHJlc3NCeXRlcwQTY3VycmVudFBlcmlvZE9yRmFpbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQEQa2V5Q3VycmVudFBlcmlvZAAJAQd3cmFwRXJyAQIOaW52YWxpZCBwZXJpb2QEDHBlcmlvZExlbmd0aAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQEPa2V5UGVyaW9kTGVuZ3RoAAkBB3dyYXBFcnIBAhVpbnZhbGlkIHBlcmlvZCBsZW5ndGgEEmN1cnJlbnRTdGFydEhlaWdodAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQEOa2V5U3RhcnRIZWlnaHQBBRNjdXJyZW50UGVyaW9kT3JGYWlsCQEHd3JhcEVycgECFGludmFsaWQgc3RhcnQgaGVpZ2h0BBJjdXJyZW50UHJpY2VPckZhaWwJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBRRmYWN0b3J5QWRkcmVzc09yRmFpbAkBEWtleVByaWNlRm9yUGVyaW9kAQUTY3VycmVudFBlcmlvZE9yRmFpbAkBB3dyYXBFcnIBAg1pbnZhbGlkIHByaWNlBBJuZXh0QmxvY2tUb1Byb2Nlc3MJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBRRmYWN0b3J5QWRkcmVzc09yRmFpbAkBFWtleU5leHRCbG9ja1RvUHJvY2VzcwAJAQd3cmFwRXJyAQIdaW52YWxpZCBuZXh0IGJsb2NrIHRvIHByb2Nlc3MED3BlcmlvZEVuZEhlaWdodAkAZQIJAGQCBRJjdXJyZW50U3RhcnRIZWlnaHQFDHBlcmlvZExlbmd0aAABBBxibG9ja3NQcm9jZXNzaW5nQmF0Y2hTaXplTWF4ACgEGWJsb2Nrc1Byb2Nlc3NpbmdCYXRjaFNpemUDAwMJAGcCBQZoZWlnaHQFEm5leHRCbG9ja1RvUHJvY2VzcwMJAGcCBRJuZXh0QmxvY2tUb1Byb2Nlc3MFEmN1cnJlbnRTdGFydEhlaWdodAYJAAACBRNjdXJyZW50UGVyaW9kT3JGYWlsAAAHCQBnAgUPcGVyaW9kRW5kSGVpZ2h0BRJuZXh0QmxvY2tUb1Byb2Nlc3MHCQCXAwEJAMwIAgkAZAIJAGUCBQ9wZXJpb2RFbmRIZWlnaHQFEm5leHRCbG9ja1RvUHJvY2VzcwABCQDMCAIFHGJsb2Nrc1Byb2Nlc3NpbmdCYXRjaFNpemVNYXgFA25pbAkBCHRocm93RXJyAQkBB3dyYXBFcnIBAhRpbnZhbGlkIHRhcmdldCBibG9jawQVYmxvY2tQcm9jZXNzaW5nUmV3YXJkCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJARhrZXlCbG9ja1Byb2Nlc3NpbmdSZXdhcmQACQEHd3JhcEVycgECH2ludmFsaWQgYmxvY2sgcHJvY2Vzc2luZyByZXdhcmQEIGJsb2NrUHJvY2Vzc2luZ1Jld2FyZEJ5R2VuZXJhdG9yCQBpAgUVYmxvY2tQcm9jZXNzaW5nUmV3YXJkBRlibG9ja3NQcm9jZXNzaW5nQmF0Y2hTaXplBClibG9ja1Byb2Nlc3NpbmdSZXdhcmRCeUdlbmVyYXRvclJlbWFpbmRlcgkAZQIFFWJsb2NrUHJvY2Vzc2luZ1Jld2FyZAkAaAIFIGJsb2NrUHJvY2Vzc2luZ1Jld2FyZEJ5R2VuZXJhdG9yBRlibG9ja3NQcm9jZXNzaW5nQmF0Y2hTaXplCgEDbWFwAgNhY2MDaW5jAwkAZwIFA2luYwUZYmxvY2tzUHJvY2Vzc2luZ0JhdGNoU2l6ZQUDYWNjBBF0YXJnZXRCbG9ja0hlaWdodAkAZAIFEm5leHRCbG9ja1RvUHJvY2VzcwUDaW5jBA90YXJnZXRCbG9ja0luZm8JARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkA7QcBBRF0YXJnZXRCbG9ja0hlaWdodAkBB3dyYXBFcnIBAhJpbnZhbGlkIGJsb2NrIGluZm8EFHRyZWFzdXJ5UmV3YXJkT3JGYWlsCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAQ9yZXdhcmRGb3JPcHRpb24CCAUPdGFyZ2V0QmxvY2tJbmZvB3Jld2FyZHMFGnByb3h5VHJlYXN1cnlBZGRyZXNzT3JGYWlsCQEHd3JhcEVycgEJAKwCAgIjaW52YWxpZCB0cmVhc3VyeSByZXdhcmQgZm9yIGhlaWdodCAJAKQDAQURdGFyZ2V0QmxvY2tIZWlnaHQECWdlbmVyYXRvcggFD3RhcmdldEJsb2NrSW5mbwlnZW5lcmF0b3IECWF2YWlsYWJsZQkBC3ZhbHVlT3JFbHNlAgkAmggCBRRmYWN0b3J5QWRkcmVzc09yRmFpbAkBDGtleUF2YWlsYWJsZQEFCWdlbmVyYXRvcgAABAxjYWxsZXJSZXdhcmQDCQAAAgUDaW5jCQBlAgUZYmxvY2tzUHJvY2Vzc2luZ0JhdGNoU2l6ZQABCQBkAgUgYmxvY2tQcm9jZXNzaW5nUmV3YXJkQnlHZW5lcmF0b3IFKWJsb2NrUHJvY2Vzc2luZ1Jld2FyZEJ5R2VuZXJhdG9yUmVtYWluZGVyBSBibG9ja1Byb2Nlc3NpbmdSZXdhcmRCeUdlbmVyYXRvcgQNbHBBc3NldEFtb3VudAMJAGYCBRJjdXJyZW50UHJpY2VPckZhaWwAAAkAawMJAGUCBRR0cmVhc3VyeVJld2FyZE9yRmFpbAUMY2FsbGVyUmV3YXJkBQZTQ0FMRTgFEmN1cnJlbnRQcmljZU9yRmFpbAAABBRmYWN0b3J5QWN0aW9uc1NpbmdsZQkAzAgCCQD8BwQFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAgtzdHJpbmdFbnRyeQkAzAgCCQERa2V5QmxvY2tQcm9jZXNzZWQBBRF0YXJnZXRCbG9ja0hlaWdodAkAzAgCCQC5CQIJAMwIAgkA2AQBCAUBaQ10cmFuc2FjdGlvbklkCQDMCAIJAKQDAQUTY3VycmVudFBlcmlvZE9yRmFpbAkAzAgCCQClCAEFCWdlbmVyYXRvcgkAzAgCCQDYBAEFEHVzZXJBZGRyZXNzQnl0ZXMJAMwIAgkApAMBBRR0cmVhc3VyeVJld2FyZE9yRmFpbAkAzAgCCQCkAwEFDGNhbGxlclJld2FyZAkAzAgCCQCkAwEFDWxwQXNzZXRBbW91bnQFA25pbAUDU0VQBQNuaWwFA25pbAkAzAgCCQD8BwQFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAgxpbnRlZ2VyRW50cnkJAMwIAgkBDGtleUF2YWlsYWJsZQEFCWdlbmVyYXRvcgkAzAgCCQBkAgUJYXZhaWxhYmxlBQ1scEFzc2V0QW1vdW50BQNuaWwFA25pbAUDbmlsAwkAAAIFFGZhY3RvcnlBY3Rpb25zU2luZ2xlBRRmYWN0b3J5QWN0aW9uc1NpbmdsZQQNJHQwMTk2MjcxOTY2MAUDYWNjBApscEFzc2V0QWNjCAUNJHQwMTk2MjcxOTY2MAJfMQQJcmV3YXJkQWNjCAUNJHQwMTk2MjcxOTY2MAJfMgkAlAoCCQBkAgUKbHBBc3NldEFjYwUNbHBBc3NldEFtb3VudAkAZAIFCXJld2FyZEFjYwUUdHJlYXN1cnlSZXdhcmRPckZhaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4EBGxpc3QJAMwIAgAACQDMCAIAAQkAzAgCAAIJAMwIAgADCQDMCAIABAkAzAgCAAUJAMwIAgAGCQDMCAIABwkAzAgCAAgJAMwIAgAJCQDMCAIACgkAzAgCAAsJAMwIAgAMCQDMCAIADQkAzAgCAA4JAMwIAgAPCQDMCAIAEAkAzAgCABEJAMwIAgASCQDMCAIAEwkAzAgCABQJAMwIAgAVCQDMCAIAFgkAzAgCABcJAMwIAgAYCQDMCAIAGQkAzAgCABoJAMwIAgAbCQDMCAIAHAkAzAgCAB0JAMwIAgAeCQDMCAIAHwkAzAgCACAJAMwIAgAhCQDMCAIAIgkAzAgCACMJAMwIAgAkCQDMCAIAJQkAzAgCACYJAMwIAgAnBQNuaWwEDSR0MDE5OTI3MjAwMDMKAAIkbAUEbGlzdAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAJAJQKAgAAAAAKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBA21hcAIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgNDAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgALAAwADQAOAA8AEAARABIAEwAUABUAFgAXABgAGQAaABsAHAAdAB4AHwAgACEAIgAjACQAJQAmACcAKAMJAAACBQ0kdDAxOTkyNzIwMDAzBQ0kdDAxOTkyNzIwMDAzBBFyZXdhcmRBbW91bnRUb3RhbAgFDSR0MDE5OTI3MjAwMDMCXzIEEmxwQXNzZXRBbW91bnRUb3RhbAgFDSR0MDE5OTI3MjAwMDMCXzEEGnJld2FyZFRvTWFpblRyZWFzdXJ5QW1vdW50CQBlAgURcmV3YXJkQW1vdW50VG90YWwFFWJsb2NrUHJvY2Vzc2luZ1Jld2FyZAQIaW52ZXN0ZWQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJAQtrZXlJbnZlc3RlZAEFBHVuaXQAAAQHYWN0aW9ucwkAzAgCCQD8BwQFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAgdyZWlzc3VlCQDMCAIFEmxwQXNzZXRBbW91bnRUb3RhbAUDbmlsBQNuaWwJAMwIAgkA/AcEBRRmYWN0b3J5QWRkcmVzc09yRmFpbAIMaW50ZWdlckVudHJ5CQDMCAIJARVrZXlOZXh0QmxvY2tUb1Byb2Nlc3MACQDMCAIJAGQCBRJuZXh0QmxvY2tUb1Byb2Nlc3MFGWJsb2Nrc1Byb2Nlc3NpbmdCYXRjaFNpemUFA25pbAUDbmlsCQDMCAIJAPwHBAUUZmFjdG9yeUFkZHJlc3NPckZhaWwCGXRyYW5zZmVyRnJvbVByb3h5VHJlYXN1cnkJAMwIAggFHGZlYXR1cmVUcmVhc3VyeUFkZHJlc3NPckZhaWwFYnl0ZXMJAMwIAgUacmV3YXJkVG9NYWluVHJlYXN1cnlBbW91bnQFA25pbAUDbmlsCQDMCAIJAPwHBAUUZmFjdG9yeUFkZHJlc3NPckZhaWwCGXRyYW5zZmVyRnJvbVByb3h5VHJlYXN1cnkJAMwIAgUQdXNlckFkZHJlc3NCeXRlcwkAzAgCBRVibG9ja1Byb2Nlc3NpbmdSZXdhcmQFA25pbAUDbmlsCQDMCAIJAPwHBAUUZmFjdG9yeUFkZHJlc3NPckZhaWwCDGludGVnZXJFbnRyeQkAzAgCCQELa2V5SW52ZXN0ZWQBBQR1bml0CQDMCAIJAGQCBQhpbnZlc3RlZAUacmV3YXJkVG9NYWluVHJlYXN1cnlBbW91bnQFA25pbAUDbmlsBQNuaWwDCQAAAgUHYWN0aW9ucwUHYWN0aW9ucwkAlAoCBQNuaWwFBHVuaXQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BAnR4AQZ2ZXJpZnkABAlwdWJsaWNLZXkEByRtYXRjaDAJARlnZXRNYW5hZ2VyUHVibGljS2V5T3JVbml0AAMJAAECBQckbWF0Y2gwAgpCeXRlVmVjdG9yBANwdWIFByRtYXRjaDAFA3B1YggFAnR4D3NlbmRlclB1YmxpY0tleQkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAAUJcHVibGljS2V5kJMcgA==", "chainId": 84, "height": 2651218, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: Cmb9wtBxqskk83PNWb3xp5h6fzUqYRBeBNCWQqs3LfMu Next: 5DuSwdMY1kQs56ZuCHXcsognf8kVwEM9GgLj1uWvg7TR Diff:
OldNewDifferences
33 {-# CONTENT_TYPE DAPP #-}
44 let SEP = "__"
55
6-let contractFilename = "factory.ride"
6+let CONTRACT_NAME = "calculator.ride"
77
8-func wrapErr (s) = ((contractFilename + ": ") + s)
8+let SCALE8 = 100000000
9+
10+let PENDING = "PENDING"
11+
12+let FINISHED = "FINISHED"
13+
14+let WAVES = "WAVES"
15+
16+func wrapErr (s) = ((CONTRACT_NAME + ": ") + s)
917
1018
1119 func throwErr (s) = throw(wrapErr(s))
1220
1321
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)
21-
22-
23-func keyFullAdminVote (prefix,adminAddress) = makeString([prefix, adminAddress], SEP)
24-
25-
26-func keyAdminAddressList () = makeString(["%s", "adminAddressList"], SEP)
27-
28-
29-func keyAllowedTxId () = makeString(["%s", "txId"], SEP)
30-
31-
32-func getAdminVote (prefix,admin) = {
33- let voteKey = keyFullAdminVote(prefix, admin)
34- valueOrElse(getInteger(voteKey), 0)
35- }
36-
37-
38-func getAdminsList () = match getString(this, keyAdminAddressList()) {
39- case s: String =>
40- split(s, SEP)
22+func assetIdToString (assetId) = match assetId {
23+ case b: ByteVector =>
24+ toBase58String(b)
25+ case _: Unit =>
26+ WAVES
4127 case _ =>
42- nil
28+ throw("Match error")
4329 }
4430
4531
46-func isInAdminList (address) = containsElement(getAdminsList(), address)
32+func abs (n) = if ((0 > n))
33+ then -(n)
34+ else n
4735
4836
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)
54- }
37+func keyFactoryAddress () = makeString(["%s", "factory"], SEP)
5538
5639
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
76- }
40+func keyManagerPublicKey () = makeString(["%s", "managerPublicKey"], SEP)
7741
7842
79-func countVotesHelper (result,voteKey) = (result + valueOrElse(getInteger(voteKey), 0))
43+func keyLpAssetId () = makeString(["%s", "lpAssetId"], SEP)
8044
8145
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)
96- }
46+func keyProxyTreasuryAddress () = makeString(["%s", "proxyTreasury"], SEP)
9747
9848
99-func clearVotesHelper (result,key) = (result :+ DeleteEntry(key))
49+func keyMainTreasuryAddress () = makeString(["%s", "mainTreasury"], SEP)
10050
10151
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)
116- }
52+func keyInvested (assetId) = makeString(["%s%s", "invested", assetIdToString(assetId)], SEP)
11753
11854
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))
128- then {
129- let votes = countVotes(keyPrefix)
130- if (((votes + 1) >= minVotes))
131- then {
132- let clearVoteEntries = getClearVoteEntries(keyPrefix)
133- (clearVoteEntries ++ voteResult)
134- }
135- else [IntegerEntry(voteKey, 1)]
136- }
137- else throw("Strict value is not equal to itself.")
138- }
55+func keyDonated (assetId) = makeString(["%s%s", "donated", assetIdToString(assetId)], SEP)
13956
14057
141-func keyCalculatorAddress () = "%s__calculator"
58+func keyAvailable (userAddress) = makeString(["%s%s", "available", toString(userAddress)], SEP)
14259
14360
144-func keyProxyTreasuryAddress () = "%s__proxyTreasury"
61+func keyClaimed (userAddress) = makeString(["%s%s", "claimed", toString(userAddress)], SEP)
14562
14663
147-func keyChildAddress () = "%s__child"
64+func keyCurrentPeriod () = makeString(["%s", "currentPeriod"], SEP)
65+
66+
67+func keyPriceForPeriod (period) = makeString(["%s%d", "price", toString(period)], SEP)
68+
69+
70+func keyStartHeight (period) = makeString(["%s%d", "startHeight", toString(period)], SEP)
71+
72+
73+func keyPeriodLength () = "%s__periodLength"
14874
14975
15076 func keyBlockProcessingReward () = "%s__blockProcessingReward"
15379 func keyNextBlockToProcess () = "%s__nextBlockToProcess"
15480
15581
156-func keyLpAssetId () = "%s__lpAssetId"
82+func keyBlockProcessed (height) = makeString(["%s%d", "blockProcessed", toString(height)], SEP)
15783
15884
159-let calculatorAddressOption = match getString(this, keyCalculatorAddress()) {
85+func keyWithdrawal () = "%s__withdrawal"
86+
87+
88+func keyWithdrawalRequest (userAddress,txId) = makeString(["%s%s%s", "withdrawal", toString(userAddress), toBase58String(txId)], SEP)
89+
90+
91+func valueWithdrawalRequest (status,lpAssetAmount,targetPeriod,claimTxId) = {
92+ let claimTxIdStr = match claimTxId {
93+ case b: ByteVector =>
94+ toBase58String(b)
95+ case _: Unit =>
96+ "SOON"
97+ case _ =>
98+ throw("Match error")
99+ }
100+ makeString(["%s%d%d%s", status, toString(lpAssetAmount), toString(targetPeriod), claimTxIdStr], SEP)
101+ }
102+
103+
104+func parseWithdrawalRequestValueOrFail (s) = {
105+ let parts = split(s, SEP)
106+ if ((size(parts) == 5))
107+ then {
108+ let status = parts[1]
109+ let lpAssetAmount = valueOrErrorMessage(parseInt(parts[2]), wrapErr("invalid lpAssetAmount"))
110+ let targetPeriod = valueOrErrorMessage(parseInt(parts[3]), wrapErr("invalid targetPeriod"))
111+ let claimTxId = parts[4]
112+ $Tuple4(status, lpAssetAmount, targetPeriod, claimTxId)
113+ }
114+ else throwErr("invalid withdrawal request value")
115+ }
116+
117+
118+let factoryAddressOption = match getString(this, keyFactoryAddress()) {
160119 case s: String =>
161120 addressFromString(s)
162121 case _: Unit =>
165124 throw("Match error")
166125 }
167126
168-let calculatorAddressOrFail = valueOrErrorMessage(calculatorAddressOption, wrapErr("invalid calculator address"))
127+let factoryAddressOrFail = valueOrErrorMessage(factoryAddressOption, wrapErr("invalid factory address"))
169128
170-let proxyTreasuryAddressOption = match getString(this, keyProxyTreasuryAddress()) {
171- case s: String =>
172- addressFromString(s)
129+let lpAssetIdOption = match factoryAddressOption {
130+ case a: Address =>
131+ match getString(a, keyLpAssetId()) {
132+ case s: String =>
133+ fromBase58String(s)
134+ case _: Unit =>
135+ unit
136+ case _ =>
137+ throw("Match error")
138+ }
173139 case _: Unit =>
174140 unit
175141 case _ =>
176142 throw("Match error")
177143 }
178144
179-let proxyTreasuryAddressOrFail = valueOrErrorMessage(proxyTreasuryAddressOption, wrapErr("invalid proxy treasury address"))
145+let lpAssetIdOrFail = valueOrErrorMessage(lpAssetIdOption, wrapErr("invalid lpAssetId"))
180146
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 {
147+let proxyTreasuryAddressOption = match factoryAddressOption {
208148 case a: Address =>
209- match getString(a, keyVotingResultAddress()) {
149+ match getString(a, keyProxyTreasuryAddress()) {
210150 case s: String =>
211151 addressFromString(s)
212152 case _: Unit =>
220160 throw("Match error")
221161 }
222162
223-let votingResultAddressOrFail = valueOrErrorMessage(votingResultAddressOption, wrapErr("invalid voting result address"))
163+let proxyTreasuryAddressOrFail = valueOrErrorMessage(proxyTreasuryAddressOption, wrapErr("invalid proxy treasury address"))
224164
225-let childrenAddressOption = match configAddressOption {
165+let featureTreasuryAddressOption = match factoryAddressOption {
226166 case a: Address =>
227- match getString(a, keyChildrenAddress()) {
167+ match getString(a, keyMainTreasuryAddress()) {
228168 case s: String =>
229169 addressFromString(s)
230170 case _: Unit =>
238178 throw("Match error")
239179 }
240180
241-let childrenAddressOrFail = valueOrErrorMessage(childrenAddressOption, wrapErr("invalid children address"))
181+let featureTreasuryAddressOrFail = valueOrErrorMessage(featureTreasuryAddressOption, wrapErr("invalid feature treasury address"))
242182
243-let lpAssetIdOption = match getString(this, keyLpAssetId()) {
244- case s: String =>
245- fromBase58String(s)
246- case _: Unit =>
183+func getManagerPublicKeyOrUnit () = match factoryAddressOption {
184+ case fa: Address =>
185+ match getString(fa, keyManagerPublicKey()) {
186+ case pub: String =>
187+ fromBase58String(pub)
188+ case _ =>
189+ unit
190+ }
191+ case _ =>
247192 unit
248- case _ =>
249- throw("Match error")
250193 }
251194
252-let lpAssetIdOrFail = valueOrErrorMessage(lpAssetIdOption, wrapErr("invalid lpAssetId"))
253195
254196 func onlyAddress (i,address) = if ((i.caller == address))
255197 then true
256198 else throwErr("permission denied")
257199
258200
259-func onlyThis (i) = onlyAddress(i, this)
201+func onlyFactory (i) = onlyAddress(i, factoryAddressOrFail)
260202
261203
262-func onlyCalculator (i) = onlyAddress(i, calculatorAddressOrFail)
204+func rewardForOption (rewards,target) = {
205+ let s = size(rewards)
206+ let $t046414666 = rewards[0]
207+ let a0 = $t046414666._1
208+ let r0 = $t046414666._2
209+ let $t046694694 = rewards[1]
210+ let a1 = $t046694694._1
211+ let r1 = $t046694694._2
212+ let $t046974722 = rewards[2]
213+ let a2 = $t046974722._1
214+ let r2 = $t046974722._2
215+ if (if ((s > 0))
216+ then (a0 == target)
217+ else false)
218+ then r0
219+ else if (if ((s > 1))
220+ then (a1 == target)
221+ else false)
222+ then r1
223+ else if (if ((s > 2))
224+ then (a2 == target)
225+ else false)
226+ then r2
227+ else unit
228+ }
263229
264230
265231 @Callable(i)
266-func stringEntry (key,val) = if (onlyCalculator(i))
267- then $Tuple2([StringEntry(key, val)], key)
268- else $Tuple2(nil, unit)
232+func claimLP (userAddressBytes) = {
233+ let checkCaller = onlyFactory(i)
234+ if ((checkCaller == checkCaller))
235+ then {
236+ let userAddress = Address(userAddressBytes)
237+ let available = valueOrElse(getInteger(factoryAddressOrFail, keyAvailable(userAddress)), 0)
238+ let claimed = valueOrElse(getInteger(factoryAddressOrFail, keyClaimed(userAddress)), 0)
239+ let factoryActions = if ((available > 0))
240+ then [invoke(factoryAddressOrFail, "transferAsset", [userAddressBytes, available, lpAssetIdOrFail], nil), invoke(factoryAddressOrFail, "integerEntry", [keyAvailable(userAddress), 0], nil), invoke(factoryAddressOrFail, "integerEntry", [keyClaimed(userAddress), (claimed + available)], nil)]
241+ else throwErr("nothing to claim")
242+ $Tuple2(nil, factoryActions)
243+ }
244+ else throw("Strict value is not equal to itself.")
245+ }
269246
270247
271248
272249 @Callable(i)
273-func integerEntry (key,val) = if (onlyCalculator(i))
274- then $Tuple2([IntegerEntry(key, val)], key)
275- else $Tuple2(nil, unit)
250+func finalize (userAddressBytes,newTreasuryVolumeInWaves,pwrManagersBonusInWaves,treasuryVolumeDiffAllocationCoef) = {
251+ let checkCaller = onlyFactory(i)
252+ if ((checkCaller == checkCaller))
253+ then {
254+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
255+ let periodLength = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPeriodLength()), wrapErr("invalid period length"))
256+ let currentStartHeight = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyStartHeight(currentPeriodOrFail)), wrapErr("invalid start height"))
257+ let currentPriceOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPriceForPeriod(currentPeriodOrFail)), wrapErr("invalid price"))
258+ let nextBlockToProcess = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyNextBlockToProcess()), wrapErr("invalid next block to process"))
259+ let periodEndHeight = ((currentStartHeight + periodLength) - 1)
260+ let checks = [if ((i.originCaller == featureTreasuryAddressOrFail))
261+ then true
262+ else throwErr("permission denied"), if ((nextBlockToProcess > periodEndHeight))
263+ then true
264+ else throwErr("unprocessed blocks"), if ((newTreasuryVolumeInWaves >= 0))
265+ then true
266+ else throwErr("invalid new treasury volume"), if ((pwrManagersBonusInWaves >= 0))
267+ then true
268+ else throwErr("invalid PWR managers bonus"), if (if ((treasuryVolumeDiffAllocationCoef >= -(SCALE8)))
269+ then (SCALE8 >= treasuryVolumeDiffAllocationCoef)
270+ else false)
271+ then true
272+ else throwErr("invalid treasury volume diff allocation coefficient")]
273+ if ((checks == checks))
274+ then {
275+ let donatedWavesAmount = valueOrElse(getInteger(factoryAddressOrFail, keyDonated(unit)), 0)
276+ let investedWavesAmount = valueOrElse(getInteger(factoryAddressOrFail, keyInvested(unit)), 0)
277+ let currentTreasuryVolumeInWaves = (donatedWavesAmount + investedWavesAmount)
278+ let profitRaw = (newTreasuryVolumeInWaves - currentTreasuryVolumeInWaves)
279+ let pwrManagersBonusAmount = if (if ((profitRaw > 0))
280+ then (profitRaw >= pwrManagersBonusInWaves)
281+ else false)
282+ then pwrManagersBonusInWaves
283+ else 0
284+ let profit = (profitRaw - pwrManagersBonusAmount)
285+ let donationPart = if ((currentTreasuryVolumeInWaves > 0))
286+ then fraction(donatedWavesAmount, SCALE8, currentTreasuryVolumeInWaves)
287+ else 0
288+ let donationProfitPartRaw = fraction(profit, donationPart, SCALE8)
289+ let investmentProfitPartRaw = (profit - donationProfitPartRaw)
290+ let treasuryVolumeDiffAllocationCoefAbs = abs(treasuryVolumeDiffAllocationCoef)
291+ let amountToDonation = fraction(investmentProfitPartRaw, if ((0 > treasuryVolumeDiffAllocationCoef))
292+ then treasuryVolumeDiffAllocationCoefAbs
293+ else 0, SCALE8)
294+ let amountToInvestment = fraction(donationProfitPartRaw, if ((treasuryVolumeDiffAllocationCoef > 0))
295+ then treasuryVolumeDiffAllocationCoefAbs
296+ else 0, SCALE8)
297+ let donationProfitPart = ((donationProfitPartRaw - amountToInvestment) + amountToDonation)
298+ let investmentProfitPart = ((investmentProfitPartRaw - amountToDonation) + amountToInvestment)
299+ let investedWavesAmountNew = (investedWavesAmount + investmentProfitPart)
300+ let newPeriod = (currentPeriodOrFail + 1)
301+ let lpAssetQuantity = valueOrErrorMessage(assetInfo(lpAssetIdOrFail), wrapErr("invalid lpAsset info")).quantity
302+ let newPrice = fraction(investedWavesAmountNew, SCALE8, lpAssetQuantity)
303+ let lpAssetAmountToBurn = valueOrElse(getInteger(factoryAddressOrFail, keyWithdrawal()), 0)
304+ let newLpAmount = (lpAssetQuantity - lpAssetAmountToBurn)
305+ let newInvestAmount = max([0, fraction(newLpAmount, newPrice, SCALE8)])
306+ let paymentAmountMin = max([0, fraction(lpAssetAmountToBurn, newPrice, SCALE8)])
307+ let paymentOption = if ((size(i.payments) > 0))
308+ then i.payments[0]
309+ else unit
310+ let paymentAmount = value(paymentOption).amount
311+ let paymentAssetId = value(paymentOption).assetId
312+ let checkPayment = if (if ((paymentAmountMin == 0))
313+ then true
314+ else if (if ((paymentOption != unit))
315+ then (paymentAssetId == unit)
316+ else false)
317+ then (paymentAmount >= paymentAmountMin)
318+ else false)
319+ then true
320+ else throwErr(("invalid payments, payment amount min: " + toString(paymentAmountMin)))
321+ if ((checkPayment == checkPayment))
322+ then {
323+ let actions = if ((paymentOption != unit))
324+ then [ScriptTransfer(factoryAddressOrFail, paymentAmount, paymentAssetId)]
325+ else nil
326+ let factoryActions = [invoke(factoryAddressOrFail, "integerEntry", [keyCurrentPeriod(), newPeriod], nil), invoke(factoryAddressOrFail, "integerEntry", [keyPriceForPeriod(newPeriod), newPrice], nil), invoke(factoryAddressOrFail, "integerEntry", [keyStartHeight(newPeriod), (periodEndHeight + 1)], nil), invoke(factoryAddressOrFail, "burn", [lpAssetAmountToBurn], nil), invoke(factoryAddressOrFail, "integerEntry", [keyWithdrawal(), 0], nil), invoke(factoryAddressOrFail, "integerEntry", [keyInvested(unit), newInvestAmount], nil)]
327+ $Tuple2(actions, factoryActions)
328+ }
329+ else throw("Strict value is not equal to itself.")
330+ }
331+ else throw("Strict value is not equal to itself.")
332+ }
333+ else throw("Strict value is not equal to itself.")
334+ }
276335
277336
278337
279338 @Callable(i)
280-func booleanEntry (key,val) = if (onlyCalculator(i))
281- then $Tuple2([BooleanEntry(key, val)], key)
282- else $Tuple2(nil, unit)
339+func invest (userAddressBytes) = {
340+ let checkCaller = onlyFactory(i)
341+ if ((checkCaller == checkCaller))
342+ then {
343+ let userAddress = Address(userAddressBytes)
344+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
345+ let currentPriceOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPriceForPeriod(currentPeriodOrFail)), wrapErr("invalid price"))
346+ let payment = if ((size(i.payments) == 1))
347+ then i.payments[0]
348+ else throwErr("invalid payments")
349+ let $t01124611423 = if (if ((payment.assetId == unit))
350+ then (payment.amount > 0)
351+ else false)
352+ then $Tuple2(payment.amount, payment.assetId)
353+ else throwErr("invalid payment amount")
354+ let paymentAmount = $t01124611423._1
355+ let paymentAssetId = $t01124611423._2
356+ let lpAssetAmount = if ((currentPriceOrFail > 0))
357+ then fraction(paymentAmount, SCALE8, currentPriceOrFail)
358+ else 0
359+ let invested = valueOrElse(getInteger(factoryAddressOrFail, keyInvested(unit)), 0)
360+ let actions = [ScriptTransfer(featureTreasuryAddressOrFail, paymentAmount, paymentAssetId)]
361+ let factoryActions = [invoke(factoryAddressOrFail, "integerEntry", [keyInvested(unit), (invested + paymentAmount)], nil), invoke(factoryAddressOrFail, "reissue", [lpAssetAmount], nil), invoke(factoryAddressOrFail, "transferAsset", [userAddressBytes, lpAssetAmount, lpAssetIdOrFail], nil)]
362+ $Tuple2(actions, factoryActions)
363+ }
364+ else throw("Strict value is not equal to itself.")
365+ }
283366
284367
285368
286369 @Callable(i)
287-func binaryEntry (key,val) = if (onlyCalculator(i))
288- then $Tuple2([BinaryEntry(key, val)], key)
289- else $Tuple2(nil, unit)
370+func withdraw (userAddressBytes) = {
371+ let checkCaller = onlyFactory(i)
372+ if ((checkCaller == checkCaller))
373+ then {
374+ let userAddress = Address(userAddressBytes)
375+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
376+ let payment = if ((size(i.payments) == 1))
377+ then i.payments[0]
378+ else throwErr(wrapErr("invalid payments"))
379+ let paymentAssetId = if ((payment.assetId == lpAssetIdOrFail))
380+ then lpAssetIdOrFail
381+ else throwErr("invalid payment asset")
382+ let paymentAmount = if ((payment.amount > 0))
383+ then payment.amount
384+ else throwErr("invalid payment amount")
385+ let withdrawal = valueOrElse(getInteger(factoryAddressOrFail, keyWithdrawal()), 0)
386+ let actions = [ScriptTransfer(factoryAddressOrFail, paymentAmount, paymentAssetId)]
387+ let factoryActions = [invoke(factoryAddressOrFail, "integerEntry", [keyWithdrawal(), (withdrawal + paymentAmount)], nil), invoke(factoryAddressOrFail, "stringEntry", [keyWithdrawalRequest(userAddress, i.transactionId), valueWithdrawalRequest(PENDING, paymentAmount, (currentPeriodOrFail + 1), unit)], nil)]
388+ if ((factoryActions == factoryActions))
389+ then $Tuple2(actions, factoryActions)
390+ else throw("Strict value is not equal to itself.")
391+ }
392+ else throw("Strict value is not equal to itself.")
393+ }
290394
291395
292396
293397 @Callable(i)
294-func deleteEntry (key) = if (onlyCalculator(i))
295- then $Tuple2([DeleteEntry(key)], key)
296- else $Tuple2(nil, unit)
398+func cancelWithdraw (userAddressBytes,txId) = {
399+ let checkCaller = onlyFactory(i)
400+ if ((checkCaller == checkCaller))
401+ then {
402+ let userAddress = Address(userAddressBytes)
403+ let withdrawalRequestOption = valueOrErrorMessage(getString(factoryAddressOrFail, keyWithdrawalRequest(userAddress, txId)), wrapErr("invalid withdrawal request"))
404+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
405+ let $t01383313946 = parseWithdrawalRequestValueOrFail(withdrawalRequestOption)
406+ let status = $t01383313946._1
407+ let lpAssetAmount = $t01383313946._2
408+ let targetPeriod = $t01383313946._3
409+ let claimTxId = $t01383313946._4
410+ let checks = [if ((status == PENDING))
411+ then true
412+ else throwErr("invalid withdrawal request status"), if ((targetPeriod > currentPeriodOrFail))
413+ then true
414+ else throwErr("invalid withdrawal request period")]
415+ if ((checks == checks))
416+ then {
417+ let withdrawal = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyWithdrawal()), wrapErr("invalid total withdrawal amount"))
418+ let factoryActions = [invoke(factoryAddressOrFail, "integerEntry", [keyWithdrawal(), if ((withdrawal >= lpAssetAmount))
419+ then (withdrawal - lpAssetAmount)
420+ else throwErr("invalid withdrawal amount")], nil), invoke(factoryAddressOrFail, "deleteEntry", [keyWithdrawalRequest(userAddress, txId)], nil), invoke(factoryAddressOrFail, "transferAsset", [userAddressBytes, lpAssetAmount, lpAssetIdOrFail], nil)]
421+ if ((factoryActions == factoryActions))
422+ then $Tuple2(nil, factoryActions)
423+ else throw("Strict value is not equal to itself.")
424+ }
425+ else throw("Strict value is not equal to itself.")
426+ }
427+ else throw("Strict value is not equal to itself.")
428+ }
297429
298430
299431
300432 @Callable(i)
301-func reissue (amount) = if (onlyCalculator(i))
302- then $Tuple2([Reissue(lpAssetIdOrFail, amount, true)], amount)
303- else $Tuple2(nil, unit)
433+func claimWaves (userAddressBytes,txId) = {
434+ let checkCaller = onlyFactory(i)
435+ if ((checkCaller == checkCaller))
436+ then {
437+ let userAddress = Address(userAddressBytes)
438+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
439+ let withdrawalRequestOption = valueOrErrorMessage(getString(factoryAddressOrFail, keyWithdrawalRequest(userAddress, txId)), wrapErr("invalid withdrawal request"))
440+ let $t01527815391 = parseWithdrawalRequestValueOrFail(withdrawalRequestOption)
441+ let status = $t01527815391._1
442+ let lpAssetAmount = $t01527815391._2
443+ let targetPeriod = $t01527815391._3
444+ let claimTxId = $t01527815391._4
445+ if ((status == FINISHED))
446+ then throwErr("invalid withdrawal request status")
447+ else if ((targetPeriod > currentPeriodOrFail))
448+ then throwErr("invalid withdrawal request period")
449+ else {
450+ let priceOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPriceForPeriod(targetPeriod)), wrapErr("invalid price"))
451+ let amount = if ((priceOrFail > 0))
452+ then fraction(lpAssetAmount, priceOrFail, SCALE8)
453+ else 0
454+ let factoryActions = [invoke(factoryAddressOrFail, "stringEntry", [keyWithdrawalRequest(userAddress, txId), valueWithdrawalRequest(FINISHED, lpAssetAmount, targetPeriod, i.transactionId)], nil), invoke(factoryAddressOrFail, "transferWaves", [userAddressBytes, amount], nil)]
455+ $Tuple2(nil, factoryActions)
456+ }
457+ }
458+ else throw("Strict value is not equal to itself.")
459+ }
304460
305461
306462
307463 @Callable(i)
308-func burn (amount) = if (onlyCalculator(i))
309- then $Tuple2([Burn(lpAssetIdOrFail, amount)], amount)
310- else $Tuple2(nil, unit)
464+func processBlocks (userAddressBytes) = {
465+ let checkCaller = onlyFactory(i)
466+ if ((checkCaller == checkCaller))
467+ then {
468+ let userAddress = Address(userAddressBytes)
469+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
470+ let periodLength = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPeriodLength()), wrapErr("invalid period length"))
471+ let currentStartHeight = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyStartHeight(currentPeriodOrFail)), wrapErr("invalid start height"))
472+ let currentPriceOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPriceForPeriod(currentPeriodOrFail)), wrapErr("invalid price"))
473+ let nextBlockToProcess = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyNextBlockToProcess()), wrapErr("invalid next block to process"))
474+ let periodEndHeight = ((currentStartHeight + periodLength) - 1)
475+ let blocksProcessingBatchSizeMax = 40
476+ let blocksProcessingBatchSize = if (if (if ((height >= nextBlockToProcess))
477+ then if ((nextBlockToProcess >= currentStartHeight))
478+ then true
479+ else (currentPeriodOrFail == 0)
480+ else false)
481+ then (periodEndHeight >= nextBlockToProcess)
482+ else false)
483+ then min([((periodEndHeight - nextBlockToProcess) + 1), blocksProcessingBatchSizeMax])
484+ else throwErr(wrapErr("invalid target block"))
485+ let blockProcessingReward = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyBlockProcessingReward()), wrapErr("invalid block processing reward"))
486+ let blockProcessingRewardByGenerator = (blockProcessingReward / blocksProcessingBatchSize)
487+ let blockProcessingRewardByGeneratorRemainder = (blockProcessingReward - (blockProcessingRewardByGenerator * blocksProcessingBatchSize))
488+ func map (acc,inc) = if ((inc >= blocksProcessingBatchSize))
489+ then acc
490+ else {
491+ let targetBlockHeight = (nextBlockToProcess + inc)
492+ let targetBlockInfo = valueOrErrorMessage(blockInfoByHeight(targetBlockHeight), wrapErr("invalid block info"))
493+ let treasuryRewardOrFail = valueOrErrorMessage(rewardForOption(targetBlockInfo.rewards, proxyTreasuryAddressOrFail), wrapErr(("invalid treasury reward for height " + toString(targetBlockHeight))))
494+ let generator = targetBlockInfo.generator
495+ let available = valueOrElse(getInteger(factoryAddressOrFail, keyAvailable(generator)), 0)
496+ let callerReward = if ((inc == (blocksProcessingBatchSize - 1)))
497+ then (blockProcessingRewardByGenerator + blockProcessingRewardByGeneratorRemainder)
498+ else blockProcessingRewardByGenerator
499+ let lpAssetAmount = if ((currentPriceOrFail > 0))
500+ then fraction((treasuryRewardOrFail - callerReward), SCALE8, currentPriceOrFail)
501+ else 0
502+ let factoryActionsSingle = [invoke(factoryAddressOrFail, "stringEntry", [keyBlockProcessed(targetBlockHeight), makeString([toBase58String(i.transactionId), toString(currentPeriodOrFail), toString(generator), toBase58String(userAddressBytes), toString(treasuryRewardOrFail), toString(callerReward), toString(lpAssetAmount)], SEP)], nil), invoke(factoryAddressOrFail, "integerEntry", [keyAvailable(generator), (available + lpAssetAmount)], nil)]
503+ if ((factoryActionsSingle == factoryActionsSingle))
504+ then {
505+ let $t01962719660 = acc
506+ let lpAssetAcc = $t01962719660._1
507+ let rewardAcc = $t01962719660._2
508+ $Tuple2((lpAssetAcc + lpAssetAmount), (rewardAcc + treasuryRewardOrFail))
509+ }
510+ else throw("Strict value is not equal to itself.")
511+ }
311512
513+ let list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39]
514+ let $t01992720003 = {
515+ let $l = list
516+ let $s = size($l)
517+ let $acc0 = $Tuple2(0, 0)
518+ func $f0_1 ($a,$i) = if (($i >= $s))
519+ then $a
520+ else map($a, $l[$i])
312521
522+ func $f0_2 ($a,$i) = if (($i >= $s))
523+ then $a
524+ else throw("List size exceeds 40")
313525
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 claimLP () = $Tuple2(nil, reentrantInvoke(calculatorAddressOrFail, "claimLP", [i.caller.bytes], i.payments))
342-
343-
344-
345-@Callable(i)
346-func claimWaves (txIdStr) = $Tuple2(nil, reentrantInvoke(calculatorAddressOrFail, "claimWaves", [i.caller.bytes, fromBase58String(txIdStr)], i.payments))
347-
348-
349-
350-@Callable(i)
351-func invest () = $Tuple2(nil, reentrantInvoke(calculatorAddressOrFail, "invest", [i.caller.bytes], i.payments))
352-
353-
354-
355-@Callable(i)
356-func withdraw () = $Tuple2(nil, reentrantInvoke(calculatorAddressOrFail, "withdraw", [i.caller.bytes], i.payments))
357-
358-
359-
360-@Callable(i)
361-func cancelWithdraw (txIdStr) = $Tuple2(nil, reentrantInvoke(calculatorAddressOrFail, "cancelWithdraw", [i.caller.bytes, fromBase58String(txIdStr)], i.payments))
362-
363-
364-
365-@Callable(i)
366-func processBlocks () = $Tuple2(nil, reentrantInvoke(calculatorAddressOrFail, "processBlocks", [i.caller.bytes], i.payments))
367-
368-
369-
370-@Callable(i)
371-func voteForTxId (txId) = {
372- let callerAddressString = toBase58String(i.caller.bytes)
373- let keyPrefix = keyAllowedTxIdVotePrefix(txId)
374- let result = [StringEntry(keyAllowedTxId(), txId)]
375- let allowedTxIdOption = getString(this, keyAllowedTxId())
376- let err = [if ((size(fromBase58String(txId)) == TXID_BYTES_LENGTH))
377- then true
378- else throwErr((txId + " is not valid txId")), if (if ((allowedTxIdOption == unit))
379- then true
380- else (value(allowedTxIdOption) != txId))
381- then true
382- else throwErr((txId + " is already allowed"))]
383- if ((err == err))
384- then voteINTERNAL(callerAddressString, keyPrefix, QUORUM, result)
526+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40)
527+ }
528+ if (($t01992720003 == $t01992720003))
529+ then {
530+ let rewardAmountTotal = $t01992720003._2
531+ let lpAssetAmountTotal = $t01992720003._1
532+ let rewardToMainTreasuryAmount = (rewardAmountTotal - blockProcessingReward)
533+ let invested = valueOrElse(getInteger(factoryAddressOrFail, keyInvested(unit)), 0)
534+ let actions = [invoke(factoryAddressOrFail, "reissue", [lpAssetAmountTotal], nil), invoke(factoryAddressOrFail, "integerEntry", [keyNextBlockToProcess(), (nextBlockToProcess + blocksProcessingBatchSize)], nil), invoke(factoryAddressOrFail, "transferFromProxyTreasury", [featureTreasuryAddressOrFail.bytes, rewardToMainTreasuryAmount], nil), invoke(factoryAddressOrFail, "transferFromProxyTreasury", [userAddressBytes, blockProcessingReward], nil), invoke(factoryAddressOrFail, "integerEntry", [keyInvested(unit), (invested + rewardToMainTreasuryAmount)], nil)]
535+ if ((actions == actions))
536+ then $Tuple2(nil, unit)
537+ else throw("Strict value is not equal to itself.")
538+ }
539+ else throw("Strict value is not equal to itself.")
540+ }
385541 else throw("Strict value is not equal to itself.")
386542 }
387543
388544
389545 @Verifier(tx)
390546 func verify () = {
391- let byProposal = match votingResultAddressOption {
392- case proposalAddress: Address =>
393- valueOrElse(getBoolean(proposalAddress, keyProposalAllowBroadcast(this, tx.id)), false)
547+ let publicKey = match getManagerPublicKeyOrUnit() {
548+ case pub: ByteVector =>
549+ pub
394550 case _ =>
395- false
551+ tx.senderPublicKey
396552 }
397- let byAdmins = (tx.id == fromBase58String(valueOrElse(getString(keyAllowedTxId()), "")))
398- let byOwner = if ((size(getAdminsList()) >= QUORUM))
399- then false
400- else sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
401- if (if (byProposal)
402- then true
403- else byAdmins)
404- then true
405- else byOwner
553+ sigVerify(tx.bodyBytes, tx.proofs[0], publicKey)
406554 }
407555
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 7 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let SEP = "__"
55
6-let contractFilename = "factory.ride"
6+let CONTRACT_NAME = "calculator.ride"
77
8-func wrapErr (s) = ((contractFilename + ": ") + s)
8+let SCALE8 = 100000000
9+
10+let PENDING = "PENDING"
11+
12+let FINISHED = "FINISHED"
13+
14+let WAVES = "WAVES"
15+
16+func wrapErr (s) = ((CONTRACT_NAME + ": ") + s)
917
1018
1119 func throwErr (s) = throw(wrapErr(s))
1220
1321
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)
21-
22-
23-func keyFullAdminVote (prefix,adminAddress) = makeString([prefix, adminAddress], SEP)
24-
25-
26-func keyAdminAddressList () = makeString(["%s", "adminAddressList"], SEP)
27-
28-
29-func keyAllowedTxId () = makeString(["%s", "txId"], SEP)
30-
31-
32-func getAdminVote (prefix,admin) = {
33- let voteKey = keyFullAdminVote(prefix, admin)
34- valueOrElse(getInteger(voteKey), 0)
35- }
36-
37-
38-func getAdminsList () = match getString(this, keyAdminAddressList()) {
39- case s: String =>
40- split(s, SEP)
22+func assetIdToString (assetId) = match assetId {
23+ case b: ByteVector =>
24+ toBase58String(b)
25+ case _: Unit =>
26+ WAVES
4127 case _ =>
42- nil
28+ throw("Match error")
4329 }
4430
4531
46-func isInAdminList (address) = containsElement(getAdminsList(), address)
32+func abs (n) = if ((0 > n))
33+ then -(n)
34+ else n
4735
4836
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)
54- }
37+func keyFactoryAddress () = makeString(["%s", "factory"], SEP)
5538
5639
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
76- }
40+func keyManagerPublicKey () = makeString(["%s", "managerPublicKey"], SEP)
7741
7842
79-func countVotesHelper (result,voteKey) = (result + valueOrElse(getInteger(voteKey), 0))
43+func keyLpAssetId () = makeString(["%s", "lpAssetId"], SEP)
8044
8145
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)
96- }
46+func keyProxyTreasuryAddress () = makeString(["%s", "proxyTreasury"], SEP)
9747
9848
99-func clearVotesHelper (result,key) = (result :+ DeleteEntry(key))
49+func keyMainTreasuryAddress () = makeString(["%s", "mainTreasury"], SEP)
10050
10151
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)
116- }
52+func keyInvested (assetId) = makeString(["%s%s", "invested", assetIdToString(assetId)], SEP)
11753
11854
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))
128- then {
129- let votes = countVotes(keyPrefix)
130- if (((votes + 1) >= minVotes))
131- then {
132- let clearVoteEntries = getClearVoteEntries(keyPrefix)
133- (clearVoteEntries ++ voteResult)
134- }
135- else [IntegerEntry(voteKey, 1)]
136- }
137- else throw("Strict value is not equal to itself.")
138- }
55+func keyDonated (assetId) = makeString(["%s%s", "donated", assetIdToString(assetId)], SEP)
13956
14057
141-func keyCalculatorAddress () = "%s__calculator"
58+func keyAvailable (userAddress) = makeString(["%s%s", "available", toString(userAddress)], SEP)
14259
14360
144-func keyProxyTreasuryAddress () = "%s__proxyTreasury"
61+func keyClaimed (userAddress) = makeString(["%s%s", "claimed", toString(userAddress)], SEP)
14562
14663
147-func keyChildAddress () = "%s__child"
64+func keyCurrentPeriod () = makeString(["%s", "currentPeriod"], SEP)
65+
66+
67+func keyPriceForPeriod (period) = makeString(["%s%d", "price", toString(period)], SEP)
68+
69+
70+func keyStartHeight (period) = makeString(["%s%d", "startHeight", toString(period)], SEP)
71+
72+
73+func keyPeriodLength () = "%s__periodLength"
14874
14975
15076 func keyBlockProcessingReward () = "%s__blockProcessingReward"
15177
15278
15379 func keyNextBlockToProcess () = "%s__nextBlockToProcess"
15480
15581
156-func keyLpAssetId () = "%s__lpAssetId"
82+func keyBlockProcessed (height) = makeString(["%s%d", "blockProcessed", toString(height)], SEP)
15783
15884
159-let calculatorAddressOption = match getString(this, keyCalculatorAddress()) {
85+func keyWithdrawal () = "%s__withdrawal"
86+
87+
88+func keyWithdrawalRequest (userAddress,txId) = makeString(["%s%s%s", "withdrawal", toString(userAddress), toBase58String(txId)], SEP)
89+
90+
91+func valueWithdrawalRequest (status,lpAssetAmount,targetPeriod,claimTxId) = {
92+ let claimTxIdStr = match claimTxId {
93+ case b: ByteVector =>
94+ toBase58String(b)
95+ case _: Unit =>
96+ "SOON"
97+ case _ =>
98+ throw("Match error")
99+ }
100+ makeString(["%s%d%d%s", status, toString(lpAssetAmount), toString(targetPeriod), claimTxIdStr], SEP)
101+ }
102+
103+
104+func parseWithdrawalRequestValueOrFail (s) = {
105+ let parts = split(s, SEP)
106+ if ((size(parts) == 5))
107+ then {
108+ let status = parts[1]
109+ let lpAssetAmount = valueOrErrorMessage(parseInt(parts[2]), wrapErr("invalid lpAssetAmount"))
110+ let targetPeriod = valueOrErrorMessage(parseInt(parts[3]), wrapErr("invalid targetPeriod"))
111+ let claimTxId = parts[4]
112+ $Tuple4(status, lpAssetAmount, targetPeriod, claimTxId)
113+ }
114+ else throwErr("invalid withdrawal request value")
115+ }
116+
117+
118+let factoryAddressOption = match getString(this, keyFactoryAddress()) {
160119 case s: String =>
161120 addressFromString(s)
162121 case _: Unit =>
163122 unit
164123 case _ =>
165124 throw("Match error")
166125 }
167126
168-let calculatorAddressOrFail = valueOrErrorMessage(calculatorAddressOption, wrapErr("invalid calculator address"))
127+let factoryAddressOrFail = valueOrErrorMessage(factoryAddressOption, wrapErr("invalid factory address"))
169128
170-let proxyTreasuryAddressOption = match getString(this, keyProxyTreasuryAddress()) {
171- case s: String =>
172- addressFromString(s)
129+let lpAssetIdOption = match factoryAddressOption {
130+ case a: Address =>
131+ match getString(a, keyLpAssetId()) {
132+ case s: String =>
133+ fromBase58String(s)
134+ case _: Unit =>
135+ unit
136+ case _ =>
137+ throw("Match error")
138+ }
173139 case _: Unit =>
174140 unit
175141 case _ =>
176142 throw("Match error")
177143 }
178144
179-let proxyTreasuryAddressOrFail = valueOrErrorMessage(proxyTreasuryAddressOption, wrapErr("invalid proxy treasury address"))
145+let lpAssetIdOrFail = valueOrErrorMessage(lpAssetIdOption, wrapErr("invalid lpAssetId"))
180146
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 {
147+let proxyTreasuryAddressOption = match factoryAddressOption {
208148 case a: Address =>
209- match getString(a, keyVotingResultAddress()) {
149+ match getString(a, keyProxyTreasuryAddress()) {
210150 case s: String =>
211151 addressFromString(s)
212152 case _: Unit =>
213153 unit
214154 case _ =>
215155 throw("Match error")
216156 }
217157 case _: Unit =>
218158 unit
219159 case _ =>
220160 throw("Match error")
221161 }
222162
223-let votingResultAddressOrFail = valueOrErrorMessage(votingResultAddressOption, wrapErr("invalid voting result address"))
163+let proxyTreasuryAddressOrFail = valueOrErrorMessage(proxyTreasuryAddressOption, wrapErr("invalid proxy treasury address"))
224164
225-let childrenAddressOption = match configAddressOption {
165+let featureTreasuryAddressOption = match factoryAddressOption {
226166 case a: Address =>
227- match getString(a, keyChildrenAddress()) {
167+ match getString(a, keyMainTreasuryAddress()) {
228168 case s: String =>
229169 addressFromString(s)
230170 case _: Unit =>
231171 unit
232172 case _ =>
233173 throw("Match error")
234174 }
235175 case _: Unit =>
236176 unit
237177 case _ =>
238178 throw("Match error")
239179 }
240180
241-let childrenAddressOrFail = valueOrErrorMessage(childrenAddressOption, wrapErr("invalid children address"))
181+let featureTreasuryAddressOrFail = valueOrErrorMessage(featureTreasuryAddressOption, wrapErr("invalid feature treasury address"))
242182
243-let lpAssetIdOption = match getString(this, keyLpAssetId()) {
244- case s: String =>
245- fromBase58String(s)
246- case _: Unit =>
183+func getManagerPublicKeyOrUnit () = match factoryAddressOption {
184+ case fa: Address =>
185+ match getString(fa, keyManagerPublicKey()) {
186+ case pub: String =>
187+ fromBase58String(pub)
188+ case _ =>
189+ unit
190+ }
191+ case _ =>
247192 unit
248- case _ =>
249- throw("Match error")
250193 }
251194
252-let lpAssetIdOrFail = valueOrErrorMessage(lpAssetIdOption, wrapErr("invalid lpAssetId"))
253195
254196 func onlyAddress (i,address) = if ((i.caller == address))
255197 then true
256198 else throwErr("permission denied")
257199
258200
259-func onlyThis (i) = onlyAddress(i, this)
201+func onlyFactory (i) = onlyAddress(i, factoryAddressOrFail)
260202
261203
262-func onlyCalculator (i) = onlyAddress(i, calculatorAddressOrFail)
204+func rewardForOption (rewards,target) = {
205+ let s = size(rewards)
206+ let $t046414666 = rewards[0]
207+ let a0 = $t046414666._1
208+ let r0 = $t046414666._2
209+ let $t046694694 = rewards[1]
210+ let a1 = $t046694694._1
211+ let r1 = $t046694694._2
212+ let $t046974722 = rewards[2]
213+ let a2 = $t046974722._1
214+ let r2 = $t046974722._2
215+ if (if ((s > 0))
216+ then (a0 == target)
217+ else false)
218+ then r0
219+ else if (if ((s > 1))
220+ then (a1 == target)
221+ else false)
222+ then r1
223+ else if (if ((s > 2))
224+ then (a2 == target)
225+ else false)
226+ then r2
227+ else unit
228+ }
263229
264230
265231 @Callable(i)
266-func stringEntry (key,val) = if (onlyCalculator(i))
267- then $Tuple2([StringEntry(key, val)], key)
268- else $Tuple2(nil, unit)
232+func claimLP (userAddressBytes) = {
233+ let checkCaller = onlyFactory(i)
234+ if ((checkCaller == checkCaller))
235+ then {
236+ let userAddress = Address(userAddressBytes)
237+ let available = valueOrElse(getInteger(factoryAddressOrFail, keyAvailable(userAddress)), 0)
238+ let claimed = valueOrElse(getInteger(factoryAddressOrFail, keyClaimed(userAddress)), 0)
239+ let factoryActions = if ((available > 0))
240+ then [invoke(factoryAddressOrFail, "transferAsset", [userAddressBytes, available, lpAssetIdOrFail], nil), invoke(factoryAddressOrFail, "integerEntry", [keyAvailable(userAddress), 0], nil), invoke(factoryAddressOrFail, "integerEntry", [keyClaimed(userAddress), (claimed + available)], nil)]
241+ else throwErr("nothing to claim")
242+ $Tuple2(nil, factoryActions)
243+ }
244+ else throw("Strict value is not equal to itself.")
245+ }
269246
270247
271248
272249 @Callable(i)
273-func integerEntry (key,val) = if (onlyCalculator(i))
274- then $Tuple2([IntegerEntry(key, val)], key)
275- else $Tuple2(nil, unit)
250+func finalize (userAddressBytes,newTreasuryVolumeInWaves,pwrManagersBonusInWaves,treasuryVolumeDiffAllocationCoef) = {
251+ let checkCaller = onlyFactory(i)
252+ if ((checkCaller == checkCaller))
253+ then {
254+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
255+ let periodLength = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPeriodLength()), wrapErr("invalid period length"))
256+ let currentStartHeight = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyStartHeight(currentPeriodOrFail)), wrapErr("invalid start height"))
257+ let currentPriceOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPriceForPeriod(currentPeriodOrFail)), wrapErr("invalid price"))
258+ let nextBlockToProcess = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyNextBlockToProcess()), wrapErr("invalid next block to process"))
259+ let periodEndHeight = ((currentStartHeight + periodLength) - 1)
260+ let checks = [if ((i.originCaller == featureTreasuryAddressOrFail))
261+ then true
262+ else throwErr("permission denied"), if ((nextBlockToProcess > periodEndHeight))
263+ then true
264+ else throwErr("unprocessed blocks"), if ((newTreasuryVolumeInWaves >= 0))
265+ then true
266+ else throwErr("invalid new treasury volume"), if ((pwrManagersBonusInWaves >= 0))
267+ then true
268+ else throwErr("invalid PWR managers bonus"), if (if ((treasuryVolumeDiffAllocationCoef >= -(SCALE8)))
269+ then (SCALE8 >= treasuryVolumeDiffAllocationCoef)
270+ else false)
271+ then true
272+ else throwErr("invalid treasury volume diff allocation coefficient")]
273+ if ((checks == checks))
274+ then {
275+ let donatedWavesAmount = valueOrElse(getInteger(factoryAddressOrFail, keyDonated(unit)), 0)
276+ let investedWavesAmount = valueOrElse(getInteger(factoryAddressOrFail, keyInvested(unit)), 0)
277+ let currentTreasuryVolumeInWaves = (donatedWavesAmount + investedWavesAmount)
278+ let profitRaw = (newTreasuryVolumeInWaves - currentTreasuryVolumeInWaves)
279+ let pwrManagersBonusAmount = if (if ((profitRaw > 0))
280+ then (profitRaw >= pwrManagersBonusInWaves)
281+ else false)
282+ then pwrManagersBonusInWaves
283+ else 0
284+ let profit = (profitRaw - pwrManagersBonusAmount)
285+ let donationPart = if ((currentTreasuryVolumeInWaves > 0))
286+ then fraction(donatedWavesAmount, SCALE8, currentTreasuryVolumeInWaves)
287+ else 0
288+ let donationProfitPartRaw = fraction(profit, donationPart, SCALE8)
289+ let investmentProfitPartRaw = (profit - donationProfitPartRaw)
290+ let treasuryVolumeDiffAllocationCoefAbs = abs(treasuryVolumeDiffAllocationCoef)
291+ let amountToDonation = fraction(investmentProfitPartRaw, if ((0 > treasuryVolumeDiffAllocationCoef))
292+ then treasuryVolumeDiffAllocationCoefAbs
293+ else 0, SCALE8)
294+ let amountToInvestment = fraction(donationProfitPartRaw, if ((treasuryVolumeDiffAllocationCoef > 0))
295+ then treasuryVolumeDiffAllocationCoefAbs
296+ else 0, SCALE8)
297+ let donationProfitPart = ((donationProfitPartRaw - amountToInvestment) + amountToDonation)
298+ let investmentProfitPart = ((investmentProfitPartRaw - amountToDonation) + amountToInvestment)
299+ let investedWavesAmountNew = (investedWavesAmount + investmentProfitPart)
300+ let newPeriod = (currentPeriodOrFail + 1)
301+ let lpAssetQuantity = valueOrErrorMessage(assetInfo(lpAssetIdOrFail), wrapErr("invalid lpAsset info")).quantity
302+ let newPrice = fraction(investedWavesAmountNew, SCALE8, lpAssetQuantity)
303+ let lpAssetAmountToBurn = valueOrElse(getInteger(factoryAddressOrFail, keyWithdrawal()), 0)
304+ let newLpAmount = (lpAssetQuantity - lpAssetAmountToBurn)
305+ let newInvestAmount = max([0, fraction(newLpAmount, newPrice, SCALE8)])
306+ let paymentAmountMin = max([0, fraction(lpAssetAmountToBurn, newPrice, SCALE8)])
307+ let paymentOption = if ((size(i.payments) > 0))
308+ then i.payments[0]
309+ else unit
310+ let paymentAmount = value(paymentOption).amount
311+ let paymentAssetId = value(paymentOption).assetId
312+ let checkPayment = if (if ((paymentAmountMin == 0))
313+ then true
314+ else if (if ((paymentOption != unit))
315+ then (paymentAssetId == unit)
316+ else false)
317+ then (paymentAmount >= paymentAmountMin)
318+ else false)
319+ then true
320+ else throwErr(("invalid payments, payment amount min: " + toString(paymentAmountMin)))
321+ if ((checkPayment == checkPayment))
322+ then {
323+ let actions = if ((paymentOption != unit))
324+ then [ScriptTransfer(factoryAddressOrFail, paymentAmount, paymentAssetId)]
325+ else nil
326+ let factoryActions = [invoke(factoryAddressOrFail, "integerEntry", [keyCurrentPeriod(), newPeriod], nil), invoke(factoryAddressOrFail, "integerEntry", [keyPriceForPeriod(newPeriod), newPrice], nil), invoke(factoryAddressOrFail, "integerEntry", [keyStartHeight(newPeriod), (periodEndHeight + 1)], nil), invoke(factoryAddressOrFail, "burn", [lpAssetAmountToBurn], nil), invoke(factoryAddressOrFail, "integerEntry", [keyWithdrawal(), 0], nil), invoke(factoryAddressOrFail, "integerEntry", [keyInvested(unit), newInvestAmount], nil)]
327+ $Tuple2(actions, factoryActions)
328+ }
329+ else throw("Strict value is not equal to itself.")
330+ }
331+ else throw("Strict value is not equal to itself.")
332+ }
333+ else throw("Strict value is not equal to itself.")
334+ }
276335
277336
278337
279338 @Callable(i)
280-func booleanEntry (key,val) = if (onlyCalculator(i))
281- then $Tuple2([BooleanEntry(key, val)], key)
282- else $Tuple2(nil, unit)
339+func invest (userAddressBytes) = {
340+ let checkCaller = onlyFactory(i)
341+ if ((checkCaller == checkCaller))
342+ then {
343+ let userAddress = Address(userAddressBytes)
344+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
345+ let currentPriceOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPriceForPeriod(currentPeriodOrFail)), wrapErr("invalid price"))
346+ let payment = if ((size(i.payments) == 1))
347+ then i.payments[0]
348+ else throwErr("invalid payments")
349+ let $t01124611423 = if (if ((payment.assetId == unit))
350+ then (payment.amount > 0)
351+ else false)
352+ then $Tuple2(payment.amount, payment.assetId)
353+ else throwErr("invalid payment amount")
354+ let paymentAmount = $t01124611423._1
355+ let paymentAssetId = $t01124611423._2
356+ let lpAssetAmount = if ((currentPriceOrFail > 0))
357+ then fraction(paymentAmount, SCALE8, currentPriceOrFail)
358+ else 0
359+ let invested = valueOrElse(getInteger(factoryAddressOrFail, keyInvested(unit)), 0)
360+ let actions = [ScriptTransfer(featureTreasuryAddressOrFail, paymentAmount, paymentAssetId)]
361+ let factoryActions = [invoke(factoryAddressOrFail, "integerEntry", [keyInvested(unit), (invested + paymentAmount)], nil), invoke(factoryAddressOrFail, "reissue", [lpAssetAmount], nil), invoke(factoryAddressOrFail, "transferAsset", [userAddressBytes, lpAssetAmount, lpAssetIdOrFail], nil)]
362+ $Tuple2(actions, factoryActions)
363+ }
364+ else throw("Strict value is not equal to itself.")
365+ }
283366
284367
285368
286369 @Callable(i)
287-func binaryEntry (key,val) = if (onlyCalculator(i))
288- then $Tuple2([BinaryEntry(key, val)], key)
289- else $Tuple2(nil, unit)
370+func withdraw (userAddressBytes) = {
371+ let checkCaller = onlyFactory(i)
372+ if ((checkCaller == checkCaller))
373+ then {
374+ let userAddress = Address(userAddressBytes)
375+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
376+ let payment = if ((size(i.payments) == 1))
377+ then i.payments[0]
378+ else throwErr(wrapErr("invalid payments"))
379+ let paymentAssetId = if ((payment.assetId == lpAssetIdOrFail))
380+ then lpAssetIdOrFail
381+ else throwErr("invalid payment asset")
382+ let paymentAmount = if ((payment.amount > 0))
383+ then payment.amount
384+ else throwErr("invalid payment amount")
385+ let withdrawal = valueOrElse(getInteger(factoryAddressOrFail, keyWithdrawal()), 0)
386+ let actions = [ScriptTransfer(factoryAddressOrFail, paymentAmount, paymentAssetId)]
387+ let factoryActions = [invoke(factoryAddressOrFail, "integerEntry", [keyWithdrawal(), (withdrawal + paymentAmount)], nil), invoke(factoryAddressOrFail, "stringEntry", [keyWithdrawalRequest(userAddress, i.transactionId), valueWithdrawalRequest(PENDING, paymentAmount, (currentPeriodOrFail + 1), unit)], nil)]
388+ if ((factoryActions == factoryActions))
389+ then $Tuple2(actions, factoryActions)
390+ else throw("Strict value is not equal to itself.")
391+ }
392+ else throw("Strict value is not equal to itself.")
393+ }
290394
291395
292396
293397 @Callable(i)
294-func deleteEntry (key) = if (onlyCalculator(i))
295- then $Tuple2([DeleteEntry(key)], key)
296- else $Tuple2(nil, unit)
398+func cancelWithdraw (userAddressBytes,txId) = {
399+ let checkCaller = onlyFactory(i)
400+ if ((checkCaller == checkCaller))
401+ then {
402+ let userAddress = Address(userAddressBytes)
403+ let withdrawalRequestOption = valueOrErrorMessage(getString(factoryAddressOrFail, keyWithdrawalRequest(userAddress, txId)), wrapErr("invalid withdrawal request"))
404+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
405+ let $t01383313946 = parseWithdrawalRequestValueOrFail(withdrawalRequestOption)
406+ let status = $t01383313946._1
407+ let lpAssetAmount = $t01383313946._2
408+ let targetPeriod = $t01383313946._3
409+ let claimTxId = $t01383313946._4
410+ let checks = [if ((status == PENDING))
411+ then true
412+ else throwErr("invalid withdrawal request status"), if ((targetPeriod > currentPeriodOrFail))
413+ then true
414+ else throwErr("invalid withdrawal request period")]
415+ if ((checks == checks))
416+ then {
417+ let withdrawal = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyWithdrawal()), wrapErr("invalid total withdrawal amount"))
418+ let factoryActions = [invoke(factoryAddressOrFail, "integerEntry", [keyWithdrawal(), if ((withdrawal >= lpAssetAmount))
419+ then (withdrawal - lpAssetAmount)
420+ else throwErr("invalid withdrawal amount")], nil), invoke(factoryAddressOrFail, "deleteEntry", [keyWithdrawalRequest(userAddress, txId)], nil), invoke(factoryAddressOrFail, "transferAsset", [userAddressBytes, lpAssetAmount, lpAssetIdOrFail], nil)]
421+ if ((factoryActions == factoryActions))
422+ then $Tuple2(nil, factoryActions)
423+ else throw("Strict value is not equal to itself.")
424+ }
425+ else throw("Strict value is not equal to itself.")
426+ }
427+ else throw("Strict value is not equal to itself.")
428+ }
297429
298430
299431
300432 @Callable(i)
301-func reissue (amount) = if (onlyCalculator(i))
302- then $Tuple2([Reissue(lpAssetIdOrFail, amount, true)], amount)
303- else $Tuple2(nil, unit)
433+func claimWaves (userAddressBytes,txId) = {
434+ let checkCaller = onlyFactory(i)
435+ if ((checkCaller == checkCaller))
436+ then {
437+ let userAddress = Address(userAddressBytes)
438+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
439+ let withdrawalRequestOption = valueOrErrorMessage(getString(factoryAddressOrFail, keyWithdrawalRequest(userAddress, txId)), wrapErr("invalid withdrawal request"))
440+ let $t01527815391 = parseWithdrawalRequestValueOrFail(withdrawalRequestOption)
441+ let status = $t01527815391._1
442+ let lpAssetAmount = $t01527815391._2
443+ let targetPeriod = $t01527815391._3
444+ let claimTxId = $t01527815391._4
445+ if ((status == FINISHED))
446+ then throwErr("invalid withdrawal request status")
447+ else if ((targetPeriod > currentPeriodOrFail))
448+ then throwErr("invalid withdrawal request period")
449+ else {
450+ let priceOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPriceForPeriod(targetPeriod)), wrapErr("invalid price"))
451+ let amount = if ((priceOrFail > 0))
452+ then fraction(lpAssetAmount, priceOrFail, SCALE8)
453+ else 0
454+ let factoryActions = [invoke(factoryAddressOrFail, "stringEntry", [keyWithdrawalRequest(userAddress, txId), valueWithdrawalRequest(FINISHED, lpAssetAmount, targetPeriod, i.transactionId)], nil), invoke(factoryAddressOrFail, "transferWaves", [userAddressBytes, amount], nil)]
455+ $Tuple2(nil, factoryActions)
456+ }
457+ }
458+ else throw("Strict value is not equal to itself.")
459+ }
304460
305461
306462
307463 @Callable(i)
308-func burn (amount) = if (onlyCalculator(i))
309- then $Tuple2([Burn(lpAssetIdOrFail, amount)], amount)
310- else $Tuple2(nil, unit)
464+func processBlocks (userAddressBytes) = {
465+ let checkCaller = onlyFactory(i)
466+ if ((checkCaller == checkCaller))
467+ then {
468+ let userAddress = Address(userAddressBytes)
469+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
470+ let periodLength = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPeriodLength()), wrapErr("invalid period length"))
471+ let currentStartHeight = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyStartHeight(currentPeriodOrFail)), wrapErr("invalid start height"))
472+ let currentPriceOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPriceForPeriod(currentPeriodOrFail)), wrapErr("invalid price"))
473+ let nextBlockToProcess = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyNextBlockToProcess()), wrapErr("invalid next block to process"))
474+ let periodEndHeight = ((currentStartHeight + periodLength) - 1)
475+ let blocksProcessingBatchSizeMax = 40
476+ let blocksProcessingBatchSize = if (if (if ((height >= nextBlockToProcess))
477+ then if ((nextBlockToProcess >= currentStartHeight))
478+ then true
479+ else (currentPeriodOrFail == 0)
480+ else false)
481+ then (periodEndHeight >= nextBlockToProcess)
482+ else false)
483+ then min([((periodEndHeight - nextBlockToProcess) + 1), blocksProcessingBatchSizeMax])
484+ else throwErr(wrapErr("invalid target block"))
485+ let blockProcessingReward = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyBlockProcessingReward()), wrapErr("invalid block processing reward"))
486+ let blockProcessingRewardByGenerator = (blockProcessingReward / blocksProcessingBatchSize)
487+ let blockProcessingRewardByGeneratorRemainder = (blockProcessingReward - (blockProcessingRewardByGenerator * blocksProcessingBatchSize))
488+ func map (acc,inc) = if ((inc >= blocksProcessingBatchSize))
489+ then acc
490+ else {
491+ let targetBlockHeight = (nextBlockToProcess + inc)
492+ let targetBlockInfo = valueOrErrorMessage(blockInfoByHeight(targetBlockHeight), wrapErr("invalid block info"))
493+ let treasuryRewardOrFail = valueOrErrorMessage(rewardForOption(targetBlockInfo.rewards, proxyTreasuryAddressOrFail), wrapErr(("invalid treasury reward for height " + toString(targetBlockHeight))))
494+ let generator = targetBlockInfo.generator
495+ let available = valueOrElse(getInteger(factoryAddressOrFail, keyAvailable(generator)), 0)
496+ let callerReward = if ((inc == (blocksProcessingBatchSize - 1)))
497+ then (blockProcessingRewardByGenerator + blockProcessingRewardByGeneratorRemainder)
498+ else blockProcessingRewardByGenerator
499+ let lpAssetAmount = if ((currentPriceOrFail > 0))
500+ then fraction((treasuryRewardOrFail - callerReward), SCALE8, currentPriceOrFail)
501+ else 0
502+ let factoryActionsSingle = [invoke(factoryAddressOrFail, "stringEntry", [keyBlockProcessed(targetBlockHeight), makeString([toBase58String(i.transactionId), toString(currentPeriodOrFail), toString(generator), toBase58String(userAddressBytes), toString(treasuryRewardOrFail), toString(callerReward), toString(lpAssetAmount)], SEP)], nil), invoke(factoryAddressOrFail, "integerEntry", [keyAvailable(generator), (available + lpAssetAmount)], nil)]
503+ if ((factoryActionsSingle == factoryActionsSingle))
504+ then {
505+ let $t01962719660 = acc
506+ let lpAssetAcc = $t01962719660._1
507+ let rewardAcc = $t01962719660._2
508+ $Tuple2((lpAssetAcc + lpAssetAmount), (rewardAcc + treasuryRewardOrFail))
509+ }
510+ else throw("Strict value is not equal to itself.")
511+ }
311512
513+ let list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39]
514+ let $t01992720003 = {
515+ let $l = list
516+ let $s = size($l)
517+ let $acc0 = $Tuple2(0, 0)
518+ func $f0_1 ($a,$i) = if (($i >= $s))
519+ then $a
520+ else map($a, $l[$i])
312521
522+ func $f0_2 ($a,$i) = if (($i >= $s))
523+ then $a
524+ else throw("List size exceeds 40")
313525
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 claimLP () = $Tuple2(nil, reentrantInvoke(calculatorAddressOrFail, "claimLP", [i.caller.bytes], i.payments))
342-
343-
344-
345-@Callable(i)
346-func claimWaves (txIdStr) = $Tuple2(nil, reentrantInvoke(calculatorAddressOrFail, "claimWaves", [i.caller.bytes, fromBase58String(txIdStr)], i.payments))
347-
348-
349-
350-@Callable(i)
351-func invest () = $Tuple2(nil, reentrantInvoke(calculatorAddressOrFail, "invest", [i.caller.bytes], i.payments))
352-
353-
354-
355-@Callable(i)
356-func withdraw () = $Tuple2(nil, reentrantInvoke(calculatorAddressOrFail, "withdraw", [i.caller.bytes], i.payments))
357-
358-
359-
360-@Callable(i)
361-func cancelWithdraw (txIdStr) = $Tuple2(nil, reentrantInvoke(calculatorAddressOrFail, "cancelWithdraw", [i.caller.bytes, fromBase58String(txIdStr)], i.payments))
362-
363-
364-
365-@Callable(i)
366-func processBlocks () = $Tuple2(nil, reentrantInvoke(calculatorAddressOrFail, "processBlocks", [i.caller.bytes], i.payments))
367-
368-
369-
370-@Callable(i)
371-func voteForTxId (txId) = {
372- let callerAddressString = toBase58String(i.caller.bytes)
373- let keyPrefix = keyAllowedTxIdVotePrefix(txId)
374- let result = [StringEntry(keyAllowedTxId(), txId)]
375- let allowedTxIdOption = getString(this, keyAllowedTxId())
376- let err = [if ((size(fromBase58String(txId)) == TXID_BYTES_LENGTH))
377- then true
378- else throwErr((txId + " is not valid txId")), if (if ((allowedTxIdOption == unit))
379- then true
380- else (value(allowedTxIdOption) != txId))
381- then true
382- else throwErr((txId + " is already allowed"))]
383- if ((err == err))
384- then voteINTERNAL(callerAddressString, keyPrefix, QUORUM, result)
526+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40)
527+ }
528+ if (($t01992720003 == $t01992720003))
529+ then {
530+ let rewardAmountTotal = $t01992720003._2
531+ let lpAssetAmountTotal = $t01992720003._1
532+ let rewardToMainTreasuryAmount = (rewardAmountTotal - blockProcessingReward)
533+ let invested = valueOrElse(getInteger(factoryAddressOrFail, keyInvested(unit)), 0)
534+ let actions = [invoke(factoryAddressOrFail, "reissue", [lpAssetAmountTotal], nil), invoke(factoryAddressOrFail, "integerEntry", [keyNextBlockToProcess(), (nextBlockToProcess + blocksProcessingBatchSize)], nil), invoke(factoryAddressOrFail, "transferFromProxyTreasury", [featureTreasuryAddressOrFail.bytes, rewardToMainTreasuryAmount], nil), invoke(factoryAddressOrFail, "transferFromProxyTreasury", [userAddressBytes, blockProcessingReward], nil), invoke(factoryAddressOrFail, "integerEntry", [keyInvested(unit), (invested + rewardToMainTreasuryAmount)], nil)]
535+ if ((actions == actions))
536+ then $Tuple2(nil, unit)
537+ else throw("Strict value is not equal to itself.")
538+ }
539+ else throw("Strict value is not equal to itself.")
540+ }
385541 else throw("Strict value is not equal to itself.")
386542 }
387543
388544
389545 @Verifier(tx)
390546 func verify () = {
391- let byProposal = match votingResultAddressOption {
392- case proposalAddress: Address =>
393- valueOrElse(getBoolean(proposalAddress, keyProposalAllowBroadcast(this, tx.id)), false)
547+ let publicKey = match getManagerPublicKeyOrUnit() {
548+ case pub: ByteVector =>
549+ pub
394550 case _ =>
395- false
551+ tx.senderPublicKey
396552 }
397- let byAdmins = (tx.id == fromBase58String(valueOrElse(getString(keyAllowedTxId()), "")))
398- let byOwner = if ((size(getAdminsList()) >= QUORUM))
399- then false
400- else sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
401- if (if (byProposal)
402- then true
403- else byAdmins)
404- then true
405- else byOwner
553+ sigVerify(tx.bodyBytes, tx.proofs[0], publicKey)
406554 }
407555

github/deemru/w8io/3ef1775 
102.38 ms