tx · 8a3BDFGh4g8n8JXpMTA6kD59wusUwGNTwyCMwavRs5Qm

3N6HSS7Toat1RhyEsyqVGgVSRzH19W1FTbP:  -0.02900000 Waves

2023.07.27 14:19 [2684188] smart account 3N6HSS7Toat1RhyEsyqVGgVSRzH19W1FTbP > SELF 0.00000000 Waves

{ "type": 13, "id": "8a3BDFGh4g8n8JXpMTA6kD59wusUwGNTwyCMwavRs5Qm", "fee": 2900000, "feeAssetId": null, "timestamp": 1690456728676, "version": 2, "chainId": 84, "sender": "3N6HSS7Toat1RhyEsyqVGgVSRzH19W1FTbP", "senderPublicKey": "AoKo4segKHU4DeJnxXQYJj2u7J6XJeux6r8KLW52cd2Q", "proofs": [ "4Beh6FiGVQSgSpGqYcfTSbormkbsaeR1wxuAwJuSqiZF3dRXaPnWQdLuFn2GijgR88b3jN9V8g6qrsw5EXCvZB9d" ], "script": "base64:BwIxCAISAwoBAhIGCgQCAQEBEgUKAwEBARIDCgECEgMKAQISBAoCAgISBAoCAgISAwoBAjEAA1NFUAICX18ADUNPTlRSQUNUX05BTUUCD2NhbGN1bGF0b3IucmlkZQAGU0NBTEU4AIDC1y8AB1BFTkRJTkcCB1BFTkRJTkcACEZJTklTSEVEAghGSU5JU0hFRAAFV0FWRVMCBVdBVkVTAQd3cmFwRXJyAQFzCQCsAgIJAKwCAgUNQ09OVFJBQ1RfTkFNRQICOiAFAXMBCHRocm93RXJyAQFzCQACAQkBB3dyYXBFcnIBBQFzAQ9hc3NldElkVG9TdHJpbmcBB2Fzc2V0SWQEByRtYXRjaDAFB2Fzc2V0SWQDCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQBYgUHJG1hdGNoMAkA2AQBBQFiAwkAAQIFByRtYXRjaDACBFVuaXQFBVdBVkVTCQACAQILTWF0Y2ggZXJyb3IBD3N0cmluZ1RvQXNzZXRJZAEBcwMJAAACBQFzBQVXQVZFUwUEdW5pdAkA2QQBBQFzAQNhYnMBAW4DCQBmAgAABQFuCQEBLQEFAW4FAW4BEWtleUZhY3RvcnlBZGRyZXNzAAkAuQkCCQDMCAICAiVzCQDMCAICB2ZhY3RvcnkFA25pbAUDU0VQARNrZXlNYW5hZ2VyUHVibGljS2V5AAkAuQkCCQDMCAICAiVzCQDMCAICEG1hbmFnZXJQdWJsaWNLZXkFA25pbAUDU0VQAQxrZXlMcEFzc2V0SWQACQC5CQIJAMwIAgICJXMJAMwIAgIJbHBBc3NldElkBQNuaWwFA1NFUAEXa2V5UHJveHlUcmVhc3VyeUFkZHJlc3MACQC5CQIJAMwIAgICJXMJAMwIAgINcHJveHlUcmVhc3VyeQUDbmlsBQNTRVABFmtleU1haW5UcmVhc3VyeUFkZHJlc3MACQC5CQIJAMwIAgICJXMJAMwIAgIMbWFpblRyZWFzdXJ5BQNuaWwFA1NFUAELa2V5SW52ZXN0ZWQBB2Fzc2V0SWQJALkJAgkAzAgCAgQlcyVzCQDMCAICCGludmVzdGVkCQDMCAIJAQ9hc3NldElkVG9TdHJpbmcBBQdhc3NldElkBQNuaWwFA1NFUAEKa2V5RG9uYXRlZAEHYXNzZXRJZAkAuQkCCQDMCAICBCVzJXMJAMwIAgIHZG9uYXRlZAkAzAgCCQEPYXNzZXRJZFRvU3RyaW5nAQUHYXNzZXRJZAUDbmlsBQNTRVABDGtleUF2YWlsYWJsZQELdXNlckFkZHJlc3MJALkJAgkAzAgCAgQlcyVzCQDMCAICCWF2YWlsYWJsZQkAzAgCCQClCAEFC3VzZXJBZGRyZXNzBQNuaWwFA1NFUAEKa2V5Q2xhaW1lZAELdXNlckFkZHJlc3MJALkJAgkAzAgCAgQlcyVzCQDMCAICB2NsYWltZWQJAMwIAgkApQgBBQt1c2VyQWRkcmVzcwUDbmlsBQNTRVABEGtleUN1cnJlbnRQZXJpb2QACQC5CQIJAMwIAgICJXMJAMwIAgINY3VycmVudFBlcmlvZAUDbmlsBQNTRVABEWtleVByaWNlRm9yUGVyaW9kAQZwZXJpb2QJALkJAgkAzAgCAgQlcyVkCQDMCAICBXByaWNlCQDMCAIJAKQDAQUGcGVyaW9kBQNuaWwFA1NFUAEOa2V5U3RhcnRIZWlnaHQBBnBlcmlvZAkAuQkCCQDMCAICBCVzJWQJAMwIAgILc3RhcnRIZWlnaHQJAMwIAgkApAMBBQZwZXJpb2QFA25pbAUDU0VQARRrZXlQb3dlck1hbmFnZXJCb251cwEGcGVyaW9kCQC5CQIJAMwIAgIEJXMlZAkAzAgCAhFwb3dlck1hbmFnZXJCb251cwkAzAgCCQCkAwEFBnBlcmlvZAUDbmlsBQNTRVABD2tleVBlcmlvZExlbmd0aAACECVzX19wZXJpb2RMZW5ndGgBGGtleUJsb2NrUHJvY2Vzc2luZ1Jld2FyZAACGSVzX19ibG9ja1Byb2Nlc3NpbmdSZXdhcmQBFWtleU5leHRCbG9ja1RvUHJvY2VzcwACFiVzX19uZXh0QmxvY2tUb1Byb2Nlc3MBEWtleUJsb2NrUHJvY2Vzc2VkAQZoZWlnaHQJALkJAgkAzAgCAgQlcyVkCQDMCAICDmJsb2NrUHJvY2Vzc2VkCQDMCAIJAKQDAQUGaGVpZ2h0BQNuaWwFA1NFUAENa2V5V2l0aGRyYXdhbAACDiVzX193aXRoZHJhd2FsARRrZXlXaXRoZHJhd2FsUmVxdWVzdAILdXNlckFkZHJlc3MEdHhJZAkAuQkCCQDMCAICBiVzJXMlcwkAzAgCAgp3aXRoZHJhd2FsCQDMCAIJAKUIAQULdXNlckFkZHJlc3MJAMwIAgkA2AQBBQR0eElkBQNuaWwFA1NFUAEWdmFsdWVXaXRoZHJhd2FsUmVxdWVzdAQGc3RhdHVzDWxwQXNzZXRBbW91bnQMdGFyZ2V0UGVyaW9kCWNsYWltVHhJZAQMY2xhaW1UeElkU3RyBAckbWF0Y2gwBQljbGFpbVR4SWQDCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQBYgUHJG1hdGNoMAkA2AQBBQFiAwkAAQIFByRtYXRjaDACBFVuaXQCBFNPT04JAAIBAgtNYXRjaCBlcnJvcgkAuQkCCQDMCAICCCVzJWQlZCVzCQDMCAIFBnN0YXR1cwkAzAgCCQCkAwEFDWxwQXNzZXRBbW91bnQJAMwIAgkApAMBBQx0YXJnZXRQZXJpb2QJAMwIAgUMY2xhaW1UeElkU3RyBQNuaWwFA1NFUAEba2V5UGVyaW9kV2l0aGRyYXdhbEFzc2V0SWRzAQZwZXJpb2QJALkJAgkAzAgCAgQlcyVkCQDMCAICDHBlcmlvZFJld2FyZAkAzAgCCQCkAwEFBnBlcmlvZAUDbmlsBQNTRVABGmtleVBlcmlvZFdpdGhkcmF3YWxBbW91bnRzAQZwZXJpb2QJALkJAgkAzAgCAgQlcyVkCQDMCAICEnBlcmlvZFJld2FyZEFtb3VudAkAzAgCCQCkAwEFBnBlcmlvZAUDbmlsBQNTRVAAF2tleU1pbkhlaWdodEZvcldpdGhkcmF3CQC5CQIJAMwIAgICJXMJAMwIAgIUbWluSGVpZ2h0Rm9yV2l0aGRyYXcFA25pbAUDU0VQABdrZXlNYXhIZWlnaHRGb3JXaXRoZHJhdwkAuQkCCQDMCAICAiVzCQDMCAICFG1heEhlaWdodEZvcldpdGhkcmF3BQNuaWwFA1NFUAEhcGFyc2VXaXRoZHJhd2FsUmVxdWVzdFZhbHVlT3JGYWlsAQFzBAVwYXJ0cwkAtQkCBQFzBQNTRVADCQAAAgkAkAMBBQVwYXJ0cwAFBAZzdGF0dXMJAJEDAgUFcGFydHMAAQQNbHBBc3NldEFtb3VudAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEJAJEDAgUFcGFydHMAAgkBB3dyYXBFcnIBAhVpbnZhbGlkIGxwQXNzZXRBbW91bnQEDHRhcmdldFBlcmlvZAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEJAJEDAgUFcGFydHMAAwkBB3dyYXBFcnIBAhRpbnZhbGlkIHRhcmdldFBlcmlvZAQJY2xhaW1UeElkCQCRAwIFBXBhcnRzAAQJAJYKBAUGc3RhdHVzBQ1scEFzc2V0QW1vdW50BQx0YXJnZXRQZXJpb2QFCWNsYWltVHhJZAkBCHRocm93RXJyAQIgaW52YWxpZCB3aXRoZHJhd2FsIHJlcXVlc3QgdmFsdWUAFGZhY3RvcnlBZGRyZXNzT3B0aW9uBAckbWF0Y2gwCQCdCAIFBHRoaXMJARFrZXlGYWN0b3J5QWRkcmVzcwADCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFzBQckbWF0Y2gwCQCmCAEFAXMDCQABAgUHJG1hdGNoMAIEVW5pdAUEdW5pdAkAAgECC01hdGNoIGVycm9yABRmYWN0b3J5QWRkcmVzc09yRmFpbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCBRRmYWN0b3J5QWRkcmVzc09wdGlvbgkBB3dyYXBFcnIBAhdpbnZhbGlkIGZhY3RvcnkgYWRkcmVzcwAPbHBBc3NldElkT3B0aW9uBAckbWF0Y2gwBRRmYWN0b3J5QWRkcmVzc09wdGlvbgMJAAECBQckbWF0Y2gwAgdBZGRyZXNzBAFhBQckbWF0Y2gwBAckbWF0Y2gxCQCdCAIFAWEJAQxrZXlMcEFzc2V0SWQAAwkAAQIFByRtYXRjaDECBlN0cmluZwQBcwUHJG1hdGNoMQkA2QQBBQFzAwkAAQIFByRtYXRjaDECBFVuaXQFBHVuaXQJAAIBAgtNYXRjaCBlcnJvcgMJAAECBQckbWF0Y2gwAgRVbml0BQR1bml0CQACAQILTWF0Y2ggZXJyb3IAD2xwQXNzZXRJZE9yRmFpbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCBQ9scEFzc2V0SWRPcHRpb24JAQd3cmFwRXJyAQIRaW52YWxpZCBscEFzc2V0SWQAGnByb3h5VHJlYXN1cnlBZGRyZXNzT3B0aW9uBAckbWF0Y2gwBRRmYWN0b3J5QWRkcmVzc09wdGlvbgMJAAECBQckbWF0Y2gwAgdBZGRyZXNzBAFhBQckbWF0Y2gwBAckbWF0Y2gxCQCdCAIFAWEJARdrZXlQcm94eVRyZWFzdXJ5QWRkcmVzcwADCQABAgUHJG1hdGNoMQIGU3RyaW5nBAFzBQckbWF0Y2gxCQCmCAEFAXMDCQABAgUHJG1hdGNoMQIEVW5pdAUEdW5pdAkAAgECC01hdGNoIGVycm9yAwkAAQIFByRtYXRjaDACBFVuaXQFBHVuaXQJAAIBAgtNYXRjaCBlcnJvcgAacHJveHlUcmVhc3VyeUFkZHJlc3NPckZhaWwJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgUacHJveHlUcmVhc3VyeUFkZHJlc3NPcHRpb24JAQd3cmFwRXJyAQIeaW52YWxpZCBwcm94eSB0cmVhc3VyeSBhZGRyZXNzABltYWluVHJlYXN1cnlBZGRyZXNzT3B0aW9uBAckbWF0Y2gwBRRmYWN0b3J5QWRkcmVzc09wdGlvbgMJAAECBQckbWF0Y2gwAgdBZGRyZXNzBAFhBQckbWF0Y2gwBAckbWF0Y2gxCQCdCAIFAWEJARZrZXlNYWluVHJlYXN1cnlBZGRyZXNzAAMJAAECBQckbWF0Y2gxAgZTdHJpbmcEAXMFByRtYXRjaDEJAKYIAQUBcwMJAAECBQckbWF0Y2gxAgRVbml0BQR1bml0CQACAQILTWF0Y2ggZXJyb3IDCQABAgUHJG1hdGNoMAIEVW5pdAUEdW5pdAkAAgECC01hdGNoIGVycm9yABltYWluVHJlYXN1cnlBZGRyZXNzT3JGYWlsCQETdmFsdWVPckVycm9yTWVzc2FnZQIFGW1haW5UcmVhc3VyeUFkZHJlc3NPcHRpb24JAQd3cmFwRXJyAQIdaW52YWxpZCBtYWluIHRyZWFzdXJ5IGFkZHJlc3MBGWdldE1hbmFnZXJQdWJsaWNLZXlPclVuaXQABAckbWF0Y2gwBRRmYWN0b3J5QWRkcmVzc09wdGlvbgMJAAECBQckbWF0Y2gwAgdBZGRyZXNzBAJmYQUHJG1hdGNoMAQHJG1hdGNoMQkAnQgCBQJmYQkBE2tleU1hbmFnZXJQdWJsaWNLZXkAAwkAAQIFByRtYXRjaDECBlN0cmluZwQDcHViBQckbWF0Y2gxCQDZBAEFA3B1YgUEdW5pdAUEdW5pdAELb25seUFkZHJlc3MCAWkHYWRkcmVzcwMJAAACCAUBaQZjYWxsZXIFB2FkZHJlc3MGCQEIdGhyb3dFcnIBAhFwZXJtaXNzaW9uIGRlbmllZAELb25seUZhY3RvcnkBAWkJAQtvbmx5QWRkcmVzcwIFAWkFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAQ9yZXdhcmRGb3JPcHRpb24CB3Jld2FyZHMGdGFyZ2V0BAFzCQCQAwEFB3Jld2FyZHMECyR0MDUyMDg1MjMzCQCRAwIFB3Jld2FyZHMAAAQCYTAIBQskdDA1MjA4NTIzMwJfMQQCcjAIBQskdDA1MjA4NTIzMwJfMgQLJHQwNTIzNjUyNjEJAJEDAgUHcmV3YXJkcwABBAJhMQgFCyR0MDUyMzY1MjYxAl8xBAJyMQgFCyR0MDUyMzY1MjYxAl8yBAskdDA1MjY0NTI4OQkAkQMCBQdyZXdhcmRzAAIEAmEyCAULJHQwNTI2NDUyODkCXzEEAnIyCAULJHQwNTI2NDUyODkCXzIDAwkAZgIFAXMAAAkAAAIFAmEwBQZ0YXJnZXQHBQJyMAMDCQBmAgUBcwABCQAAAgUCYTEFBnRhcmdldAcFAnIxAwMJAGYCBQFzAAIJAAACBQJhMgUGdGFyZ2V0BwUCcjIFBHVuaXQBEGZpbmFsaXplSU5URVJOQUwDGG5ld1RyZWFzdXJ5Vm9sdW1lSW5XYXZlcxdwd3JNYW5hZ2Vyc0JvbnVzSW5XYXZlcyB0cmVhc3VyeVZvbHVtZURpZmZBbGxvY2F0aW9uQ29lZgQSZG9uYXRlZFdhdmVzQW1vdW50CQELdmFsdWVPckVsc2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQEKa2V5RG9uYXRlZAEFBHVuaXQAAAQTaW52ZXN0ZWRXYXZlc0Ftb3VudAkBC3ZhbHVlT3JFbHNlAgkAmggCBRRmYWN0b3J5QWRkcmVzc09yRmFpbAkBC2tleUludmVzdGVkAQUEdW5pdAAABBxjdXJyZW50VHJlYXN1cnlWb2x1bWVJbldhdmVzCQBkAgUSZG9uYXRlZFdhdmVzQW1vdW50BRNpbnZlc3RlZFdhdmVzQW1vdW50BAlwcm9maXRSYXcJAGUCBRhuZXdUcmVhc3VyeVZvbHVtZUluV2F2ZXMFHGN1cnJlbnRUcmVhc3VyeVZvbHVtZUluV2F2ZXMEFnB3ck1hbmFnZXJzQm9udXNBbW91bnQDAwkAZwIFCXByb2ZpdFJhdwUXcHdyTWFuYWdlcnNCb251c0luV2F2ZXMGCQAAAgUXcHdyTWFuYWdlcnNCb251c0luV2F2ZXMAAAUXcHdyTWFuYWdlcnNCb251c0luV2F2ZXMJAQh0aHJvd0VycgECH3Bvd2VyIGJvbnVzIGlzIG1vcmUgdGhhbiBwcm9maXQEBnByb2ZpdAkAZQIFCXByb2ZpdFJhdwUWcHdyTWFuYWdlcnNCb251c0Ftb3VudAQMZG9uYXRpb25QYXJ0AwkAZgIFHGN1cnJlbnRUcmVhc3VyeVZvbHVtZUluV2F2ZXMAAAkAawMFEmRvbmF0ZWRXYXZlc0Ftb3VudAUGU0NBTEU4BRxjdXJyZW50VHJlYXN1cnlWb2x1bWVJbldhdmVzAAAEFWRvbmF0aW9uUHJvZml0UGFydFJhdwkAawMFBnByb2ZpdAUMZG9uYXRpb25QYXJ0BQZTQ0FMRTgEF2ludmVzdG1lbnRQcm9maXRQYXJ0UmF3CQBlAgUGcHJvZml0BRVkb25hdGlvblByb2ZpdFBhcnRSYXcEI3RyZWFzdXJ5Vm9sdW1lRGlmZkFsbG9jYXRpb25Db2VmQWJzCQEDYWJzAQUgdHJlYXN1cnlWb2x1bWVEaWZmQWxsb2NhdGlvbkNvZWYEEGFtb3VudFRvRG9uYXRpb24JAGsDBRdpbnZlc3RtZW50UHJvZml0UGFydFJhdwMJAGYCAAAFIHRyZWFzdXJ5Vm9sdW1lRGlmZkFsbG9jYXRpb25Db2VmBSN0cmVhc3VyeVZvbHVtZURpZmZBbGxvY2F0aW9uQ29lZkFicwAABQZTQ0FMRTgEEmFtb3VudFRvSW52ZXN0bWVudAkAawMFFWRvbmF0aW9uUHJvZml0UGFydFJhdwMJAGYCBSB0cmVhc3VyeVZvbHVtZURpZmZBbGxvY2F0aW9uQ29lZgAABSN0cmVhc3VyeVZvbHVtZURpZmZBbGxvY2F0aW9uQ29lZkFicwAABQZTQ0FMRTgEEmRvbmF0aW9uUHJvZml0UGFydAkAZAIJAGUCBRVkb25hdGlvblByb2ZpdFBhcnRSYXcFEmFtb3VudFRvSW52ZXN0bWVudAUQYW1vdW50VG9Eb25hdGlvbgQUaW52ZXN0bWVudFByb2ZpdFBhcnQJAGQCCQBlAgUXaW52ZXN0bWVudFByb2ZpdFBhcnRSYXcFEGFtb3VudFRvRG9uYXRpb24FEmFtb3VudFRvSW52ZXN0bWVudAQYZG9uYXRlZFdhdmVzQW1vdW50TmV3UmF3CQBkAgUSZG9uYXRlZFdhdmVzQW1vdW50BRJkb25hdGlvblByb2ZpdFBhcnQEGWludmVzdGVkV2F2ZXNBbW91bnROZXdSYXcJAGQCBRNpbnZlc3RlZFdhdmVzQW1vdW50BRRpbnZlc3RtZW50UHJvZml0UGFydAQPZG9uYXRlZFBhcnREZWJ0CQCXAwEJAMwIAgAACQDMCAIFGGRvbmF0ZWRXYXZlc0Ftb3VudE5ld1JhdwUDbmlsBBBpbnZlc3RlZFBhcnREZWJ0CQCXAwEJAMwIAgAACQDMCAIFGWludmVzdGVkV2F2ZXNBbW91bnROZXdSYXcFA25pbAQVZG9uYXRlZFdhdmVzQW1vdW50TmV3CQBkAgkAlgMBCQDMCAIAAAkAzAgCBRhkb25hdGVkV2F2ZXNBbW91bnROZXdSYXcFA25pbAUQaW52ZXN0ZWRQYXJ0RGVidAQWaW52ZXN0ZWRXYXZlc0Ftb3VudE5ldwkAZAIJAJYDAQkAzAgCAAAJAMwIAgUZaW52ZXN0ZWRXYXZlc0Ftb3VudE5ld1JhdwUDbmlsBQ9kb25hdGVkUGFydERlYnQED2xwQXNzZXRRdWFudGl0eQgJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkA7AcBBQ9scEFzc2V0SWRPckZhaWwJAQd3cmFwRXJyAQIUaW52YWxpZCBscEFzc2V0IGluZm8IcXVhbnRpdHkECG5ld1ByaWNlCQBrAwUWaW52ZXN0ZWRXYXZlc0Ftb3VudE5ldwUGU0NBTEU4BQ9scEFzc2V0UXVhbnRpdHkEE2NoZWNrSWZQcmljZU5vdFplcm8DCQECIT0CBQhuZXdQcmljZQAABgkBCHRocm93RXJyAQIUTFAgcHJpY2UgY2Fubm90IGJlIDADCQAAAgUTY2hlY2tJZlByaWNlTm90WmVybwUTY2hlY2tJZlByaWNlTm90WmVybwQTbHBBc3NldEFtb3VudFRvQnVybgkBC3ZhbHVlT3JFbHNlAgkAmggCBRRmYWN0b3J5QWRkcmVzc09yRmFpbAkBDWtleVdpdGhkcmF3YWwAAAAEEHBheW1lbnRBbW91bnRNaW4JAJYDAQkAzAgCAAAJAMwIAgkAawMFE2xwQXNzZXRBbW91bnRUb0J1cm4FCG5ld1ByaWNlBQZTQ0FMRTgFA25pbAQYZmluYWxJbnZlc3RlZFdhdmVzQW1vdW50CQBlAgUWaW52ZXN0ZWRXYXZlc0Ftb3VudE5ldwUQcGF5bWVudEFtb3VudE1pbgQUbHBBc3NldEZpbmFsUXVhbnRpdHkJAGUCBQ9scEFzc2V0UXVhbnRpdHkFE2xwQXNzZXRBbW91bnRUb0J1cm4JAJgKBgUQcGF5bWVudEFtb3VudE1pbgUYZmluYWxJbnZlc3RlZFdhdmVzQW1vdW50BRVkb25hdGVkV2F2ZXNBbW91bnROZXcFCG5ld1ByaWNlBRNscEFzc2V0QW1vdW50VG9CdXJuBRRscEFzc2V0RmluYWxRdWFudGl0eQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLggBaQEHY2xhaW1MUAEQdXNlckFkZHJlc3NCeXRlcwQLY2hlY2tDYWxsZXIJAQtvbmx5RmFjdG9yeQEFAWkDCQAAAgULY2hlY2tDYWxsZXIFC2NoZWNrQ2FsbGVyBAt1c2VyQWRkcmVzcwkBB0FkZHJlc3MBBRB1c2VyQWRkcmVzc0J5dGVzBAlhdmFpbGFibGUJAQt2YWx1ZU9yRWxzZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJAQxrZXlBdmFpbGFibGUBBQt1c2VyQWRkcmVzcwAABAdjbGFpbWVkCQELdmFsdWVPckVsc2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQEKa2V5Q2xhaW1lZAEFC3VzZXJBZGRyZXNzAAAEDmZhY3RvcnlBY3Rpb25zAwkAZgIFCWF2YWlsYWJsZQAACQDMCAIJAPwHBAUUZmFjdG9yeUFkZHJlc3NPckZhaWwCDXRyYW5zZmVyQXNzZXQJAMwIAgUQdXNlckFkZHJlc3NCeXRlcwkAzAgCBQlhdmFpbGFibGUJAMwIAgUPbHBBc3NldElkT3JGYWlsBQNuaWwFA25pbAkAzAgCCQD8BwQFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAgxpbnRlZ2VyRW50cnkJAMwIAgkBDGtleUF2YWlsYWJsZQEFC3VzZXJBZGRyZXNzCQDMCAIAAAUDbmlsBQNuaWwJAMwIAgkA/AcEBRRmYWN0b3J5QWRkcmVzc09yRmFpbAIMaW50ZWdlckVudHJ5CQDMCAIJAQprZXlDbGFpbWVkAQULdXNlckFkZHJlc3MJAMwIAgkAZAIFB2NsYWltZWQFCWF2YWlsYWJsZQUDbmlsBQNuaWwFA25pbAkBCHRocm93RXJyAQIQbm90aGluZyB0byBjbGFpbQkAlAoCBQNuaWwFDmZhY3RvcnlBY3Rpb25zCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCGZpbmFsaXplBBB1c2VyQWRkcmVzc0J5dGVzGG5ld1RyZWFzdXJ5Vm9sdW1lSW5XYXZlcxdwd3JNYW5hZ2Vyc0JvbnVzSW5XYXZlcyB0cmVhc3VyeVZvbHVtZURpZmZBbGxvY2F0aW9uQ29lZgQLY2hlY2tDYWxsZXIJAQtvbmx5RmFjdG9yeQEFAWkDCQAAAgULY2hlY2tDYWxsZXIFC2NoZWNrQ2FsbGVyBBNjdXJyZW50UGVyaW9kT3JGYWlsCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJARBrZXlDdXJyZW50UGVyaW9kAAkBB3dyYXBFcnIBAg5pbnZhbGlkIHBlcmlvZAQMcGVyaW9kTGVuZ3RoCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJAQ9rZXlQZXJpb2RMZW5ndGgACQEHd3JhcEVycgECFWludmFsaWQgcGVyaW9kIGxlbmd0aAQSY3VycmVudFN0YXJ0SGVpZ2h0CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJAQ5rZXlTdGFydEhlaWdodAEFE2N1cnJlbnRQZXJpb2RPckZhaWwJAQd3cmFwRXJyAQIUaW52YWxpZCBzdGFydCBoZWlnaHQEEmN1cnJlbnRQcmljZU9yRmFpbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQERa2V5UHJpY2VGb3JQZXJpb2QBBRNjdXJyZW50UGVyaW9kT3JGYWlsCQEHd3JhcEVycgECDWludmFsaWQgcHJpY2UEEm5leHRCbG9ja1RvUHJvY2VzcwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQEVa2V5TmV4dEJsb2NrVG9Qcm9jZXNzAAkBB3dyYXBFcnIBAh1pbnZhbGlkIG5leHQgYmxvY2sgdG8gcHJvY2VzcwQPcGVyaW9kRW5kSGVpZ2h0CQBlAgkAZAIFEmN1cnJlbnRTdGFydEhlaWdodAUMcGVyaW9kTGVuZ3RoAAEEBmNoZWNrcwkAzAgCAwkAAAIIBQFpDG9yaWdpbkNhbGxlcgUZbWFpblRyZWFzdXJ5QWRkcmVzc09yRmFpbAYJAQh0aHJvd0VycgECEXBlcm1pc3Npb24gZGVuaWVkCQDMCAIDCQBmAgUSbmV4dEJsb2NrVG9Qcm9jZXNzBQ9wZXJpb2RFbmRIZWlnaHQGCQEIdGhyb3dFcnIBAhJ1bnByb2Nlc3NlZCBibG9ja3MJAMwIAgMJAGcCBRhuZXdUcmVhc3VyeVZvbHVtZUluV2F2ZXMAAAYJAQh0aHJvd0VycgECG2ludmFsaWQgbmV3IHRyZWFzdXJ5IHZvbHVtZQkAzAgCAwkAZwIFF3B3ck1hbmFnZXJzQm9udXNJbldhdmVzAAAGCQEIdGhyb3dFcnIBAhppbnZhbGlkIFBXUiBtYW5hZ2VycyBib251cwkAzAgCAwMJAGcCBSB0cmVhc3VyeVZvbHVtZURpZmZBbGxvY2F0aW9uQ29lZgkBAS0BBQZTQ0FMRTgJAGcCBQZTQ0FMRTgFIHRyZWFzdXJ5Vm9sdW1lRGlmZkFsbG9jYXRpb25Db2VmBwYJAQh0aHJvd0VycgECM2ludmFsaWQgdHJlYXN1cnkgdm9sdW1lIGRpZmYgYWxsb2NhdGlvbiBjb2VmZmljaWVudAUDbmlsAwkAAAIFBmNoZWNrcwUGY2hlY2tzBA0kdDAxMDc4MzExMDQzCQEQZmluYWxpemVJTlRFUk5BTAMFGG5ld1RyZWFzdXJ5Vm9sdW1lSW5XYXZlcwUXcHdyTWFuYWdlcnNCb251c0luV2F2ZXMFIHRyZWFzdXJ5Vm9sdW1lRGlmZkFsbG9jYXRpb25Db2VmBBBwYXltZW50QW1vdW50TWluCAUNJHQwMTA3ODMxMTA0MwJfMQQYZmluYWxJbnZlc3RlZFdhdmVzQW1vdW50CAUNJHQwMTA3ODMxMTA0MwJfMgQVZG9uYXRlZFdhdmVzQW1vdW50TmV3CAUNJHQwMTA3ODMxMTA0MwJfMwQIbmV3UHJpY2UIBQ0kdDAxMDc4MzExMDQzAl80BBNscEFzc2V0QW1vdW50VG9CdXJuCAUNJHQwMTA3ODMxMTA0MwJfNQQUbHBBc3NldEZpbmFsUXVhbnRpdHkIBQ0kdDAxMDc4MzExMDQzAl82BAluZXdQZXJpb2QJAGQCBRNjdXJyZW50UGVyaW9kT3JGYWlsAAEKAQxhZGROZXdBY3Rpb24CB2FjdGlvbnMHcGF5bWVudAQNJHQwMTExOTExMTI1MwUHYWN0aW9ucwQPc2NyaXB0VHJhbnNmZXJzCAUNJHQwMTExOTExMTI1MwJfMQQOYXNzZXRJZHNTdHJpbmcIBQ0kdDAxMTE5MTExMjUzAl8yBA1hbW91bnRzU3RyaW5nCAUNJHQwMTExOTExMTI1MwJfMwQNcGF5bWVudEFtb3VudAgFB3BheW1lbnQGYW1vdW50BA5wYXltZW50QXNzZXRJZAgFB3BheW1lbnQHYXNzZXRJZAQRbmV3QXNzZXRJZHNTdHJpbmcJAKwCAgICJXMJALkJAgkAzAgCBQ5hc3NldElkc1N0cmluZwkAzAgCCQEPYXNzZXRJZFRvU3RyaW5nAQUOcGF5bWVudEFzc2V0SWQFA25pbAUDU0VQBBBuZXdBbW91bnRzU3RyaW5nCQCsAgICAiVkCQC5CQIJAMwIAgUNYW1vdW50c1N0cmluZwkAzAgCCQCkAwEFDXBheW1lbnRBbW91bnQFA25pbAUDU0VQBBFuZXdTY3JpcHRUcmFuc2ZlcgkBDlNjcmlwdFRyYW5zZmVyAwUUZmFjdG9yeUFkZHJlc3NPckZhaWwFDXBheW1lbnRBbW91bnQFDnBheW1lbnRBc3NldElkCQCVCgMJAM0IAgUPc2NyaXB0VHJhbnNmZXJzBRFuZXdTY3JpcHRUcmFuc2ZlcgURbmV3QXNzZXRJZHNTdHJpbmcFEG5ld0Ftb3VudHNTdHJpbmcEDSR0MDExNzEzMTE4MDQKAAIkbAgFAWkIcGF5bWVudHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwCQCVCgMFA25pbAIAAgAKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBDGFkZE5ld0FjdGlvbgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgQPc2NyaXB0VHJhbnNmZXJzCAUNJHQwMTE3MTMxMTgwNAJfMQQIQXNzZXRJZHMIBQ0kdDAxMTcxMzExODA0Al8yBAdBbW91bnRzCAUNJHQwMTE3MTMxMTgwNAJfMwQOZmFjdG9yeUFjdGlvbnMJAMwIAgkA/AcEBRRmYWN0b3J5QWRkcmVzc09yRmFpbAIMaW50ZWdlckVudHJ5CQDMCAIJARRrZXlQb3dlck1hbmFnZXJCb251cwEFE2N1cnJlbnRQZXJpb2RPckZhaWwJAMwIAgUXcHdyTWFuYWdlcnNCb251c0luV2F2ZXMFA25pbAUDbmlsCQDMCAIJAPwHBAUUZmFjdG9yeUFkZHJlc3NPckZhaWwCDGludGVnZXJFbnRyeQkAzAgCCQEQa2V5Q3VycmVudFBlcmlvZAAJAMwIAgUJbmV3UGVyaW9kBQNuaWwFA25pbAkAzAgCCQD8BwQFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAgxpbnRlZ2VyRW50cnkJAMwIAgkBEWtleVByaWNlRm9yUGVyaW9kAQUJbmV3UGVyaW9kCQDMCAIFCG5ld1ByaWNlBQNuaWwFA25pbAkAzAgCCQD8BwQFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAgxpbnRlZ2VyRW50cnkJAMwIAgkBDmtleVN0YXJ0SGVpZ2h0AQUJbmV3UGVyaW9kCQDMCAIJAGQCBQ9wZXJpb2RFbmRIZWlnaHQAAQUDbmlsBQNuaWwJAMwIAgkA/AcEBRRmYWN0b3J5QWRkcmVzc09yRmFpbAIEYnVybgkAzAgCBRNscEFzc2V0QW1vdW50VG9CdXJuBQNuaWwFA25pbAkAzAgCCQD8BwQFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAgxpbnRlZ2VyRW50cnkJAMwIAgkBDWtleVdpdGhkcmF3YWwACQDMCAIAAAUDbmlsBQNuaWwJAMwIAgkA/AcEBRRmYWN0b3J5QWRkcmVzc09yRmFpbAIMaW50ZWdlckVudHJ5CQDMCAIJAQtrZXlJbnZlc3RlZAEFBHVuaXQJAMwIAgUYZmluYWxJbnZlc3RlZFdhdmVzQW1vdW50BQNuaWwFA25pbAkAzAgCCQD8BwQFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAgxpbnRlZ2VyRW50cnkJAMwIAgkBCmtleURvbmF0ZWQBBQR1bml0CQDMCAIFFWRvbmF0ZWRXYXZlc0Ftb3VudE5ldwUDbmlsBQNuaWwJAMwIAgkA/AcEBRRmYWN0b3J5QWRkcmVzc09yRmFpbAILc3RyaW5nRW50cnkJAMwIAgkBG2tleVBlcmlvZFdpdGhkcmF3YWxBc3NldElkcwEFCW5ld1BlcmlvZAkAzAgCBQhBc3NldElkcwUDbmlsBQNuaWwJAMwIAgkA/AcEBRRmYWN0b3J5QWRkcmVzc09yRmFpbAILc3RyaW5nRW50cnkJAMwIAgkBGmtleVBlcmlvZFdpdGhkcmF3YWxBbW91bnRzAQUJbmV3UGVyaW9kCQDMCAIFB0Ftb3VudHMFA25pbAUDbmlsBQNuaWwJAJQKAgUPc2NyaXB0VHJhbnNmZXJzBQ5mYWN0b3J5QWN0aW9ucwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARBmaW5hbGl6ZVJFQURPTkxZAxhuZXdUcmVhc3VyeVZvbHVtZUluV2F2ZXMXcHdyTWFuYWdlcnNCb251c0luV2F2ZXMgdHJlYXN1cnlWb2x1bWVEaWZmQWxsb2NhdGlvbkNvZWYEE2N1cnJlbnRQZXJpb2RPckZhaWwJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBRRmYWN0b3J5QWRkcmVzc09yRmFpbAkBEGtleUN1cnJlbnRQZXJpb2QACQEHd3JhcEVycgECDmludmFsaWQgcGVyaW9kBAxwZXJpb2RMZW5ndGgJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBRRmYWN0b3J5QWRkcmVzc09yRmFpbAkBD2tleVBlcmlvZExlbmd0aAAJAQd3cmFwRXJyAQIVaW52YWxpZCBwZXJpb2QgbGVuZ3RoBBJjdXJyZW50U3RhcnRIZWlnaHQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBRRmYWN0b3J5QWRkcmVzc09yRmFpbAkBDmtleVN0YXJ0SGVpZ2h0AQUTY3VycmVudFBlcmlvZE9yRmFpbAkBB3dyYXBFcnIBAhRpbnZhbGlkIHN0YXJ0IGhlaWdodAQSY3VycmVudFByaWNlT3JGYWlsCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJARFrZXlQcmljZUZvclBlcmlvZAEFE2N1cnJlbnRQZXJpb2RPckZhaWwJAQd3cmFwRXJyAQINaW52YWxpZCBwcmljZQQSbmV4dEJsb2NrVG9Qcm9jZXNzCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJARVrZXlOZXh0QmxvY2tUb1Byb2Nlc3MACQEHd3JhcEVycgECHWludmFsaWQgbmV4dCBibG9jayB0byBwcm9jZXNzBA9wZXJpb2RFbmRIZWlnaHQJAGUCCQBkAgUSY3VycmVudFN0YXJ0SGVpZ2h0BQxwZXJpb2RMZW5ndGgAAQQGY2hlY2tzCQDMCAIDCQBmAgUSbmV4dEJsb2NrVG9Qcm9jZXNzBQ9wZXJpb2RFbmRIZWlnaHQGCQEIdGhyb3dFcnIBAhJ1bnByb2Nlc3NlZCBibG9ja3MJAMwIAgMJAGcCBRhuZXdUcmVhc3VyeVZvbHVtZUluV2F2ZXMAAAYJAQh0aHJvd0VycgECG2ludmFsaWQgbmV3IHRyZWFzdXJ5IHZvbHVtZQkAzAgCAwkAZwIFF3B3ck1hbmFnZXJzQm9udXNJbldhdmVzAAAGCQEIdGhyb3dFcnIBAhppbnZhbGlkIFBXUiBtYW5hZ2VycyBib251cwkAzAgCAwMJAGcCBSB0cmVhc3VyeVZvbHVtZURpZmZBbGxvY2F0aW9uQ29lZgkBAS0BBQZTQ0FMRTgJAGcCBQZTQ0FMRTgFIHRyZWFzdXJ5Vm9sdW1lRGlmZkFsbG9jYXRpb25Db2VmBwYJAQh0aHJvd0VycgECM2ludmFsaWQgdHJlYXN1cnkgdm9sdW1lIGRpZmYgYWxsb2NhdGlvbiBjb2VmZmljaWVudAUDbmlsAwkAAAIFBmNoZWNrcwUGY2hlY2tzCQCUCgIFA25pbAkBEGZpbmFsaXplSU5URVJOQUwDBRhuZXdUcmVhc3VyeVZvbHVtZUluV2F2ZXMFF3B3ck1hbmFnZXJzQm9udXNJbldhdmVzBSB0cmVhc3VyeVZvbHVtZURpZmZBbGxvY2F0aW9uQ29lZgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQZpbnZlc3QBEHVzZXJBZGRyZXNzQnl0ZXMEC2NoZWNrQ2FsbGVyCQELb25seUZhY3RvcnkBBQFpAwkAAAIFC2NoZWNrQ2FsbGVyBQtjaGVja0NhbGxlcgQLdXNlckFkZHJlc3MJAQdBZGRyZXNzAQUQdXNlckFkZHJlc3NCeXRlcwQTY3VycmVudFBlcmlvZE9yRmFpbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQEQa2V5Q3VycmVudFBlcmlvZAAJAQd3cmFwRXJyAQIOaW52YWxpZCBwZXJpb2QEEmN1cnJlbnRQcmljZU9yRmFpbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQERa2V5UHJpY2VGb3JQZXJpb2QBBRNjdXJyZW50UGVyaW9kT3JGYWlsCQEHd3JhcEVycgECDWludmFsaWQgcHJpY2UEB3BheW1lbnQDCQAAAgkAkAMBCAUBaQhwYXltZW50cwABCQCRAwIIBQFpCHBheW1lbnRzAAAJAQh0aHJvd0VycgECEGludmFsaWQgcGF5bWVudHMEDSR0MDE1Mjg1MTU0NjIDAwkAAAIIBQdwYXltZW50B2Fzc2V0SWQFBHVuaXQJAGYCCAUHcGF5bWVudAZhbW91bnQAAAcJAJQKAggFB3BheW1lbnQGYW1vdW50CAUHcGF5bWVudAdhc3NldElkCQEIdGhyb3dFcnIBAhZpbnZhbGlkIHBheW1lbnQgYW1vdW50BA1wYXltZW50QW1vdW50CAUNJHQwMTUyODUxNTQ2MgJfMQQOcGF5bWVudEFzc2V0SWQIBQ0kdDAxNTI4NTE1NDYyAl8yBA1scEFzc2V0QW1vdW50AwkAZgIFEmN1cnJlbnRQcmljZU9yRmFpbAAACQBrAwUNcGF5bWVudEFtb3VudAUGU0NBTEU4BRJjdXJyZW50UHJpY2VPckZhaWwAAAQIaW52ZXN0ZWQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJAQtrZXlJbnZlc3RlZAEFBHVuaXQAAAQHYWN0aW9ucwkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDBRltYWluVHJlYXN1cnlBZGRyZXNzT3JGYWlsBQ1wYXltZW50QW1vdW50BQ5wYXltZW50QXNzZXRJZAUDbmlsBA5mYWN0b3J5QWN0aW9ucwkAzAgCCQD8BwQFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAgxpbnRlZ2VyRW50cnkJAMwIAgkBC2tleUludmVzdGVkAQUEdW5pdAkAzAgCCQBkAgUIaW52ZXN0ZWQFDXBheW1lbnRBbW91bnQFA25pbAUDbmlsCQDMCAIJAPwHBAUUZmFjdG9yeUFkZHJlc3NPckZhaWwCB3JlaXNzdWUJAMwIAgUNbHBBc3NldEFtb3VudAUDbmlsBQNuaWwJAMwIAgkA/AcEBRRmYWN0b3J5QWRkcmVzc09yRmFpbAINdHJhbnNmZXJBc3NldAkAzAgCBRB1c2VyQWRkcmVzc0J5dGVzCQDMCAIFDWxwQXNzZXRBbW91bnQJAMwIAgUPbHBBc3NldElkT3JGYWlsBQNuaWwFA25pbAUDbmlsCQCUCgIFB2FjdGlvbnMFDmZhY3RvcnlBY3Rpb25zCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCHdpdGhkcmF3ARB1c2VyQWRkcmVzc0J5dGVzBAtjaGVja0NhbGxlcgkBC29ubHlGYWN0b3J5AQUBaQMJAAACBQtjaGVja0NhbGxlcgULY2hlY2tDYWxsZXIEC3VzZXJBZGRyZXNzCQEHQWRkcmVzcwEFEHVzZXJBZGRyZXNzQnl0ZXMEE2N1cnJlbnRQZXJpb2RPckZhaWwJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBRRmYWN0b3J5QWRkcmVzc09yRmFpbAkBEGtleUN1cnJlbnRQZXJpb2QACQEHd3JhcEVycgECDmludmFsaWQgcGVyaW9kBAdwYXltZW50AwkAAAIJAJADAQgFAWkIcGF5bWVudHMAAQkAkQMCCAUBaQhwYXltZW50cwAACQEIdGhyb3dFcnIBCQEHd3JhcEVycgECEGludmFsaWQgcGF5bWVudHMEDnBheW1lbnRBc3NldElkAwkAAAIIBQdwYXltZW50B2Fzc2V0SWQFD2xwQXNzZXRJZE9yRmFpbAUPbHBBc3NldElkT3JGYWlsCQEIdGhyb3dFcnIBAhVpbnZhbGlkIHBheW1lbnQgYXNzZXQEDXBheW1lbnRBbW91bnQDCQBmAggFB3BheW1lbnQGYW1vdW50AAAIBQdwYXltZW50BmFtb3VudAkBCHRocm93RXJyAQIWaW52YWxpZCBwYXltZW50IGFtb3VudAQKd2l0aGRyYXdhbAkBC3ZhbHVlT3JFbHNlAgkAmggCBRRmYWN0b3J5QWRkcmVzc09yRmFpbAkBDWtleVdpdGhkcmF3YWwAAAAEB2FjdGlvbnMJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwUUZmFjdG9yeUFkZHJlc3NPckZhaWwFDXBheW1lbnRBbW91bnQFDnBheW1lbnRBc3NldElkBQNuaWwEDmZhY3RvcnlBY3Rpb25zCQDMCAIJAPwHBAUUZmFjdG9yeUFkZHJlc3NPckZhaWwCDGludGVnZXJFbnRyeQkAzAgCCQENa2V5V2l0aGRyYXdhbAAJAMwIAgkAZAIFCndpdGhkcmF3YWwFDXBheW1lbnRBbW91bnQFA25pbAUDbmlsCQDMCAIJAPwHBAUUZmFjdG9yeUFkZHJlc3NPckZhaWwCC3N0cmluZ0VudHJ5CQDMCAIJARRrZXlXaXRoZHJhd2FsUmVxdWVzdAIFC3VzZXJBZGRyZXNzCAUBaQ10cmFuc2FjdGlvbklkCQDMCAIJARZ2YWx1ZVdpdGhkcmF3YWxSZXF1ZXN0BAUHUEVORElORwUNcGF5bWVudEFtb3VudAkAZAIFE2N1cnJlbnRQZXJpb2RPckZhaWwAAQUEdW5pdAUDbmlsBQNuaWwFA25pbAMJAAACBQ5mYWN0b3J5QWN0aW9ucwUOZmFjdG9yeUFjdGlvbnMJAJQKAgUHYWN0aW9ucwUOZmFjdG9yeUFjdGlvbnMJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEOY2FuY2VsV2l0aGRyYXcCEHVzZXJBZGRyZXNzQnl0ZXMEdHhJZAQLY2hlY2tDYWxsZXIJAQtvbmx5RmFjdG9yeQEFAWkDCQAAAgULY2hlY2tDYWxsZXIFC2NoZWNrQ2FsbGVyBAt1c2VyQWRkcmVzcwkBB0FkZHJlc3MBBRB1c2VyQWRkcmVzc0J5dGVzBBd3aXRoZHJhd2FsUmVxdWVzdE9wdGlvbgkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQEUa2V5V2l0aGRyYXdhbFJlcXVlc3QCBQt1c2VyQWRkcmVzcwUEdHhJZAkBB3dyYXBFcnIBAhppbnZhbGlkIHdpdGhkcmF3YWwgcmVxdWVzdAQTY3VycmVudFBlcmlvZE9yRmFpbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQEQa2V5Q3VycmVudFBlcmlvZAAJAQd3cmFwRXJyAQIOaW52YWxpZCBwZXJpb2QEDSR0MDE3ODY5MTc5ODIJASFwYXJzZVdpdGhkcmF3YWxSZXF1ZXN0VmFsdWVPckZhaWwBBRd3aXRoZHJhd2FsUmVxdWVzdE9wdGlvbgQGc3RhdHVzCAUNJHQwMTc4NjkxNzk4MgJfMQQNbHBBc3NldEFtb3VudAgFDSR0MDE3ODY5MTc5ODICXzIEDHRhcmdldFBlcmlvZAgFDSR0MDE3ODY5MTc5ODICXzMECWNsYWltVHhJZAgFDSR0MDE3ODY5MTc5ODICXzQEBmNoZWNrcwkAzAgCAwkAAAIFBnN0YXR1cwUHUEVORElORwYJAQh0aHJvd0VycgECIWludmFsaWQgd2l0aGRyYXdhbCByZXF1ZXN0IHN0YXR1cwkAzAgCAwkAZgIFDHRhcmdldFBlcmlvZAUTY3VycmVudFBlcmlvZE9yRmFpbAYJAQh0aHJvd0VycgECIWludmFsaWQgd2l0aGRyYXdhbCByZXF1ZXN0IHBlcmlvZAUDbmlsAwkAAAIFBmNoZWNrcwUGY2hlY2tzBAp3aXRoZHJhd2FsCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJAQ1rZXlXaXRoZHJhd2FsAAkBB3dyYXBFcnIBAh9pbnZhbGlkIHRvdGFsIHdpdGhkcmF3YWwgYW1vdW50BA5mYWN0b3J5QWN0aW9ucwkAzAgCCQD8BwQFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAgxpbnRlZ2VyRW50cnkJAMwIAgkBDWtleVdpdGhkcmF3YWwACQDMCAIDCQBnAgUKd2l0aGRyYXdhbAUNbHBBc3NldEFtb3VudAkAZQIFCndpdGhkcmF3YWwFDWxwQXNzZXRBbW91bnQJAQh0aHJvd0VycgECGWludmFsaWQgd2l0aGRyYXdhbCBhbW91bnQFA25pbAUDbmlsCQDMCAIJAPwHBAUUZmFjdG9yeUFkZHJlc3NPckZhaWwCC2RlbGV0ZUVudHJ5CQDMCAIJARRrZXlXaXRoZHJhd2FsUmVxdWVzdAIFC3VzZXJBZGRyZXNzBQR0eElkBQNuaWwFA25pbAkAzAgCCQD8BwQFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAg10cmFuc2ZlckFzc2V0CQDMCAIFEHVzZXJBZGRyZXNzQnl0ZXMJAMwIAgUNbHBBc3NldEFtb3VudAkAzAgCBQ9scEFzc2V0SWRPckZhaWwFA25pbAUDbmlsBQNuaWwDCQAAAgUOZmFjdG9yeUFjdGlvbnMFDmZhY3RvcnlBY3Rpb25zCQCUCgIFA25pbAUOZmFjdG9yeUFjdGlvbnMJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEPY2xhaW1Db2xsYXRlcmFsAhB1c2VyQWRkcmVzc0J5dGVzBHR4SWQEC2NoZWNrQ2FsbGVyCQELb25seUZhY3RvcnkBBQFpAwkAAAIFC2NoZWNrQ2FsbGVyBQtjaGVja0NhbGxlcgQLdXNlckFkZHJlc3MJAQdBZGRyZXNzAQUQdXNlckFkZHJlc3NCeXRlcwQTY3VycmVudFBlcmlvZE9yRmFpbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQEQa2V5Q3VycmVudFBlcmlvZAAJAQd3cmFwRXJyAQIOaW52YWxpZCBwZXJpb2QEF3dpdGhkcmF3YWxSZXF1ZXN0T3B0aW9uCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ0IAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJARRrZXlXaXRoZHJhd2FsUmVxdWVzdAIFC3VzZXJBZGRyZXNzBQR0eElkCQEHd3JhcEVycgECGmludmFsaWQgd2l0aGRyYXdhbCByZXF1ZXN0BA0kdDAxOTMxOTE5NDMyCQEhcGFyc2VXaXRoZHJhd2FsUmVxdWVzdFZhbHVlT3JGYWlsAQUXd2l0aGRyYXdhbFJlcXVlc3RPcHRpb24EBnN0YXR1cwgFDSR0MDE5MzE5MTk0MzICXzEEDWxwQXNzZXRBbW91bnQIBQ0kdDAxOTMxOTE5NDMyAl8yBAx0YXJnZXRQZXJpb2QIBQ0kdDAxOTMxOTE5NDMyAl8zBAljbGFpbVR4SWQIBQ0kdDAxOTMxOTE5NDMyAl80AwkAAAIFBnN0YXR1cwUIRklOSVNIRUQJAQh0aHJvd0VycgECIWludmFsaWQgd2l0aGRyYXdhbCByZXF1ZXN0IHN0YXR1cwMJAGYCBQx0YXJnZXRQZXJpb2QFE2N1cnJlbnRQZXJpb2RPckZhaWwJAQh0aHJvd0VycgECIWludmFsaWQgd2l0aGRyYXdhbCByZXF1ZXN0IHBlcmlvZAQLcHJpY2VPckZhaWwJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBRRmYWN0b3J5QWRkcmVzc09yRmFpbAkBEWtleVByaWNlRm9yUGVyaW9kAQUMdGFyZ2V0UGVyaW9kCQEHd3JhcEVycgECDWludmFsaWQgcHJpY2UEBmFtb3VudAMJAGYCBQtwcmljZU9yRmFpbAAACQBrAwUNbHBBc3NldEFtb3VudAULcHJpY2VPckZhaWwFBlNDQUxFOAAABA5mYWN0b3J5QWN0aW9ucwkAzAgCCQD8BwQFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAgtzdHJpbmdFbnRyeQkAzAgCCQEUa2V5V2l0aGRyYXdhbFJlcXVlc3QCBQt1c2VyQWRkcmVzcwUEdHhJZAkAzAgCCQEWdmFsdWVXaXRoZHJhd2FsUmVxdWVzdAQFCEZJTklTSEVEBQ1scEFzc2V0QW1vdW50BQx0YXJnZXRQZXJpb2QIBQFpDXRyYW5zYWN0aW9uSWQFA25pbAUDbmlsCQDMCAIECmFzc2V0c0xpc3QJANEIAgkAvQkCCQERQGV4dHJOYXRpdmUoMTA1MykCBRRmYWN0b3J5QWRkcmVzc09yRmFpbAkBG2tleVBlcmlvZFdpdGhkcmF3YWxBc3NldElkcwEFE2N1cnJlbnRQZXJpb2RPckZhaWwFA1NFUAAABAthbW91bnRzTGlzdAkA0QgCCQC9CQIJARFAZXh0ck5hdGl2ZSgxMDUzKQIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQEaa2V5UGVyaW9kV2l0aGRyYXdhbEFtb3VudHMBBRNjdXJyZW50UGVyaW9kT3JGYWlsBQNTRVAAAAkA/AcEBRRmYWN0b3J5QWRkcmVzc09yRmFpbAIOdHJhbnNmZXJBc3NldHMJAMwIAgUQdXNlckFkZHJlc3NCeXRlcwkAzAgCBQphc3NldHNMaXN0CQDMCAIFC2Ftb3VudHNMaXN0BQNuaWwFA25pbAUDbmlsCQCUCgIFA25pbAUOZmFjdG9yeUFjdGlvbnMJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQENcHJvY2Vzc0Jsb2NrcwEQdXNlckFkZHJlc3NCeXRlcwQLY2hlY2tDYWxsZXIJAQtvbmx5RmFjdG9yeQEFAWkDCQAAAgULY2hlY2tDYWxsZXIFC2NoZWNrQ2FsbGVyBAt1c2VyQWRkcmVzcwkBB0FkZHJlc3MBBRB1c2VyQWRkcmVzc0J5dGVzBBNjdXJyZW50UGVyaW9kT3JGYWlsCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJARBrZXlDdXJyZW50UGVyaW9kAAkBB3dyYXBFcnIBAg5pbnZhbGlkIHBlcmlvZAQMcGVyaW9kTGVuZ3RoCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJAQ9rZXlQZXJpb2RMZW5ndGgACQEHd3JhcEVycgECFWludmFsaWQgcGVyaW9kIGxlbmd0aAQSY3VycmVudFN0YXJ0SGVpZ2h0CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUUZmFjdG9yeUFkZHJlc3NPckZhaWwJAQ5rZXlTdGFydEhlaWdodAEFE2N1cnJlbnRQZXJpb2RPckZhaWwJAQd3cmFwRXJyAQIUaW52YWxpZCBzdGFydCBoZWlnaHQEEmN1cnJlbnRQcmljZU9yRmFpbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQERa2V5UHJpY2VGb3JQZXJpb2QBBRNjdXJyZW50UGVyaW9kT3JGYWlsCQEHd3JhcEVycgECDWludmFsaWQgcHJpY2UEEm5leHRCbG9ja1RvUHJvY2VzcwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQEVa2V5TmV4dEJsb2NrVG9Qcm9jZXNzAAkBB3dyYXBFcnIBAh1pbnZhbGlkIG5leHQgYmxvY2sgdG8gcHJvY2VzcwQPcGVyaW9kRW5kSGVpZ2h0CQBlAgkAZAIFEmN1cnJlbnRTdGFydEhlaWdodAUMcGVyaW9kTGVuZ3RoAAEEHGJsb2Nrc1Byb2Nlc3NpbmdCYXRjaFNpemVNYXgAKAQZYmxvY2tzUHJvY2Vzc2luZ0JhdGNoU2l6ZQMDAwkAZwIFBmhlaWdodAUSbmV4dEJsb2NrVG9Qcm9jZXNzAwkAZwIFEm5leHRCbG9ja1RvUHJvY2VzcwUSY3VycmVudFN0YXJ0SGVpZ2h0BgkAAAIFE2N1cnJlbnRQZXJpb2RPckZhaWwAAAcJAGcCBQ9wZXJpb2RFbmRIZWlnaHQFEm5leHRCbG9ja1RvUHJvY2VzcwcJAJcDAQkAzAgCCQBkAgkAZQIFD3BlcmlvZEVuZEhlaWdodAUSbmV4dEJsb2NrVG9Qcm9jZXNzAAEJAMwIAgUcYmxvY2tzUHJvY2Vzc2luZ0JhdGNoU2l6ZU1heAUDbmlsCQEIdGhyb3dFcnIBCQEHd3JhcEVycgECFGludmFsaWQgdGFyZ2V0IGJsb2NrBBVibG9ja1Byb2Nlc3NpbmdSZXdhcmQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBRRmYWN0b3J5QWRkcmVzc09yRmFpbAkBGGtleUJsb2NrUHJvY2Vzc2luZ1Jld2FyZAAJAQd3cmFwRXJyAQIfaW52YWxpZCBibG9jayBwcm9jZXNzaW5nIHJld2FyZAQgYmxvY2tQcm9jZXNzaW5nUmV3YXJkQnlHZW5lcmF0b3IJAGkCBRVibG9ja1Byb2Nlc3NpbmdSZXdhcmQFGWJsb2Nrc1Byb2Nlc3NpbmdCYXRjaFNpemUEKWJsb2NrUHJvY2Vzc2luZ1Jld2FyZEJ5R2VuZXJhdG9yUmVtYWluZGVyCQBlAgUVYmxvY2tQcm9jZXNzaW5nUmV3YXJkCQBoAgUgYmxvY2tQcm9jZXNzaW5nUmV3YXJkQnlHZW5lcmF0b3IFGWJsb2Nrc1Byb2Nlc3NpbmdCYXRjaFNpemUKAQNtYXACA2FjYwNpbmMDCQBnAgUDaW5jBRlibG9ja3NQcm9jZXNzaW5nQmF0Y2hTaXplBQNhY2MEEXRhcmdldEJsb2NrSGVpZ2h0CQBkAgUSbmV4dEJsb2NrVG9Qcm9jZXNzBQNpbmMED3RhcmdldEJsb2NrSW5mbwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQDtBwEFEXRhcmdldEJsb2NrSGVpZ2h0CQEHd3JhcEVycgECEmludmFsaWQgYmxvY2sgaW5mbwQUdHJlYXN1cnlSZXdhcmRPckZhaWwJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkBD3Jld2FyZEZvck9wdGlvbgIIBQ90YXJnZXRCbG9ja0luZm8HcmV3YXJkcwUacHJveHlUcmVhc3VyeUFkZHJlc3NPckZhaWwJAQd3cmFwRXJyAQkArAICAiNpbnZhbGlkIHRyZWFzdXJ5IHJld2FyZCBmb3IgaGVpZ2h0IAkApAMBBRF0YXJnZXRCbG9ja0hlaWdodAQJZ2VuZXJhdG9yCAUPdGFyZ2V0QmxvY2tJbmZvCWdlbmVyYXRvcgQJYXZhaWxhYmxlCQELdmFsdWVPckVsc2UCCQCaCAIFFGZhY3RvcnlBZGRyZXNzT3JGYWlsCQEMa2V5QXZhaWxhYmxlAQUJZ2VuZXJhdG9yAAAEDGNhbGxlclJld2FyZAMJAAACBQNpbmMJAGUCBRlibG9ja3NQcm9jZXNzaW5nQmF0Y2hTaXplAAEJAGQCBSBibG9ja1Byb2Nlc3NpbmdSZXdhcmRCeUdlbmVyYXRvcgUpYmxvY2tQcm9jZXNzaW5nUmV3YXJkQnlHZW5lcmF0b3JSZW1haW5kZXIFIGJsb2NrUHJvY2Vzc2luZ1Jld2FyZEJ5R2VuZXJhdG9yBA1scEFzc2V0QW1vdW50AwkAZgIFEmN1cnJlbnRQcmljZU9yRmFpbAAACQBrAwkAZQIFFHRyZWFzdXJ5UmV3YXJkT3JGYWlsBQxjYWxsZXJSZXdhcmQFBlNDQUxFOAUSY3VycmVudFByaWNlT3JGYWlsAAAEFGZhY3RvcnlBY3Rpb25zU2luZ2xlCQDMCAIJAPwHBAUUZmFjdG9yeUFkZHJlc3NPckZhaWwCC3N0cmluZ0VudHJ5CQDMCAIJARFrZXlCbG9ja1Byb2Nlc3NlZAEFEXRhcmdldEJsb2NrSGVpZ2h0CQDMCAIJALkJAgkAzAgCCQDYBAEIBQFpDXRyYW5zYWN0aW9uSWQJAMwIAgkApAMBBRNjdXJyZW50UGVyaW9kT3JGYWlsCQDMCAIJAKUIAQUJZ2VuZXJhdG9yCQDMCAIJANgEAQUQdXNlckFkZHJlc3NCeXRlcwkAzAgCCQCkAwEFFHRyZWFzdXJ5UmV3YXJkT3JGYWlsCQDMCAIJAKQDAQUMY2FsbGVyUmV3YXJkCQDMCAIJAKQDAQUNbHBBc3NldEFtb3VudAUDbmlsBQNTRVAFA25pbAUDbmlsCQDMCAIJAPwHBAUUZmFjdG9yeUFkZHJlc3NPckZhaWwCDGludGVnZXJFbnRyeQkAzAgCCQEMa2V5QXZhaWxhYmxlAQUJZ2VuZXJhdG9yCQDMCAIJAGQCBQlhdmFpbGFibGUFDWxwQXNzZXRBbW91bnQFA25pbAUDbmlsBQNuaWwDCQAAAgUUZmFjdG9yeUFjdGlvbnNTaW5nbGUFFGZhY3RvcnlBY3Rpb25zU2luZ2xlBA0kdDAyNDAwMjI0MDM1BQNhY2MECmxwQXNzZXRBY2MIBQ0kdDAyNDAwMjI0MDM1Al8xBAlyZXdhcmRBY2MIBQ0kdDAyNDAwMjI0MDM1Al8yCQCUCgIJAGQCBQpscEFzc2V0QWNjBQ1scEFzc2V0QW1vdW50CQBkAgUJcmV3YXJkQWNjBRR0cmVhc3VyeVJld2FyZE9yRmFpbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgQEbGlzdAkAzAgCAAAJAMwIAgABCQDMCAIAAgkAzAgCAAMJAMwIAgAECQDMCAIABQkAzAgCAAYJAMwIAgAHCQDMCAIACAkAzAgCAAkJAMwIAgAKCQDMCAIACwkAzAgCAAwJAMwIAgANCQDMCAIADgkAzAgCAA8JAMwIAgAQCQDMCAIAEQkAzAgCABIJAMwIAgATCQDMCAIAFAkAzAgCABUJAMwIAgAWCQDMCAIAFwkAzAgCABgJAMwIAgAZCQDMCAIAGgkAzAgCABsJAMwIAgAcCQDMCAIAHQkAzAgCAB4JAMwIAgAfCQDMCAIAIAkAzAgCACEJAMwIAgAiCQDMCAIAIwkAzAgCACQJAMwIAgAlCQDMCAIAJgkAzAgCACcFA25pbAQNJHQwMjQzMDIyNDM3OAoAAiRsBQRsaXN0CgACJHMJAJADAQUCJGwKAAUkYWNjMAkAlAoCAAAAAAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEDbWFwAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyA0MAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoAwkAAAIFDSR0MDI0MzAyMjQzNzgFDSR0MDI0MzAyMjQzNzgEEXJld2FyZEFtb3VudFRvdGFsCAUNJHQwMjQzMDIyNDM3OAJfMgQSbHBBc3NldEFtb3VudFRvdGFsCAUNJHQwMjQzMDIyNDM3OAJfMQQacmV3YXJkVG9NYWluVHJlYXN1cnlBbW91bnQJAGUCBRFyZXdhcmRBbW91bnRUb3RhbAUVYmxvY2tQcm9jZXNzaW5nUmV3YXJkBAhpbnZlc3RlZAkBC3ZhbHVlT3JFbHNlAgkAmggCBRRmYWN0b3J5QWRkcmVzc09yRmFpbAkBC2tleUludmVzdGVkAQUEdW5pdAAABAdhY3Rpb25zCQDMCAIJAPwHBAUUZmFjdG9yeUFkZHJlc3NPckZhaWwCB3JlaXNzdWUJAMwIAgUSbHBBc3NldEFtb3VudFRvdGFsBQNuaWwFA25pbAkAzAgCCQD8BwQFFGZhY3RvcnlBZGRyZXNzT3JGYWlsAgxpbnRlZ2VyRW50cnkJAMwIAgkBFWtleU5leHRCbG9ja1RvUHJvY2VzcwAJAMwIAgkAZAIFEm5leHRCbG9ja1RvUHJvY2VzcwUZYmxvY2tzUHJvY2Vzc2luZ0JhdGNoU2l6ZQUDbmlsBQNuaWwJAMwIAgkA/AcEBRRmYWN0b3J5QWRkcmVzc09yRmFpbAIZdHJhbnNmZXJGcm9tUHJveHlUcmVhc3VyeQkAzAgCCAUZbWFpblRyZWFzdXJ5QWRkcmVzc09yRmFpbAVieXRlcwkAzAgCBRpyZXdhcmRUb01haW5UcmVhc3VyeUFtb3VudAUDbmlsBQNuaWwJAMwIAgkA/AcEBRRmYWN0b3J5QWRkcmVzc09yRmFpbAIZdHJhbnNmZXJGcm9tUHJveHlUcmVhc3VyeQkAzAgCBRB1c2VyQWRkcmVzc0J5dGVzCQDMCAIFFWJsb2NrUHJvY2Vzc2luZ1Jld2FyZAUDbmlsBQNuaWwJAMwIAgkA/AcEBRRmYWN0b3J5QWRkcmVzc09yRmFpbAIMaW50ZWdlckVudHJ5CQDMCAIJAQtrZXlJbnZlc3RlZAEFBHVuaXQJAMwIAgkAZAIFCGludmVzdGVkBRpyZXdhcmRUb01haW5UcmVhc3VyeUFtb3VudAUDbmlsBQNuaWwFA25pbAMJAAACBQdhY3Rpb25zBQdhY3Rpb25zCQCUCgIFA25pbAUEdW5pdAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgECdHgBBnZlcmlmeQAECXB1YmxpY0tleQQHJG1hdGNoMAkBGWdldE1hbmFnZXJQdWJsaWNLZXlPclVuaXQAAwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEA3B1YgUHJG1hdGNoMAUDcHViCAUCdHgPc2VuZGVyUHVibGljS2V5CQD0AwMIBQJ0eAlib2R5Qnl0ZXMJAJEDAggFAnR4BnByb29mcwAABQlwdWJsaWNLZXl3O/N/", "height": 2684188, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: CK4sYcu67kpWrryazaT54bguTXR2LWzHnenFWnhhvLGn Next: 5Ckarhp8XofjGwC1C3A8iQ5HomdERTtzi2SvuwSa8tEb Diff:
OldNewDifferences
1-{-# STDLIB_VERSION 6 #-}
1+{-# STDLIB_VERSION 7 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let separator = "__"
4+let SEP = "__"
55
6-let MULT8 = 100000000
6+let CONTRACT_NAME = "calculator.ride"
77
8-func wrapErr (msg) = makeString(["voting_verified_v2.ride:", msg], " ")
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
11-func throwErr (msg) = throw(wrapErr(msg))
19+func throwErr (s) = throw(wrapErr(s))
1220
1321
14-func asInt (val) = match val {
15- case valInt: Int =>
16- valInt
22+func assetIdToString (assetId) = match assetId {
23+ case b: ByteVector =>
24+ toBase58String(b)
25+ case _: Unit =>
26+ WAVES
1727 case _ =>
18- throw("Failed to cast into Integer")
28+ throw("Match error")
1929 }
2030
2131
22-func getIntegerOrZero (address,key) = valueOrElse(getInteger(address, key), 0)
32+func stringToAssetId (s) = if ((s == WAVES))
33+ then unit
34+ else fromBase58String(s)
2335
2436
25-func getIntegerOrFail (address,key) = valueOrErrorMessage(getInteger(address, key), wrapErr((key + " is not defined")))
37+func abs (n) = if ((0 > n))
38+ then -(n)
39+ else n
2640
2741
28-func getStringOrEmpty (address,key) = valueOrElse(getString(address, key), "")
42+func keyFactoryAddress () = makeString(["%s", "factory"], SEP)
2943
3044
31-func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), wrapErr((key + " is not defined")))
45+func keyManagerPublicKey () = makeString(["%s", "managerPublicKey"], SEP)
3246
3347
34-let keyBoostingContract = makeString(["%s", "boostingContract"], separator)
35-
36-let keyEmissionContract = makeString(["%s", "emissionContract"], separator)
37-
38-let keyAssetsStoreContract = makeString(["%s", "assetsStoreContract"], separator)
39-
40-let boostingContract = addressFromStringValue(getStringValue(keyBoostingContract))
41-
42-let emissionContract = addressFromStringValue(getStringValue(keyEmissionContract))
43-
44-let assetsStoreContract = addressFromStringValue(getStringValue(keyAssetsStoreContract))
45-
46-let keyEmissionConfig = makeString(["%s", "config"], separator)
47-
48-let wxAssetIdStr = split(getStringOrFail(emissionContract, keyEmissionConfig), separator)[1]
49-
50-let wxAssetId = fromBase58String(wxAssetIdStr)
51-
52-let keyVotingThresholdAdd = makeString(["%s%s", "votingThreshold", "add"], separator)
53-
54-let keyVotingThresholdRemove = makeString(["%s%s", "votingThreshold", "remove"], separator)
55-
56-let keyPeriodLengthRemove = makeString(["%s", "periodLengthRemove"], separator)
57-
58-let keyMaxPeriodLength = makeString(["%s", "maxPeriodLength"], separator)
59-
60-let keyMinPeriodLength = makeString(["%s", "minPeriodLength"], separator)
61-
62-func keyVotingRewardAssetId (assetId,index) = makeString(["%s%s%d", "votingRewardAssetId", assetId, toString(index)], separator)
48+func keyLpAssetId () = makeString(["%s", "lpAssetId"], SEP)
6349
6450
65-func keyVotingReward (userAddress,assetId,index) = makeString(["%s%s%s%d", "votingReward", toString(userAddress), assetId, toString(index)], separator)
51+func keyProxyTreasuryAddress () = makeString(["%s", "proxyTreasury"], SEP)
6652
6753
68-func keyTotalVotingReward (assetId,index) = makeString(["%s%s%d", "totalVotingReward", assetId, toString(index)], separator)
54+func keyMainTreasuryAddress () = makeString(["%s", "mainTreasury"], SEP)
6955
7056
71-let keyFinalizeCallRewardAmount = makeString(["%s", "finalizeCallRewardAmount"], separator)
72-
73-let keyMinSuggestRemoveBalance = makeString(["%s", "minSuggestRemoveBalance"], separator)
74-
75-func keyCurrentIndex (assetId) = makeString(["%s%s", "currentIndex", assetId], separator)
57+func keyInvested (assetId) = makeString(["%s%s", "invested", assetIdToString(assetId)], SEP)
7658
7759
78-func keyVote (assetId,index,caller) = makeString(["%s%s%d%s", "vote", assetId, toString(index), toString(caller)], separator)
60+func keyDonated (assetId) = makeString(["%s%s", "donated", assetIdToString(assetId)], SEP)
7961
8062
81-func voteValue (inFavor,gwxAmount) = makeString(["%s%d", toString(inFavor), toString(gwxAmount)], separator)
63+func keyAvailable (userAddress) = makeString(["%s%s", "available", toString(userAddress)], SEP)
8264
8365
84-func keySuggestIssuer (assetId,index) = makeString(["%s%s%d", "suggestIssuer", assetId, toString(index)], separator)
66+func keyClaimed (userAddress) = makeString(["%s%s", "claimed", toString(userAddress)], SEP)
8567
8668
87-func keyClaimHistory (userAddress,assetId,index) = makeString(["%s%s%s%d", "history", toString(userAddress), assetId, toString(index)], separator)
69+func keyCurrentPeriod () = makeString(["%s", "currentPeriod"], SEP)
8870
8971
90-let keyFeePerBlock = makeString(["%s", "feePerBlock"], separator)
91-
92-let feePerBlock = getIntegerOrFail(this, keyFeePerBlock)
93-
94-let keyMinWxMinForSuggestAddAmountRequired = makeString(["%s", "wxMinForSuggestAddAmountRequired"], separator)
95-
96-let keyWxForSuggestRemoveAmountRequired = makeString(["%s", "wxForSuggestRemoveAmountRequired"], separator)
97-
98-func keyVotingInfo (assetId,index) = makeString(["%s%s%d", "votingInfo", assetId, toString(index)], separator)
72+func keyPriceForPeriod (period) = makeString(["%s%d", "price", toString(period)], SEP)
9973
10074
101-func votingInfoValue (isRewardExist,rewardAssetId,rewardAmount,votingType,status,votingStartHeight,votingEndHeight,votesQuorum,votesFor,votesAgainst) = makeString(["%s%s%d%s%s%d%d%d%d%d", toString(isRewardExist), rewardAssetId, toString(rewardAmount), votingType, status, toString(votingStartHeight), toString(votingEndHeight), toString(votesQuorum), toString(votesFor), toString(votesAgainst)], separator)
75+func keyStartHeight (period) = makeString(["%s%d", "startHeight", toString(period)], SEP)
10276
10377
104-func keyAssetImage (assetId) = makeString(["%s%s", "assetImage", assetId], separator)
78+func keyPowerManagerBonus (period) = makeString(["%s%d", "powerManagerBonus", toString(period)], SEP)
10579
10680
107-func getUserGwxAmountAtHeight (userAddress,targetHeight) = {
108- let gwxAmount = invoke(boostingContract, "getUserGwxAmountAtHeightREADONLY", [userAddress, targetHeight], nil)
109- asInt(gwxAmount)
81+func keyPeriodLength () = "%s__periodLength"
82+
83+
84+func keyBlockProcessingReward () = "%s__blockProcessingReward"
85+
86+
87+func keyNextBlockToProcess () = "%s__nextBlockToProcess"
88+
89+
90+func keyBlockProcessed (height) = makeString(["%s%d", "blockProcessed", toString(height)], SEP)
91+
92+
93+func keyWithdrawal () = "%s__withdrawal"
94+
95+
96+func keyWithdrawalRequest (userAddress,txId) = makeString(["%s%s%s", "withdrawal", toString(userAddress), toBase58String(txId)], SEP)
97+
98+
99+func valueWithdrawalRequest (status,lpAssetAmount,targetPeriod,claimTxId) = {
100+ let claimTxIdStr = match claimTxId {
101+ case b: ByteVector =>
102+ toBase58String(b)
103+ case _: Unit =>
104+ "SOON"
105+ case _ =>
106+ throw("Match error")
107+ }
108+ makeString(["%s%d%d%s", status, toString(lpAssetAmount), toString(targetPeriod), claimTxIdStr], SEP)
110109 }
111110
112111
113-func keyManagerVaultAddress () = "%s__managerVaultAddress"
112+func keyPeriodWithdrawalAssetIds (period) = makeString(["%s%d", "periodReward", toString(period)], SEP)
114113
115114
116-func keyManagerPublicKey () = "%s__managerPublicKey"
115+func keyPeriodWithdrawalAmounts (period) = makeString(["%s%d", "periodRewardAmount", toString(period)], SEP)
117116
118117
119-func getManagerVaultAddressOrThis () = match getString(keyManagerVaultAddress()) {
118+let keyMinHeightForWithdraw = makeString(["%s", "minHeightForWithdraw"], SEP)
119+
120+let keyMaxHeightForWithdraw = makeString(["%s", "maxHeightForWithdraw"], SEP)
121+
122+func parseWithdrawalRequestValueOrFail (s) = {
123+ let parts = split(s, SEP)
124+ if ((size(parts) == 5))
125+ then {
126+ let status = parts[1]
127+ let lpAssetAmount = valueOrErrorMessage(parseInt(parts[2]), wrapErr("invalid lpAssetAmount"))
128+ let targetPeriod = valueOrErrorMessage(parseInt(parts[3]), wrapErr("invalid targetPeriod"))
129+ let claimTxId = parts[4]
130+ $Tuple4(status, lpAssetAmount, targetPeriod, claimTxId)
131+ }
132+ else throwErr("invalid withdrawal request value")
133+ }
134+
135+
136+let factoryAddressOption = match getString(this, keyFactoryAddress()) {
120137 case s: String =>
121- addressFromStringValue(s)
138+ addressFromString(s)
139+ case _: Unit =>
140+ unit
122141 case _ =>
123- this
142+ throw("Match error")
143+}
144+
145+let factoryAddressOrFail = valueOrErrorMessage(factoryAddressOption, wrapErr("invalid factory address"))
146+
147+let lpAssetIdOption = match factoryAddressOption {
148+ case a: Address =>
149+ match getString(a, keyLpAssetId()) {
150+ case s: String =>
151+ fromBase58String(s)
152+ case _: Unit =>
153+ unit
154+ case _ =>
155+ throw("Match error")
156+ }
157+ case _: Unit =>
158+ unit
159+ case _ =>
160+ throw("Match error")
161+}
162+
163+let lpAssetIdOrFail = valueOrErrorMessage(lpAssetIdOption, wrapErr("invalid lpAssetId"))
164+
165+let proxyTreasuryAddressOption = match factoryAddressOption {
166+ case a: Address =>
167+ match getString(a, keyProxyTreasuryAddress()) {
168+ case s: String =>
169+ addressFromString(s)
170+ case _: Unit =>
171+ unit
172+ case _ =>
173+ throw("Match error")
174+ }
175+ case _: Unit =>
176+ unit
177+ case _ =>
178+ throw("Match error")
179+}
180+
181+let proxyTreasuryAddressOrFail = valueOrErrorMessage(proxyTreasuryAddressOption, wrapErr("invalid proxy treasury address"))
182+
183+let mainTreasuryAddressOption = match factoryAddressOption {
184+ case a: Address =>
185+ match getString(a, keyMainTreasuryAddress()) {
186+ case s: String =>
187+ addressFromString(s)
188+ case _: Unit =>
189+ unit
190+ case _ =>
191+ throw("Match error")
192+ }
193+ case _: Unit =>
194+ unit
195+ case _ =>
196+ throw("Match error")
197+}
198+
199+let mainTreasuryAddressOrFail = valueOrErrorMessage(mainTreasuryAddressOption, wrapErr("invalid main treasury address"))
200+
201+func getManagerPublicKeyOrUnit () = match factoryAddressOption {
202+ case fa: Address =>
203+ match getString(fa, keyManagerPublicKey()) {
204+ case pub: String =>
205+ fromBase58String(pub)
206+ case _ =>
207+ unit
208+ }
209+ case _ =>
210+ unit
124211 }
125212
126213
127-func managerPublicKeyOrUnit () = {
128- let managerVaultAddress = getManagerVaultAddressOrThis()
129- match getString(managerVaultAddress, keyManagerPublicKey()) {
130- case s: String =>
131- fromBase58String(s)
132- case _: Unit =>
133- unit
134- case _ =>
135- throw("Match error")
136- }
214+func onlyAddress (i,address) = if ((i.caller == address))
215+ then true
216+ else throwErr("permission denied")
217+
218+
219+func onlyFactory (i) = onlyAddress(i, factoryAddressOrFail)
220+
221+
222+func rewardForOption (rewards,target) = {
223+ let s = size(rewards)
224+ let $t052085233 = rewards[0]
225+ let a0 = $t052085233._1
226+ let r0 = $t052085233._2
227+ let $t052365261 = rewards[1]
228+ let a1 = $t052365261._1
229+ let r1 = $t052365261._2
230+ let $t052645289 = rewards[2]
231+ let a2 = $t052645289._1
232+ let r2 = $t052645289._2
233+ if (if ((s > 0))
234+ then (a0 == target)
235+ else false)
236+ then r0
237+ else if (if ((s > 1))
238+ then (a1 == target)
239+ else false)
240+ then r1
241+ else if (if ((s > 2))
242+ then (a2 == target)
243+ else false)
244+ then r2
245+ else unit
137246 }
138247
139248
140-func getVotingInfoParts (votingInfo) = {
141- let votingInfoParts = split(votingInfo, separator)
142- let isRewardExistStr = votingInfoParts[1]
143- let isRewardExist = if ((isRewardExistStr == "true"))
249+func finalizeINTERNAL (newTreasuryVolumeInWaves,pwrManagersBonusInWaves,treasuryVolumeDiffAllocationCoef) = {
250+ let donatedWavesAmount = valueOrElse(getInteger(factoryAddressOrFail, keyDonated(unit)), 0)
251+ let investedWavesAmount = valueOrElse(getInteger(factoryAddressOrFail, keyInvested(unit)), 0)
252+ let currentTreasuryVolumeInWaves = (donatedWavesAmount + investedWavesAmount)
253+ let profitRaw = (newTreasuryVolumeInWaves - currentTreasuryVolumeInWaves)
254+ let pwrManagersBonusAmount = if (if ((profitRaw >= pwrManagersBonusInWaves))
144255 then true
145- else false
146- let rewardAssetId = votingInfoParts[2]
147- let rewardAmount = parseIntValue(votingInfoParts[3])
148- let votingType = votingInfoParts[4]
149- let status = votingInfoParts[5]
150- let votingStartHeight = parseIntValue(votingInfoParts[6])
151- let votingEndHeight = parseIntValue(votingInfoParts[7])
152- let votesQuorum = parseIntValue(votingInfoParts[8])
153- let votesFor = parseIntValue(votingInfoParts[9])
154- let votesAgainst = parseIntValue(votingInfoParts[10])
155- $Tuple10(isRewardExist, rewardAssetId, rewardAmount, votingType, status, votingStartHeight, votingEndHeight, votesQuorum, votesFor, votesAgainst)
156- }
157-
158-
159-func votingExistChecks (assetId,currentIndex) = {
160- let votingInfo = valueOrErrorMessage(getString(keyVotingInfo(assetId, currentIndex)), wrapErr("voting info not found"))
161- let votingInfoArray = split(votingInfo, separator)
162- let status = votingInfoArray[5]
163- let votingEndHeight = valueOrErrorMessage(parseIntValue(votingInfoArray[7]), wrapErr("voting start height not found"))
164- let suggestIssuer = valueOrErrorMessage(getString(keySuggestIssuer(assetId, currentIndex)), wrapErr("voting issuer not found"))
165- let checks = [if ((status == "inProgress"))
256+ else (pwrManagersBonusInWaves == 0))
257+ then pwrManagersBonusInWaves
258+ else throwErr("power bonus is more than profit")
259+ let profit = (profitRaw - pwrManagersBonusAmount)
260+ let donationPart = if ((currentTreasuryVolumeInWaves > 0))
261+ then fraction(donatedWavesAmount, SCALE8, currentTreasuryVolumeInWaves)
262+ else 0
263+ let donationProfitPartRaw = fraction(profit, donationPart, SCALE8)
264+ let investmentProfitPartRaw = (profit - donationProfitPartRaw)
265+ let treasuryVolumeDiffAllocationCoefAbs = abs(treasuryVolumeDiffAllocationCoef)
266+ let amountToDonation = fraction(investmentProfitPartRaw, if ((0 > treasuryVolumeDiffAllocationCoef))
267+ then treasuryVolumeDiffAllocationCoefAbs
268+ else 0, SCALE8)
269+ let amountToInvestment = fraction(donationProfitPartRaw, if ((treasuryVolumeDiffAllocationCoef > 0))
270+ then treasuryVolumeDiffAllocationCoefAbs
271+ else 0, SCALE8)
272+ let donationProfitPart = ((donationProfitPartRaw - amountToInvestment) + amountToDonation)
273+ let investmentProfitPart = ((investmentProfitPartRaw - amountToDonation) + amountToInvestment)
274+ let donatedWavesAmountNewRaw = (donatedWavesAmount + donationProfitPart)
275+ let investedWavesAmountNewRaw = (investedWavesAmount + investmentProfitPart)
276+ let donatedPartDebt = min([0, donatedWavesAmountNewRaw])
277+ let investedPartDebt = min([0, investedWavesAmountNewRaw])
278+ let donatedWavesAmountNew = (max([0, donatedWavesAmountNewRaw]) + investedPartDebt)
279+ let investedWavesAmountNew = (max([0, investedWavesAmountNewRaw]) + donatedPartDebt)
280+ let lpAssetQuantity = valueOrErrorMessage(assetInfo(lpAssetIdOrFail), wrapErr("invalid lpAsset info")).quantity
281+ let newPrice = fraction(investedWavesAmountNew, SCALE8, lpAssetQuantity)
282+ let checkIfPriceNotZero = if ((newPrice != 0))
166283 then true
167- else throwErr("no voting in progress"), if ((votingEndHeight > height))
168- then true
169- else throwErr("voting expired")]
170- if ((checks == checks))
171- then $Tuple3(status, votingEndHeight, suggestIssuer)
284+ else throwErr("LP price cannot be 0")
285+ if ((checkIfPriceNotZero == checkIfPriceNotZero))
286+ then {
287+ let lpAssetAmountToBurn = valueOrElse(getInteger(factoryAddressOrFail, keyWithdrawal()), 0)
288+ let paymentAmountMin = max([0, fraction(lpAssetAmountToBurn, newPrice, SCALE8)])
289+ let finalInvestedWavesAmount = (investedWavesAmountNew - paymentAmountMin)
290+ let lpAssetFinalQuantity = (lpAssetQuantity - lpAssetAmountToBurn)
291+ $Tuple6(paymentAmountMin, finalInvestedWavesAmount, donatedWavesAmountNew, newPrice, lpAssetAmountToBurn, lpAssetFinalQuantity)
292+ }
172293 else throw("Strict value is not equal to itself.")
173294 }
174295
175296
176-func calculateReward (voter,assetId,index) = {
177- let voteKey = keyVote(assetId, index, voter)
178- let lastVote = valueOrErrorMessage(getString(voteKey), wrapErr("you have not voted"))
179- let lastVoteParts = split(lastVote, separator)
180- let gwxAmount = parseIntValue(lastVoteParts[2])
181- let votingInfoStr = valueOrErrorMessage(getString(keyVotingInfo(assetId, index)), wrapErr("voting info not found"))
182- let votingParts = getVotingInfoParts(votingInfoStr)
183- let votesFor = votingParts._9
184- let votesAgainst = votingParts._10
185- let partOfTheTotalVotesX8 = fraction(gwxAmount, MULT8, (votesFor + votesAgainst))
186- let totalVotingReward = valueOrElse(getInteger(keyTotalVotingReward(assetId, index)), 0)
187- let voterRewardAmount = fraction(partOfTheTotalVotesX8, totalVotingReward, MULT8, FLOOR)
188- voterRewardAmount
189- }
190-
191-
192297 @Callable(i)
193-func suggestAdd (assetId,periodLength,assetImage) = {
194- let wxPayment = i.payments[0]
195- let wxPaymentAssetId = value(wxPayment.assetId)
196- let wxPaymentAmount = value(wxPayment.amount)
197- let minPeriodLength = getIntegerValue(keyMinPeriodLength)
198- let maxPeriodLength = getIntegerValue(keyMaxPeriodLength)
199- let tokenIsVerified = {
200- let @ = invoke(assetsStoreContract, "isVerifiedREADONLY", [assetId], nil)
201- if ($isInstanceOf(@, "Boolean"))
202- then @
203- else throw(($getType(@) + " couldn't be cast to Boolean"))
204- }
205- let checks = [if (if ((periodLength >= minPeriodLength))
206- then (maxPeriodLength >= periodLength)
207- else false)
208- then true
209- else throwErr("invalid periodLength"), if ((tokenIsVerified == false))
210- then true
211- else throwErr("token already verified"), if ((wxPaymentAmount > (periodLength * feePerBlock)))
212- then true
213- else throwErr("not enough wx for given period"), if ((wxPaymentAmount >= getIntegerValue(keyMinWxMinForSuggestAddAmountRequired)))
214- then true
215- else throwErr("payment less then min for suggest")]
216- if ((checks == checks))
298+func claimLP (userAddressBytes) = {
299+ let checkCaller = onlyFactory(i)
300+ if ((checkCaller == checkCaller))
217301 then {
218- let currentIndexKey = keyCurrentIndex(assetId)
219- let currentIndex = getInteger(currentIndexKey)
220- let newIndex = if (isDefined(currentIndex))
221- then (value(currentIndex) + 1)
222- else 0
223- let $t087849424 = if ((size(i.payments) > 1))
224- then {
225- let votingRewardPayment = i.payments[1]
226- let votingRewardPaymentAssetId = toBase58String(value(votingRewardPayment.assetId))
227- let votingRewardPaymentAmount = value(votingRewardPayment.amount)
228- $Tuple4(true, votingRewardPaymentAssetId, votingRewardPaymentAmount, [StringEntry(keyVotingRewardAssetId(assetId, newIndex), votingRewardPaymentAssetId), IntegerEntry(keyTotalVotingReward(assetId, newIndex), votingRewardPaymentAmount)])
229- }
230- else $Tuple4(false, "EMPTY", 0, nil)
231- let isRewardExist = $t087849424._1
232- let rewardAssetId = $t087849424._2
233- let rewardAmount = $t087849424._3
234- let votingRewardActions = $t087849424._4
235- let votesQuorum = valueOrErrorMessage(getInteger(keyVotingThresholdAdd), wrapErr("votingThresholdAdd not set"))
236- let votingInfo = votingInfoValue(isRewardExist, rewardAssetId, rewardAmount, "verification", "inProgress", height, (height + periodLength), votesQuorum, 0, 0)
237- let finalizeCallRewardAmount = getIntegerValue(keyFinalizeCallRewardAmount)
238- let burnWxAmount = (wxPaymentAmount - finalizeCallRewardAmount)
239- ([IntegerEntry(currentIndexKey, newIndex), StringEntry(keySuggestIssuer(assetId, newIndex), toString(i.caller)), StringEntry(keyVotingInfo(assetId, newIndex), votingInfo), StringEntry(keyAssetImage(assetId), assetImage), Burn(wxPaymentAssetId, burnWxAmount)] ++ votingRewardActions)
302+ let userAddress = Address(userAddressBytes)
303+ let available = valueOrElse(getInteger(factoryAddressOrFail, keyAvailable(userAddress)), 0)
304+ let claimed = valueOrElse(getInteger(factoryAddressOrFail, keyClaimed(userAddress)), 0)
305+ let factoryActions = if ((available > 0))
306+ then [invoke(factoryAddressOrFail, "transferAsset", [userAddressBytes, available, lpAssetIdOrFail], nil), invoke(factoryAddressOrFail, "integerEntry", [keyAvailable(userAddress), 0], nil), invoke(factoryAddressOrFail, "integerEntry", [keyClaimed(userAddress), (claimed + available)], nil)]
307+ else throwErr("nothing to claim")
308+ $Tuple2(nil, factoryActions)
240309 }
241310 else throw("Strict value is not equal to itself.")
242311 }
244313
245314
246315 @Callable(i)
247-func suggestRemove (assetId) = {
248- let gwxAmountAtNow = getUserGwxAmountAtHeight(toString(i.caller), height)
249- let minSuggestRemoveBalance = getIntegerValue(keyMinSuggestRemoveBalance)
250- let wxPayment = i.payments[0]
251- let wxPaymentAssetId = value(wxPayment.assetId)
252- let wxPaymentAmount = value(wxPayment.amount)
253- let tokenIsVerified = {
254- let @ = invoke(assetsStoreContract, "isVerifiedREADONLY", [assetId], nil)
255- if ($isInstanceOf(@, "Boolean"))
256- then @
257- else throw(($getType(@) + " couldn't be cast to Boolean"))
258- }
259- let checks = [if (tokenIsVerified)
260- then true
261- else throwErr("token not verified"), if ((gwxAmountAtNow >= minSuggestRemoveBalance))
262- then true
263- else throwErr("not enough gWXes"), if ((wxPaymentAmount >= getIntegerValue(keyWxForSuggestRemoveAmountRequired)))
264- then true
265- else throwErr("payment less then min for suggest")]
266- if ((checks == checks))
316+func finalize (userAddressBytes,newTreasuryVolumeInWaves,pwrManagersBonusInWaves,treasuryVolumeDiffAllocationCoef) = {
317+ let checkCaller = onlyFactory(i)
318+ if ((checkCaller == checkCaller))
267319 then {
268- let currentIndexKey = keyCurrentIndex(assetId)
269- let currentIndex = getInteger(currentIndexKey)
270- let newIndex = if (isDefined(currentIndex))
271- then (value(currentIndex) + 1)
272- else 0
273- let periodLength = valueOrErrorMessage(getInteger(keyPeriodLengthRemove), wrapErr("periodLengthRemove not set"))
274- let votingEndHeight = (height + periodLength)
275- let votesQuorum = valueOrErrorMessage(getInteger(keyVotingThresholdRemove), wrapErr("votingThresholdRemove not set"))
276- let votingInfo = votingInfoValue(false, "EMPTY", 0, "deverification", "inProgress", height, (height + periodLength), votesQuorum, 0, 0)
277-[IntegerEntry(currentIndexKey, newIndex), StringEntry(keySuggestIssuer(assetId, newIndex), toString(i.caller)), StringEntry(keyVotingInfo(assetId, newIndex), votingInfo)]
278- }
279- else throw("Strict value is not equal to itself.")
280- }
281-
282-
283-
284-@Callable(i)
285-func vote (assetId,inFavor) = {
286- let currentIndexKey = keyCurrentIndex(assetId)
287- let currentIndex = valueOrErrorMessage(getInteger(currentIndexKey), wrapErr("voting does not exist"))
288- let votingInfo = votingExistChecks(assetId, currentIndex)
289- if ((votingInfo == votingInfo))
290- then {
291- let currentVotingEndHeight = votingInfo._2
292- let gwxAmountAtEnd = getUserGwxAmountAtHeight(toString(i.caller), currentVotingEndHeight)
293- let voteKey = keyVote(assetId, currentIndex, i.caller)
294- let checks = [if ((getString(voteKey) == unit))
320+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
321+ let periodLength = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPeriodLength()), wrapErr("invalid period length"))
322+ let currentStartHeight = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyStartHeight(currentPeriodOrFail)), wrapErr("invalid start height"))
323+ let currentPriceOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPriceForPeriod(currentPeriodOrFail)), wrapErr("invalid price"))
324+ let nextBlockToProcess = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyNextBlockToProcess()), wrapErr("invalid next block to process"))
325+ let periodEndHeight = ((currentStartHeight + periodLength) - 1)
326+ let checks = [if ((i.originCaller == mainTreasuryAddressOrFail))
295327 then true
296- else throwErr("You have already voted"), if ((gwxAmountAtEnd > 0))
328+ else throwErr("permission denied"), if ((nextBlockToProcess > periodEndHeight))
297329 then true
298- else throw("You'll not have gWX at the end of voting")]
330+ else throwErr("unprocessed blocks"), if ((newTreasuryVolumeInWaves >= 0))
331+ then true
332+ else throwErr("invalid new treasury volume"), if ((pwrManagersBonusInWaves >= 0))
333+ then true
334+ else throwErr("invalid PWR managers bonus"), if (if ((treasuryVolumeDiffAllocationCoef >= -(SCALE8)))
335+ then (SCALE8 >= treasuryVolumeDiffAllocationCoef)
336+ else false)
337+ then true
338+ else throwErr("invalid treasury volume diff allocation coefficient")]
299339 if ((checks == checks))
300340 then {
301- let votingInfoStr = valueOrErrorMessage(getString(keyVotingInfo(assetId, currentIndex)), wrapErr("voting info not found"))
302- let votingInfoParts = getVotingInfoParts(votingInfoStr)
303- let votesFor = votingInfoParts._9
304- let votesAgainst = votingInfoParts._10
305- let $t01274512906 = if (inFavor)
306- then $Tuple2((votesFor + gwxAmountAtEnd), votesAgainst)
307- else $Tuple2(votesFor, (votesAgainst + gwxAmountAtEnd))
308- let newVotesFor = $t01274512906._1
309- let newVotesAgainst = $t01274512906._2
310- let newVotingInfoValue = votingInfoValue(votingInfoParts._1, votingInfoParts._2, votingInfoParts._3, votingInfoParts._4, votingInfoParts._5, votingInfoParts._6, votingInfoParts._7, votingInfoParts._8, newVotesFor, newVotesAgainst)
311- let votingRewardAction = match getString(keyVotingRewardAssetId(assetId, currentIndex)) {
312- case pk: String =>
313-[StringEntry(keyVotingReward(i.caller, assetId, currentIndex), voteValue(inFavor, gwxAmountAtEnd))]
314- case _: Unit =>
315- nil
316- case _ =>
317- throw("Match error")
318- }
319- ([StringEntry(voteKey, voteValue(inFavor, gwxAmountAtEnd)), StringEntry(keyVotingInfo(assetId, currentIndex), newVotingInfoValue)] ++ votingRewardAction)
341+ let $t01078311043 = finalizeINTERNAL(newTreasuryVolumeInWaves, pwrManagersBonusInWaves, treasuryVolumeDiffAllocationCoef)
342+ let paymentAmountMin = $t01078311043._1
343+ let finalInvestedWavesAmount = $t01078311043._2
344+ let donatedWavesAmountNew = $t01078311043._3
345+ let newPrice = $t01078311043._4
346+ let lpAssetAmountToBurn = $t01078311043._5
347+ let lpAssetFinalQuantity = $t01078311043._6
348+ let newPeriod = (currentPeriodOrFail + 1)
349+ func addNewAction (actions,payment) = {
350+ let $t01119111253 = actions
351+ let scriptTransfers = $t01119111253._1
352+ let assetIdsString = $t01119111253._2
353+ let amountsString = $t01119111253._3
354+ let paymentAmount = payment.amount
355+ let paymentAssetId = payment.assetId
356+ let newAssetIdsString = ("%s" + makeString([assetIdsString, assetIdToString(paymentAssetId)], SEP))
357+ let newAmountsString = ("%d" + makeString([amountsString, toString(paymentAmount)], SEP))
358+ let newScriptTransfer = ScriptTransfer(factoryAddressOrFail, paymentAmount, paymentAssetId)
359+ $Tuple3((scriptTransfers :+ newScriptTransfer), newAssetIdsString, newAmountsString)
360+ }
361+
362+ let $t01171311804 = {
363+ let $l = i.payments
364+ let $s = size($l)
365+ let $acc0 = $Tuple3(nil, "", "")
366+ func $f0_1 ($a,$i) = if (($i >= $s))
367+ then $a
368+ else addNewAction($a, $l[$i])
369+
370+ func $f0_2 ($a,$i) = if (($i >= $s))
371+ then $a
372+ else throw("List size exceeds 10")
373+
374+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
375+ }
376+ let scriptTransfers = $t01171311804._1
377+ let AssetIds = $t01171311804._2
378+ let Amounts = $t01171311804._3
379+ let factoryActions = [invoke(factoryAddressOrFail, "integerEntry", [keyPowerManagerBonus(currentPeriodOrFail), pwrManagersBonusInWaves], nil), 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), finalInvestedWavesAmount], nil), invoke(factoryAddressOrFail, "integerEntry", [keyDonated(unit), donatedWavesAmountNew], nil), invoke(factoryAddressOrFail, "stringEntry", [keyPeriodWithdrawalAssetIds(newPeriod), AssetIds], nil), invoke(factoryAddressOrFail, "stringEntry", [keyPeriodWithdrawalAmounts(newPeriod), Amounts], nil)]
380+ $Tuple2(scriptTransfers, factoryActions)
320381 }
321382 else throw("Strict value is not equal to itself.")
322383 }
326387
327388
328389 @Callable(i)
329-func cancelVote (assetId) = {
330- let currentIndexKey = keyCurrentIndex(assetId)
331- let currentIndex = valueOrErrorMessage(getInteger(currentIndexKey), wrapErr("voting does not exist"))
332- let voteKey = keyVote(assetId, currentIndex, i.caller)
333- let lastVote = valueOrErrorMessage(getString(voteKey), wrapErr("you have not voted"))
334- let lastVoteParts = split(lastVote, separator)
335- let inFavor = lastVoteParts[1]
336- let gwxAmount = parseIntValue(lastVoteParts[2])
337- let votingInfo = votingExistChecks(assetId, currentIndex)
338- if ((votingInfo == votingInfo))
390+func finalizeREADONLY (newTreasuryVolumeInWaves,pwrManagersBonusInWaves,treasuryVolumeDiffAllocationCoef) = {
391+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
392+ let periodLength = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPeriodLength()), wrapErr("invalid period length"))
393+ let currentStartHeight = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyStartHeight(currentPeriodOrFail)), wrapErr("invalid start height"))
394+ let currentPriceOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPriceForPeriod(currentPeriodOrFail)), wrapErr("invalid price"))
395+ let nextBlockToProcess = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyNextBlockToProcess()), wrapErr("invalid next block to process"))
396+ let periodEndHeight = ((currentStartHeight + periodLength) - 1)
397+ let checks = [if ((nextBlockToProcess > periodEndHeight))
398+ then true
399+ else throwErr("unprocessed blocks"), if ((newTreasuryVolumeInWaves >= 0))
400+ then true
401+ else throwErr("invalid new treasury volume"), if ((pwrManagersBonusInWaves >= 0))
402+ then true
403+ else throwErr("invalid PWR managers bonus"), if (if ((treasuryVolumeDiffAllocationCoef >= -(SCALE8)))
404+ then (SCALE8 >= treasuryVolumeDiffAllocationCoef)
405+ else false)
406+ then true
407+ else throwErr("invalid treasury volume diff allocation coefficient")]
408+ if ((checks == checks))
409+ then $Tuple2(nil, finalizeINTERNAL(newTreasuryVolumeInWaves, pwrManagersBonusInWaves, treasuryVolumeDiffAllocationCoef))
410+ else throw("Strict value is not equal to itself.")
411+ }
412+
413+
414+
415+@Callable(i)
416+func invest (userAddressBytes) = {
417+ let checkCaller = onlyFactory(i)
418+ if ((checkCaller == checkCaller))
339419 then {
340- let checks = [if (if ((inFavor == "true"))
420+ let userAddress = Address(userAddressBytes)
421+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
422+ let currentPriceOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPriceForPeriod(currentPeriodOrFail)), wrapErr("invalid price"))
423+ let payment = if ((size(i.payments) == 1))
424+ then i.payments[0]
425+ else throwErr("invalid payments")
426+ let $t01528515462 = if (if ((payment.assetId == unit))
427+ then (payment.amount > 0)
428+ else false)
429+ then $Tuple2(payment.amount, payment.assetId)
430+ else throwErr("invalid payment amount")
431+ let paymentAmount = $t01528515462._1
432+ let paymentAssetId = $t01528515462._2
433+ let lpAssetAmount = if ((currentPriceOrFail > 0))
434+ then fraction(paymentAmount, SCALE8, currentPriceOrFail)
435+ else 0
436+ let invested = valueOrElse(getInteger(factoryAddressOrFail, keyInvested(unit)), 0)
437+ let actions = [ScriptTransfer(mainTreasuryAddressOrFail, paymentAmount, paymentAssetId)]
438+ let factoryActions = [invoke(factoryAddressOrFail, "integerEntry", [keyInvested(unit), (invested + paymentAmount)], nil), invoke(factoryAddressOrFail, "reissue", [lpAssetAmount], nil), invoke(factoryAddressOrFail, "transferAsset", [userAddressBytes, lpAssetAmount, lpAssetIdOrFail], nil)]
439+ $Tuple2(actions, factoryActions)
440+ }
441+ else throw("Strict value is not equal to itself.")
442+ }
443+
444+
445+
446+@Callable(i)
447+func withdraw (userAddressBytes) = {
448+ let checkCaller = onlyFactory(i)
449+ if ((checkCaller == checkCaller))
450+ then {
451+ let userAddress = Address(userAddressBytes)
452+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
453+ let payment = if ((size(i.payments) == 1))
454+ then i.payments[0]
455+ else throwErr(wrapErr("invalid payments"))
456+ let paymentAssetId = if ((payment.assetId == lpAssetIdOrFail))
457+ then lpAssetIdOrFail
458+ else throwErr("invalid payment asset")
459+ let paymentAmount = if ((payment.amount > 0))
460+ then payment.amount
461+ else throwErr("invalid payment amount")
462+ let withdrawal = valueOrElse(getInteger(factoryAddressOrFail, keyWithdrawal()), 0)
463+ let actions = [ScriptTransfer(factoryAddressOrFail, paymentAmount, paymentAssetId)]
464+ let factoryActions = [invoke(factoryAddressOrFail, "integerEntry", [keyWithdrawal(), (withdrawal + paymentAmount)], nil), invoke(factoryAddressOrFail, "stringEntry", [keyWithdrawalRequest(userAddress, i.transactionId), valueWithdrawalRequest(PENDING, paymentAmount, (currentPeriodOrFail + 1), unit)], nil)]
465+ if ((factoryActions == factoryActions))
466+ then $Tuple2(actions, factoryActions)
467+ else throw("Strict value is not equal to itself.")
468+ }
469+ else throw("Strict value is not equal to itself.")
470+ }
471+
472+
473+
474+@Callable(i)
475+func cancelWithdraw (userAddressBytes,txId) = {
476+ let checkCaller = onlyFactory(i)
477+ if ((checkCaller == checkCaller))
478+ then {
479+ let userAddress = Address(userAddressBytes)
480+ let withdrawalRequestOption = valueOrErrorMessage(getString(factoryAddressOrFail, keyWithdrawalRequest(userAddress, txId)), wrapErr("invalid withdrawal request"))
481+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
482+ let $t01786917982 = parseWithdrawalRequestValueOrFail(withdrawalRequestOption)
483+ let status = $t01786917982._1
484+ let lpAssetAmount = $t01786917982._2
485+ let targetPeriod = $t01786917982._3
486+ let claimTxId = $t01786917982._4
487+ let checks = [if ((status == PENDING))
341488 then true
342- else (inFavor == "false"))
489+ else throwErr("invalid withdrawal request status"), if ((targetPeriod > currentPeriodOrFail))
343490 then true
344- else throwErr("invalid vote")]
491+ else throwErr("invalid withdrawal request period")]
345492 if ((checks == checks))
346493 then {
347- let votingInfoStr = valueOrErrorMessage(getString(keyVotingInfo(assetId, currentIndex)), wrapErr("voting info not found"))
348- let votingInfoParts = getVotingInfoParts(votingInfoStr)
349- let votesFor = votingInfoParts._9
350- let votesAgainst = votingInfoParts._10
351- let $t01453114692 = if ((inFavor == "true"))
352- then $Tuple2((votesFor - gwxAmount), votesAgainst)
353- else $Tuple2(votesFor, (votesAgainst - gwxAmount))
354- let newVotesFor = $t01453114692._1
355- let newVotesAgainst = $t01453114692._2
356- let newVotingInfoValue = votingInfoValue(votingInfoParts._1, votingInfoParts._2, votingInfoParts._3, votingInfoParts._4, votingInfoParts._5, votingInfoParts._6, votingInfoParts._7, votingInfoParts._8, newVotesFor, newVotesAgainst)
357-[StringEntry(keyVotingInfo(assetId, currentIndex), newVotingInfoValue), DeleteEntry(voteKey), DeleteEntry(keyVotingReward(i.caller, assetId, currentIndex))]
494+ let withdrawal = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyWithdrawal()), wrapErr("invalid total withdrawal amount"))
495+ let factoryActions = [invoke(factoryAddressOrFail, "integerEntry", [keyWithdrawal(), if ((withdrawal >= lpAssetAmount))
496+ then (withdrawal - lpAssetAmount)
497+ else throwErr("invalid withdrawal amount")], nil), invoke(factoryAddressOrFail, "deleteEntry", [keyWithdrawalRequest(userAddress, txId)], nil), invoke(factoryAddressOrFail, "transferAsset", [userAddressBytes, lpAssetAmount, lpAssetIdOrFail], nil)]
498+ if ((factoryActions == factoryActions))
499+ then $Tuple2(nil, factoryActions)
500+ else throw("Strict value is not equal to itself.")
358501 }
359502 else throw("Strict value is not equal to itself.")
360503 }
364507
365508
366509 @Callable(i)
367-func finalize (assetId) = {
368- let currentIndexKey = keyCurrentIndex(assetId)
369- let currentIndex = valueOrElse(getInteger(currentIndexKey), 0)
370- let votingThresholdAdd = valueOrErrorMessage(getInteger(keyVotingThresholdAdd), wrapErr("votingThresholdAdd not set"))
371- let votingThresholdRemove = valueOrErrorMessage(getInteger(keyVotingThresholdRemove), wrapErr("votingThresholdRemove not set"))
372- let votingInfoStr = valueOrErrorMessage(getString(keyVotingInfo(assetId, currentIndex)), wrapErr("voting info not found"))
373- let votingInfoParts = getVotingInfoParts(votingInfoStr)
374- let votingType = votingInfoParts._4
375- let status = votingInfoParts._5
376- let votingEndHeight = votingInfoParts._7
377- let votingQuorum = votingInfoParts._8
378- let votesFor = votingInfoParts._9
379- let votesAgainst = votingInfoParts._10
380- let checks = [if ((status == "inProgress"))
381- then true
382- else throwErr("voting not in progress"), if ((height >= votingEndHeight))
383- then true
384- else throwErr("voting not finished"), if (isDefined(getString(keyAssetImage(assetId))))
385- then true
386- else throwErr("asset image not set")]
387- if ((checks == checks))
510+func claimCollateral (userAddressBytes,txId) = {
511+ let checkCaller = onlyFactory(i)
512+ if ((checkCaller == checkCaller))
388513 then {
389- let votingAccepted = if (if (((votesFor + votesAgainst) >= votingQuorum))
390- then (votesFor > votesAgainst)
514+ let userAddress = Address(userAddressBytes)
515+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
516+ let withdrawalRequestOption = valueOrErrorMessage(getString(factoryAddressOrFail, keyWithdrawalRequest(userAddress, txId)), wrapErr("invalid withdrawal request"))
517+ let $t01931919432 = parseWithdrawalRequestValueOrFail(withdrawalRequestOption)
518+ let status = $t01931919432._1
519+ let lpAssetAmount = $t01931919432._2
520+ let targetPeriod = $t01931919432._3
521+ let claimTxId = $t01931919432._4
522+ if ((status == FINISHED))
523+ then throwErr("invalid withdrawal request status")
524+ else if ((targetPeriod > currentPeriodOrFail))
525+ then throwErr("invalid withdrawal request period")
526+ else {
527+ let priceOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPriceForPeriod(targetPeriod)), wrapErr("invalid price"))
528+ let amount = if ((priceOrFail > 0))
529+ then fraction(lpAssetAmount, priceOrFail, SCALE8)
530+ else 0
531+ let factoryActions = [invoke(factoryAddressOrFail, "stringEntry", [keyWithdrawalRequest(userAddress, txId), valueWithdrawalRequest(FINISHED, lpAssetAmount, targetPeriod, i.transactionId)], nil), {
532+ let assetsList = removeByIndex(split_51C(getStringValue(factoryAddressOrFail, keyPeriodWithdrawalAssetIds(currentPeriodOrFail)), SEP), 0)
533+ let amountsList = removeByIndex(split_51C(getStringValue(factoryAddressOrFail, keyPeriodWithdrawalAmounts(currentPeriodOrFail)), SEP), 0)
534+ invoke(factoryAddressOrFail, "transferAssets", [userAddressBytes, assetsList, amountsList], nil)
535+ }]
536+ $Tuple2(nil, factoryActions)
537+ }
538+ }
539+ else throw("Strict value is not equal to itself.")
540+ }
541+
542+
543+
544+@Callable(i)
545+func processBlocks (userAddressBytes) = {
546+ let checkCaller = onlyFactory(i)
547+ if ((checkCaller == checkCaller))
548+ then {
549+ let userAddress = Address(userAddressBytes)
550+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
551+ let periodLength = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPeriodLength()), wrapErr("invalid period length"))
552+ let currentStartHeight = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyStartHeight(currentPeriodOrFail)), wrapErr("invalid start height"))
553+ let currentPriceOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPriceForPeriod(currentPeriodOrFail)), wrapErr("invalid price"))
554+ let nextBlockToProcess = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyNextBlockToProcess()), wrapErr("invalid next block to process"))
555+ let periodEndHeight = ((currentStartHeight + periodLength) - 1)
556+ let blocksProcessingBatchSizeMax = 40
557+ let blocksProcessingBatchSize = if (if (if ((height >= nextBlockToProcess))
558+ then if ((nextBlockToProcess >= currentStartHeight))
559+ then true
560+ else (currentPeriodOrFail == 0)
391561 else false)
392- then true
393- else false
394- let newStatus = if (votingAccepted)
395- then "accepted"
396- else "rejected"
397- let assetImage = getStringValue(keyAssetImage(assetId))
398- let isVotingAccepted = if (votingAccepted)
562+ then (periodEndHeight >= nextBlockToProcess)
563+ else false)
564+ then min([((periodEndHeight - nextBlockToProcess) + 1), blocksProcessingBatchSizeMax])
565+ else throwErr(wrapErr("invalid target block"))
566+ let blockProcessingReward = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyBlockProcessingReward()), wrapErr("invalid block processing reward"))
567+ let blockProcessingRewardByGenerator = (blockProcessingReward / blocksProcessingBatchSize)
568+ let blockProcessingRewardByGeneratorRemainder = (blockProcessingReward - (blockProcessingRewardByGenerator * blocksProcessingBatchSize))
569+ func map (acc,inc) = if ((inc >= blocksProcessingBatchSize))
570+ then acc
571+ else {
572+ let targetBlockHeight = (nextBlockToProcess + inc)
573+ let targetBlockInfo = valueOrErrorMessage(blockInfoByHeight(targetBlockHeight), wrapErr("invalid block info"))
574+ let treasuryRewardOrFail = valueOrErrorMessage(rewardForOption(targetBlockInfo.rewards, proxyTreasuryAddressOrFail), wrapErr(("invalid treasury reward for height " + toString(targetBlockHeight))))
575+ let generator = targetBlockInfo.generator
576+ let available = valueOrElse(getInteger(factoryAddressOrFail, keyAvailable(generator)), 0)
577+ let callerReward = if ((inc == (blocksProcessingBatchSize - 1)))
578+ then (blockProcessingRewardByGenerator + blockProcessingRewardByGeneratorRemainder)
579+ else blockProcessingRewardByGenerator
580+ let lpAssetAmount = if ((currentPriceOrFail > 0))
581+ then fraction((treasuryRewardOrFail - callerReward), SCALE8, currentPriceOrFail)
582+ else 0
583+ 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)]
584+ if ((factoryActionsSingle == factoryActionsSingle))
585+ then {
586+ let $t02400224035 = acc
587+ let lpAssetAcc = $t02400224035._1
588+ let rewardAcc = $t02400224035._2
589+ $Tuple2((lpAssetAcc + lpAssetAmount), (rewardAcc + treasuryRewardOrFail))
590+ }
591+ else throw("Strict value is not equal to itself.")
592+ }
593+
594+ 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]
595+ let $t02430224378 = {
596+ let $l = list
597+ let $s = size($l)
598+ let $acc0 = $Tuple2(0, 0)
599+ func $f0_1 ($a,$i) = if (($i >= $s))
600+ then $a
601+ else map($a, $l[$i])
602+
603+ func $f0_2 ($a,$i) = if (($i >= $s))
604+ then $a
605+ else throw("List size exceeds 40")
606+
607+ $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)
608+ }
609+ if (($t02430224378 == $t02430224378))
399610 then {
400- let votingAcceptedInvokes = if ((votingType == "verification"))
401- then invoke(assetsStoreContract, "createOrUpdate", [assetId, assetImage, true], nil)
402- else invoke(assetsStoreContract, "setVerified", [assetId, false], nil)
403- votingAcceptedInvokes
404- }
405- else nil
406- if ((isVotingAccepted == isVotingAccepted))
407- then {
408- let newVotingInfoValue = votingInfoValue(votingInfoParts._1, votingInfoParts._2, votingInfoParts._3, votingInfoParts._4, newStatus, votingInfoParts._6, votingInfoParts._7, votingInfoParts._8, votingInfoParts._9, votingInfoParts._10)
409- let finalizeCallRewardAmount = getIntegerValue(keyFinalizeCallRewardAmount)
410-[StringEntry(keyVotingInfo(assetId, currentIndex), newVotingInfoValue), ScriptTransfer(i.caller, finalizeCallRewardAmount, wxAssetId)]
611+ let rewardAmountTotal = $t02430224378._2
612+ let lpAssetAmountTotal = $t02430224378._1
613+ let rewardToMainTreasuryAmount = (rewardAmountTotal - blockProcessingReward)
614+ let invested = valueOrElse(getInteger(factoryAddressOrFail, keyInvested(unit)), 0)
615+ let actions = [invoke(factoryAddressOrFail, "reissue", [lpAssetAmountTotal], nil), invoke(factoryAddressOrFail, "integerEntry", [keyNextBlockToProcess(), (nextBlockToProcess + blocksProcessingBatchSize)], nil), invoke(factoryAddressOrFail, "transferFromProxyTreasury", [mainTreasuryAddressOrFail.bytes, rewardToMainTreasuryAmount], nil), invoke(factoryAddressOrFail, "transferFromProxyTreasury", [userAddressBytes, blockProcessingReward], nil), invoke(factoryAddressOrFail, "integerEntry", [keyInvested(unit), (invested + rewardToMainTreasuryAmount)], nil)]
616+ if ((actions == actions))
617+ then $Tuple2(nil, unit)
618+ else throw("Strict value is not equal to itself.")
411619 }
412620 else throw("Strict value is not equal to itself.")
413621 }
415623 }
416624
417625
418-
419-@Callable(i)
420-func claimREADONLY (assetId,index,userAddressStr) = {
421- let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid address"))
422- let votingRewardAssetIdStr = getString(keyVotingRewardAssetId(assetId, index))
423- let rewardAmount = if (isDefined(votingRewardAssetIdStr))
424- then calculateReward(userAddress, assetId, index)
425- else 0
426- $Tuple2(nil, rewardAmount)
427- }
428-
429-
430-
431-@Callable(i)
432-func claim (assetId,index) = {
433- let callerAddress = i.caller
434- let claimHistoryKey = keyClaimHistory(callerAddress, assetId, index)
435- let claimHistory = getInteger(claimHistoryKey)
436- let checks = [if ((claimHistory == unit))
437- then true
438- else throwErr("already claimed")]
439- if ((checks == checks))
440- then {
441- let rewardAmount = if ((calculateReward(callerAddress, assetId, index) > 0))
442- then calculateReward(callerAddress, assetId, index)
443- else throwErr("nothing to claim")
444- let votingRewardAssetIdStr = getString(keyVotingRewardAssetId(assetId, index))
445- let rewardAction = if (isDefined(votingRewardAssetIdStr))
446- then {
447- let votingRewardAssetId = fromBase58String(value(votingRewardAssetIdStr))
448-[ScriptTransfer(callerAddress, rewardAmount, votingRewardAssetId), IntegerEntry(claimHistoryKey, rewardAmount), DeleteEntry(keyVotingReward(callerAddress, assetId, index))]
449- }
450- else throwErr("nothing to claim")
451- rewardAction
452- }
453- else throw("Strict value is not equal to itself.")
454- }
455-
456-
457626 @Verifier(tx)
458627 func verify () = {
459- let targetPublicKey = match managerPublicKeyOrUnit() {
460- case pk: ByteVector =>
461- pk
462- case _: Unit =>
628+ let publicKey = match getManagerPublicKeyOrUnit() {
629+ case pub: ByteVector =>
630+ pub
631+ case _ =>
463632 tx.senderPublicKey
464- case _ =>
465- throw("Match error")
466633 }
467- sigVerify(tx.bodyBytes, tx.proofs[0], targetPublicKey)
634+ sigVerify(tx.bodyBytes, tx.proofs[0], publicKey)
468635 }
469636
Full:
OldNewDifferences
1-{-# STDLIB_VERSION 6 #-}
1+{-# STDLIB_VERSION 7 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let separator = "__"
4+let SEP = "__"
55
6-let MULT8 = 100000000
6+let CONTRACT_NAME = "calculator.ride"
77
8-func wrapErr (msg) = makeString(["voting_verified_v2.ride:", msg], " ")
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
11-func throwErr (msg) = throw(wrapErr(msg))
19+func throwErr (s) = throw(wrapErr(s))
1220
1321
14-func asInt (val) = match val {
15- case valInt: Int =>
16- valInt
22+func assetIdToString (assetId) = match assetId {
23+ case b: ByteVector =>
24+ toBase58String(b)
25+ case _: Unit =>
26+ WAVES
1727 case _ =>
18- throw("Failed to cast into Integer")
28+ throw("Match error")
1929 }
2030
2131
22-func getIntegerOrZero (address,key) = valueOrElse(getInteger(address, key), 0)
32+func stringToAssetId (s) = if ((s == WAVES))
33+ then unit
34+ else fromBase58String(s)
2335
2436
25-func getIntegerOrFail (address,key) = valueOrErrorMessage(getInteger(address, key), wrapErr((key + " is not defined")))
37+func abs (n) = if ((0 > n))
38+ then -(n)
39+ else n
2640
2741
28-func getStringOrEmpty (address,key) = valueOrElse(getString(address, key), "")
42+func keyFactoryAddress () = makeString(["%s", "factory"], SEP)
2943
3044
31-func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), wrapErr((key + " is not defined")))
45+func keyManagerPublicKey () = makeString(["%s", "managerPublicKey"], SEP)
3246
3347
34-let keyBoostingContract = makeString(["%s", "boostingContract"], separator)
35-
36-let keyEmissionContract = makeString(["%s", "emissionContract"], separator)
37-
38-let keyAssetsStoreContract = makeString(["%s", "assetsStoreContract"], separator)
39-
40-let boostingContract = addressFromStringValue(getStringValue(keyBoostingContract))
41-
42-let emissionContract = addressFromStringValue(getStringValue(keyEmissionContract))
43-
44-let assetsStoreContract = addressFromStringValue(getStringValue(keyAssetsStoreContract))
45-
46-let keyEmissionConfig = makeString(["%s", "config"], separator)
47-
48-let wxAssetIdStr = split(getStringOrFail(emissionContract, keyEmissionConfig), separator)[1]
49-
50-let wxAssetId = fromBase58String(wxAssetIdStr)
51-
52-let keyVotingThresholdAdd = makeString(["%s%s", "votingThreshold", "add"], separator)
53-
54-let keyVotingThresholdRemove = makeString(["%s%s", "votingThreshold", "remove"], separator)
55-
56-let keyPeriodLengthRemove = makeString(["%s", "periodLengthRemove"], separator)
57-
58-let keyMaxPeriodLength = makeString(["%s", "maxPeriodLength"], separator)
59-
60-let keyMinPeriodLength = makeString(["%s", "minPeriodLength"], separator)
61-
62-func keyVotingRewardAssetId (assetId,index) = makeString(["%s%s%d", "votingRewardAssetId", assetId, toString(index)], separator)
48+func keyLpAssetId () = makeString(["%s", "lpAssetId"], SEP)
6349
6450
65-func keyVotingReward (userAddress,assetId,index) = makeString(["%s%s%s%d", "votingReward", toString(userAddress), assetId, toString(index)], separator)
51+func keyProxyTreasuryAddress () = makeString(["%s", "proxyTreasury"], SEP)
6652
6753
68-func keyTotalVotingReward (assetId,index) = makeString(["%s%s%d", "totalVotingReward", assetId, toString(index)], separator)
54+func keyMainTreasuryAddress () = makeString(["%s", "mainTreasury"], SEP)
6955
7056
71-let keyFinalizeCallRewardAmount = makeString(["%s", "finalizeCallRewardAmount"], separator)
72-
73-let keyMinSuggestRemoveBalance = makeString(["%s", "minSuggestRemoveBalance"], separator)
74-
75-func keyCurrentIndex (assetId) = makeString(["%s%s", "currentIndex", assetId], separator)
57+func keyInvested (assetId) = makeString(["%s%s", "invested", assetIdToString(assetId)], SEP)
7658
7759
78-func keyVote (assetId,index,caller) = makeString(["%s%s%d%s", "vote", assetId, toString(index), toString(caller)], separator)
60+func keyDonated (assetId) = makeString(["%s%s", "donated", assetIdToString(assetId)], SEP)
7961
8062
81-func voteValue (inFavor,gwxAmount) = makeString(["%s%d", toString(inFavor), toString(gwxAmount)], separator)
63+func keyAvailable (userAddress) = makeString(["%s%s", "available", toString(userAddress)], SEP)
8264
8365
84-func keySuggestIssuer (assetId,index) = makeString(["%s%s%d", "suggestIssuer", assetId, toString(index)], separator)
66+func keyClaimed (userAddress) = makeString(["%s%s", "claimed", toString(userAddress)], SEP)
8567
8668
87-func keyClaimHistory (userAddress,assetId,index) = makeString(["%s%s%s%d", "history", toString(userAddress), assetId, toString(index)], separator)
69+func keyCurrentPeriod () = makeString(["%s", "currentPeriod"], SEP)
8870
8971
90-let keyFeePerBlock = makeString(["%s", "feePerBlock"], separator)
91-
92-let feePerBlock = getIntegerOrFail(this, keyFeePerBlock)
93-
94-let keyMinWxMinForSuggestAddAmountRequired = makeString(["%s", "wxMinForSuggestAddAmountRequired"], separator)
95-
96-let keyWxForSuggestRemoveAmountRequired = makeString(["%s", "wxForSuggestRemoveAmountRequired"], separator)
97-
98-func keyVotingInfo (assetId,index) = makeString(["%s%s%d", "votingInfo", assetId, toString(index)], separator)
72+func keyPriceForPeriod (period) = makeString(["%s%d", "price", toString(period)], SEP)
9973
10074
101-func votingInfoValue (isRewardExist,rewardAssetId,rewardAmount,votingType,status,votingStartHeight,votingEndHeight,votesQuorum,votesFor,votesAgainst) = makeString(["%s%s%d%s%s%d%d%d%d%d", toString(isRewardExist), rewardAssetId, toString(rewardAmount), votingType, status, toString(votingStartHeight), toString(votingEndHeight), toString(votesQuorum), toString(votesFor), toString(votesAgainst)], separator)
75+func keyStartHeight (period) = makeString(["%s%d", "startHeight", toString(period)], SEP)
10276
10377
104-func keyAssetImage (assetId) = makeString(["%s%s", "assetImage", assetId], separator)
78+func keyPowerManagerBonus (period) = makeString(["%s%d", "powerManagerBonus", toString(period)], SEP)
10579
10680
107-func getUserGwxAmountAtHeight (userAddress,targetHeight) = {
108- let gwxAmount = invoke(boostingContract, "getUserGwxAmountAtHeightREADONLY", [userAddress, targetHeight], nil)
109- asInt(gwxAmount)
81+func keyPeriodLength () = "%s__periodLength"
82+
83+
84+func keyBlockProcessingReward () = "%s__blockProcessingReward"
85+
86+
87+func keyNextBlockToProcess () = "%s__nextBlockToProcess"
88+
89+
90+func keyBlockProcessed (height) = makeString(["%s%d", "blockProcessed", toString(height)], SEP)
91+
92+
93+func keyWithdrawal () = "%s__withdrawal"
94+
95+
96+func keyWithdrawalRequest (userAddress,txId) = makeString(["%s%s%s", "withdrawal", toString(userAddress), toBase58String(txId)], SEP)
97+
98+
99+func valueWithdrawalRequest (status,lpAssetAmount,targetPeriod,claimTxId) = {
100+ let claimTxIdStr = match claimTxId {
101+ case b: ByteVector =>
102+ toBase58String(b)
103+ case _: Unit =>
104+ "SOON"
105+ case _ =>
106+ throw("Match error")
107+ }
108+ makeString(["%s%d%d%s", status, toString(lpAssetAmount), toString(targetPeriod), claimTxIdStr], SEP)
110109 }
111110
112111
113-func keyManagerVaultAddress () = "%s__managerVaultAddress"
112+func keyPeriodWithdrawalAssetIds (period) = makeString(["%s%d", "periodReward", toString(period)], SEP)
114113
115114
116-func keyManagerPublicKey () = "%s__managerPublicKey"
115+func keyPeriodWithdrawalAmounts (period) = makeString(["%s%d", "periodRewardAmount", toString(period)], SEP)
117116
118117
119-func getManagerVaultAddressOrThis () = match getString(keyManagerVaultAddress()) {
118+let keyMinHeightForWithdraw = makeString(["%s", "minHeightForWithdraw"], SEP)
119+
120+let keyMaxHeightForWithdraw = makeString(["%s", "maxHeightForWithdraw"], SEP)
121+
122+func parseWithdrawalRequestValueOrFail (s) = {
123+ let parts = split(s, SEP)
124+ if ((size(parts) == 5))
125+ then {
126+ let status = parts[1]
127+ let lpAssetAmount = valueOrErrorMessage(parseInt(parts[2]), wrapErr("invalid lpAssetAmount"))
128+ let targetPeriod = valueOrErrorMessage(parseInt(parts[3]), wrapErr("invalid targetPeriod"))
129+ let claimTxId = parts[4]
130+ $Tuple4(status, lpAssetAmount, targetPeriod, claimTxId)
131+ }
132+ else throwErr("invalid withdrawal request value")
133+ }
134+
135+
136+let factoryAddressOption = match getString(this, keyFactoryAddress()) {
120137 case s: String =>
121- addressFromStringValue(s)
138+ addressFromString(s)
139+ case _: Unit =>
140+ unit
122141 case _ =>
123- this
142+ throw("Match error")
143+}
144+
145+let factoryAddressOrFail = valueOrErrorMessage(factoryAddressOption, wrapErr("invalid factory address"))
146+
147+let lpAssetIdOption = match factoryAddressOption {
148+ case a: Address =>
149+ match getString(a, keyLpAssetId()) {
150+ case s: String =>
151+ fromBase58String(s)
152+ case _: Unit =>
153+ unit
154+ case _ =>
155+ throw("Match error")
156+ }
157+ case _: Unit =>
158+ unit
159+ case _ =>
160+ throw("Match error")
161+}
162+
163+let lpAssetIdOrFail = valueOrErrorMessage(lpAssetIdOption, wrapErr("invalid lpAssetId"))
164+
165+let proxyTreasuryAddressOption = match factoryAddressOption {
166+ case a: Address =>
167+ match getString(a, keyProxyTreasuryAddress()) {
168+ case s: String =>
169+ addressFromString(s)
170+ case _: Unit =>
171+ unit
172+ case _ =>
173+ throw("Match error")
174+ }
175+ case _: Unit =>
176+ unit
177+ case _ =>
178+ throw("Match error")
179+}
180+
181+let proxyTreasuryAddressOrFail = valueOrErrorMessage(proxyTreasuryAddressOption, wrapErr("invalid proxy treasury address"))
182+
183+let mainTreasuryAddressOption = match factoryAddressOption {
184+ case a: Address =>
185+ match getString(a, keyMainTreasuryAddress()) {
186+ case s: String =>
187+ addressFromString(s)
188+ case _: Unit =>
189+ unit
190+ case _ =>
191+ throw("Match error")
192+ }
193+ case _: Unit =>
194+ unit
195+ case _ =>
196+ throw("Match error")
197+}
198+
199+let mainTreasuryAddressOrFail = valueOrErrorMessage(mainTreasuryAddressOption, wrapErr("invalid main treasury address"))
200+
201+func getManagerPublicKeyOrUnit () = match factoryAddressOption {
202+ case fa: Address =>
203+ match getString(fa, keyManagerPublicKey()) {
204+ case pub: String =>
205+ fromBase58String(pub)
206+ case _ =>
207+ unit
208+ }
209+ case _ =>
210+ unit
124211 }
125212
126213
127-func managerPublicKeyOrUnit () = {
128- let managerVaultAddress = getManagerVaultAddressOrThis()
129- match getString(managerVaultAddress, keyManagerPublicKey()) {
130- case s: String =>
131- fromBase58String(s)
132- case _: Unit =>
133- unit
134- case _ =>
135- throw("Match error")
136- }
214+func onlyAddress (i,address) = if ((i.caller == address))
215+ then true
216+ else throwErr("permission denied")
217+
218+
219+func onlyFactory (i) = onlyAddress(i, factoryAddressOrFail)
220+
221+
222+func rewardForOption (rewards,target) = {
223+ let s = size(rewards)
224+ let $t052085233 = rewards[0]
225+ let a0 = $t052085233._1
226+ let r0 = $t052085233._2
227+ let $t052365261 = rewards[1]
228+ let a1 = $t052365261._1
229+ let r1 = $t052365261._2
230+ let $t052645289 = rewards[2]
231+ let a2 = $t052645289._1
232+ let r2 = $t052645289._2
233+ if (if ((s > 0))
234+ then (a0 == target)
235+ else false)
236+ then r0
237+ else if (if ((s > 1))
238+ then (a1 == target)
239+ else false)
240+ then r1
241+ else if (if ((s > 2))
242+ then (a2 == target)
243+ else false)
244+ then r2
245+ else unit
137246 }
138247
139248
140-func getVotingInfoParts (votingInfo) = {
141- let votingInfoParts = split(votingInfo, separator)
142- let isRewardExistStr = votingInfoParts[1]
143- let isRewardExist = if ((isRewardExistStr == "true"))
249+func finalizeINTERNAL (newTreasuryVolumeInWaves,pwrManagersBonusInWaves,treasuryVolumeDiffAllocationCoef) = {
250+ let donatedWavesAmount = valueOrElse(getInteger(factoryAddressOrFail, keyDonated(unit)), 0)
251+ let investedWavesAmount = valueOrElse(getInteger(factoryAddressOrFail, keyInvested(unit)), 0)
252+ let currentTreasuryVolumeInWaves = (donatedWavesAmount + investedWavesAmount)
253+ let profitRaw = (newTreasuryVolumeInWaves - currentTreasuryVolumeInWaves)
254+ let pwrManagersBonusAmount = if (if ((profitRaw >= pwrManagersBonusInWaves))
144255 then true
145- else false
146- let rewardAssetId = votingInfoParts[2]
147- let rewardAmount = parseIntValue(votingInfoParts[3])
148- let votingType = votingInfoParts[4]
149- let status = votingInfoParts[5]
150- let votingStartHeight = parseIntValue(votingInfoParts[6])
151- let votingEndHeight = parseIntValue(votingInfoParts[7])
152- let votesQuorum = parseIntValue(votingInfoParts[8])
153- let votesFor = parseIntValue(votingInfoParts[9])
154- let votesAgainst = parseIntValue(votingInfoParts[10])
155- $Tuple10(isRewardExist, rewardAssetId, rewardAmount, votingType, status, votingStartHeight, votingEndHeight, votesQuorum, votesFor, votesAgainst)
156- }
157-
158-
159-func votingExistChecks (assetId,currentIndex) = {
160- let votingInfo = valueOrErrorMessage(getString(keyVotingInfo(assetId, currentIndex)), wrapErr("voting info not found"))
161- let votingInfoArray = split(votingInfo, separator)
162- let status = votingInfoArray[5]
163- let votingEndHeight = valueOrErrorMessage(parseIntValue(votingInfoArray[7]), wrapErr("voting start height not found"))
164- let suggestIssuer = valueOrErrorMessage(getString(keySuggestIssuer(assetId, currentIndex)), wrapErr("voting issuer not found"))
165- let checks = [if ((status == "inProgress"))
256+ else (pwrManagersBonusInWaves == 0))
257+ then pwrManagersBonusInWaves
258+ else throwErr("power bonus is more than profit")
259+ let profit = (profitRaw - pwrManagersBonusAmount)
260+ let donationPart = if ((currentTreasuryVolumeInWaves > 0))
261+ then fraction(donatedWavesAmount, SCALE8, currentTreasuryVolumeInWaves)
262+ else 0
263+ let donationProfitPartRaw = fraction(profit, donationPart, SCALE8)
264+ let investmentProfitPartRaw = (profit - donationProfitPartRaw)
265+ let treasuryVolumeDiffAllocationCoefAbs = abs(treasuryVolumeDiffAllocationCoef)
266+ let amountToDonation = fraction(investmentProfitPartRaw, if ((0 > treasuryVolumeDiffAllocationCoef))
267+ then treasuryVolumeDiffAllocationCoefAbs
268+ else 0, SCALE8)
269+ let amountToInvestment = fraction(donationProfitPartRaw, if ((treasuryVolumeDiffAllocationCoef > 0))
270+ then treasuryVolumeDiffAllocationCoefAbs
271+ else 0, SCALE8)
272+ let donationProfitPart = ((donationProfitPartRaw - amountToInvestment) + amountToDonation)
273+ let investmentProfitPart = ((investmentProfitPartRaw - amountToDonation) + amountToInvestment)
274+ let donatedWavesAmountNewRaw = (donatedWavesAmount + donationProfitPart)
275+ let investedWavesAmountNewRaw = (investedWavesAmount + investmentProfitPart)
276+ let donatedPartDebt = min([0, donatedWavesAmountNewRaw])
277+ let investedPartDebt = min([0, investedWavesAmountNewRaw])
278+ let donatedWavesAmountNew = (max([0, donatedWavesAmountNewRaw]) + investedPartDebt)
279+ let investedWavesAmountNew = (max([0, investedWavesAmountNewRaw]) + donatedPartDebt)
280+ let lpAssetQuantity = valueOrErrorMessage(assetInfo(lpAssetIdOrFail), wrapErr("invalid lpAsset info")).quantity
281+ let newPrice = fraction(investedWavesAmountNew, SCALE8, lpAssetQuantity)
282+ let checkIfPriceNotZero = if ((newPrice != 0))
166283 then true
167- else throwErr("no voting in progress"), if ((votingEndHeight > height))
168- then true
169- else throwErr("voting expired")]
170- if ((checks == checks))
171- then $Tuple3(status, votingEndHeight, suggestIssuer)
284+ else throwErr("LP price cannot be 0")
285+ if ((checkIfPriceNotZero == checkIfPriceNotZero))
286+ then {
287+ let lpAssetAmountToBurn = valueOrElse(getInteger(factoryAddressOrFail, keyWithdrawal()), 0)
288+ let paymentAmountMin = max([0, fraction(lpAssetAmountToBurn, newPrice, SCALE8)])
289+ let finalInvestedWavesAmount = (investedWavesAmountNew - paymentAmountMin)
290+ let lpAssetFinalQuantity = (lpAssetQuantity - lpAssetAmountToBurn)
291+ $Tuple6(paymentAmountMin, finalInvestedWavesAmount, donatedWavesAmountNew, newPrice, lpAssetAmountToBurn, lpAssetFinalQuantity)
292+ }
172293 else throw("Strict value is not equal to itself.")
173294 }
174295
175296
176-func calculateReward (voter,assetId,index) = {
177- let voteKey = keyVote(assetId, index, voter)
178- let lastVote = valueOrErrorMessage(getString(voteKey), wrapErr("you have not voted"))
179- let lastVoteParts = split(lastVote, separator)
180- let gwxAmount = parseIntValue(lastVoteParts[2])
181- let votingInfoStr = valueOrErrorMessage(getString(keyVotingInfo(assetId, index)), wrapErr("voting info not found"))
182- let votingParts = getVotingInfoParts(votingInfoStr)
183- let votesFor = votingParts._9
184- let votesAgainst = votingParts._10
185- let partOfTheTotalVotesX8 = fraction(gwxAmount, MULT8, (votesFor + votesAgainst))
186- let totalVotingReward = valueOrElse(getInteger(keyTotalVotingReward(assetId, index)), 0)
187- let voterRewardAmount = fraction(partOfTheTotalVotesX8, totalVotingReward, MULT8, FLOOR)
188- voterRewardAmount
189- }
190-
191-
192297 @Callable(i)
193-func suggestAdd (assetId,periodLength,assetImage) = {
194- let wxPayment = i.payments[0]
195- let wxPaymentAssetId = value(wxPayment.assetId)
196- let wxPaymentAmount = value(wxPayment.amount)
197- let minPeriodLength = getIntegerValue(keyMinPeriodLength)
198- let maxPeriodLength = getIntegerValue(keyMaxPeriodLength)
199- let tokenIsVerified = {
200- let @ = invoke(assetsStoreContract, "isVerifiedREADONLY", [assetId], nil)
201- if ($isInstanceOf(@, "Boolean"))
202- then @
203- else throw(($getType(@) + " couldn't be cast to Boolean"))
204- }
205- let checks = [if (if ((periodLength >= minPeriodLength))
206- then (maxPeriodLength >= periodLength)
207- else false)
208- then true
209- else throwErr("invalid periodLength"), if ((tokenIsVerified == false))
210- then true
211- else throwErr("token already verified"), if ((wxPaymentAmount > (periodLength * feePerBlock)))
212- then true
213- else throwErr("not enough wx for given period"), if ((wxPaymentAmount >= getIntegerValue(keyMinWxMinForSuggestAddAmountRequired)))
214- then true
215- else throwErr("payment less then min for suggest")]
216- if ((checks == checks))
298+func claimLP (userAddressBytes) = {
299+ let checkCaller = onlyFactory(i)
300+ if ((checkCaller == checkCaller))
217301 then {
218- let currentIndexKey = keyCurrentIndex(assetId)
219- let currentIndex = getInteger(currentIndexKey)
220- let newIndex = if (isDefined(currentIndex))
221- then (value(currentIndex) + 1)
222- else 0
223- let $t087849424 = if ((size(i.payments) > 1))
224- then {
225- let votingRewardPayment = i.payments[1]
226- let votingRewardPaymentAssetId = toBase58String(value(votingRewardPayment.assetId))
227- let votingRewardPaymentAmount = value(votingRewardPayment.amount)
228- $Tuple4(true, votingRewardPaymentAssetId, votingRewardPaymentAmount, [StringEntry(keyVotingRewardAssetId(assetId, newIndex), votingRewardPaymentAssetId), IntegerEntry(keyTotalVotingReward(assetId, newIndex), votingRewardPaymentAmount)])
229- }
230- else $Tuple4(false, "EMPTY", 0, nil)
231- let isRewardExist = $t087849424._1
232- let rewardAssetId = $t087849424._2
233- let rewardAmount = $t087849424._3
234- let votingRewardActions = $t087849424._4
235- let votesQuorum = valueOrErrorMessage(getInteger(keyVotingThresholdAdd), wrapErr("votingThresholdAdd not set"))
236- let votingInfo = votingInfoValue(isRewardExist, rewardAssetId, rewardAmount, "verification", "inProgress", height, (height + periodLength), votesQuorum, 0, 0)
237- let finalizeCallRewardAmount = getIntegerValue(keyFinalizeCallRewardAmount)
238- let burnWxAmount = (wxPaymentAmount - finalizeCallRewardAmount)
239- ([IntegerEntry(currentIndexKey, newIndex), StringEntry(keySuggestIssuer(assetId, newIndex), toString(i.caller)), StringEntry(keyVotingInfo(assetId, newIndex), votingInfo), StringEntry(keyAssetImage(assetId), assetImage), Burn(wxPaymentAssetId, burnWxAmount)] ++ votingRewardActions)
302+ let userAddress = Address(userAddressBytes)
303+ let available = valueOrElse(getInteger(factoryAddressOrFail, keyAvailable(userAddress)), 0)
304+ let claimed = valueOrElse(getInteger(factoryAddressOrFail, keyClaimed(userAddress)), 0)
305+ let factoryActions = if ((available > 0))
306+ then [invoke(factoryAddressOrFail, "transferAsset", [userAddressBytes, available, lpAssetIdOrFail], nil), invoke(factoryAddressOrFail, "integerEntry", [keyAvailable(userAddress), 0], nil), invoke(factoryAddressOrFail, "integerEntry", [keyClaimed(userAddress), (claimed + available)], nil)]
307+ else throwErr("nothing to claim")
308+ $Tuple2(nil, factoryActions)
240309 }
241310 else throw("Strict value is not equal to itself.")
242311 }
243312
244313
245314
246315 @Callable(i)
247-func suggestRemove (assetId) = {
248- let gwxAmountAtNow = getUserGwxAmountAtHeight(toString(i.caller), height)
249- let minSuggestRemoveBalance = getIntegerValue(keyMinSuggestRemoveBalance)
250- let wxPayment = i.payments[0]
251- let wxPaymentAssetId = value(wxPayment.assetId)
252- let wxPaymentAmount = value(wxPayment.amount)
253- let tokenIsVerified = {
254- let @ = invoke(assetsStoreContract, "isVerifiedREADONLY", [assetId], nil)
255- if ($isInstanceOf(@, "Boolean"))
256- then @
257- else throw(($getType(@) + " couldn't be cast to Boolean"))
258- }
259- let checks = [if (tokenIsVerified)
260- then true
261- else throwErr("token not verified"), if ((gwxAmountAtNow >= minSuggestRemoveBalance))
262- then true
263- else throwErr("not enough gWXes"), if ((wxPaymentAmount >= getIntegerValue(keyWxForSuggestRemoveAmountRequired)))
264- then true
265- else throwErr("payment less then min for suggest")]
266- if ((checks == checks))
316+func finalize (userAddressBytes,newTreasuryVolumeInWaves,pwrManagersBonusInWaves,treasuryVolumeDiffAllocationCoef) = {
317+ let checkCaller = onlyFactory(i)
318+ if ((checkCaller == checkCaller))
267319 then {
268- let currentIndexKey = keyCurrentIndex(assetId)
269- let currentIndex = getInteger(currentIndexKey)
270- let newIndex = if (isDefined(currentIndex))
271- then (value(currentIndex) + 1)
272- else 0
273- let periodLength = valueOrErrorMessage(getInteger(keyPeriodLengthRemove), wrapErr("periodLengthRemove not set"))
274- let votingEndHeight = (height + periodLength)
275- let votesQuorum = valueOrErrorMessage(getInteger(keyVotingThresholdRemove), wrapErr("votingThresholdRemove not set"))
276- let votingInfo = votingInfoValue(false, "EMPTY", 0, "deverification", "inProgress", height, (height + periodLength), votesQuorum, 0, 0)
277-[IntegerEntry(currentIndexKey, newIndex), StringEntry(keySuggestIssuer(assetId, newIndex), toString(i.caller)), StringEntry(keyVotingInfo(assetId, newIndex), votingInfo)]
278- }
279- else throw("Strict value is not equal to itself.")
280- }
281-
282-
283-
284-@Callable(i)
285-func vote (assetId,inFavor) = {
286- let currentIndexKey = keyCurrentIndex(assetId)
287- let currentIndex = valueOrErrorMessage(getInteger(currentIndexKey), wrapErr("voting does not exist"))
288- let votingInfo = votingExistChecks(assetId, currentIndex)
289- if ((votingInfo == votingInfo))
290- then {
291- let currentVotingEndHeight = votingInfo._2
292- let gwxAmountAtEnd = getUserGwxAmountAtHeight(toString(i.caller), currentVotingEndHeight)
293- let voteKey = keyVote(assetId, currentIndex, i.caller)
294- let checks = [if ((getString(voteKey) == unit))
320+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
321+ let periodLength = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPeriodLength()), wrapErr("invalid period length"))
322+ let currentStartHeight = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyStartHeight(currentPeriodOrFail)), wrapErr("invalid start height"))
323+ let currentPriceOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPriceForPeriod(currentPeriodOrFail)), wrapErr("invalid price"))
324+ let nextBlockToProcess = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyNextBlockToProcess()), wrapErr("invalid next block to process"))
325+ let periodEndHeight = ((currentStartHeight + periodLength) - 1)
326+ let checks = [if ((i.originCaller == mainTreasuryAddressOrFail))
295327 then true
296- else throwErr("You have already voted"), if ((gwxAmountAtEnd > 0))
328+ else throwErr("permission denied"), if ((nextBlockToProcess > periodEndHeight))
297329 then true
298- else throw("You'll not have gWX at the end of voting")]
330+ else throwErr("unprocessed blocks"), if ((newTreasuryVolumeInWaves >= 0))
331+ then true
332+ else throwErr("invalid new treasury volume"), if ((pwrManagersBonusInWaves >= 0))
333+ then true
334+ else throwErr("invalid PWR managers bonus"), if (if ((treasuryVolumeDiffAllocationCoef >= -(SCALE8)))
335+ then (SCALE8 >= treasuryVolumeDiffAllocationCoef)
336+ else false)
337+ then true
338+ else throwErr("invalid treasury volume diff allocation coefficient")]
299339 if ((checks == checks))
300340 then {
301- let votingInfoStr = valueOrErrorMessage(getString(keyVotingInfo(assetId, currentIndex)), wrapErr("voting info not found"))
302- let votingInfoParts = getVotingInfoParts(votingInfoStr)
303- let votesFor = votingInfoParts._9
304- let votesAgainst = votingInfoParts._10
305- let $t01274512906 = if (inFavor)
306- then $Tuple2((votesFor + gwxAmountAtEnd), votesAgainst)
307- else $Tuple2(votesFor, (votesAgainst + gwxAmountAtEnd))
308- let newVotesFor = $t01274512906._1
309- let newVotesAgainst = $t01274512906._2
310- let newVotingInfoValue = votingInfoValue(votingInfoParts._1, votingInfoParts._2, votingInfoParts._3, votingInfoParts._4, votingInfoParts._5, votingInfoParts._6, votingInfoParts._7, votingInfoParts._8, newVotesFor, newVotesAgainst)
311- let votingRewardAction = match getString(keyVotingRewardAssetId(assetId, currentIndex)) {
312- case pk: String =>
313-[StringEntry(keyVotingReward(i.caller, assetId, currentIndex), voteValue(inFavor, gwxAmountAtEnd))]
314- case _: Unit =>
315- nil
316- case _ =>
317- throw("Match error")
318- }
319- ([StringEntry(voteKey, voteValue(inFavor, gwxAmountAtEnd)), StringEntry(keyVotingInfo(assetId, currentIndex), newVotingInfoValue)] ++ votingRewardAction)
341+ let $t01078311043 = finalizeINTERNAL(newTreasuryVolumeInWaves, pwrManagersBonusInWaves, treasuryVolumeDiffAllocationCoef)
342+ let paymentAmountMin = $t01078311043._1
343+ let finalInvestedWavesAmount = $t01078311043._2
344+ let donatedWavesAmountNew = $t01078311043._3
345+ let newPrice = $t01078311043._4
346+ let lpAssetAmountToBurn = $t01078311043._5
347+ let lpAssetFinalQuantity = $t01078311043._6
348+ let newPeriod = (currentPeriodOrFail + 1)
349+ func addNewAction (actions,payment) = {
350+ let $t01119111253 = actions
351+ let scriptTransfers = $t01119111253._1
352+ let assetIdsString = $t01119111253._2
353+ let amountsString = $t01119111253._3
354+ let paymentAmount = payment.amount
355+ let paymentAssetId = payment.assetId
356+ let newAssetIdsString = ("%s" + makeString([assetIdsString, assetIdToString(paymentAssetId)], SEP))
357+ let newAmountsString = ("%d" + makeString([amountsString, toString(paymentAmount)], SEP))
358+ let newScriptTransfer = ScriptTransfer(factoryAddressOrFail, paymentAmount, paymentAssetId)
359+ $Tuple3((scriptTransfers :+ newScriptTransfer), newAssetIdsString, newAmountsString)
360+ }
361+
362+ let $t01171311804 = {
363+ let $l = i.payments
364+ let $s = size($l)
365+ let $acc0 = $Tuple3(nil, "", "")
366+ func $f0_1 ($a,$i) = if (($i >= $s))
367+ then $a
368+ else addNewAction($a, $l[$i])
369+
370+ func $f0_2 ($a,$i) = if (($i >= $s))
371+ then $a
372+ else throw("List size exceeds 10")
373+
374+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
375+ }
376+ let scriptTransfers = $t01171311804._1
377+ let AssetIds = $t01171311804._2
378+ let Amounts = $t01171311804._3
379+ let factoryActions = [invoke(factoryAddressOrFail, "integerEntry", [keyPowerManagerBonus(currentPeriodOrFail), pwrManagersBonusInWaves], nil), 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), finalInvestedWavesAmount], nil), invoke(factoryAddressOrFail, "integerEntry", [keyDonated(unit), donatedWavesAmountNew], nil), invoke(factoryAddressOrFail, "stringEntry", [keyPeriodWithdrawalAssetIds(newPeriod), AssetIds], nil), invoke(factoryAddressOrFail, "stringEntry", [keyPeriodWithdrawalAmounts(newPeriod), Amounts], nil)]
380+ $Tuple2(scriptTransfers, factoryActions)
320381 }
321382 else throw("Strict value is not equal to itself.")
322383 }
323384 else throw("Strict value is not equal to itself.")
324385 }
325386
326387
327388
328389 @Callable(i)
329-func cancelVote (assetId) = {
330- let currentIndexKey = keyCurrentIndex(assetId)
331- let currentIndex = valueOrErrorMessage(getInteger(currentIndexKey), wrapErr("voting does not exist"))
332- let voteKey = keyVote(assetId, currentIndex, i.caller)
333- let lastVote = valueOrErrorMessage(getString(voteKey), wrapErr("you have not voted"))
334- let lastVoteParts = split(lastVote, separator)
335- let inFavor = lastVoteParts[1]
336- let gwxAmount = parseIntValue(lastVoteParts[2])
337- let votingInfo = votingExistChecks(assetId, currentIndex)
338- if ((votingInfo == votingInfo))
390+func finalizeREADONLY (newTreasuryVolumeInWaves,pwrManagersBonusInWaves,treasuryVolumeDiffAllocationCoef) = {
391+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
392+ let periodLength = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPeriodLength()), wrapErr("invalid period length"))
393+ let currentStartHeight = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyStartHeight(currentPeriodOrFail)), wrapErr("invalid start height"))
394+ let currentPriceOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPriceForPeriod(currentPeriodOrFail)), wrapErr("invalid price"))
395+ let nextBlockToProcess = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyNextBlockToProcess()), wrapErr("invalid next block to process"))
396+ let periodEndHeight = ((currentStartHeight + periodLength) - 1)
397+ let checks = [if ((nextBlockToProcess > periodEndHeight))
398+ then true
399+ else throwErr("unprocessed blocks"), if ((newTreasuryVolumeInWaves >= 0))
400+ then true
401+ else throwErr("invalid new treasury volume"), if ((pwrManagersBonusInWaves >= 0))
402+ then true
403+ else throwErr("invalid PWR managers bonus"), if (if ((treasuryVolumeDiffAllocationCoef >= -(SCALE8)))
404+ then (SCALE8 >= treasuryVolumeDiffAllocationCoef)
405+ else false)
406+ then true
407+ else throwErr("invalid treasury volume diff allocation coefficient")]
408+ if ((checks == checks))
409+ then $Tuple2(nil, finalizeINTERNAL(newTreasuryVolumeInWaves, pwrManagersBonusInWaves, treasuryVolumeDiffAllocationCoef))
410+ else throw("Strict value is not equal to itself.")
411+ }
412+
413+
414+
415+@Callable(i)
416+func invest (userAddressBytes) = {
417+ let checkCaller = onlyFactory(i)
418+ if ((checkCaller == checkCaller))
339419 then {
340- let checks = [if (if ((inFavor == "true"))
420+ let userAddress = Address(userAddressBytes)
421+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
422+ let currentPriceOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPriceForPeriod(currentPeriodOrFail)), wrapErr("invalid price"))
423+ let payment = if ((size(i.payments) == 1))
424+ then i.payments[0]
425+ else throwErr("invalid payments")
426+ let $t01528515462 = if (if ((payment.assetId == unit))
427+ then (payment.amount > 0)
428+ else false)
429+ then $Tuple2(payment.amount, payment.assetId)
430+ else throwErr("invalid payment amount")
431+ let paymentAmount = $t01528515462._1
432+ let paymentAssetId = $t01528515462._2
433+ let lpAssetAmount = if ((currentPriceOrFail > 0))
434+ then fraction(paymentAmount, SCALE8, currentPriceOrFail)
435+ else 0
436+ let invested = valueOrElse(getInteger(factoryAddressOrFail, keyInvested(unit)), 0)
437+ let actions = [ScriptTransfer(mainTreasuryAddressOrFail, paymentAmount, paymentAssetId)]
438+ let factoryActions = [invoke(factoryAddressOrFail, "integerEntry", [keyInvested(unit), (invested + paymentAmount)], nil), invoke(factoryAddressOrFail, "reissue", [lpAssetAmount], nil), invoke(factoryAddressOrFail, "transferAsset", [userAddressBytes, lpAssetAmount, lpAssetIdOrFail], nil)]
439+ $Tuple2(actions, factoryActions)
440+ }
441+ else throw("Strict value is not equal to itself.")
442+ }
443+
444+
445+
446+@Callable(i)
447+func withdraw (userAddressBytes) = {
448+ let checkCaller = onlyFactory(i)
449+ if ((checkCaller == checkCaller))
450+ then {
451+ let userAddress = Address(userAddressBytes)
452+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
453+ let payment = if ((size(i.payments) == 1))
454+ then i.payments[0]
455+ else throwErr(wrapErr("invalid payments"))
456+ let paymentAssetId = if ((payment.assetId == lpAssetIdOrFail))
457+ then lpAssetIdOrFail
458+ else throwErr("invalid payment asset")
459+ let paymentAmount = if ((payment.amount > 0))
460+ then payment.amount
461+ else throwErr("invalid payment amount")
462+ let withdrawal = valueOrElse(getInteger(factoryAddressOrFail, keyWithdrawal()), 0)
463+ let actions = [ScriptTransfer(factoryAddressOrFail, paymentAmount, paymentAssetId)]
464+ let factoryActions = [invoke(factoryAddressOrFail, "integerEntry", [keyWithdrawal(), (withdrawal + paymentAmount)], nil), invoke(factoryAddressOrFail, "stringEntry", [keyWithdrawalRequest(userAddress, i.transactionId), valueWithdrawalRequest(PENDING, paymentAmount, (currentPeriodOrFail + 1), unit)], nil)]
465+ if ((factoryActions == factoryActions))
466+ then $Tuple2(actions, factoryActions)
467+ else throw("Strict value is not equal to itself.")
468+ }
469+ else throw("Strict value is not equal to itself.")
470+ }
471+
472+
473+
474+@Callable(i)
475+func cancelWithdraw (userAddressBytes,txId) = {
476+ let checkCaller = onlyFactory(i)
477+ if ((checkCaller == checkCaller))
478+ then {
479+ let userAddress = Address(userAddressBytes)
480+ let withdrawalRequestOption = valueOrErrorMessage(getString(factoryAddressOrFail, keyWithdrawalRequest(userAddress, txId)), wrapErr("invalid withdrawal request"))
481+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
482+ let $t01786917982 = parseWithdrawalRequestValueOrFail(withdrawalRequestOption)
483+ let status = $t01786917982._1
484+ let lpAssetAmount = $t01786917982._2
485+ let targetPeriod = $t01786917982._3
486+ let claimTxId = $t01786917982._4
487+ let checks = [if ((status == PENDING))
341488 then true
342- else (inFavor == "false"))
489+ else throwErr("invalid withdrawal request status"), if ((targetPeriod > currentPeriodOrFail))
343490 then true
344- else throwErr("invalid vote")]
491+ else throwErr("invalid withdrawal request period")]
345492 if ((checks == checks))
346493 then {
347- let votingInfoStr = valueOrErrorMessage(getString(keyVotingInfo(assetId, currentIndex)), wrapErr("voting info not found"))
348- let votingInfoParts = getVotingInfoParts(votingInfoStr)
349- let votesFor = votingInfoParts._9
350- let votesAgainst = votingInfoParts._10
351- let $t01453114692 = if ((inFavor == "true"))
352- then $Tuple2((votesFor - gwxAmount), votesAgainst)
353- else $Tuple2(votesFor, (votesAgainst - gwxAmount))
354- let newVotesFor = $t01453114692._1
355- let newVotesAgainst = $t01453114692._2
356- let newVotingInfoValue = votingInfoValue(votingInfoParts._1, votingInfoParts._2, votingInfoParts._3, votingInfoParts._4, votingInfoParts._5, votingInfoParts._6, votingInfoParts._7, votingInfoParts._8, newVotesFor, newVotesAgainst)
357-[StringEntry(keyVotingInfo(assetId, currentIndex), newVotingInfoValue), DeleteEntry(voteKey), DeleteEntry(keyVotingReward(i.caller, assetId, currentIndex))]
494+ let withdrawal = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyWithdrawal()), wrapErr("invalid total withdrawal amount"))
495+ let factoryActions = [invoke(factoryAddressOrFail, "integerEntry", [keyWithdrawal(), if ((withdrawal >= lpAssetAmount))
496+ then (withdrawal - lpAssetAmount)
497+ else throwErr("invalid withdrawal amount")], nil), invoke(factoryAddressOrFail, "deleteEntry", [keyWithdrawalRequest(userAddress, txId)], nil), invoke(factoryAddressOrFail, "transferAsset", [userAddressBytes, lpAssetAmount, lpAssetIdOrFail], nil)]
498+ if ((factoryActions == factoryActions))
499+ then $Tuple2(nil, factoryActions)
500+ else throw("Strict value is not equal to itself.")
358501 }
359502 else throw("Strict value is not equal to itself.")
360503 }
361504 else throw("Strict value is not equal to itself.")
362505 }
363506
364507
365508
366509 @Callable(i)
367-func finalize (assetId) = {
368- let currentIndexKey = keyCurrentIndex(assetId)
369- let currentIndex = valueOrElse(getInteger(currentIndexKey), 0)
370- let votingThresholdAdd = valueOrErrorMessage(getInteger(keyVotingThresholdAdd), wrapErr("votingThresholdAdd not set"))
371- let votingThresholdRemove = valueOrErrorMessage(getInteger(keyVotingThresholdRemove), wrapErr("votingThresholdRemove not set"))
372- let votingInfoStr = valueOrErrorMessage(getString(keyVotingInfo(assetId, currentIndex)), wrapErr("voting info not found"))
373- let votingInfoParts = getVotingInfoParts(votingInfoStr)
374- let votingType = votingInfoParts._4
375- let status = votingInfoParts._5
376- let votingEndHeight = votingInfoParts._7
377- let votingQuorum = votingInfoParts._8
378- let votesFor = votingInfoParts._9
379- let votesAgainst = votingInfoParts._10
380- let checks = [if ((status == "inProgress"))
381- then true
382- else throwErr("voting not in progress"), if ((height >= votingEndHeight))
383- then true
384- else throwErr("voting not finished"), if (isDefined(getString(keyAssetImage(assetId))))
385- then true
386- else throwErr("asset image not set")]
387- if ((checks == checks))
510+func claimCollateral (userAddressBytes,txId) = {
511+ let checkCaller = onlyFactory(i)
512+ if ((checkCaller == checkCaller))
388513 then {
389- let votingAccepted = if (if (((votesFor + votesAgainst) >= votingQuorum))
390- then (votesFor > votesAgainst)
514+ let userAddress = Address(userAddressBytes)
515+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
516+ let withdrawalRequestOption = valueOrErrorMessage(getString(factoryAddressOrFail, keyWithdrawalRequest(userAddress, txId)), wrapErr("invalid withdrawal request"))
517+ let $t01931919432 = parseWithdrawalRequestValueOrFail(withdrawalRequestOption)
518+ let status = $t01931919432._1
519+ let lpAssetAmount = $t01931919432._2
520+ let targetPeriod = $t01931919432._3
521+ let claimTxId = $t01931919432._4
522+ if ((status == FINISHED))
523+ then throwErr("invalid withdrawal request status")
524+ else if ((targetPeriod > currentPeriodOrFail))
525+ then throwErr("invalid withdrawal request period")
526+ else {
527+ let priceOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPriceForPeriod(targetPeriod)), wrapErr("invalid price"))
528+ let amount = if ((priceOrFail > 0))
529+ then fraction(lpAssetAmount, priceOrFail, SCALE8)
530+ else 0
531+ let factoryActions = [invoke(factoryAddressOrFail, "stringEntry", [keyWithdrawalRequest(userAddress, txId), valueWithdrawalRequest(FINISHED, lpAssetAmount, targetPeriod, i.transactionId)], nil), {
532+ let assetsList = removeByIndex(split_51C(getStringValue(factoryAddressOrFail, keyPeriodWithdrawalAssetIds(currentPeriodOrFail)), SEP), 0)
533+ let amountsList = removeByIndex(split_51C(getStringValue(factoryAddressOrFail, keyPeriodWithdrawalAmounts(currentPeriodOrFail)), SEP), 0)
534+ invoke(factoryAddressOrFail, "transferAssets", [userAddressBytes, assetsList, amountsList], nil)
535+ }]
536+ $Tuple2(nil, factoryActions)
537+ }
538+ }
539+ else throw("Strict value is not equal to itself.")
540+ }
541+
542+
543+
544+@Callable(i)
545+func processBlocks (userAddressBytes) = {
546+ let checkCaller = onlyFactory(i)
547+ if ((checkCaller == checkCaller))
548+ then {
549+ let userAddress = Address(userAddressBytes)
550+ let currentPeriodOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyCurrentPeriod()), wrapErr("invalid period"))
551+ let periodLength = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPeriodLength()), wrapErr("invalid period length"))
552+ let currentStartHeight = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyStartHeight(currentPeriodOrFail)), wrapErr("invalid start height"))
553+ let currentPriceOrFail = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyPriceForPeriod(currentPeriodOrFail)), wrapErr("invalid price"))
554+ let nextBlockToProcess = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyNextBlockToProcess()), wrapErr("invalid next block to process"))
555+ let periodEndHeight = ((currentStartHeight + periodLength) - 1)
556+ let blocksProcessingBatchSizeMax = 40
557+ let blocksProcessingBatchSize = if (if (if ((height >= nextBlockToProcess))
558+ then if ((nextBlockToProcess >= currentStartHeight))
559+ then true
560+ else (currentPeriodOrFail == 0)
391561 else false)
392- then true
393- else false
394- let newStatus = if (votingAccepted)
395- then "accepted"
396- else "rejected"
397- let assetImage = getStringValue(keyAssetImage(assetId))
398- let isVotingAccepted = if (votingAccepted)
562+ then (periodEndHeight >= nextBlockToProcess)
563+ else false)
564+ then min([((periodEndHeight - nextBlockToProcess) + 1), blocksProcessingBatchSizeMax])
565+ else throwErr(wrapErr("invalid target block"))
566+ let blockProcessingReward = valueOrErrorMessage(getInteger(factoryAddressOrFail, keyBlockProcessingReward()), wrapErr("invalid block processing reward"))
567+ let blockProcessingRewardByGenerator = (blockProcessingReward / blocksProcessingBatchSize)
568+ let blockProcessingRewardByGeneratorRemainder = (blockProcessingReward - (blockProcessingRewardByGenerator * blocksProcessingBatchSize))
569+ func map (acc,inc) = if ((inc >= blocksProcessingBatchSize))
570+ then acc
571+ else {
572+ let targetBlockHeight = (nextBlockToProcess + inc)
573+ let targetBlockInfo = valueOrErrorMessage(blockInfoByHeight(targetBlockHeight), wrapErr("invalid block info"))
574+ let treasuryRewardOrFail = valueOrErrorMessage(rewardForOption(targetBlockInfo.rewards, proxyTreasuryAddressOrFail), wrapErr(("invalid treasury reward for height " + toString(targetBlockHeight))))
575+ let generator = targetBlockInfo.generator
576+ let available = valueOrElse(getInteger(factoryAddressOrFail, keyAvailable(generator)), 0)
577+ let callerReward = if ((inc == (blocksProcessingBatchSize - 1)))
578+ then (blockProcessingRewardByGenerator + blockProcessingRewardByGeneratorRemainder)
579+ else blockProcessingRewardByGenerator
580+ let lpAssetAmount = if ((currentPriceOrFail > 0))
581+ then fraction((treasuryRewardOrFail - callerReward), SCALE8, currentPriceOrFail)
582+ else 0
583+ 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)]
584+ if ((factoryActionsSingle == factoryActionsSingle))
585+ then {
586+ let $t02400224035 = acc
587+ let lpAssetAcc = $t02400224035._1
588+ let rewardAcc = $t02400224035._2
589+ $Tuple2((lpAssetAcc + lpAssetAmount), (rewardAcc + treasuryRewardOrFail))
590+ }
591+ else throw("Strict value is not equal to itself.")
592+ }
593+
594+ 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]
595+ let $t02430224378 = {
596+ let $l = list
597+ let $s = size($l)
598+ let $acc0 = $Tuple2(0, 0)
599+ func $f0_1 ($a,$i) = if (($i >= $s))
600+ then $a
601+ else map($a, $l[$i])
602+
603+ func $f0_2 ($a,$i) = if (($i >= $s))
604+ then $a
605+ else throw("List size exceeds 40")
606+
607+ $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)
608+ }
609+ if (($t02430224378 == $t02430224378))
399610 then {
400- let votingAcceptedInvokes = if ((votingType == "verification"))
401- then invoke(assetsStoreContract, "createOrUpdate", [assetId, assetImage, true], nil)
402- else invoke(assetsStoreContract, "setVerified", [assetId, false], nil)
403- votingAcceptedInvokes
404- }
405- else nil
406- if ((isVotingAccepted == isVotingAccepted))
407- then {
408- let newVotingInfoValue = votingInfoValue(votingInfoParts._1, votingInfoParts._2, votingInfoParts._3, votingInfoParts._4, newStatus, votingInfoParts._6, votingInfoParts._7, votingInfoParts._8, votingInfoParts._9, votingInfoParts._10)
409- let finalizeCallRewardAmount = getIntegerValue(keyFinalizeCallRewardAmount)
410-[StringEntry(keyVotingInfo(assetId, currentIndex), newVotingInfoValue), ScriptTransfer(i.caller, finalizeCallRewardAmount, wxAssetId)]
611+ let rewardAmountTotal = $t02430224378._2
612+ let lpAssetAmountTotal = $t02430224378._1
613+ let rewardToMainTreasuryAmount = (rewardAmountTotal - blockProcessingReward)
614+ let invested = valueOrElse(getInteger(factoryAddressOrFail, keyInvested(unit)), 0)
615+ let actions = [invoke(factoryAddressOrFail, "reissue", [lpAssetAmountTotal], nil), invoke(factoryAddressOrFail, "integerEntry", [keyNextBlockToProcess(), (nextBlockToProcess + blocksProcessingBatchSize)], nil), invoke(factoryAddressOrFail, "transferFromProxyTreasury", [mainTreasuryAddressOrFail.bytes, rewardToMainTreasuryAmount], nil), invoke(factoryAddressOrFail, "transferFromProxyTreasury", [userAddressBytes, blockProcessingReward], nil), invoke(factoryAddressOrFail, "integerEntry", [keyInvested(unit), (invested + rewardToMainTreasuryAmount)], nil)]
616+ if ((actions == actions))
617+ then $Tuple2(nil, unit)
618+ else throw("Strict value is not equal to itself.")
411619 }
412620 else throw("Strict value is not equal to itself.")
413621 }
414622 else throw("Strict value is not equal to itself.")
415623 }
416624
417625
418-
419-@Callable(i)
420-func claimREADONLY (assetId,index,userAddressStr) = {
421- let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid address"))
422- let votingRewardAssetIdStr = getString(keyVotingRewardAssetId(assetId, index))
423- let rewardAmount = if (isDefined(votingRewardAssetIdStr))
424- then calculateReward(userAddress, assetId, index)
425- else 0
426- $Tuple2(nil, rewardAmount)
427- }
428-
429-
430-
431-@Callable(i)
432-func claim (assetId,index) = {
433- let callerAddress = i.caller
434- let claimHistoryKey = keyClaimHistory(callerAddress, assetId, index)
435- let claimHistory = getInteger(claimHistoryKey)
436- let checks = [if ((claimHistory == unit))
437- then true
438- else throwErr("already claimed")]
439- if ((checks == checks))
440- then {
441- let rewardAmount = if ((calculateReward(callerAddress, assetId, index) > 0))
442- then calculateReward(callerAddress, assetId, index)
443- else throwErr("nothing to claim")
444- let votingRewardAssetIdStr = getString(keyVotingRewardAssetId(assetId, index))
445- let rewardAction = if (isDefined(votingRewardAssetIdStr))
446- then {
447- let votingRewardAssetId = fromBase58String(value(votingRewardAssetIdStr))
448-[ScriptTransfer(callerAddress, rewardAmount, votingRewardAssetId), IntegerEntry(claimHistoryKey, rewardAmount), DeleteEntry(keyVotingReward(callerAddress, assetId, index))]
449- }
450- else throwErr("nothing to claim")
451- rewardAction
452- }
453- else throw("Strict value is not equal to itself.")
454- }
455-
456-
457626 @Verifier(tx)
458627 func verify () = {
459- let targetPublicKey = match managerPublicKeyOrUnit() {
460- case pk: ByteVector =>
461- pk
462- case _: Unit =>
628+ let publicKey = match getManagerPublicKeyOrUnit() {
629+ case pub: ByteVector =>
630+ pub
631+ case _ =>
463632 tx.senderPublicKey
464- case _ =>
465- throw("Match error")
466633 }
467- sigVerify(tx.bodyBytes, tx.proofs[0], targetPublicKey)
634+ sigVerify(tx.bodyBytes, tx.proofs[0], publicKey)
468635 }
469636

github/deemru/w8io/169f3d6 
86.28 ms