2022.12.02 19:39 [3408455] smart account 3PJL8Hn8LACaSBWLQ3UVhctA5cTQLBFwBAP > SELF 0.00000000 Waves

{ "type": 13, "id": "CGhhbCs9bLpH5zzrLoUkuoeVDp7bqz8FadTDaLGR3PgF", "fee": 3100000, "feeAssetId": null, "timestamp": 1669999071223, "version": 1, "sender": "3PJL8Hn8LACaSBWLQ3UVhctA5cTQLBFwBAP", "senderPublicKey": "6PdA345SW1zresPEKuWiLPsh9Ku14mFDW6cZtpCQrp3E", "proofs": [ "F8Du5KBgsREfrmTzLceEvymR9ZSKujCZYZL5Z9uNuKzRoiSekzAbNg6Jiytpw9gtDtfniZnqGyaJtsjiJ3GYm5m" ], "script": "base64:BgJCCAISCAoGCAgBAQEIEgUKAwEIAhIDCgEBEgMKAQESBAoCCAgSBAoCCAgSAwoBCBIDCgEIEgQKAggBEgASAwoBCBIAbgADU0VQAgJfXwAGU0NBTEU4AAgABU1VTFQ4AIDC1y8ADlBPT0xXRUlHSFRNVUxUBQVNVUxUOAEEc3RyZgIHYWRkcmVzcwNrZXkJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBQdhZGRyZXNzBQNrZXkJAKwCAgkArAICAg9tYW5kYXRvcnkgdGhpcy4FA2tleQIPIGlzIG5vdCBkZWZpbmVkAQNpb3oCB2FkZHJlc3MDa2V5CQELdmFsdWVPckVsc2UCCQCaCAIFB2FkZHJlc3MFA2tleQAAAQNpb2QDB2FkZHJlc3MDa2V5CmRlZmF1bHRWYWwJAQt2YWx1ZU9yRWxzZQIJAJoIAgUHYWRkcmVzcwUDa2V5BQpkZWZhdWx0VmFsAQNpb2YCB2FkZHJlc3MDa2V5CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUHYWRkcmVzcwUDa2V5CQCsAgIJAKwCAgIPbWFuZGF0b3J5IHRoaXMuBQNrZXkCDyBpcyBub3QgZGVmaW5lZAEDYWJzAQN2YWwDCQBmAgAABQN2YWwJAQEtAQUDdmFsBQN2YWwBA2FhbAEDdmFsBAckbWF0Y2gwBQN2YWwDCQABAgUHJG1hdGNoMAIJTGlzdFtBbnldBAp2YWxBbnlMeXN0BQckbWF0Y2gwBQp2YWxBbnlMeXN0CQACAQIbZmFpbCB0byBjYXN0IGludG8gTGlzdFtBbnldAQJhaQEDdmFsBAckbWF0Y2gwBQN2YWwDCQABAgUHJG1hdGNoMAIDSW50BAZ2YWxJbnQFByRtYXRjaDAFBnZhbEludAkAAgECFWZhaWwgdG8gY2FzdCBpbnRvIEludAEba2V5UmVmZXJyYWxzQ29udHJhY3RBZGRyZXNzAAkAuQkCCQDMCAICBCVzJXMJAMwIAgIGY29uZmlnCQDMCAICGHJlZmVycmFsc0NvbnRyYWN0QWRkcmVzcwUDbmlsBQNTRVAAHnJlZmVycmFsc0NvbnRyYWN0QWRkcmVzc09yRmFpbAkBEUBleHRyTmF0aXZlKDEwNjIpAQkBBHN0cmYCBQR0aGlzCQEba2V5UmVmZXJyYWxzQ29udHJhY3RBZGRyZXNzAAAWa2V5UmVmZXJyYWxQcm9ncmFtTmFtZQkAuQkCCQDMCAICBCVzJXMJAMwIAgIIcmVmZXJyYWwJAMwIAgILcHJvZ3JhbU5hbWUFA25pbAUDU0VQABpyZWZlcnJhbFByb2dyYW1OYW1lRGVmYXVsdAIGd3hsb2NrABNyZWZlcnJhbFByb2dyYW1OYW1lCQELdmFsdWVPckVsc2UCCQCdCAIFBHRoaXMFFmtleVJlZmVycmFsUHJvZ3JhbU5hbWUFGnJlZmVycmFsUHJvZ3JhbU5hbWVEZWZhdWx0ARFrZXlGYWN0b3J5QWRkcmVzcwACHCVzJXNfX2NvbmZpZ19fZmFjdG9yeUFkZHJlc3MAGElkeEZhY3RvcnlDZmdTdGFraW5nRGFwcAABABlJZHhGYWN0b3J5Q2ZnQm9vc3RpbmdEYXBwAAIAFElkeEZhY3RvcnlDZmdJZG9EYXBwAAMAFUlkeEZhY3RvcnlDZmdUZWFtRGFwcAAEABlJZHhGYWN0b3J5Q2ZnRW1pc3Npb25EYXBwAAUAFUlkeEZhY3RvcnlDZmdSZXN0RGFwcAAGABlJZHhGYWN0b3J5Q2ZnU2xpcHBhZ2VEYXBwAAcAFElkeEZhY3RvcnlDZmdEYW9EYXBwAAgAGklkeEZhY3RvcnlDZmdNYXJrZXRpbmdEYXBwAAkAGklkeEZhY3RvcnlDZmdHd3hSZXdhcmREYXBwAAoAFklkeEZhY3RvcnlDZmdCaXJkc0RhcHAACwENa2V5RmFjdG9yeUNmZwACESVzX19mYWN0b3J5Q29uZmlnARprZXlGYWN0b3J5THAyQXNzZXRzTWFwcGluZwEKbHBBc3NldFN0cgkAuQkCCQDMCAICBiVzJXMlcwkAzAgCBQpscEFzc2V0U3RyCQDMCAICHm1hcHBpbmdzX19scEFzc2V0MlBvb2xDb250cmFjdAUDbmlsBQNTRVABEGtleUZhY3RvcnlMcExpc3QAAhAlc19fbHBUb2tlbnNMaXN0ASZrZXlGYWN0b3J5THBBc3NldFRvUG9vbENvbnRyYWN0QWRkcmVzcwEKbHBBc3NldFN0cgkAuQkCCQDMCAICBiVzJXMlcwkAzAgCBQpscEFzc2V0U3RyCQDMCAICHm1hcHBpbmdzX19scEFzc2V0MlBvb2xDb250cmFjdAUDbmlsBQNTRVABFGtleUZhY3RvcnlQb29sV2VpZ2h0AQ9jb250cmFjdEFkZHJlc3MJALkJAgkAzAgCAgQlcyVzCQDMCAICCnBvb2xXZWlnaHQJAMwIAgUPY29udHJhY3RBZGRyZXNzBQNuaWwFA1NFUAEba2V5RmFjdG9yeVBvb2xXZWlnaHRIaXN0b3J5Agtwb29sQWRkcmVzcwNudW0JAKwCAgkArAICCQCsAgICEiVzJXNfX3Bvb2xXZWlnaHRfXwULcG9vbEFkZHJlc3MCAl9fCQCkAwEFA251bQEYcmVhZEZhY3RvcnlBZGRyZXNzT3JGYWlsAAkBEUBleHRyTmF0aXZlKDEwNjIpAQkBBHN0cmYCBQR0aGlzCQERa2V5RmFjdG9yeUFkZHJlc3MAAQpyZWFkTHBMaXN0AAkAtQkCCQELdmFsdWVPckVsc2UCCQCdCAIJARhyZWFkRmFjdG9yeUFkZHJlc3NPckZhaWwACQEQa2V5RmFjdG9yeUxwTGlzdAACAAUDU0VQARRyZWFkRmFjdG9yeUNmZ09yRmFpbAEHZmFjdG9yeQkAtQkCCQEEc3RyZgIFB2ZhY3RvcnkJAQ1rZXlGYWN0b3J5Q2ZnAAUDU0VQARhnZXRCb29zdGluZ0FkZHJlc3NPckZhaWwBCmZhY3RvcnlDZmcJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAJEDAgUKZmFjdG9yeUNmZwUZSWR4RmFjdG9yeUNmZ0Jvb3N0aW5nRGFwcAEYZ2V0RW1pc3Npb25BZGRyZXNzT3JGYWlsAQpmYWN0b3J5Q2ZnCQERQGV4dHJOYXRpdmUoMTA2MikBCQCRAwIFCmZhY3RvcnlDZmcFGUlkeEZhY3RvcnlDZmdFbWlzc2lvbkRhcHABF2dldFN0YWtpbmdBZGRyZXNzT3JGYWlsAQpmYWN0b3J5Q2ZnCQERQGV4dHJOYXRpdmUoMTA2MikBCQCRAwIFCmZhY3RvcnlDZmcFGElkeEZhY3RvcnlDZmdTdGFraW5nRGFwcAEZZ2V0R3d4UmV3YXJkQWRkcmVzc09yRmFpbAEKZmFjdG9yeUNmZwkBEUBleHRyTmF0aXZlKDEwNjIpAQkAkQMCBQpmYWN0b3J5Q2ZnBRpJZHhGYWN0b3J5Q2ZnR3d4UmV3YXJkRGFwcAETa2V5TWFuYWdlclB1YmxpY0tleQACFCVzX19tYW5hZ2VyUHVibGljS2V5ARprZXlQZW5kaW5nTWFuYWdlclB1YmxpY0tleQACGyVzX19wZW5kaW5nTWFuYWdlclB1YmxpY0tleQEea2V5RW1pc3Npb25SYXRlUGVyQmxvY2tDdXJyZW50AAIbJXMlc19fcmF0ZVBlckJsb2NrX19jdXJyZW50ASFrZXlFbWlzc2lvblJhdGVQZXJCbG9ja01heEN1cnJlbnQAAh4lcyVzX19yYXRlUGVyQmxvY2tNYXhfX2N1cnJlbnQBFWtleUVtaXNzaW9uU3RhcnRCbG9jawACGiVzJXNfX2VtaXNzaW9uX19zdGFydEJsb2NrARtrZXlFbWlzc2lvbkR1cmF0aW9uSW5CbG9ja3MAAhglcyVzX19lbWlzc2lvbl9fZHVyYXRpb24BE2tleUVtaXNzaW9uRW5kQmxvY2sAAhglcyVzX19lbWlzc2lvbl9fZW5kQmxvY2sBDWtleU5leHRQZXJpb2QAAg4lc19fbmV4dFBlcmlvZAEfa2V5R3d4UmV3YXJkRW1pc3Npb25TdGFydEhlaWdodAACKCVzJXNfX2d3eFJld2FyZEVtaXNzaW9uUGFydF9fc3RhcnRIZWlnaHQADUlkeENmZ0Fzc2V0SWQAAQATSWR4Q2ZnTWluTG9ja0Ftb3VudAACABVJZHhDZmdNaW5Mb2NrRHVyYXRpb24AAwAVSWR4Q2ZnTWF4TG9ja0R1cmF0aW9uAAQAEklkeENmZ01hdGhDb250cmFjdAAFAQlrZXlDb25maWcAAgolc19fY29uZmlnARVyZWFkQ29uZmlnQXJyYXlPckZhaWwACQC1CQIJAQRzdHJmAgUEdGhpcwkBCWtleUNvbmZpZwAFA1NFUAAMbWF0aENvbnRyYWN0CQERQGV4dHJOYXRpdmUoMTA2MikBCQCRAwIJARVyZWFkQ29uZmlnQXJyYXlPckZhaWwABRJJZHhDZmdNYXRoQ29udHJhY3QBDWZvcm1hdENvbmZpZ1MFB2Fzc2V0SWQNbWluTG9ja0Ftb3VudA9taW5Mb2NrRHVyYXRpb24PbWF4TG9ja0R1cmF0aW9uDG1hdGhDb250cmFjdAkAuQkCCQDMCAICCCVzJWQlZCVkCQDMCAIFB2Fzc2V0SWQJAMwIAgUNbWluTG9ja0Ftb3VudAkAzAgCBQ9taW5Mb2NrRHVyYXRpb24JAMwIAgUPbWF4TG9ja0R1cmF0aW9uCQDMCAIFDG1hdGhDb250cmFjdAUDbmlsBQNTRVABDGZvcm1hdENvbmZpZwUHYXNzZXRJZA1taW5Mb2NrQW1vdW50D21pbkxvY2tEdXJhdGlvbg9tYXhMb2NrRHVyYXRpb24MbWF0aENvbnRyYWN0CQENZm9ybWF0Q29uZmlnUwUFB2Fzc2V0SWQJAKQDAQUNbWluTG9ja0Ftb3VudAkApAMBBQ9taW5Mb2NrRHVyYXRpb24JAKQDAQUPbWF4TG9ja0R1cmF0aW9uBQxtYXRoQ29udHJhY3QBFm1hbmFnZXJQdWJsaWNLZXlPclVuaXQABAckbWF0Y2gwCQCiCAEJARNrZXlNYW5hZ2VyUHVibGljS2V5AAMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAXMFByRtYXRjaDAJANkEAQUBcwMJAAECBQckbWF0Y2gwAgRVbml0BQR1bml0CQACAQILTWF0Y2ggZXJyb3IBHXBlbmRpbmdNYW5hZ2VyUHVibGljS2V5T3JVbml0AAQHJG1hdGNoMAkAoggBCQEaa2V5UGVuZGluZ01hbmFnZXJQdWJsaWNLZXkAAwkAAQIFByRtYXRjaDACBlN0cmluZwQBcwUHJG1hdGNoMAkA2QQBBQFzAwkAAQIFByRtYXRjaDACBFVuaXQFBHVuaXQJAAIBAgtNYXRjaCBlcnJvcgELbXVzdE1hbmFnZXIBAWkEAnBkCQACAQIRUGVybWlzc2lvbiBkZW5pZWQEByRtYXRjaDAJARZtYW5hZ2VyUHVibGljS2V5T3JVbml0AAMJAAECBQckbWF0Y2gwAgpCeXRlVmVjdG9yBAJwawUHJG1hdGNoMAMJAAACCAUBaQ9jYWxsZXJQdWJsaWNLZXkFAnBrBgUCcGQDCQABAgUHJG1hdGNoMAIEVW5pdAMJAAACCAUBaQZjYWxsZXIFBHRoaXMGBQJwZAkAAgECC01hdGNoIGVycm9yAA5JZHhMb2NrVXNlck51bQABAA1JZHhMb2NrQW1vdW50AAIADElkeExvY2tTdGFydAADAA9JZHhMb2NrRHVyYXRpb24ABAANSWR4TG9ja1BhcmFtSwAFAA1JZHhMb2NrUGFyYW1CAAYBE2tleUxvY2tQYXJhbXNSZWNvcmQBC3VzZXJBZGRyZXNzCQC5CQIJAMwIAgIKJXMlc19fbG9jawkAzAgCBQt1c2VyQWRkcmVzcwUDbmlsBQNTRVABGnJlYWRMb2NrUGFyYW1zUmVjb3JkT3JGYWlsAQt1c2VyQWRkcmVzcwkAtQkCCQEEc3RyZgIFBHRoaXMJARNrZXlMb2NrUGFyYW1zUmVjb3JkAQULdXNlckFkZHJlc3MFA1NFUAEXZm9ybWF0TG9ja1BhcmFtc1JlY29yZFMIB3VzZXJOdW0GYW1vdW50BXN0YXJ0CGR1cmF0aW9uBnBhcmFtSwZwYXJhbUIQbGFzdFVwZFRpbWVzdGFtcAlnd3hBbW91bnQJALkJAgkAzAgCAhAlZCVkJWQlZCVkJWQlZCVkCQDMCAIFB3VzZXJOdW0JAMwIAgUGYW1vdW50CQDMCAIFBXN0YXJ0CQDMCAIFCGR1cmF0aW9uCQDMCAIFBnBhcmFtSwkAzAgCBQZwYXJhbUIJAMwIAgUQbGFzdFVwZFRpbWVzdGFtcAkAzAgCBQlnd3hBbW91bnQFA25pbAUDU0VQARZmb3JtYXRMb2NrUGFyYW1zUmVjb3JkBwd1c2VyTnVtBmFtb3VudAVzdGFydAhkdXJhdGlvbgZwYXJhbUsGcGFyYW1CCWd3eEFtb3VudAkBF2Zvcm1hdExvY2tQYXJhbXNSZWNvcmRTCAUHdXNlck51bQkApAMBBQZhbW91bnQJAKQDAQUFc3RhcnQJAKQDAQUIZHVyYXRpb24JAKQDAQUGcGFyYW1LCQCkAwEFBnBhcmFtQgkApAMBCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAkApAMBBQlnd3hBbW91bnQBDmtleU5leHRVc2VyTnVtAAIPJXNfX25leHRVc2VyTnVtARJrZXlVc2VyMk51bU1hcHBpbmcBC3VzZXJBZGRyZXNzCQC5CQIJAMwIAgIZJXMlcyVzX19tYXBwaW5nX191c2VyMm51bQkAzAgCBQt1c2VyQWRkcmVzcwUDbmlsBQNTRVABEmtleU51bTJVc2VyTWFwcGluZwEDbnVtCQC5CQIJAMwIAgIZJXMlcyVzX19tYXBwaW5nX19udW0ydXNlcgkAzAgCBQNudW0FA25pbAUDU0VQARZrZXlMb2NrUGFyYW1Vc2VyQW1vdW50AQd1c2VyTnVtCQC5CQIJAMwIAgIWJXMlZCVzX19wYXJhbUJ5VXNlck51bQkAzAgCBQd1c2VyTnVtCQDMCAICBmFtb3VudAUDbmlsBQNTRVABFmtleUxvY2tQYXJhbVN0YXJ0QmxvY2sBB3VzZXJOdW0JALkJAgkAzAgCAhYlcyVkJXNfX3BhcmFtQnlVc2VyTnVtCQDMCAIFB3VzZXJOdW0JAMwIAgIFc3RhcnQFA25pbAUDU0VQARRrZXlMb2NrUGFyYW1EdXJhdGlvbgEHdXNlck51bQkAuQkCCQDMCAICFiVzJWQlc19fcGFyYW1CeVVzZXJOdW0JAMwIAgUHdXNlck51bQkAzAgCAghkdXJhdGlvbgUDbmlsBQNTRVABDWtleUxvY2tQYXJhbUsBB3VzZXJOdW0JALkJAgkAzAgCAhYlcyVkJXNfX3BhcmFtQnlVc2VyTnVtCQDMCAIFB3VzZXJOdW0JAMwIAgIBawUDbmlsBQNTRVABDWtleUxvY2tQYXJhbUIBB3VzZXJOdW0JALkJAgkAzAgCAhYlcyVkJXNfX3BhcmFtQnlVc2VyTnVtCQDMCAIFB3VzZXJOdW0JAMwIAgIBYgUDbmlsBQNTRVABFWtleUxvY2tQYXJhbUJ5UGVyaW9kSwIHdXNlck51bQZwZXJpb2QJALkJAgkAzAgCAhclcyVkJXMlZF9fcGFyYW1CeVBlcmlvZAkAzAgCBQd1c2VyTnVtCQDMCAICAWsJAMwIAgUGcGVyaW9kBQNuaWwFA1NFUAEVa2V5TG9ja1BhcmFtQnlQZXJpb2RCAgd1c2VyTnVtBnBlcmlvZAkAuQkCCQDMCAICFyVzJWQlcyVkX19wYXJhbUJ5UGVyaW9kCQDMCAIFB3VzZXJOdW0JAMwIAgIBYgkAzAgCBQZwZXJpb2QFA25pbAUDU0VQARdrZXlMb2NrUGFyYW1Ub3RhbEFtb3VudAACHiVzJXNfX3N0YXRzX19hY3RpdmVUb3RhbExvY2tlZAEga2V5U3RhdHNMb2Nrc0R1cmF0aW9uU3VtSW5CbG9ja3MAAiUlcyVzX19zdGF0c19fbG9ja3NEdXJhdGlvblN1bUluQmxvY2tzARJrZXlTdGF0c0xvY2tzQ291bnQAAhclcyVzX19zdGF0c19fbG9ja3NDb3VudAESa2V5U3RhdHNVc2Vyc0NvdW50AAIdJXMlc19fc3RhdHNfX2FjdGl2ZVVzZXJzQ291bnQBIGtleVVzZXJCb29zdEVtaXNzaW9uTGFzdElOVEVHUkFMAQd1c2VyTnVtCQC5CQIJAMwIAgIeJXMlZF9fdXNlckJvb3N0RW1pc3Npb25MYXN0SW50CQDMCAIFB3VzZXJOdW0FA25pbAUDU0VQASJrZXlVc2VyTHBCb29zdEVtaXNzaW9uTGFzdElOVEVHUkFMAgd1c2VyTnVtCWxwQXNzZXRJZAkAuQkCCQDMCAICHiVzJWRfX3VzZXJCb29zdEVtaXNzaW9uTGFzdEludAkAzAgCBQd1c2VyTnVtCQDMCAIFCWxwQXNzZXRJZAUDbmlsBQNTRVABF2tleVVzZXJNYXhCb29zdElOVEVHUkFMAQd1c2VyTnVtCQC5CQIJAMwIAgIRJXMlZF9fbWF4Qm9vc3RJbnQJAMwIAgUHdXNlck51bQUDbmlsBQNTRVABGGtleVRvdGFsTWF4Qm9vc3RJTlRFR1JBTAACGCVzJXNfX21heEJvb3N0SW50X190b3RhbAEha2V5VXNlckJvb3N0QXZhbGFpYmxlVG9DbGFpbVRvdGFsAQd1c2VyTnVtCQC5CQIJAMwIAgIkJXMlZF9fdXNlckJvb3N0QXZhbGlhYmxlVG9DbGFpbVRvdGFsCQDMCAIFB3VzZXJOdW0FA25pbAUDU0VQARNrZXlVc2VyQm9vc3RDbGFpbWVkAQd1c2VyTnVtCQC5CQIJAMwIAgIWJXMlZF9fdXNlckJvb3N0Q2xhaW1lZAkAzAgCBQd1c2VyTnVtBQNuaWwFA1NFUAERa2V5VG90YWxDYWNoZWRHd3gAAhYlcyVzX19nd3hDYWNoZWRfX3RvdGFsARtrZXlUb3RhbENhY2hlZEd3eENvcnJlY3RpdmUAAhwlc19fZ3d4Q2FjaGVkVG90YWxDb3JyZWN0aXZlAA9mYWN0b3J5Q29udHJhY3QJARhyZWFkRmFjdG9yeUFkZHJlc3NPckZhaWwAAApmYWN0b3J5Q2ZnCQEUcmVhZEZhY3RvcnlDZmdPckZhaWwBBQ9mYWN0b3J5Q29udHJhY3QAEGVtaXNzaW9uQ29udHJhY3QJARhnZXRFbWlzc2lvbkFkZHJlc3NPckZhaWwBBQpmYWN0b3J5Q2ZnAA9zdGFraW5nQ29udHJhY3QJARdnZXRTdGFraW5nQWRkcmVzc09yRmFpbAEFCmZhY3RvcnlDZmcAEWd3eFJld2FyZENvbnRyYWN0CQEZZ2V0R3d4UmV3YXJkQWRkcmVzc09yRmFpbAEFCmZhY3RvcnlDZmcBEWdldFRvdGFsQ2FjaGVkR3d4AQdjb3JyZWN0BBlrZXlWb3RpbmdFbWlzc2lvbkNvbnRyYWN0CQC5CQIJAMwIAgICJXMJAMwIAgIWdm90aW5nRW1pc3Npb25Db250cmFjdAUDbmlsBQNTRVAEFnZvdGluZ0VtaXNzaW9uQ29udHJhY3QJARFAZXh0ck5hdGl2ZSgxMDYyKQEJARFAZXh0ck5hdGl2ZSgxMDUzKQIFD2ZhY3RvcnlDb250cmFjdAUZa2V5Vm90aW5nRW1pc3Npb25Db250cmFjdAQRa2V5Q3VycmVudEVwb2NoVWkJALkJAgkAzAgCAgIlcwkAzAgCAg5jdXJyZW50RXBvY2hVaQUDbmlsBQNTRVAEDmN1cnJlbnRFcG9jaFVpCQERQGV4dHJOYXRpdmUoMTA1MCkCBRZ2b3RpbmdFbWlzc2lvbkNvbnRyYWN0BRFrZXlDdXJyZW50RXBvY2hVaQQOa2V5VGFyZ2V0RXBvY2gJALkJAgkAzAgCAgQlcyVzCQDMCAICKXRvdGFsQ2FjaGVkR3d4Q29ycmVjdGlvbl9fYWN0aXZhdGlvbkVwb2NoBQNuaWwFA1NFUAQRdGFyZ2V0RXBvY2hPcHRpb24JAJoIAgUEdGhpcwUOa2V5VGFyZ2V0RXBvY2gEEXRvdGFsQ2FjaGVkR3d4UmF3CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJARFrZXlUb3RhbENhY2hlZEd3eAAAAAQVaXNDb3JyZWN0aW9uQWN0aXZhdGVkAwkBCWlzRGVmaW5lZAEFEXRhcmdldEVwb2NoT3B0aW9uCQBnAgUOY3VycmVudEVwb2NoVWkJAQV2YWx1ZQEFEXRhcmdldEVwb2NoT3B0aW9uBwQKY29ycmVjdGl2ZQMDBRVpc0NvcnJlY3Rpb25BY3RpdmF0ZWQFB2NvcnJlY3QHCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJARtrZXlUb3RhbENhY2hlZEd3eENvcnJlY3RpdmUAAAAAAAkAlgMBCQDMCAIAAAkAzAgCCQBkAgURdG90YWxDYWNoZWRHd3hSYXcFCmNvcnJlY3RpdmUFA25pbAEMSGlzdG9yeUVudHJ5CAR0eXBlBHVzZXIGYW1vdW50CWxvY2tTdGFydAhkdXJhdGlvbgFrAWIBaQQKaGlzdG9yeUtFWQkAuQkCCQDMCAICESVzJXMlcyVzX19oaXN0b3J5CQDMCAIFBHR5cGUJAMwIAgUEdXNlcgkAzAgCCQDYBAEIBQFpDXRyYW5zYWN0aW9uSWQFA25pbAUDU0VQBAtoaXN0b3J5REFUQQkAuQkCCQDMCAICDiVkJWQlZCVkJWQlZCVkCQDMCAIJAKQDAQgFCWxhc3RCbG9jawZoZWlnaHQJAMwIAgkApAMBCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAkAzAgCCQCkAwEFBmFtb3VudAkAzAgCCQCkAwEFCWxvY2tTdGFydAkAzAgCCQCkAwEFCGR1cmF0aW9uCQDMCAIJAKQDAQUBawkAzAgCCQCkAwEFAWIFA25pbAUDU0VQCQELU3RyaW5nRW50cnkCBQpoaXN0b3J5S0VZBQtoaXN0b3J5REFUQQEKU3RhdHNFbnRyeQQOdG90YWxMb2NrZWRJbmMLZHVyYXRpb25JbmMMbG9ja0NvdW50SW5jDXVzZXJzQ291bnRJbmMEG2xvY2tzRHVyYXRpb25TdW1JbkJsb2Nrc0tFWQkBIGtleVN0YXRzTG9ja3NEdXJhdGlvblN1bUluQmxvY2tzAAQNbG9ja3NDb3VudEtFWQkBEmtleVN0YXRzTG9ja3NDb3VudAAEDXVzZXJzQ291bnRLRVkJARJrZXlTdGF0c1VzZXJzQ291bnQABA50b3RhbEFtb3VudEtFWQkBF2tleUxvY2tQYXJhbVRvdGFsQW1vdW50AAQYbG9ja3NEdXJhdGlvblN1bUluQmxvY2tzCQEDaW96AgUEdGhpcwUbbG9ja3NEdXJhdGlvblN1bUluQmxvY2tzS0VZBApsb2Nrc0NvdW50CQEDaW96AgUEdGhpcwUNbG9ja3NDb3VudEtFWQQKdXNlcnNDb3VudAkBA2lvegIFBHRoaXMFDXVzZXJzQ291bnRLRVkEC3RvdGFsQW1vdW50CQEDaW96AgUEdGhpcwUOdG90YWxBbW91bnRLRVkJAMwIAgkBDEludGVnZXJFbnRyeQIFG2xvY2tzRHVyYXRpb25TdW1JbkJsb2Nrc0tFWQkAZAIFGGxvY2tzRHVyYXRpb25TdW1JbkJsb2NrcwULZHVyYXRpb25JbmMJAMwIAgkBDEludGVnZXJFbnRyeQIFDWxvY2tzQ291bnRLRVkJAGQCBQpsb2Nrc0NvdW50BQxsb2NrQ291bnRJbmMJAMwIAgkBDEludGVnZXJFbnRyeQIFDXVzZXJzQ291bnRLRVkJAGQCBQp1c2Vyc0NvdW50BQ11c2Vyc0NvdW50SW5jCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ50b3RhbEFtb3VudEtFWQkAZAIFC3RvdGFsQW1vdW50BQ50b3RhbExvY2tlZEluYwUDbmlsAQ1jYWxjR3d4QW1vdW50AwRrUmF3BGJSYXcBaAQFU0NBTEUA6AcJAGkCCQBkAgkAaAIFBGtSYXcFAWgFBGJSYXcFBVNDQUxFAQ9Mb2NrUGFyYW1zRW50cnkIC3VzZXJBZGRyZXNzB3VzZXJOdW0GYW1vdW50BXN0YXJ0CGR1cmF0aW9uAWsBYgZwZXJpb2QEDXVzZXJBbW91bnRLRVkJARZrZXlMb2NrUGFyYW1Vc2VyQW1vdW50AQUHdXNlck51bQQNc3RhcnRCbG9ja0tFWQkBFmtleUxvY2tQYXJhbVN0YXJ0QmxvY2sBBQd1c2VyTnVtBAtkdXJhdGlvbktFWQkBFGtleUxvY2tQYXJhbUR1cmF0aW9uAQUHdXNlck51bQQEa0tFWQkBDWtleUxvY2tQYXJhbUsBBQd1c2VyTnVtBARiS0VZCQENa2V5TG9ja1BhcmFtQgEFB3VzZXJOdW0EDGtCeVBlcmlvZEtFWQkBFWtleUxvY2tQYXJhbUJ5UGVyaW9kSwIFB3VzZXJOdW0FBnBlcmlvZAQMYkJ5UGVyaW9kS0VZCQEVa2V5TG9ja1BhcmFtQnlQZXJpb2RCAgUHdXNlck51bQUGcGVyaW9kBAlnd3hBbW91bnQJAQ1jYWxjR3d4QW1vdW50AwUBawUBYgUGaGVpZ2h0CQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ11c2VyQW1vdW50S0VZBQZhbW91bnQJAMwIAgkBDEludGVnZXJFbnRyeQIFDXN0YXJ0QmxvY2tLRVkFBXN0YXJ0CQDMCAIJAQxJbnRlZ2VyRW50cnkCBQtkdXJhdGlvbktFWQUIZHVyYXRpb24JAMwIAgkBDEludGVnZXJFbnRyeQIFBGtLRVkFAWsJAMwIAgkBDEludGVnZXJFbnRyeQIFBGJLRVkFAWIJAMwIAgkBDEludGVnZXJFbnRyeQIFDGtCeVBlcmlvZEtFWQUBawkAzAgCCQEMSW50ZWdlckVudHJ5AgUMYkJ5UGVyaW9kS0VZBQFiCQDMCAIJAQtTdHJpbmdFbnRyeQIJARNrZXlMb2NrUGFyYW1zUmVjb3JkAQULdXNlckFkZHJlc3MJARZmb3JtYXRMb2NrUGFyYW1zUmVjb3JkBwUHdXNlck51bQUGYW1vdW50BQVzdGFydAUIZHVyYXRpb24FAWsFAWIFCWd3eEFtb3VudAUDbmlsASJleHRyYWN0T3B0aW9uYWxQYXltZW50QW1vdW50T3JGYWlsAgFpD2V4cGVjdGVkQXNzZXRJZAMJAGYCCQCQAwEIBQFpCHBheW1lbnRzAAEJAAIBAhtvbmx5IG9uZSBwYXltZW50IGlzIGFsbG93ZWQDCQAAAgkAkAMBCAUBaQhwYXltZW50cwAAAAAEA3BtdAkAkQMCCAUBaQhwYXltZW50cwAAAwkBAiE9AgkBBXZhbHVlAQgFA3BtdAdhc3NldElkBQ9leHBlY3RlZEFzc2V0SWQJAAIBAhtpbnZhbGlkIGFzc2V0IGlkIGluIHBheW1lbnQIBQNwbXQGYW1vdW50ARljYWxjVXNlckd3eEFtb3VudEF0SGVpZ2h0Agt1c2VyQWRkcmVzcwx0YXJnZXRIZWlnaHQEBUVNUFRZAgVlbXB0eQQSdXNlcjJOdW1NYXBwaW5nS0VZCQESa2V5VXNlcjJOdW1NYXBwaW5nAQULdXNlckFkZHJlc3MEB3VzZXJOdW0JAQt2YWx1ZU9yRWxzZQIJAKIIAQUSdXNlcjJOdW1NYXBwaW5nS0VZBQVFTVBUWQQBawkBC3ZhbHVlT3JFbHNlAgkAnwgBCQENa2V5TG9ja1BhcmFtSwEFB3VzZXJOdW0AAAQBYgkBC3ZhbHVlT3JFbHNlAgkAnwgBCQENa2V5TG9ja1BhcmFtQgEFB3VzZXJOdW0AAAQNZ3d4QW1vdW50Q2FsYwkBDWNhbGNHd3hBbW91bnQDBQFrBQFiBQx0YXJnZXRIZWlnaHQECWd3eEFtb3VudAMJAGYCAAAFDWd3eEFtb3VudENhbGMAAAUNZ3d4QW1vdW50Q2FsYwUJZ3d4QW1vdW50ARRjYWxjQ3VycmVudEd3eEFtb3VudAELdXNlckFkZHJlc3MJARljYWxjVXNlckd3eEFtb3VudEF0SGVpZ2h0AgULdXNlckFkZHJlc3MFBmhlaWdodAEUaW50ZXJuYWxDbGFpbVd4Qm9vc3QDDGxwQXNzZXRJZFN0cg51c2VyQWRkcmVzc1N0cghyZWFkT25seQQFRU1QVFkCBUVNUFRZBBF1c2VyUmVjb3JkT3JFbXB0eQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzCQETa2V5TG9ja1BhcmFtc1JlY29yZAEFDnVzZXJBZGRyZXNzU3RyBQVFTVBUWQMJAAACBRF1c2VyUmVjb3JkT3JFbXB0eQUFRU1QVFkJAJUKAwAABQNuaWwCFXVzZXJSZWNvcmQ6OmlzOjplbXB0eQQPdXNlclJlY29yZEFycmF5CQC1CQIFEXVzZXJSZWNvcmRPckVtcHR5BQNTRVAECnVzZXJOdW1TdHIJAJEDAgUPdXNlclJlY29yZEFycmF5BQ5JZHhMb2NrVXNlck51bQQcZ3d4UmV3YXJkRW1pc3Npb25TdGFydEhlaWdodAkBC3ZhbHVlT3JFbHNlAgkAmggCBRFnd3hSZXdhcmRDb250cmFjdAkBH2tleUd3eFJld2FyZEVtaXNzaW9uU3RhcnRIZWlnaHQAAAAECEVNUFRZU1RSAgVlbXB0eQQNJHQwMTQ5NjUxNTUzMwMJAQIhPQIFDGxwQXNzZXRJZFN0cgUIRU1QVFlTVFIEDnBvb2xBZGRyZXNzU3RyCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ0IAgUPZmFjdG9yeUNvbnRyYWN0CQEaa2V5RmFjdG9yeUxwMkFzc2V0c01hcHBpbmcBBQxscEFzc2V0SWRTdHIJAKwCAgIVdW5zdXBwb3J0ZWQgbHAgYXNzZXQgBQxscEFzc2V0SWRTdHIEA3B3MQkBEUBleHRyTmF0aXZlKDEwNTApAgUPZmFjdG9yeUNvbnRyYWN0CQEUa2V5RmFjdG9yeVBvb2xXZWlnaHQBBQ5wb29sQWRkcmVzc1N0cgQDcHcwCQELdmFsdWVPckVsc2UCCQCaCAIFD2ZhY3RvcnlDb250cmFjdAkBG2tleUZhY3RvcnlQb29sV2VpZ2h0SGlzdG9yeQIFDnBvb2xBZGRyZXNzU3RyAAAFA3B3MQkAlAoCBQNwdzAFA3B3MQMFCHJlYWRPbmx5CQCUCgIAAAAACQACAQkArAICAihub3QgcmVhZG9ubHkgbW9kZTogdW5zdXBwb3J0ZWQgbHAgYXNzZXQgBQxscEFzc2V0SWRTdHIEC3Bvb2xXZWlnaHQwCAUNJHQwMTQ5NjUxNTUzMwJfMQQLcG9vbFdlaWdodDEIBQ0kdDAxNDk2NTE1NTMzAl8yBBJ3eEVtaXNzaW9uUGVyQmxvY2sJAQNpb2YCBRBlbWlzc2lvbkNvbnRyYWN0CQEea2V5RW1pc3Npb25SYXRlUGVyQmxvY2tDdXJyZW50AAQNZW1pc3Npb25TdGFydAkBA2lvZgIFEGVtaXNzaW9uQ29udHJhY3QJARVrZXlFbWlzc2lvblN0YXJ0QmxvY2sABAtlbWlzc2lvbkVuZAkBA2lvZgIFEGVtaXNzaW9uQ29udHJhY3QJARNrZXlFbWlzc2lvbkVuZEJsb2NrAAQBaAMJAGYCBQZoZWlnaHQFC2VtaXNzaW9uRW5kBQtlbWlzc2lvbkVuZAUGaGVpZ2h0BAJkaAkAlgMBCQDMCAIJAGUCBQFoBQ1lbWlzc2lvblN0YXJ0CQDMCAIAAAUDbmlsBCJ1c2VyTHBCb29zdEVtaXNzaW9uTGFzdEludGVncmFsS0VZCQEia2V5VXNlckxwQm9vc3RFbWlzc2lvbkxhc3RJTlRFR1JBTAIFCnVzZXJOdW1TdHIFDGxwQXNzZXRJZFN0cgQgdXNlckJvb3N0RW1pc3Npb25MYXN0SW50ZWdyYWxLRVkJASBrZXlVc2VyQm9vc3RFbWlzc2lvbkxhc3RJTlRFR1JBTAEFCnVzZXJOdW1TdHIEHXVzZXJCb29zdEVtaXNzaW9uTGFzdEludGVncmFsCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFInVzZXJMcEJvb3N0RW1pc3Npb25MYXN0SW50ZWdyYWxLRVkJAQNpb3oCBQR0aGlzBSB1c2VyQm9vc3RFbWlzc2lvbkxhc3RJbnRlZ3JhbEtFWQQVYm9vc3RFbWlzc2lvbkludGVncmFsCQBpAgkAaAIJAGgCBRJ3eEVtaXNzaW9uUGVyQmxvY2sFAmRoAAIAAwQZdXNlckJvb3N0RW1pc3Npb25JbnRlZ3JhbAkAZQIFFWJvb3N0RW1pc3Npb25JbnRlZ3JhbAUddXNlckJvb3N0RW1pc3Npb25MYXN0SW50ZWdyYWwEA3VkaAkAawMFGXVzZXJCb29zdEVtaXNzaW9uSW50ZWdyYWwAAwkAaAIAAgUSd3hFbWlzc2lvblBlckJsb2NrBAZ1TGFzdEgJAGUCBQFoBQN1ZGgEBHVkaDAJAJYDAQkAzAgCCQBlAgUcZ3d4UmV3YXJkRW1pc3Npb25TdGFydEhlaWdodAUGdUxhc3RICQDMCAIAAAUDbmlsBAR1ZGgxCQBlAgkAZQIFAWgFBnVMYXN0SAUEdWRoMAMDAwkAZgIAAAUGdUxhc3RIBgkAZgIAAAUEdWRoMQYJAGcCCQEDYWJzAQkAZQIJAGQCBQR1ZGgwBQR1ZGgxBQN1ZGgAAQkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgIWaW52YWxpZCB1ZGggY2FsYzogdWRoPQkApAMBBQN1ZGgCCCB1TGFzdEg9CQCkAwEFBnVMYXN0SAIGIHVkaDA9CQCkAwEFBHVkaDACBiB1ZGgxPQkApAMBBQR1ZGgxAwkAZgIAAAUZdXNlckJvb3N0RW1pc3Npb25JbnRlZ3JhbAkAAgECEndyb25nIGNhbGN1bGF0aW9ucwQXdXNlck1heEJvb3N0SW50ZWdyYWxLRVkJARdrZXlVc2VyTWF4Qm9vc3RJTlRFR1JBTAEFCnVzZXJOdW1TdHIEGHRvdGFsTWF4Qm9vc3RJbnRlZ3JhbEtFWQkBGGtleVRvdGFsTWF4Qm9vc3RJTlRFR1JBTAAED3VzZXJNYXhCb29zdEludAkBA2lvegIFBHRoaXMFF3VzZXJNYXhCb29zdEludGVncmFsS0VZBBB0b3RhbE1heEJvb3N0SW50CQEDaW96AgUEdGhpcwUYdG90YWxNYXhCb29zdEludGVncmFsS0VZBBd0b3RhbENhY2hlZEd3eENvcnJlY3RlZAkBEWdldFRvdGFsQ2FjaGVkR3d4AQYEC3VzZXJDdXJyR3d4CQEUY2FsY0N1cnJlbnRHd3hBbW91bnQBBQ51c2VyQWRkcmVzc1N0cgQhdXNlckJvb3N0QXZhbGFpYmxlVG9DbGFpbVRvdGFsS0VZCQEha2V5VXNlckJvb3N0QXZhbGFpYmxlVG9DbGFpbVRvdGFsAQUKdXNlck51bVN0cgQedXNlckJvb3N0QXZhbGlhYmxlVG9DbGFpbVRvdGFsCQEDaW96AgUEdGhpcwUhdXNlckJvb3N0QXZhbGFpYmxlVG9DbGFpbVRvdGFsS0VZBBp1c2VyQm9vc3RFbWlzc2lvbkludGVncmFsMAMJAAACBQN1ZGgAAAAACQBrAwUZdXNlckJvb3N0RW1pc3Npb25JbnRlZ3JhbAUEdWRoMAUDdWRoBBp1c2VyQm9vc3RFbWlzc2lvbkludGVncmFsMQMJAAACBQN1ZGgAAAAACQBrAwUZdXNlckJvb3N0RW1pc3Npb25JbnRlZ3JhbAUEdWRoMQUDdWRoBB5wb29sVXNlckJvb3N0RW1pc3Npb25JbnRlZ3JhbDAJAGsDBRp1c2VyQm9vc3RFbWlzc2lvbkludGVncmFsMAULcG9vbFdlaWdodDAFDlBPT0xXRUlHSFRNVUxUBB5wb29sVXNlckJvb3N0RW1pc3Npb25JbnRlZ3JhbDEJAGsDBRp1c2VyQm9vc3RFbWlzc2lvbkludGVncmFsMQULcG9vbFdlaWdodDEFDlBPT0xXRUlHSFRNVUxUBCJ1c2VyQm9vc3RBdmFsaWFibGVUb0NsYWltVG90YWxOZXcwAwkAAAIFF3RvdGFsQ2FjaGVkR3d4Q29ycmVjdGVkAAAAAAkAawMFHnBvb2xVc2VyQm9vc3RFbWlzc2lvbkludGVncmFsMAULdXNlckN1cnJHd3gFF3RvdGFsQ2FjaGVkR3d4Q29ycmVjdGVkBCJ1c2VyQm9vc3RBdmFsaWFibGVUb0NsYWltVG90YWxOZXcxAwkAAAIFF3RvdGFsQ2FjaGVkR3d4Q29ycmVjdGVkAAAAAAkAawMFHnBvb2xVc2VyQm9vc3RFbWlzc2lvbkludGVncmFsMQULdXNlckN1cnJHd3gFF3RvdGFsQ2FjaGVkR3d4Q29ycmVjdGVkBCF1c2VyQm9vc3RBdmFsaWFibGVUb0NsYWltVG90YWxOZXcJAGQCBSJ1c2VyQm9vc3RBdmFsaWFibGVUb0NsYWltVG90YWxOZXcwBSJ1c2VyQm9vc3RBdmFsaWFibGVUb0NsYWltVG90YWxOZXcxBBN1c2VyQm9vc3RDbGFpbWVkS0VZCQETa2V5VXNlckJvb3N0Q2xhaW1lZAEFCnVzZXJOdW1TdHIEEHVzZXJCb29zdENsYWltZWQJAQNpb3oCBQR0aGlzBRN1c2VyQm9vc3RDbGFpbWVkS0VZBBJ1c2VyQm9vc3RBdmFpbGFibGUJAGUCBSF1c2VyQm9vc3RBdmFsaWFibGVUb0NsYWltVG90YWxOZXcFEHVzZXJCb29zdENsYWltZWQECWRhdGFTdGF0ZQkAzAgCCQEMSW50ZWdlckVudHJ5AgUidXNlckxwQm9vc3RFbWlzc2lvbkxhc3RJbnRlZ3JhbEtFWQUVYm9vc3RFbWlzc2lvbkludGVncmFsBQNuaWwEBWRlYnVnCQC5CQIJAMwIAgkApAMBBR11c2VyQm9vc3RFbWlzc2lvbkxhc3RJbnRlZ3JhbAkAzAgCCQCkAwEFGXVzZXJCb29zdEVtaXNzaW9uSW50ZWdyYWwJAMwIAgkApAMBBRB1c2VyQm9vc3RDbGFpbWVkCQDMCAIJAKQDAQUSdXNlckJvb3N0QXZhaWxhYmxlCQDMCAIJAKQDAQULcG9vbFdlaWdodDAJAMwIAgkApAMBBQtwb29sV2VpZ2h0MQkAzAgCCQCkAwEFAWgJAMwIAgkApAMBBQN1ZGgJAMwIAgkApAMBBQZ1TGFzdEgJAMwIAgkApAMBBQR1ZGgwCQDMCAIJAKQDAQUEdWRoMQkAzAgCCQCkAwEFC3VzZXJDdXJyR3d4CQDMCAIJAKQDAQUXdG90YWxDYWNoZWRHd3hDb3JyZWN0ZWQFA25pbAIBOgkAlQoDBSF1c2VyQm9vc3RBdmFsaWFibGVUb0NsYWltVG90YWxOZXcFCWRhdGFTdGF0ZQUFZGVidWcBC2xvY2tBY3Rpb25zAgFpCGR1cmF0aW9uBAhjZmdBcnJheQkBFXJlYWRDb25maWdBcnJheU9yRmFpbAAECmFzc2V0SWRTdHIJAJEDAgUIY2ZnQXJyYXkFDUlkeENmZ0Fzc2V0SWQEB2Fzc2V0SWQJANkEAQUKYXNzZXRJZFN0cgQNbWluTG9ja0Ftb3VudAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCGNmZ0FycmF5BRNJZHhDZmdNaW5Mb2NrQW1vdW50BA9taW5Mb2NrRHVyYXRpb24JAQ1wYXJzZUludFZhbHVlAQkAkQMCBQhjZmdBcnJheQUVSWR4Q2ZnTWluTG9ja0R1cmF0aW9uBA9tYXhMb2NrRHVyYXRpb24JAQ1wYXJzZUludFZhbHVlAQkAkQMCBQhjZmdBcnJheQUVSWR4Q2ZnTWF4TG9ja0R1cmF0aW9uAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwABCQACAQI0aW52YWxpZCBwYXltZW50IC0gZXhhY3Qgb25lIHBheW1lbnQgbXVzdCBiZSBhdHRhY2hlZAQDcG10CQCRAwIIBQFpCHBheW1lbnRzAAAECXBtdEFtb3VudAgFA3BtdAZhbW91bnQDCQECIT0CBQdhc3NldElkCQEFdmFsdWUBCAUDcG10B2Fzc2V0SWQJAAIBCQCsAgIJAKwCAgIeaW52YWxpZCBhc3NldCBpcyBpbiBwYXltZW50IC0gBQphc3NldElkU3RyAgwgaXMgZXhwZWN0ZWQEDm5leHRVc2VyTnVtS0VZCQEOa2V5TmV4dFVzZXJOdW0ABA51c2VyQWRkcmVzc1N0cgkApQgBCAUBaQZjYWxsZXIEDnVzZXJJc0V4aXN0aW5nCQEJaXNEZWZpbmVkAQkAoggBCQESa2V5VXNlcjJOdW1NYXBwaW5nAQUOdXNlckFkZHJlc3NTdHIECnVzZXJOdW1TdHIDBQ51c2VySXNFeGlzdGluZwkBBXZhbHVlAQkAoggBCQESa2V5VXNlcjJOdW1NYXBwaW5nAQUOdXNlckFkZHJlc3NTdHIJAKQDAQkBA2lvZgIFBHRoaXMFDm5leHRVc2VyTnVtS0VZBAd1c2VyTnVtCQENcGFyc2VJbnRWYWx1ZQEFCnVzZXJOdW1TdHIECWxvY2tTdGFydAUGaGVpZ2h0BA1zdGFydEJsb2NrS0VZCQEWa2V5TG9ja1BhcmFtU3RhcnRCbG9jawEFCnVzZXJOdW1TdHIEC2R1cmF0aW9uS0VZCQEUa2V5TG9ja1BhcmFtRHVyYXRpb24BBQp1c2VyTnVtU3RyBA11c2VyQW1vdW50S0VZCQEWa2V5TG9ja1BhcmFtVXNlckFtb3VudAEFCnVzZXJOdW1TdHIDCQBmAgUNbWluTG9ja0Ftb3VudAUJcG10QW1vdW50CQACAQkArAICAiJhbW91bnQgaXMgbGVzcyB0aGVuIG1pbkxvY2tBbW91bnQ9CQCkAwEFDW1pbkxvY2tBbW91bnQDCQBmAgUPbWluTG9ja0R1cmF0aW9uBQhkdXJhdGlvbgkAAgEJAKwCAgItcGFzc2VkIGR1cmF0aW9uIGlzIGxlc3MgdGhlbiBtaW5Mb2NrRHVyYXRpb249CQCkAwEFD21pbkxvY2tEdXJhdGlvbgMJAGYCBQhkdXJhdGlvbgUPbWF4TG9ja0R1cmF0aW9uCQACAQkArAICAjBwYXNzZWQgZHVyYXRpb24gaXMgZ3JlYXRlciB0aGVuIG1heExvY2tEdXJhdGlvbj0JAKQDAQUPbWF4TG9ja0R1cmF0aW9uAwMFDnVzZXJJc0V4aXN0aW5nCQBnAgkAZAIJAQNpb2YCBQR0aGlzBQ1zdGFydEJsb2NrS0VZCQEDaW9mAgUEdGhpcwULZHVyYXRpb25LRVkFCWxvY2tTdGFydAcJAAIBAjZ0aGVyZSBpcyBhbiBhY3RpdmUgbG9jayAtIGNvbnNpZGVyIHRvIHVzZSBpbmNyZWFzZUxvY2sDCQBmAgkBA2lvegIFBHRoaXMFDXVzZXJBbW91bnRLRVkAAAkAAgEJAKwCAgI0dGhlcmUgYXJlIGxvY2tlZCBXWHMgLSBjb25zaWRlciB0byB1c2UgaW5jcmVhc2VMb2NrIAUNdXNlckFtb3VudEtFWQQHY29lZmZYOAkAawMFCGR1cmF0aW9uBQVNVUxUOAUPbWF4TG9ja0R1cmF0aW9uBA5nV3hBbW91bnRTdGFydAkAawMFCXBtdEFtb3VudAUHY29lZmZYOAUFTVVMVDgEE2dXeFBhcmFtc1Jlc3VsdExpc3QJAQNhYWwBCQD8BwQFDG1hdGhDb250cmFjdAIVY2FsY0d3eFBhcmFtc1JFQURPTkxZCQDMCAIFDmdXeEFtb3VudFN0YXJ0CQDMCAIFCWxvY2tTdGFydAkAzAgCBQhkdXJhdGlvbgUDbmlsBQNuaWwEAWsJAQJhaQEJAJEDAgUTZ1d4UGFyYW1zUmVzdWx0TGlzdAAABAFiCQECYWkBCQCRAwIFE2dXeFBhcmFtc1Jlc3VsdExpc3QAAQQGcGVyaW9kCQCkAwEJAQJhaQEJAJEDAgUTZ1d4UGFyYW1zUmVzdWx0TGlzdAACBBJ3eEVtaXNzaW9uUGVyQmxvY2sJAQNpb2YCBRBlbWlzc2lvbkNvbnRyYWN0CQEea2V5RW1pc3Npb25SYXRlUGVyQmxvY2tDdXJyZW50AAQNZW1pc3Npb25TdGFydAkBA2lvZgIFEGVtaXNzaW9uQ29udHJhY3QJARVrZXlFbWlzc2lvblN0YXJ0QmxvY2sABAtlbWlzc2lvbkVuZAkBA2lvZgIFEGVtaXNzaW9uQ29udHJhY3QJARNrZXlFbWlzc2lvbkVuZEJsb2NrAAQBaAMJAGYCBQZoZWlnaHQFC2VtaXNzaW9uRW5kBQtlbWlzc2lvbkVuZAUGaGVpZ2h0BAJkaAkAlgMBCQDMCAIJAGUCBQFoBQ1lbWlzc2lvblN0YXJ0CQDMCAIAAAUDbmlsBCB1c2VyQm9vc3RFbWlzc2lvbkxhc3RJbnRlZ3JhbEtFWQkBIGtleVVzZXJCb29zdEVtaXNzaW9uTGFzdElOVEVHUkFMAQUKdXNlck51bVN0cgQVYm9vc3RFbWlzc2lvbkludGVncmFsCQBpAgkAaAIJAGgCBRJ3eEVtaXNzaW9uUGVyQmxvY2sFAmRoAAIAAwQXdXNlck1heEJvb3N0SW50ZWdyYWxLRVkJARdrZXlVc2VyTWF4Qm9vc3RJTlRFR1JBTAEFCnVzZXJOdW1TdHIEGHRvdGFsTWF4Qm9vc3RJbnRlZ3JhbEtFWQkBGGtleVRvdGFsTWF4Qm9vc3RJTlRFR1JBTAAED3VzZXJNYXhCb29zdEludAkAaQIJAGgCBQ5nV3hBbW91bnRTdGFydAUIZHVyYXRpb24AAgQQdG90YWxNYXhCb29zdEludAkBA2lvegIFBHRoaXMFGHRvdGFsTWF4Qm9vc3RJbnRlZ3JhbEtFWQQRdG90YWxDYWNoZWRHd3hSYXcJARFnZXRUb3RhbENhY2hlZEd3eAEHBANhcnIDBQ51c2VySXNFeGlzdGluZwUDbmlsCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ5uZXh0VXNlck51bUtFWQkAZAIFB3VzZXJOdW0AAQkAzAgCCQELU3RyaW5nRW50cnkCCQESa2V5VXNlcjJOdW1NYXBwaW5nAQUOdXNlckFkZHJlc3NTdHIFCnVzZXJOdW1TdHIJAMwIAgkBC1N0cmluZ0VudHJ5AgkBEmtleU51bTJVc2VyTWFwcGluZwEFCnVzZXJOdW1TdHIFDnVzZXJBZGRyZXNzU3RyBQNuaWwJAJQKAgkAzggCCQDNCAIJAM4IAgkAzggCBQNhcnIJAQ9Mb2NrUGFyYW1zRW50cnkIBQ51c2VyQWRkcmVzc1N0cgUKdXNlck51bVN0cgUJcG10QW1vdW50BQlsb2NrU3RhcnQFCGR1cmF0aW9uBQFrBQFiBQZwZXJpb2QJAQpTdGF0c0VudHJ5BAUJcG10QW1vdW50BQhkdXJhdGlvbgABAwUOdXNlcklzRXhpc3RpbmcAAAABCQEMSGlzdG9yeUVudHJ5CAIEbG9jawUOdXNlckFkZHJlc3NTdHIFCXBtdEFtb3VudAUJbG9ja1N0YXJ0BQhkdXJhdGlvbgUBawUBYgUBaQkAzAgCCQEMSW50ZWdlckVudHJ5AgUgdXNlckJvb3N0RW1pc3Npb25MYXN0SW50ZWdyYWxLRVkFFWJvb3N0RW1pc3Npb25JbnRlZ3JhbAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBEWtleVRvdGFsQ2FjaGVkR3d4AAkAZAIFEXRvdGFsQ2FjaGVkR3d4UmF3BQ5nV3hBbW91bnRTdGFydAUDbmlsBQ5nV3hBbW91bnRTdGFydAwBaQELY29uc3RydWN0b3IGEWZhY3RvcnlBZGRyZXNzU3RyDmxvY2tBc3NldElkU3RyDW1pbkxvY2tBbW91bnQLbWluRHVyYXRpb24LbWF4RHVyYXRpb24MbWF0aENvbnRyYWN0BAtjaGVja0NhbGxlcgkBC211c3RNYW5hZ2VyAQUBaQMJAAACBQtjaGVja0NhbGxlcgULY2hlY2tDYWxsZXIJAM4IAgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDmtleU5leHRVc2VyTnVtAAAACQDMCAIJAQtTdHJpbmdFbnRyeQIJAQlrZXlDb25maWcACQEMZm9ybWF0Q29uZmlnBQUObG9ja0Fzc2V0SWRTdHIFDW1pbkxvY2tBbW91bnQFC21pbkR1cmF0aW9uBQttYXhEdXJhdGlvbgUMbWF0aENvbnRyYWN0CQDMCAIJAQtTdHJpbmdFbnRyeQIJARFrZXlGYWN0b3J5QWRkcmVzcwAFEWZhY3RvcnlBZGRyZXNzU3RyBQNuaWwJAQpTdGF0c0VudHJ5BAAAAAAAAAAACQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBB2xvY2tSZWYDCGR1cmF0aW9uD3JlZmVycmVyQWRkcmVzcwlzaWduYXR1cmUEDSR0MDIzODkyMjM5NTcJAQtsb2NrQWN0aW9ucwIFAWkFCGR1cmF0aW9uBBFsb2NrQWN0aW9uc1Jlc3VsdAgFDSR0MDIzODkyMjM5NTcCXzEEDmdXeEFtb3VudFN0YXJ0CAUNJHQwMjM4OTIyMzk1NwJfMgQPcmVmZXJyYWxBZGRyZXNzCQClCAEIBQFpBmNhbGxlcgQGcmVmSW52AwMJAAACBQ9yZWZlcnJlckFkZHJlc3MCAAYJAAACBQlzaWduYXR1cmUBAAUEdW5pdAkA/AcEBR5yZWZlcnJhbHNDb250cmFjdEFkZHJlc3NPckZhaWwCCmNyZWF0ZVBhaXIJAMwIAgUTcmVmZXJyYWxQcm9ncmFtTmFtZQkAzAgCBQ9yZWZlcnJlckFkZHJlc3MJAMwIAgUPcmVmZXJyYWxBZGRyZXNzCQDMCAIFCXNpZ25hdHVyZQUDbmlsBQNuaWwDCQAAAgUGcmVmSW52BQZyZWZJbnYEEXVwZGF0ZVJlZkFjdGl2aXR5CQD8BwQFDG1hdGhDb250cmFjdAIWdXBkYXRlUmVmZXJyYWxBY3Rpdml0eQkAzAgCCQClCAEIBQFpBmNhbGxlcgkAzAgCBQ5nV3hBbW91bnRTdGFydAUDbmlsBQNuaWwDCQAAAgURdXBkYXRlUmVmQWN0aXZpdHkFEXVwZGF0ZVJlZkFjdGl2aXR5CQCUCgIFEWxvY2tBY3Rpb25zUmVzdWx0BQR1bml0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBBGxvY2sBCGR1cmF0aW9uBA0kdDAyNDQxNTI0NDgwCQELbG9ja0FjdGlvbnMCBQFpBQhkdXJhdGlvbgQRbG9ja0FjdGlvbnNSZXN1bHQIBQ0kdDAyNDQxNTI0NDgwAl8xBA5nV3hBbW91bnRTdGFydAgFDSR0MDI0NDE1MjQ0ODACXzIEEXVwZGF0ZVJlZkFjdGl2aXR5CQD8BwQFDG1hdGhDb250cmFjdAIWdXBkYXRlUmVmZXJyYWxBY3Rpdml0eQkAzAgCCQClCAEIBQFpBmNhbGxlcgkAzAgCBQ5nV3hBbW91bnRTdGFydAUDbmlsBQNuaWwDCQAAAgURdXBkYXRlUmVmQWN0aXZpdHkFEXVwZGF0ZVJlZkFjdGl2aXR5CQCUCgIFEWxvY2tBY3Rpb25zUmVzdWx0BQR1bml0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDGluY3JlYXNlTG9jawENZGVsdGFEdXJhdGlvbgQIY2ZnQXJyYXkJARVyZWFkQ29uZmlnQXJyYXlPckZhaWwABAphc3NldElkU3RyCQCRAwIFCGNmZ0FycmF5BQ1JZHhDZmdBc3NldElkBAdhc3NldElkCQDZBAEFCmFzc2V0SWRTdHIED21pbkxvY2tEdXJhdGlvbgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCGNmZ0FycmF5BRVJZHhDZmdNaW5Mb2NrRHVyYXRpb24ED21heExvY2tEdXJhdGlvbgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCGNmZ0FycmF5BRVJZHhDZmdNYXhMb2NrRHVyYXRpb24ECXBtdEFtb3VudAkBImV4dHJhY3RPcHRpb25hbFBheW1lbnRBbW91bnRPckZhaWwCBQFpBQdhc3NldElkBA51c2VyQWRkcmVzc1N0cgkApQgBCAUBaQZjYWxsZXIED3VzZXJSZWNvcmRBcnJheQkBGnJlYWRMb2NrUGFyYW1zUmVjb3JkT3JGYWlsAQUOdXNlckFkZHJlc3NTdHIECnVzZXJOdW1TdHIJAJEDAgUPdXNlclJlY29yZEFycmF5BQ5JZHhMb2NrVXNlck51bQQKdXNlckFtb3VudAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFD3VzZXJSZWNvcmRBcnJheQUNSWR4TG9ja0Ftb3VudAQJbG9ja1N0YXJ0CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUPdXNlclJlY29yZEFycmF5BQxJZHhMb2NrU3RhcnQEDGxvY2tEdXJhdGlvbgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFD3VzZXJSZWNvcmRBcnJheQUPSWR4TG9ja0R1cmF0aW9uBAdsb2NrRW5kCQBkAgUJbG9ja1N0YXJ0BQxsb2NrRHVyYXRpb24EEXJlbWFpbmluZ0R1cmF0aW9uCQCWAwEJAMwIAgkAZQIFB2xvY2tFbmQFBmhlaWdodAkAzAgCAAAFA25pbAQNdXNlckFtb3VudE5ldwkAZAIFCnVzZXJBbW91bnQFCXBtdEFtb3VudAQPbG9ja0R1cmF0aW9uTmV3CQBkAgURcmVtYWluaW5nRHVyYXRpb24FDWRlbHRhRHVyYXRpb24DCQBmAgAABQ1kZWx0YUR1cmF0aW9uCQACAQIaZHVyYXRpb24gaXMgbGVzcyB0aGVuIHplcm8DCQBmAgUPbWluTG9ja0R1cmF0aW9uBQ9sb2NrRHVyYXRpb25OZXcJAAIBCQCsAgICLWxvY2tEdXJhdGlvbk5ldyBpcyBsZXNzIHRoZW4gbWluTG9ja0R1cmF0aW9uPQkApAMBBQ9taW5Mb2NrRHVyYXRpb24DCQBmAgUPbG9ja0R1cmF0aW9uTmV3BQ9tYXhMb2NrRHVyYXRpb24JAAIBCQCsAgICRGRlbHRhRHVyYXRpb24gKyBleGlzdGVkTG9ja0R1cmF0aW9uIGlzIGdyZWF0ZXIgdGhlbiBtYXhMb2NrRHVyYXRpb249CQCkAwEFD21heExvY2tEdXJhdGlvbgQHY29lZmZYOAkAawMFD2xvY2tEdXJhdGlvbk5ldwUFTVVMVDgFD21heExvY2tEdXJhdGlvbgQOZ1d4QW1vdW50U3RhcnQJAGsDBQ11c2VyQW1vdW50TmV3BQdjb2VmZlg4BQVNVUxUOAQRdXBkYXRlUmVmQWN0aXZpdHkJAPwHBAUMbWF0aENvbnRyYWN0AhZ1cGRhdGVSZWZlcnJhbEFjdGl2aXR5CQDMCAIJAKUIAQgFAWkGY2FsbGVyCQDMCAIFDmdXeEFtb3VudFN0YXJ0BQNuaWwFA25pbAMJAAACBRF1cGRhdGVSZWZBY3Rpdml0eQURdXBkYXRlUmVmQWN0aXZpdHkEDGxvY2tTdGFydE5ldwUGaGVpZ2h0BBNnV3hQYXJhbXNSZXN1bHRMaXN0CQEDYWFsAQkA/AcEBQxtYXRoQ29udHJhY3QCFWNhbGNHd3hQYXJhbXNSRUFET05MWQkAzAgCBQ5nV3hBbW91bnRTdGFydAkAzAgCBQxsb2NrU3RhcnROZXcJAMwIAgUPbG9ja0R1cmF0aW9uTmV3BQNuaWwFA25pbAQBawkBAmFpAQkAkQMCBRNnV3hQYXJhbXNSZXN1bHRMaXN0AAAEAWIJAQJhaQEJAJEDAgUTZ1d4UGFyYW1zUmVzdWx0TGlzdAABBAZwZXJpb2QJAKQDAQkBAmFpAQkAkQMCBRNnV3hQYXJhbXNSZXN1bHRMaXN0AAIEEnd4RW1pc3Npb25QZXJCbG9jawkBA2lvZgIFEGVtaXNzaW9uQ29udHJhY3QJAR5rZXlFbWlzc2lvblJhdGVQZXJCbG9ja0N1cnJlbnQABA1lbWlzc2lvblN0YXJ0CQEDaW9mAgUQZW1pc3Npb25Db250cmFjdAkBFWtleUVtaXNzaW9uU3RhcnRCbG9jawAEC2VtaXNzaW9uRW5kCQEDaW9mAgUQZW1pc3Npb25Db250cmFjdAkBE2tleUVtaXNzaW9uRW5kQmxvY2sABAFoAwkAZgIFBmhlaWdodAULZW1pc3Npb25FbmQFC2VtaXNzaW9uRW5kBQZoZWlnaHQEAmRoCQCWAwEJAMwIAgkAZQIFAWgFDWVtaXNzaW9uU3RhcnQJAMwIAgAABQNuaWwEIHVzZXJCb29zdEVtaXNzaW9uTGFzdEludGVncmFsS0VZCQEga2V5VXNlckJvb3N0RW1pc3Npb25MYXN0SU5URUdSQUwBBQp1c2VyTnVtU3RyBB11c2VyQm9vc3RFbWlzc2lvbkxhc3RJbnRlZ3JhbAkBA2lvegIFBHRoaXMFIHVzZXJCb29zdEVtaXNzaW9uTGFzdEludGVncmFsS0VZBBVib29zdEVtaXNzaW9uSW50ZWdyYWwJAGkCCQBoAgkAaAIFEnd4RW1pc3Npb25QZXJCbG9jawUCZGgAAgADBBl1c2VyQm9vc3RFbWlzc2lvbkludGVncmFsCQBlAgUVYm9vc3RFbWlzc2lvbkludGVncmFsBR11c2VyQm9vc3RFbWlzc2lvbkxhc3RJbnRlZ3JhbAMJAGYCAAAFGXVzZXJCb29zdEVtaXNzaW9uSW50ZWdyYWwJAAIBAhJ3cm9uZyBjYWxjdWxhdGlvbnMEF3VzZXJNYXhCb29zdEludGVncmFsS0VZCQEXa2V5VXNlck1heEJvb3N0SU5URUdSQUwBBQp1c2VyTnVtU3RyBBh0b3RhbE1heEJvb3N0SW50ZWdyYWxLRVkJARhrZXlUb3RhbE1heEJvb3N0SU5URUdSQUwABA91c2VyTWF4Qm9vc3RJbnQJAQNpb3oCBQR0aGlzBRd1c2VyTWF4Qm9vc3RJbnRlZ3JhbEtFWQQQdG90YWxNYXhCb29zdEludAkBA2lvegIFBHRoaXMFGHRvdGFsTWF4Qm9vc3RJbnRlZ3JhbEtFWQQLY3VyclVzZXJHd3gJARRjYWxjQ3VycmVudEd3eEFtb3VudAEFDnVzZXJBZGRyZXNzU3RyBAdnd3hEaWZmCQBlAgUOZ1d4QW1vdW50U3RhcnQFC2N1cnJVc2VyR3d4AwkAZgIAAAUHZ3d4RGlmZgkAAgEJAKwCAgIYZ3d4RGlmZiBpcyBsZXNzIHRoZW4gMDogCQCkAwEFB2d3eERpZmYEEXRvdGFsQ2FjaGVkR3d4UmF3CQERZ2V0VG90YWxDYWNoZWRHd3gBBwQXdG90YWxDYWNoZWRHd3hDb3JyZWN0ZWQJARFnZXRUb3RhbENhY2hlZEd3eAEGBCF1c2VyQm9vc3RBdmFsYWlibGVUb0NsYWltVG90YWxLRVkJASFrZXlVc2VyQm9vc3RBdmFsYWlibGVUb0NsYWltVG90YWwBBQp1c2VyTnVtU3RyBB51c2VyQm9vc3RBdmFsaWFibGVUb0NsYWltVG90YWwJAQNpb3oCBQR0aGlzBSF1c2VyQm9vc3RBdmFsYWlibGVUb0NsYWltVG90YWxLRVkEIXVzZXJCb29zdEF2YWxpYWJsZVRvQ2xhaW1Ub3RhbE5ldwkAawMFGXVzZXJCb29zdEVtaXNzaW9uSW50ZWdyYWwFC2N1cnJVc2VyR3d4BRd0b3RhbENhY2hlZEd3eENvcnJlY3RlZAQSdXNlck1heEJvb3N0SW50TmV3CQBpAgkAaAIFDmdXeEFtb3VudFN0YXJ0BQ9sb2NrRHVyYXRpb25OZXcAAgQYcmVtYWluaW5nVXNlck1heEJvb3N0SW50CQBpAgkAaAIFC2N1cnJVc2VyR3d4BRFyZW1haW5pbmdEdXJhdGlvbgACBBN1c2VyTWF4Qm9vc3RJbnREaWZmCQBlAgUSdXNlck1heEJvb3N0SW50TmV3BRhyZW1haW5pbmdVc2VyTWF4Qm9vc3RJbnQJAM4IAgkAzQgCCQDOCAIJAQ9Mb2NrUGFyYW1zRW50cnkIBQ51c2VyQWRkcmVzc1N0cgUKdXNlck51bVN0cgUNdXNlckFtb3VudE5ldwUMbG9ja1N0YXJ0TmV3BQ9sb2NrRHVyYXRpb25OZXcFAWsFAWIFBnBlcmlvZAkBClN0YXRzRW50cnkEBQlwbXRBbW91bnQFDWRlbHRhRHVyYXRpb24AAAAACQEMSGlzdG9yeUVudHJ5CAIEbG9jawUOdXNlckFkZHJlc3NTdHIFCXBtdEFtb3VudAUJbG9ja1N0YXJ0BQ9sb2NrRHVyYXRpb25OZXcFAWsFAWIFAWkJAMwIAgkBDEludGVnZXJFbnRyeQIJARFrZXlUb3RhbENhY2hlZEd3eAAJAGQCBRF0b3RhbENhY2hlZEd3eFJhdwUHZ3d4RGlmZgUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDGNsYWltV3hCb29zdAIMbHBBc3NldElkU3RyDnVzZXJBZGRyZXNzU3RyAwkBAiE9AgUPc3Rha2luZ0NvbnRyYWN0CAUBaQZjYWxsZXIJAAIBAhJwZXJtaXNzaW9ucyBkZW5pZWQEDSR0MDI5NDYxMjk1NjMJARRpbnRlcm5hbENsYWltV3hCb29zdAMFDGxwQXNzZXRJZFN0cgUOdXNlckFkZHJlc3NTdHIHBBJ1c2VyQm9vc3RBdmFpbGFibGUIBQ0kdDAyOTQ2MTI5NTYzAl8xBAlkYXRhU3RhdGUIBQ0kdDAyOTQ2MTI5NTYzAl8yBAVkZWJ1ZwgFDSR0MDI5NDYxMjk1NjMCXzMJAJQKAgUJZGF0YVN0YXRlCQDMCAIFEnVzZXJCb29zdEF2YWlsYWJsZQUDbmlsAWkBFGNsYWltV3hCb29zdFJFQURPTkxZAgxscEFzc2V0SWRTdHIOdXNlckFkZHJlc3NTdHIEDSR0MDI5Njk1Mjk3OTYJARRpbnRlcm5hbENsYWltV3hCb29zdAMFDGxwQXNzZXRJZFN0cgUOdXNlckFkZHJlc3NTdHIGBBJ1c2VyQm9vc3RBdmFpbGFibGUIBQ0kdDAyOTY5NTI5Nzk2Al8xBAlkYXRhU3RhdGUIBQ0kdDAyOTY5NTI5Nzk2Al8yBAVkZWJ1ZwgFDSR0MDI5Njk1Mjk3OTYCXzMJAJQKAgUDbmlsCQDMCAIFEnVzZXJCb29zdEF2YWlsYWJsZQkAzAgCBQVkZWJ1ZwUDbmlsAWkBBnVubG9jawELdXNlckFkZHJlc3MED3VzZXJSZWNvcmRBcnJheQkBGnJlYWRMb2NrUGFyYW1zUmVjb3JkT3JGYWlsAQULdXNlckFkZHJlc3MECnVzZXJOdW1TdHIJAJEDAgUPdXNlclJlY29yZEFycmF5BQ5JZHhMb2NrVXNlck51bQQKdXNlckFtb3VudAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFD3VzZXJSZWNvcmRBcnJheQUNSWR4TG9ja0Ftb3VudAQJbG9ja1N0YXJ0CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUPdXNlclJlY29yZEFycmF5BQxJZHhMb2NrU3RhcnQEDGxvY2tEdXJhdGlvbgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFD3VzZXJSZWNvcmRBcnJheQUPSWR4TG9ja0R1cmF0aW9uBAdsb2NrRW5kCQBkAgUJbG9ja1N0YXJ0BQxsb2NrRHVyYXRpb24ECGNmZ0FycmF5CQEVcmVhZENvbmZpZ0FycmF5T3JGYWlsAAQHYXNzZXRJZAkA2QQBCQCRAwIFCGNmZ0FycmF5BQ1JZHhDZmdBc3NldElkAwkAZwIFB2xvY2tFbmQFBmhlaWdodAkAAgEJAKwCAgkArAICAgV3YWl0IAkApAMBBQdsb2NrRW5kAgogdG8gdW5sb2NrAwkAZwIAAAUKdXNlckFtb3VudAkAAgECEW5vdGhpbmcgdG8gdW5sb2NrBAZwZXJpb2QJAQt2YWx1ZU9yRWxzZQIJAJoIAgUMbWF0aENvbnRyYWN0CQENa2V5TmV4dFBlcmlvZAAAAAkAzQgCCQDNCAIJAM4IAgkBD0xvY2tQYXJhbXNFbnRyeQgFC3VzZXJBZGRyZXNzBQp1c2VyTnVtU3RyAAAFCWxvY2tTdGFydAUMbG9ja0R1cmF0aW9uAAAAAAkApAMBBQZwZXJpb2QJAQpTdGF0c0VudHJ5BAkBAS0BBQp1c2VyQW1vdW50AAAAAAD///////////8BCQEMSGlzdG9yeUVudHJ5CAIGdW5sb2NrBQt1c2VyQWRkcmVzcwUKdXNlckFtb3VudAUJbG9ja1N0YXJ0BQxsb2NrRHVyYXRpb24AAAAABQFpCQEOU2NyaXB0VHJhbnNmZXIDCQERQGV4dHJOYXRpdmUoMTA2MikBBQt1c2VyQWRkcmVzcwUKdXNlckFtb3VudAUHYXNzZXRJZAFpARNnd3hVc2VySW5mb1JFQURPTkxZAQt1c2VyQWRkcmVzcwQJZ3d4QW1vdW50CQEUY2FsY0N1cnJlbnRHd3hBbW91bnQBBQt1c2VyQWRkcmVzcwkAlAoCBQNuaWwJAMwIAgUJZ3d4QW1vdW50BQNuaWwBaQEgZ2V0VXNlckd3eEFtb3VudEF0SGVpZ2h0UkVBRE9OTFkCC3VzZXJBZGRyZXNzDHRhcmdldEhlaWdodAQJZ3d4QW1vdW50CQEZY2FsY1VzZXJHd3hBbW91bnRBdEhlaWdodAIFC3VzZXJBZGRyZXNzBQx0YXJnZXRIZWlnaHQJAJQKAgUDbmlsBQlnd3hBbW91bnQBaQEZZ2V0VG90YWxDYWNoZWRHd3hSRUFET05MWQAJAJQKAgUDbmlsCQERZ2V0VG90YWxDYWNoZWRHd3gBBgFpAQpzZXRNYW5hZ2VyARdwZW5kaW5nTWFuYWdlclB1YmxpY0tleQQLY2hlY2tDYWxsZXIJAQttdXN0TWFuYWdlcgEFAWkDCQAAAgULY2hlY2tDYWxsZXIFC2NoZWNrQ2FsbGVyBBVjaGVja01hbmFnZXJQdWJsaWNLZXkJANkEAQUXcGVuZGluZ01hbmFnZXJQdWJsaWNLZXkDCQAAAgUVY2hlY2tNYW5hZ2VyUHVibGljS2V5BRVjaGVja01hbmFnZXJQdWJsaWNLZXkJAMwIAgkBC1N0cmluZ0VudHJ5AgkBGmtleVBlbmRpbmdNYW5hZ2VyUHVibGljS2V5AAUXcGVuZGluZ01hbmFnZXJQdWJsaWNLZXkFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ5jb25maXJtTWFuYWdlcgAEAnBtCQEdcGVuZGluZ01hbmFnZXJQdWJsaWNLZXlPclVuaXQABAVoYXNQTQMJAQlpc0RlZmluZWQBBQJwbQYJAAIBAhJObyBwZW5kaW5nIG1hbmFnZXIDCQAAAgUFaGFzUE0FBWhhc1BNBAdjaGVja1BNAwkAAAIIBQFpD2NhbGxlclB1YmxpY0tleQkBBXZhbHVlAQUCcG0GCQACAQIbWW91IGFyZSBub3QgcGVuZGluZyBtYW5hZ2VyAwkAAAIFB2NoZWNrUE0FB2NoZWNrUE0JAMwIAgkBC1N0cmluZ0VudHJ5AgkBE2tleU1hbmFnZXJQdWJsaWNLZXkACQDYBAEJAQV2YWx1ZQEFAnBtCQDMCAIJAQtEZWxldGVFbnRyeQEJARprZXlQZW5kaW5nTWFuYWdlclB1YmxpY0tleQAFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgECdHgBBnZlcmlmeQAED3RhcmdldFB1YmxpY0tleQQHJG1hdGNoMAkBFm1hbmFnZXJQdWJsaWNLZXlPclVuaXQAAwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEAnBrBQckbWF0Y2gwBQJwawMJAAECBQckbWF0Y2gwAgRVbml0CAUCdHgPc2VuZGVyUHVibGljS2V5CQACAQILTWF0Y2ggZXJyb3IJAPQDAwgFAnR4CWJvZHlCeXRlcwkAkQMCCAUCdHgGcHJvb2ZzAAAFD3RhcmdldFB1YmxpY0tleUfYpbQ=", "chainId": 87, "height": 3408455, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 97RfoaU2E85yx3oek7mJLcFpXBvpML66G4f9JrZFLYTg Next: H6XKpsfMEJRFkMEcLNeCMTFyigeYzYMd6p8T1HHwAJBu Diff:
OldNewDifferences
292292 func keyTotalCachedGwx () = "%s%s__gwxCached__total"
293293
294294
295+func keyTotalCachedGwxCorrective () = "%s__gwxCachedTotalCorrective"
296+
297+
295298 let factoryContract = readFactoryAddressOrFail()
296299
297300 let factoryCfg = readFactoryCfgOrFail(factoryContract)
301304 let stakingContract = getStakingAddressOrFail(factoryCfg)
302305
303306 let gwxRewardContract = getGwxRewardAddressOrFail(factoryCfg)
307+
308+func getTotalCachedGwx (correct) = {
309+ let keyVotingEmissionContract = makeString(["%s", "votingEmissionContract"], SEP)
310+ let votingEmissionContract = addressFromStringValue(getStringValue(factoryContract, keyVotingEmissionContract))
311+ let keyCurrentEpochUi = makeString(["%s", "currentEpochUi"], SEP)
312+ let currentEpochUi = getIntegerValue(votingEmissionContract, keyCurrentEpochUi)
313+ let keyTargetEpoch = makeString(["%s%s", "totalCachedGwxCorrection__activationEpoch"], SEP)
314+ let targetEpochOption = getInteger(this, keyTargetEpoch)
315+ let totalCachedGwxRaw = valueOrElse(getInteger(this, keyTotalCachedGwx()), 0)
316+ let isCorrectionActivated = if (isDefined(targetEpochOption))
317+ then (currentEpochUi >= value(targetEpochOption))
318+ else false
319+ let corrective = if (if (isCorrectionActivated)
320+ then correct
321+ else false)
322+ then valueOrElse(getInteger(this, keyTotalCachedGwxCorrective()), 0)
323+ else 0
324+ max([0, (totalCachedGwxRaw + corrective)])
325+ }
326+
304327
305328 func HistoryEntry (type,user,amount,lockStart,duration,k,b,i) = {
306329 let historyKEY = makeString(["%s%s%s%s__history", type, user, toBase58String(i.transactionId)], SEP)
380403 let userNumStr = userRecordArray[IdxLockUserNum]
381404 let gwxRewardEmissionStartHeight = valueOrElse(getInteger(gwxRewardContract, keyGwxRewardEmissionStartHeight()), 0)
382405 let EMPTYSTR = "empty"
383- let $t01397714545 = if ((lpAssetIdStr != EMPTYSTR))
406+ let $t01496515533 = if ((lpAssetIdStr != EMPTYSTR))
384407 then {
385408 let poolAddressStr = valueOrErrorMessage(getString(factoryContract, keyFactoryLp2AssetsMapping(lpAssetIdStr)), ("unsupported lp asset " + lpAssetIdStr))
386409 let pw1 = getIntegerValue(factoryContract, keyFactoryPoolWeight(poolAddressStr))
390413 else if (readOnly)
391414 then $Tuple2(0, 0)
392415 else throw(("not readonly mode: unsupported lp asset " + lpAssetIdStr))
393- let poolWeight0 = $t01397714545._1
394- let poolWeight1 = $t01397714545._2
416+ let poolWeight0 = $t01496515533._1
417+ let poolWeight1 = $t01496515533._2
395418 let wxEmissionPerBlock = iof(emissionContract, keyEmissionRatePerBlockCurrent())
396419 let emissionStart = iof(emissionContract, keyEmissionStartBlock())
397420 let emissionEnd = iof(emissionContract, keyEmissionEndBlock())
421444 let totalMaxBoostIntegralKEY = keyTotalMaxBoostINTEGRAL()
422445 let userMaxBoostInt = ioz(this, userMaxBoostIntegralKEY)
423446 let totalMaxBoostInt = ioz(this, totalMaxBoostIntegralKEY)
424- let totalCachedGwxKEY = keyTotalCachedGwx()
425- let totalCachedGwx = valueOrElse(getInteger(this, totalCachedGwxKEY), 0)
447+ let totalCachedGwxCorrected = getTotalCachedGwx(true)
426448 let userCurrGwx = calcCurrentGwxAmount(userAddressStr)
427449 let userBoostAvalaibleToClaimTotalKEY = keyUserBoostAvalaibleToClaimTotal(userNumStr)
428450 let userBoostAvaliableToClaimTotal = ioz(this, userBoostAvalaibleToClaimTotalKEY)
434456 else fraction(userBoostEmissionIntegral, udh1, udh)
435457 let poolUserBoostEmissionIntegral0 = fraction(userBoostEmissionIntegral0, poolWeight0, POOLWEIGHTMULT)
436458 let poolUserBoostEmissionIntegral1 = fraction(userBoostEmissionIntegral1, poolWeight1, POOLWEIGHTMULT)
437- let userBoostAvaliableToClaimTotalNew0 = if ((totalCachedGwx == 0))
459+ let userBoostAvaliableToClaimTotalNew0 = if ((totalCachedGwxCorrected == 0))
438460 then 0
439- else fraction(poolUserBoostEmissionIntegral0, userCurrGwx, totalCachedGwx)
440- let userBoostAvaliableToClaimTotalNew1 = if ((totalCachedGwx == 0))
461+ else fraction(poolUserBoostEmissionIntegral0, userCurrGwx, totalCachedGwxCorrected)
462+ let userBoostAvaliableToClaimTotalNew1 = if ((totalCachedGwxCorrected == 0))
441463 then 0
442- else fraction(poolUserBoostEmissionIntegral1, userCurrGwx, totalCachedGwx)
464+ else fraction(poolUserBoostEmissionIntegral1, userCurrGwx, totalCachedGwxCorrected)
443465 let userBoostAvaliableToClaimTotalNew = (userBoostAvaliableToClaimTotalNew0 + userBoostAvaliableToClaimTotalNew1)
444466 let userBoostClaimedKEY = keyUserBoostClaimed(userNumStr)
445467 let userBoostClaimed = ioz(this, userBoostClaimedKEY)
446468 let userBoostAvailable = (userBoostAvaliableToClaimTotalNew - userBoostClaimed)
447469 let dataState = [IntegerEntry(userLpBoostEmissionLastIntegralKEY, boostEmissionIntegral)]
448- let debug = makeString([toString(userBoostEmissionLastIntegral), toString(userBoostEmissionIntegral), toString(userBoostClaimed), toString(userBoostAvailable), toString(poolWeight0), toString(poolWeight1), toString(h), toString(udh), toString(uLastH), toString(udh0), toString(udh1), toString(userCurrGwx), toString(totalCachedGwx)], ":")
470+ let debug = makeString([toString(userBoostEmissionLastIntegral), toString(userBoostEmissionIntegral), toString(userBoostClaimed), toString(userBoostAvailable), toString(poolWeight0), toString(poolWeight1), toString(h), toString(udh), toString(uLastH), toString(udh0), toString(udh1), toString(userCurrGwx), toString(totalCachedGwxCorrected)], ":")
449471 $Tuple3(userBoostAvaliableToClaimTotalNew, dataState, debug)
450472 }
451473 }
510532 let totalMaxBoostIntegralKEY = keyTotalMaxBoostINTEGRAL()
511533 let userMaxBoostInt = ((gWxAmountStart * duration) / 2)
512534 let totalMaxBoostInt = ioz(this, totalMaxBoostIntegralKEY)
513- let totalCachedGwxKEY = keyTotalCachedGwx()
514- let totalCachedGwx = valueOrElse(getInteger(this, totalCachedGwxKEY), 0)
535+ let totalCachedGwxRaw = getTotalCachedGwx(false)
515536 let arr = if (userIsExisting)
516537 then nil
517538 else [IntegerEntry(nextUserNumKEY, (userNum + 1)), StringEntry(keyUser2NumMapping(userAddressStr), userNumStr), StringEntry(keyNum2UserMapping(userNumStr), userAddressStr)]
518539 $Tuple2(((((arr ++ LockParamsEntry(userAddressStr, userNumStr, pmtAmount, lockStart, duration, k, b, period)) ++ StatsEntry(pmtAmount, duration, 1, if (userIsExisting)
519540 then 0
520- else 1)) :+ HistoryEntry("lock", userAddressStr, pmtAmount, lockStart, duration, k, b, i)) ++ [IntegerEntry(userBoostEmissionLastIntegralKEY, boostEmissionIntegral), IntegerEntry(totalCachedGwxKEY, (totalCachedGwx + gWxAmountStart))]), gWxAmountStart)
541+ else 1)) :+ HistoryEntry("lock", userAddressStr, pmtAmount, lockStart, duration, k, b, i)) ++ [IntegerEntry(userBoostEmissionLastIntegralKEY, boostEmissionIntegral), IntegerEntry(keyTotalCachedGwx(), (totalCachedGwxRaw + gWxAmountStart))]), gWxAmountStart)
521542 }
522543 }
523544 }
536557
537558 @Callable(i)
538559 func lockRef (duration,referrerAddress,signature) = {
539- let $t02298523050 = lockActions(i, duration)
540- let lockActionsResult = $t02298523050._1
541- let gWxAmountStart = $t02298523050._2
560+ let $t02389223957 = lockActions(i, duration)
561+ let lockActionsResult = $t02389223957._1
562+ let gWxAmountStart = $t02389223957._2
542563 let referralAddress = toString(i.caller)
543564 let refInv = if (if ((referrerAddress == ""))
544565 then true
559580
560581 @Callable(i)
561582 func lock (duration) = {
562- let $t02350823573 = lockActions(i, duration)
563- let lockActionsResult = $t02350823573._1
564- let gWxAmountStart = $t02350823573._2
583+ let $t02441524480 = lockActions(i, duration)
584+ let lockActionsResult = $t02441524480._1
585+ let gWxAmountStart = $t02441524480._2
565586 let updateRefActivity = invoke(mathContract, "updateReferralActivity", [toString(i.caller), gWxAmountStart], nil)
566587 if ((updateRefActivity == updateRefActivity))
567588 then $Tuple2(lockActionsResult, unit)
628649 if ((0 > gwxDiff))
629650 then throw(("gwxDiff is less then 0: " + toString(gwxDiff)))
630651 else {
631- let totalCachedGwxKEY = keyTotalCachedGwx()
632- let totalCachedGwx = valueOrElse(getInteger(this, totalCachedGwxKEY), 0)
652+ let totalCachedGwxRaw = getTotalCachedGwx(false)
653+ let totalCachedGwxCorrected = getTotalCachedGwx(true)
633654 let userBoostAvalaibleToClaimTotalKEY = keyUserBoostAvalaibleToClaimTotal(userNumStr)
634655 let userBoostAvaliableToClaimTotal = ioz(this, userBoostAvalaibleToClaimTotalKEY)
635- let userBoostAvaliableToClaimTotalNew = fraction(userBoostEmissionIntegral, currUserGwx, totalCachedGwx)
656+ let userBoostAvaliableToClaimTotalNew = fraction(userBoostEmissionIntegral, currUserGwx, totalCachedGwxCorrected)
636657 let userMaxBoostIntNew = ((gWxAmountStart * lockDurationNew) / 2)
637658 let remainingUserMaxBoostInt = ((currUserGwx * remainingDuration) / 2)
638659 let userMaxBoostIntDiff = (userMaxBoostIntNew - remainingUserMaxBoostInt)
639- (((LockParamsEntry(userAddressStr, userNumStr, userAmountNew, lockStartNew, lockDurationNew, k, b, period) ++ StatsEntry(pmtAmount, deltaDuration, 0, 0)) :+ HistoryEntry("lock", userAddressStr, pmtAmount, lockStart, lockDurationNew, k, b, i)) ++ [IntegerEntry(totalCachedGwxKEY, (totalCachedGwx + gwxDiff))])
660+ (((LockParamsEntry(userAddressStr, userNumStr, userAmountNew, lockStartNew, lockDurationNew, k, b, period) ++ StatsEntry(pmtAmount, deltaDuration, 0, 0)) :+ HistoryEntry("lock", userAddressStr, pmtAmount, lockStart, lockDurationNew, k, b, i)) ++ [IntegerEntry(keyTotalCachedGwx(), (totalCachedGwxRaw + gwxDiff))])
640661 }
641662 }
642663 }
650671 func claimWxBoost (lpAssetIdStr,userAddressStr) = if ((stakingContract != i.caller))
651672 then throw("permissions denied")
652673 else {
653- let $t02855228654 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, false)
654- let userBoostAvailable = $t02855228654._1
655- let dataState = $t02855228654._2
656- let debug = $t02855228654._3
674+ let $t02946129563 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, false)
675+ let userBoostAvailable = $t02946129563._1
676+ let dataState = $t02946129563._2
677+ let debug = $t02946129563._3
657678 $Tuple2(dataState, [userBoostAvailable])
658679 }
659680
661682
662683 @Callable(i)
663684 func claimWxBoostREADONLY (lpAssetIdStr,userAddressStr) = {
664- let $t02878628887 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, true)
665- let userBoostAvailable = $t02878628887._1
666- let dataState = $t02878628887._2
667- let debug = $t02878628887._3
685+ let $t02969529796 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, true)
686+ let userBoostAvailable = $t02969529796._1
687+ let dataState = $t02969529796._2
688+ let debug = $t02969529796._3
668689 $Tuple2(nil, [userBoostAvailable, debug])
669690 }
670691
705726 let gwxAmount = calcUserGwxAmountAtHeight(userAddress, targetHeight)
706727 $Tuple2(nil, gwxAmount)
707728 }
729+
730+
731+
732+@Callable(i)
733+func getTotalCachedGwxREADONLY () = $Tuple2(nil, getTotalCachedGwx(true))
708734
709735
710736
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let SEP = "__"
55
66 let SCALE8 = 8
77
88 let MULT8 = 100000000
99
1010 let POOLWEIGHTMULT = MULT8
1111
1212 func strf (address,key) = valueOrErrorMessage(getString(address, key), (("mandatory this." + key) + " is not defined"))
1313
1414
1515 func ioz (address,key) = valueOrElse(getInteger(address, key), 0)
1616
1717
1818 func iod (address,key,defaultVal) = valueOrElse(getInteger(address, key), defaultVal)
1919
2020
2121 func iof (address,key) = valueOrErrorMessage(getInteger(address, key), (("mandatory this." + key) + " is not defined"))
2222
2323
2424 func abs (val) = if ((0 > val))
2525 then -(val)
2626 else val
2727
2828
2929 func aal (val) = match val {
3030 case valAnyLyst: List[Any] =>
3131 valAnyLyst
3232 case _ =>
3333 throw("fail to cast into List[Any]")
3434 }
3535
3636
3737 func ai (val) = match val {
3838 case valInt: Int =>
3939 valInt
4040 case _ =>
4141 throw("fail to cast into Int")
4242 }
4343
4444
4545 func keyReferralsContractAddress () = makeString(["%s%s", "config", "referralsContractAddress"], SEP)
4646
4747
4848 let referralsContractAddressOrFail = addressFromStringValue(strf(this, keyReferralsContractAddress()))
4949
5050 let keyReferralProgramName = makeString(["%s%s", "referral", "programName"], SEP)
5151
5252 let referralProgramNameDefault = "wxlock"
5353
5454 let referralProgramName = valueOrElse(getString(this, keyReferralProgramName), referralProgramNameDefault)
5555
5656 func keyFactoryAddress () = "%s%s__config__factoryAddress"
5757
5858
5959 let IdxFactoryCfgStakingDapp = 1
6060
6161 let IdxFactoryCfgBoostingDapp = 2
6262
6363 let IdxFactoryCfgIdoDapp = 3
6464
6565 let IdxFactoryCfgTeamDapp = 4
6666
6767 let IdxFactoryCfgEmissionDapp = 5
6868
6969 let IdxFactoryCfgRestDapp = 6
7070
7171 let IdxFactoryCfgSlippageDapp = 7
7272
7373 let IdxFactoryCfgDaoDapp = 8
7474
7575 let IdxFactoryCfgMarketingDapp = 9
7676
7777 let IdxFactoryCfgGwxRewardDapp = 10
7878
7979 let IdxFactoryCfgBirdsDapp = 11
8080
8181 func keyFactoryCfg () = "%s__factoryConfig"
8282
8383
8484 func keyFactoryLp2AssetsMapping (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP)
8585
8686
8787 func keyFactoryLpList () = "%s__lpTokensList"
8888
8989
9090 func keyFactoryLpAssetToPoolContractAddress (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP)
9191
9292
9393 func keyFactoryPoolWeight (contractAddress) = makeString(["%s%s", "poolWeight", contractAddress], SEP)
9494
9595
9696 func keyFactoryPoolWeightHistory (poolAddress,num) = ((("%s%s__poolWeight__" + poolAddress) + "__") + toString(num))
9797
9898
9999 func readFactoryAddressOrFail () = addressFromStringValue(strf(this, keyFactoryAddress()))
100100
101101
102102 func readLpList () = split(valueOrElse(getString(readFactoryAddressOrFail(), keyFactoryLpList()), ""), SEP)
103103
104104
105105 func readFactoryCfgOrFail (factory) = split(strf(factory, keyFactoryCfg()), SEP)
106106
107107
108108 func getBoostingAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgBoostingDapp])
109109
110110
111111 func getEmissionAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgEmissionDapp])
112112
113113
114114 func getStakingAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgStakingDapp])
115115
116116
117117 func getGwxRewardAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgGwxRewardDapp])
118118
119119
120120 func keyManagerPublicKey () = "%s__managerPublicKey"
121121
122122
123123 func keyPendingManagerPublicKey () = "%s__pendingManagerPublicKey"
124124
125125
126126 func keyEmissionRatePerBlockCurrent () = "%s%s__ratePerBlock__current"
127127
128128
129129 func keyEmissionRatePerBlockMaxCurrent () = "%s%s__ratePerBlockMax__current"
130130
131131
132132 func keyEmissionStartBlock () = "%s%s__emission__startBlock"
133133
134134
135135 func keyEmissionDurationInBlocks () = "%s%s__emission__duration"
136136
137137
138138 func keyEmissionEndBlock () = "%s%s__emission__endBlock"
139139
140140
141141 func keyNextPeriod () = "%s__nextPeriod"
142142
143143
144144 func keyGwxRewardEmissionStartHeight () = "%s%s__gwxRewardEmissionPart__startHeight"
145145
146146
147147 let IdxCfgAssetId = 1
148148
149149 let IdxCfgMinLockAmount = 2
150150
151151 let IdxCfgMinLockDuration = 3
152152
153153 let IdxCfgMaxLockDuration = 4
154154
155155 let IdxCfgMathContract = 5
156156
157157 func keyConfig () = "%s__config"
158158
159159
160160 func readConfigArrayOrFail () = split(strf(this, keyConfig()), SEP)
161161
162162
163163 let mathContract = addressFromStringValue(readConfigArrayOrFail()[IdxCfgMathContract])
164164
165165 func formatConfigS (assetId,minLockAmount,minLockDuration,maxLockDuration,mathContract) = makeString(["%s%d%d%d", assetId, minLockAmount, minLockDuration, maxLockDuration, mathContract], SEP)
166166
167167
168168 func formatConfig (assetId,minLockAmount,minLockDuration,maxLockDuration,mathContract) = formatConfigS(assetId, toString(minLockAmount), toString(minLockDuration), toString(maxLockDuration), mathContract)
169169
170170
171171 func managerPublicKeyOrUnit () = match getString(keyManagerPublicKey()) {
172172 case s: String =>
173173 fromBase58String(s)
174174 case _: Unit =>
175175 unit
176176 case _ =>
177177 throw("Match error")
178178 }
179179
180180
181181 func pendingManagerPublicKeyOrUnit () = match getString(keyPendingManagerPublicKey()) {
182182 case s: String =>
183183 fromBase58String(s)
184184 case _: Unit =>
185185 unit
186186 case _ =>
187187 throw("Match error")
188188 }
189189
190190
191191 func mustManager (i) = {
192192 let pd = throw("Permission denied")
193193 match managerPublicKeyOrUnit() {
194194 case pk: ByteVector =>
195195 if ((i.callerPublicKey == pk))
196196 then true
197197 else pd
198198 case _: Unit =>
199199 if ((i.caller == this))
200200 then true
201201 else pd
202202 case _ =>
203203 throw("Match error")
204204 }
205205 }
206206
207207
208208 let IdxLockUserNum = 1
209209
210210 let IdxLockAmount = 2
211211
212212 let IdxLockStart = 3
213213
214214 let IdxLockDuration = 4
215215
216216 let IdxLockParamK = 5
217217
218218 let IdxLockParamB = 6
219219
220220 func keyLockParamsRecord (userAddress) = makeString(["%s%s__lock", userAddress], SEP)
221221
222222
223223 func readLockParamsRecordOrFail (userAddress) = split(strf(this, keyLockParamsRecord(userAddress)), SEP)
224224
225225
226226 func formatLockParamsRecordS (userNum,amount,start,duration,paramK,paramB,lastUpdTimestamp,gwxAmount) = makeString(["%d%d%d%d%d%d%d%d", userNum, amount, start, duration, paramK, paramB, lastUpdTimestamp, gwxAmount], SEP)
227227
228228
229229 func formatLockParamsRecord (userNum,amount,start,duration,paramK,paramB,gwxAmount) = formatLockParamsRecordS(userNum, toString(amount), toString(start), toString(duration), toString(paramK), toString(paramB), toString(lastBlock.timestamp), toString(gwxAmount))
230230
231231
232232 func keyNextUserNum () = "%s__nextUserNum"
233233
234234
235235 func keyUser2NumMapping (userAddress) = makeString(["%s%s%s__mapping__user2num", userAddress], SEP)
236236
237237
238238 func keyNum2UserMapping (num) = makeString(["%s%s%s__mapping__num2user", num], SEP)
239239
240240
241241 func keyLockParamUserAmount (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "amount"], SEP)
242242
243243
244244 func keyLockParamStartBlock (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "start"], SEP)
245245
246246
247247 func keyLockParamDuration (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "duration"], SEP)
248248
249249
250250 func keyLockParamK (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "k"], SEP)
251251
252252
253253 func keyLockParamB (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "b"], SEP)
254254
255255
256256 func keyLockParamByPeriodK (userNum,period) = makeString(["%s%d%s%d__paramByPeriod", userNum, "k", period], SEP)
257257
258258
259259 func keyLockParamByPeriodB (userNum,period) = makeString(["%s%d%s%d__paramByPeriod", userNum, "b", period], SEP)
260260
261261
262262 func keyLockParamTotalAmount () = "%s%s__stats__activeTotalLocked"
263263
264264
265265 func keyStatsLocksDurationSumInBlocks () = "%s%s__stats__locksDurationSumInBlocks"
266266
267267
268268 func keyStatsLocksCount () = "%s%s__stats__locksCount"
269269
270270
271271 func keyStatsUsersCount () = "%s%s__stats__activeUsersCount"
272272
273273
274274 func keyUserBoostEmissionLastINTEGRAL (userNum) = makeString(["%s%d__userBoostEmissionLastInt", userNum], SEP)
275275
276276
277277 func keyUserLpBoostEmissionLastINTEGRAL (userNum,lpAssetId) = makeString(["%s%d__userBoostEmissionLastInt", userNum, lpAssetId], SEP)
278278
279279
280280 func keyUserMaxBoostINTEGRAL (userNum) = makeString(["%s%d__maxBoostInt", userNum], SEP)
281281
282282
283283 func keyTotalMaxBoostINTEGRAL () = "%s%s__maxBoostInt__total"
284284
285285
286286 func keyUserBoostAvalaibleToClaimTotal (userNum) = makeString(["%s%d__userBoostAvaliableToClaimTotal", userNum], SEP)
287287
288288
289289 func keyUserBoostClaimed (userNum) = makeString(["%s%d__userBoostClaimed", userNum], SEP)
290290
291291
292292 func keyTotalCachedGwx () = "%s%s__gwxCached__total"
293293
294294
295+func keyTotalCachedGwxCorrective () = "%s__gwxCachedTotalCorrective"
296+
297+
295298 let factoryContract = readFactoryAddressOrFail()
296299
297300 let factoryCfg = readFactoryCfgOrFail(factoryContract)
298301
299302 let emissionContract = getEmissionAddressOrFail(factoryCfg)
300303
301304 let stakingContract = getStakingAddressOrFail(factoryCfg)
302305
303306 let gwxRewardContract = getGwxRewardAddressOrFail(factoryCfg)
307+
308+func getTotalCachedGwx (correct) = {
309+ let keyVotingEmissionContract = makeString(["%s", "votingEmissionContract"], SEP)
310+ let votingEmissionContract = addressFromStringValue(getStringValue(factoryContract, keyVotingEmissionContract))
311+ let keyCurrentEpochUi = makeString(["%s", "currentEpochUi"], SEP)
312+ let currentEpochUi = getIntegerValue(votingEmissionContract, keyCurrentEpochUi)
313+ let keyTargetEpoch = makeString(["%s%s", "totalCachedGwxCorrection__activationEpoch"], SEP)
314+ let targetEpochOption = getInteger(this, keyTargetEpoch)
315+ let totalCachedGwxRaw = valueOrElse(getInteger(this, keyTotalCachedGwx()), 0)
316+ let isCorrectionActivated = if (isDefined(targetEpochOption))
317+ then (currentEpochUi >= value(targetEpochOption))
318+ else false
319+ let corrective = if (if (isCorrectionActivated)
320+ then correct
321+ else false)
322+ then valueOrElse(getInteger(this, keyTotalCachedGwxCorrective()), 0)
323+ else 0
324+ max([0, (totalCachedGwxRaw + corrective)])
325+ }
326+
304327
305328 func HistoryEntry (type,user,amount,lockStart,duration,k,b,i) = {
306329 let historyKEY = makeString(["%s%s%s%s__history", type, user, toBase58String(i.transactionId)], SEP)
307330 let historyDATA = makeString(["%d%d%d%d%d%d%d", toString(lastBlock.height), toString(lastBlock.timestamp), toString(amount), toString(lockStart), toString(duration), toString(k), toString(b)], SEP)
308331 StringEntry(historyKEY, historyDATA)
309332 }
310333
311334
312335 func StatsEntry (totalLockedInc,durationInc,lockCountInc,usersCountInc) = {
313336 let locksDurationSumInBlocksKEY = keyStatsLocksDurationSumInBlocks()
314337 let locksCountKEY = keyStatsLocksCount()
315338 let usersCountKEY = keyStatsUsersCount()
316339 let totalAmountKEY = keyLockParamTotalAmount()
317340 let locksDurationSumInBlocks = ioz(this, locksDurationSumInBlocksKEY)
318341 let locksCount = ioz(this, locksCountKEY)
319342 let usersCount = ioz(this, usersCountKEY)
320343 let totalAmount = ioz(this, totalAmountKEY)
321344 [IntegerEntry(locksDurationSumInBlocksKEY, (locksDurationSumInBlocks + durationInc)), IntegerEntry(locksCountKEY, (locksCount + lockCountInc)), IntegerEntry(usersCountKEY, (usersCount + usersCountInc)), IntegerEntry(totalAmountKEY, (totalAmount + totalLockedInc))]
322345 }
323346
324347
325348 func calcGwxAmount (kRaw,bRaw,h) = {
326349 let SCALE = 1000
327350 (((kRaw * h) + bRaw) / SCALE)
328351 }
329352
330353
331354 func LockParamsEntry (userAddress,userNum,amount,start,duration,k,b,period) = {
332355 let userAmountKEY = keyLockParamUserAmount(userNum)
333356 let startBlockKEY = keyLockParamStartBlock(userNum)
334357 let durationKEY = keyLockParamDuration(userNum)
335358 let kKEY = keyLockParamK(userNum)
336359 let bKEY = keyLockParamB(userNum)
337360 let kByPeriodKEY = keyLockParamByPeriodK(userNum, period)
338361 let bByPeriodKEY = keyLockParamByPeriodB(userNum, period)
339362 let gwxAmount = calcGwxAmount(k, b, height)
340363 [IntegerEntry(userAmountKEY, amount), IntegerEntry(startBlockKEY, start), IntegerEntry(durationKEY, duration), IntegerEntry(kKEY, k), IntegerEntry(bKEY, b), IntegerEntry(kByPeriodKEY, k), IntegerEntry(bByPeriodKEY, b), StringEntry(keyLockParamsRecord(userAddress), formatLockParamsRecord(userNum, amount, start, duration, k, b, gwxAmount))]
341364 }
342365
343366
344367 func extractOptionalPaymentAmountOrFail (i,expectedAssetId) = if ((size(i.payments) > 1))
345368 then throw("only one payment is allowed")
346369 else if ((size(i.payments) == 0))
347370 then 0
348371 else {
349372 let pmt = i.payments[0]
350373 if ((value(pmt.assetId) != expectedAssetId))
351374 then throw("invalid asset id in payment")
352375 else pmt.amount
353376 }
354377
355378
356379 func calcUserGwxAmountAtHeight (userAddress,targetHeight) = {
357380 let EMPTY = "empty"
358381 let user2NumMappingKEY = keyUser2NumMapping(userAddress)
359382 let userNum = valueOrElse(getString(user2NumMappingKEY), EMPTY)
360383 let k = valueOrElse(getInteger(keyLockParamK(userNum)), 0)
361384 let b = valueOrElse(getInteger(keyLockParamB(userNum)), 0)
362385 let gwxAmountCalc = calcGwxAmount(k, b, targetHeight)
363386 let gwxAmount = if ((0 > gwxAmountCalc))
364387 then 0
365388 else gwxAmountCalc
366389 gwxAmount
367390 }
368391
369392
370393 func calcCurrentGwxAmount (userAddress) = calcUserGwxAmountAtHeight(userAddress, height)
371394
372395
373396 func internalClaimWxBoost (lpAssetIdStr,userAddressStr,readOnly) = {
374397 let EMPTY = "EMPTY"
375398 let userRecordOrEmpty = valueOrElse(getString(this, keyLockParamsRecord(userAddressStr)), EMPTY)
376399 if ((userRecordOrEmpty == EMPTY))
377400 then $Tuple3(0, nil, "userRecord::is::empty")
378401 else {
379402 let userRecordArray = split(userRecordOrEmpty, SEP)
380403 let userNumStr = userRecordArray[IdxLockUserNum]
381404 let gwxRewardEmissionStartHeight = valueOrElse(getInteger(gwxRewardContract, keyGwxRewardEmissionStartHeight()), 0)
382405 let EMPTYSTR = "empty"
383- let $t01397714545 = if ((lpAssetIdStr != EMPTYSTR))
406+ let $t01496515533 = if ((lpAssetIdStr != EMPTYSTR))
384407 then {
385408 let poolAddressStr = valueOrErrorMessage(getString(factoryContract, keyFactoryLp2AssetsMapping(lpAssetIdStr)), ("unsupported lp asset " + lpAssetIdStr))
386409 let pw1 = getIntegerValue(factoryContract, keyFactoryPoolWeight(poolAddressStr))
387410 let pw0 = valueOrElse(getInteger(factoryContract, keyFactoryPoolWeightHistory(poolAddressStr, 0)), pw1)
388411 $Tuple2(pw0, pw1)
389412 }
390413 else if (readOnly)
391414 then $Tuple2(0, 0)
392415 else throw(("not readonly mode: unsupported lp asset " + lpAssetIdStr))
393- let poolWeight0 = $t01397714545._1
394- let poolWeight1 = $t01397714545._2
416+ let poolWeight0 = $t01496515533._1
417+ let poolWeight1 = $t01496515533._2
395418 let wxEmissionPerBlock = iof(emissionContract, keyEmissionRatePerBlockCurrent())
396419 let emissionStart = iof(emissionContract, keyEmissionStartBlock())
397420 let emissionEnd = iof(emissionContract, keyEmissionEndBlock())
398421 let h = if ((height > emissionEnd))
399422 then emissionEnd
400423 else height
401424 let dh = max([(h - emissionStart), 0])
402425 let userLpBoostEmissionLastIntegralKEY = keyUserLpBoostEmissionLastINTEGRAL(userNumStr, lpAssetIdStr)
403426 let userBoostEmissionLastIntegralKEY = keyUserBoostEmissionLastINTEGRAL(userNumStr)
404427 let userBoostEmissionLastIntegral = valueOrElse(getInteger(this, userLpBoostEmissionLastIntegralKEY), ioz(this, userBoostEmissionLastIntegralKEY))
405428 let boostEmissionIntegral = (((wxEmissionPerBlock * dh) * 2) / 3)
406429 let userBoostEmissionIntegral = (boostEmissionIntegral - userBoostEmissionLastIntegral)
407430 let udh = fraction(userBoostEmissionIntegral, 3, (2 * wxEmissionPerBlock))
408431 let uLastH = (h - udh)
409432 let udh0 = max([(gwxRewardEmissionStartHeight - uLastH), 0])
410433 let udh1 = ((h - uLastH) - udh0)
411434 if (if (if ((0 > uLastH))
412435 then true
413436 else (0 > udh1))
414437 then true
415438 else (abs(((udh0 + udh1) - udh)) >= 1))
416439 then throw(((((((("invalid udh calc: udh=" + toString(udh)) + " uLastH=") + toString(uLastH)) + " udh0=") + toString(udh0)) + " udh1=") + toString(udh1)))
417440 else if ((0 > userBoostEmissionIntegral))
418441 then throw("wrong calculations")
419442 else {
420443 let userMaxBoostIntegralKEY = keyUserMaxBoostINTEGRAL(userNumStr)
421444 let totalMaxBoostIntegralKEY = keyTotalMaxBoostINTEGRAL()
422445 let userMaxBoostInt = ioz(this, userMaxBoostIntegralKEY)
423446 let totalMaxBoostInt = ioz(this, totalMaxBoostIntegralKEY)
424- let totalCachedGwxKEY = keyTotalCachedGwx()
425- let totalCachedGwx = valueOrElse(getInteger(this, totalCachedGwxKEY), 0)
447+ let totalCachedGwxCorrected = getTotalCachedGwx(true)
426448 let userCurrGwx = calcCurrentGwxAmount(userAddressStr)
427449 let userBoostAvalaibleToClaimTotalKEY = keyUserBoostAvalaibleToClaimTotal(userNumStr)
428450 let userBoostAvaliableToClaimTotal = ioz(this, userBoostAvalaibleToClaimTotalKEY)
429451 let userBoostEmissionIntegral0 = if ((udh == 0))
430452 then 0
431453 else fraction(userBoostEmissionIntegral, udh0, udh)
432454 let userBoostEmissionIntegral1 = if ((udh == 0))
433455 then 0
434456 else fraction(userBoostEmissionIntegral, udh1, udh)
435457 let poolUserBoostEmissionIntegral0 = fraction(userBoostEmissionIntegral0, poolWeight0, POOLWEIGHTMULT)
436458 let poolUserBoostEmissionIntegral1 = fraction(userBoostEmissionIntegral1, poolWeight1, POOLWEIGHTMULT)
437- let userBoostAvaliableToClaimTotalNew0 = if ((totalCachedGwx == 0))
459+ let userBoostAvaliableToClaimTotalNew0 = if ((totalCachedGwxCorrected == 0))
438460 then 0
439- else fraction(poolUserBoostEmissionIntegral0, userCurrGwx, totalCachedGwx)
440- let userBoostAvaliableToClaimTotalNew1 = if ((totalCachedGwx == 0))
461+ else fraction(poolUserBoostEmissionIntegral0, userCurrGwx, totalCachedGwxCorrected)
462+ let userBoostAvaliableToClaimTotalNew1 = if ((totalCachedGwxCorrected == 0))
441463 then 0
442- else fraction(poolUserBoostEmissionIntegral1, userCurrGwx, totalCachedGwx)
464+ else fraction(poolUserBoostEmissionIntegral1, userCurrGwx, totalCachedGwxCorrected)
443465 let userBoostAvaliableToClaimTotalNew = (userBoostAvaliableToClaimTotalNew0 + userBoostAvaliableToClaimTotalNew1)
444466 let userBoostClaimedKEY = keyUserBoostClaimed(userNumStr)
445467 let userBoostClaimed = ioz(this, userBoostClaimedKEY)
446468 let userBoostAvailable = (userBoostAvaliableToClaimTotalNew - userBoostClaimed)
447469 let dataState = [IntegerEntry(userLpBoostEmissionLastIntegralKEY, boostEmissionIntegral)]
448- let debug = makeString([toString(userBoostEmissionLastIntegral), toString(userBoostEmissionIntegral), toString(userBoostClaimed), toString(userBoostAvailable), toString(poolWeight0), toString(poolWeight1), toString(h), toString(udh), toString(uLastH), toString(udh0), toString(udh1), toString(userCurrGwx), toString(totalCachedGwx)], ":")
470+ let debug = makeString([toString(userBoostEmissionLastIntegral), toString(userBoostEmissionIntegral), toString(userBoostClaimed), toString(userBoostAvailable), toString(poolWeight0), toString(poolWeight1), toString(h), toString(udh), toString(uLastH), toString(udh0), toString(udh1), toString(userCurrGwx), toString(totalCachedGwxCorrected)], ":")
449471 $Tuple3(userBoostAvaliableToClaimTotalNew, dataState, debug)
450472 }
451473 }
452474 }
453475
454476
455477 func lockActions (i,duration) = {
456478 let cfgArray = readConfigArrayOrFail()
457479 let assetIdStr = cfgArray[IdxCfgAssetId]
458480 let assetId = fromBase58String(assetIdStr)
459481 let minLockAmount = parseIntValue(cfgArray[IdxCfgMinLockAmount])
460482 let minLockDuration = parseIntValue(cfgArray[IdxCfgMinLockDuration])
461483 let maxLockDuration = parseIntValue(cfgArray[IdxCfgMaxLockDuration])
462484 if ((size(i.payments) != 1))
463485 then throw("invalid payment - exact one payment must be attached")
464486 else {
465487 let pmt = i.payments[0]
466488 let pmtAmount = pmt.amount
467489 if ((assetId != value(pmt.assetId)))
468490 then throw((("invalid asset is in payment - " + assetIdStr) + " is expected"))
469491 else {
470492 let nextUserNumKEY = keyNextUserNum()
471493 let userAddressStr = toString(i.caller)
472494 let userIsExisting = isDefined(getString(keyUser2NumMapping(userAddressStr)))
473495 let userNumStr = if (userIsExisting)
474496 then value(getString(keyUser2NumMapping(userAddressStr)))
475497 else toString(iof(this, nextUserNumKEY))
476498 let userNum = parseIntValue(userNumStr)
477499 let lockStart = height
478500 let startBlockKEY = keyLockParamStartBlock(userNumStr)
479501 let durationKEY = keyLockParamDuration(userNumStr)
480502 let userAmountKEY = keyLockParamUserAmount(userNumStr)
481503 if ((minLockAmount > pmtAmount))
482504 then throw(("amount is less then minLockAmount=" + toString(minLockAmount)))
483505 else if ((minLockDuration > duration))
484506 then throw(("passed duration is less then minLockDuration=" + toString(minLockDuration)))
485507 else if ((duration > maxLockDuration))
486508 then throw(("passed duration is greater then maxLockDuration=" + toString(maxLockDuration)))
487509 else if (if (userIsExisting)
488510 then ((iof(this, startBlockKEY) + iof(this, durationKEY)) >= lockStart)
489511 else false)
490512 then throw("there is an active lock - consider to use increaseLock")
491513 else if ((ioz(this, userAmountKEY) > 0))
492514 then throw(("there are locked WXs - consider to use increaseLock " + userAmountKEY))
493515 else {
494516 let coeffX8 = fraction(duration, MULT8, maxLockDuration)
495517 let gWxAmountStart = fraction(pmtAmount, coeffX8, MULT8)
496518 let gWxParamsResultList = aal(invoke(mathContract, "calcGwxParamsREADONLY", [gWxAmountStart, lockStart, duration], nil))
497519 let k = ai(gWxParamsResultList[0])
498520 let b = ai(gWxParamsResultList[1])
499521 let period = toString(ai(gWxParamsResultList[2]))
500522 let wxEmissionPerBlock = iof(emissionContract, keyEmissionRatePerBlockCurrent())
501523 let emissionStart = iof(emissionContract, keyEmissionStartBlock())
502524 let emissionEnd = iof(emissionContract, keyEmissionEndBlock())
503525 let h = if ((height > emissionEnd))
504526 then emissionEnd
505527 else height
506528 let dh = max([(h - emissionStart), 0])
507529 let userBoostEmissionLastIntegralKEY = keyUserBoostEmissionLastINTEGRAL(userNumStr)
508530 let boostEmissionIntegral = (((wxEmissionPerBlock * dh) * 2) / 3)
509531 let userMaxBoostIntegralKEY = keyUserMaxBoostINTEGRAL(userNumStr)
510532 let totalMaxBoostIntegralKEY = keyTotalMaxBoostINTEGRAL()
511533 let userMaxBoostInt = ((gWxAmountStart * duration) / 2)
512534 let totalMaxBoostInt = ioz(this, totalMaxBoostIntegralKEY)
513- let totalCachedGwxKEY = keyTotalCachedGwx()
514- let totalCachedGwx = valueOrElse(getInteger(this, totalCachedGwxKEY), 0)
535+ let totalCachedGwxRaw = getTotalCachedGwx(false)
515536 let arr = if (userIsExisting)
516537 then nil
517538 else [IntegerEntry(nextUserNumKEY, (userNum + 1)), StringEntry(keyUser2NumMapping(userAddressStr), userNumStr), StringEntry(keyNum2UserMapping(userNumStr), userAddressStr)]
518539 $Tuple2(((((arr ++ LockParamsEntry(userAddressStr, userNumStr, pmtAmount, lockStart, duration, k, b, period)) ++ StatsEntry(pmtAmount, duration, 1, if (userIsExisting)
519540 then 0
520- else 1)) :+ HistoryEntry("lock", userAddressStr, pmtAmount, lockStart, duration, k, b, i)) ++ [IntegerEntry(userBoostEmissionLastIntegralKEY, boostEmissionIntegral), IntegerEntry(totalCachedGwxKEY, (totalCachedGwx + gWxAmountStart))]), gWxAmountStart)
541+ else 1)) :+ HistoryEntry("lock", userAddressStr, pmtAmount, lockStart, duration, k, b, i)) ++ [IntegerEntry(userBoostEmissionLastIntegralKEY, boostEmissionIntegral), IntegerEntry(keyTotalCachedGwx(), (totalCachedGwxRaw + gWxAmountStart))]), gWxAmountStart)
521542 }
522543 }
523544 }
524545 }
525546
526547
527548 @Callable(i)
528549 func constructor (factoryAddressStr,lockAssetIdStr,minLockAmount,minDuration,maxDuration,mathContract) = {
529550 let checkCaller = mustManager(i)
530551 if ((checkCaller == checkCaller))
531552 then ([IntegerEntry(keyNextUserNum(), 0), StringEntry(keyConfig(), formatConfig(lockAssetIdStr, minLockAmount, minDuration, maxDuration, mathContract)), StringEntry(keyFactoryAddress(), factoryAddressStr)] ++ StatsEntry(0, 0, 0, 0))
532553 else throw("Strict value is not equal to itself.")
533554 }
534555
535556
536557
537558 @Callable(i)
538559 func lockRef (duration,referrerAddress,signature) = {
539- let $t02298523050 = lockActions(i, duration)
540- let lockActionsResult = $t02298523050._1
541- let gWxAmountStart = $t02298523050._2
560+ let $t02389223957 = lockActions(i, duration)
561+ let lockActionsResult = $t02389223957._1
562+ let gWxAmountStart = $t02389223957._2
542563 let referralAddress = toString(i.caller)
543564 let refInv = if (if ((referrerAddress == ""))
544565 then true
545566 else (signature == base58''))
546567 then unit
547568 else invoke(referralsContractAddressOrFail, "createPair", [referralProgramName, referrerAddress, referralAddress, signature], nil)
548569 if ((refInv == refInv))
549570 then {
550571 let updateRefActivity = invoke(mathContract, "updateReferralActivity", [toString(i.caller), gWxAmountStart], nil)
551572 if ((updateRefActivity == updateRefActivity))
552573 then $Tuple2(lockActionsResult, unit)
553574 else throw("Strict value is not equal to itself.")
554575 }
555576 else throw("Strict value is not equal to itself.")
556577 }
557578
558579
559580
560581 @Callable(i)
561582 func lock (duration) = {
562- let $t02350823573 = lockActions(i, duration)
563- let lockActionsResult = $t02350823573._1
564- let gWxAmountStart = $t02350823573._2
583+ let $t02441524480 = lockActions(i, duration)
584+ let lockActionsResult = $t02441524480._1
585+ let gWxAmountStart = $t02441524480._2
565586 let updateRefActivity = invoke(mathContract, "updateReferralActivity", [toString(i.caller), gWxAmountStart], nil)
566587 if ((updateRefActivity == updateRefActivity))
567588 then $Tuple2(lockActionsResult, unit)
568589 else throw("Strict value is not equal to itself.")
569590 }
570591
571592
572593
573594 @Callable(i)
574595 func increaseLock (deltaDuration) = {
575596 let cfgArray = readConfigArrayOrFail()
576597 let assetIdStr = cfgArray[IdxCfgAssetId]
577598 let assetId = fromBase58String(assetIdStr)
578599 let minLockDuration = parseIntValue(cfgArray[IdxCfgMinLockDuration])
579600 let maxLockDuration = parseIntValue(cfgArray[IdxCfgMaxLockDuration])
580601 let pmtAmount = extractOptionalPaymentAmountOrFail(i, assetId)
581602 let userAddressStr = toString(i.caller)
582603 let userRecordArray = readLockParamsRecordOrFail(userAddressStr)
583604 let userNumStr = userRecordArray[IdxLockUserNum]
584605 let userAmount = parseIntValue(userRecordArray[IdxLockAmount])
585606 let lockStart = parseIntValue(userRecordArray[IdxLockStart])
586607 let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
587608 let lockEnd = (lockStart + lockDuration)
588609 let remainingDuration = max([(lockEnd - height), 0])
589610 let userAmountNew = (userAmount + pmtAmount)
590611 let lockDurationNew = (remainingDuration + deltaDuration)
591612 if ((0 > deltaDuration))
592613 then throw("duration is less then zero")
593614 else if ((minLockDuration > lockDurationNew))
594615 then throw(("lockDurationNew is less then minLockDuration=" + toString(minLockDuration)))
595616 else if ((lockDurationNew > maxLockDuration))
596617 then throw(("deltaDuration + existedLockDuration is greater then maxLockDuration=" + toString(maxLockDuration)))
597618 else {
598619 let coeffX8 = fraction(lockDurationNew, MULT8, maxLockDuration)
599620 let gWxAmountStart = fraction(userAmountNew, coeffX8, MULT8)
600621 let updateRefActivity = invoke(mathContract, "updateReferralActivity", [toString(i.caller), gWxAmountStart], nil)
601622 if ((updateRefActivity == updateRefActivity))
602623 then {
603624 let lockStartNew = height
604625 let gWxParamsResultList = aal(invoke(mathContract, "calcGwxParamsREADONLY", [gWxAmountStart, lockStartNew, lockDurationNew], nil))
605626 let k = ai(gWxParamsResultList[0])
606627 let b = ai(gWxParamsResultList[1])
607628 let period = toString(ai(gWxParamsResultList[2]))
608629 let wxEmissionPerBlock = iof(emissionContract, keyEmissionRatePerBlockCurrent())
609630 let emissionStart = iof(emissionContract, keyEmissionStartBlock())
610631 let emissionEnd = iof(emissionContract, keyEmissionEndBlock())
611632 let h = if ((height > emissionEnd))
612633 then emissionEnd
613634 else height
614635 let dh = max([(h - emissionStart), 0])
615636 let userBoostEmissionLastIntegralKEY = keyUserBoostEmissionLastINTEGRAL(userNumStr)
616637 let userBoostEmissionLastIntegral = ioz(this, userBoostEmissionLastIntegralKEY)
617638 let boostEmissionIntegral = (((wxEmissionPerBlock * dh) * 2) / 3)
618639 let userBoostEmissionIntegral = (boostEmissionIntegral - userBoostEmissionLastIntegral)
619640 if ((0 > userBoostEmissionIntegral))
620641 then throw("wrong calculations")
621642 else {
622643 let userMaxBoostIntegralKEY = keyUserMaxBoostINTEGRAL(userNumStr)
623644 let totalMaxBoostIntegralKEY = keyTotalMaxBoostINTEGRAL()
624645 let userMaxBoostInt = ioz(this, userMaxBoostIntegralKEY)
625646 let totalMaxBoostInt = ioz(this, totalMaxBoostIntegralKEY)
626647 let currUserGwx = calcCurrentGwxAmount(userAddressStr)
627648 let gwxDiff = (gWxAmountStart - currUserGwx)
628649 if ((0 > gwxDiff))
629650 then throw(("gwxDiff is less then 0: " + toString(gwxDiff)))
630651 else {
631- let totalCachedGwxKEY = keyTotalCachedGwx()
632- let totalCachedGwx = valueOrElse(getInteger(this, totalCachedGwxKEY), 0)
652+ let totalCachedGwxRaw = getTotalCachedGwx(false)
653+ let totalCachedGwxCorrected = getTotalCachedGwx(true)
633654 let userBoostAvalaibleToClaimTotalKEY = keyUserBoostAvalaibleToClaimTotal(userNumStr)
634655 let userBoostAvaliableToClaimTotal = ioz(this, userBoostAvalaibleToClaimTotalKEY)
635- let userBoostAvaliableToClaimTotalNew = fraction(userBoostEmissionIntegral, currUserGwx, totalCachedGwx)
656+ let userBoostAvaliableToClaimTotalNew = fraction(userBoostEmissionIntegral, currUserGwx, totalCachedGwxCorrected)
636657 let userMaxBoostIntNew = ((gWxAmountStart * lockDurationNew) / 2)
637658 let remainingUserMaxBoostInt = ((currUserGwx * remainingDuration) / 2)
638659 let userMaxBoostIntDiff = (userMaxBoostIntNew - remainingUserMaxBoostInt)
639- (((LockParamsEntry(userAddressStr, userNumStr, userAmountNew, lockStartNew, lockDurationNew, k, b, period) ++ StatsEntry(pmtAmount, deltaDuration, 0, 0)) :+ HistoryEntry("lock", userAddressStr, pmtAmount, lockStart, lockDurationNew, k, b, i)) ++ [IntegerEntry(totalCachedGwxKEY, (totalCachedGwx + gwxDiff))])
660+ (((LockParamsEntry(userAddressStr, userNumStr, userAmountNew, lockStartNew, lockDurationNew, k, b, period) ++ StatsEntry(pmtAmount, deltaDuration, 0, 0)) :+ HistoryEntry("lock", userAddressStr, pmtAmount, lockStart, lockDurationNew, k, b, i)) ++ [IntegerEntry(keyTotalCachedGwx(), (totalCachedGwxRaw + gwxDiff))])
640661 }
641662 }
642663 }
643664 else throw("Strict value is not equal to itself.")
644665 }
645666 }
646667
647668
648669
649670 @Callable(i)
650671 func claimWxBoost (lpAssetIdStr,userAddressStr) = if ((stakingContract != i.caller))
651672 then throw("permissions denied")
652673 else {
653- let $t02855228654 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, false)
654- let userBoostAvailable = $t02855228654._1
655- let dataState = $t02855228654._2
656- let debug = $t02855228654._3
674+ let $t02946129563 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, false)
675+ let userBoostAvailable = $t02946129563._1
676+ let dataState = $t02946129563._2
677+ let debug = $t02946129563._3
657678 $Tuple2(dataState, [userBoostAvailable])
658679 }
659680
660681
661682
662683 @Callable(i)
663684 func claimWxBoostREADONLY (lpAssetIdStr,userAddressStr) = {
664- let $t02878628887 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, true)
665- let userBoostAvailable = $t02878628887._1
666- let dataState = $t02878628887._2
667- let debug = $t02878628887._3
685+ let $t02969529796 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, true)
686+ let userBoostAvailable = $t02969529796._1
687+ let dataState = $t02969529796._2
688+ let debug = $t02969529796._3
668689 $Tuple2(nil, [userBoostAvailable, debug])
669690 }
670691
671692
672693
673694 @Callable(i)
674695 func unlock (userAddress) = {
675696 let userRecordArray = readLockParamsRecordOrFail(userAddress)
676697 let userNumStr = userRecordArray[IdxLockUserNum]
677698 let userAmount = parseIntValue(userRecordArray[IdxLockAmount])
678699 let lockStart = parseIntValue(userRecordArray[IdxLockStart])
679700 let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
680701 let lockEnd = (lockStart + lockDuration)
681702 let cfgArray = readConfigArrayOrFail()
682703 let assetId = fromBase58String(cfgArray[IdxCfgAssetId])
683704 if ((lockEnd >= height))
684705 then throw((("wait " + toString(lockEnd)) + " to unlock"))
685706 else if ((0 >= userAmount))
686707 then throw("nothing to unlock")
687708 else {
688709 let period = valueOrElse(getInteger(mathContract, keyNextPeriod()), 0)
689710 (((LockParamsEntry(userAddress, userNumStr, 0, lockStart, lockDuration, 0, 0, toString(period)) ++ StatsEntry(-(userAmount), 0, 0, -1)) :+ HistoryEntry("unlock", userAddress, userAmount, lockStart, lockDuration, 0, 0, i)) :+ ScriptTransfer(addressFromStringValue(userAddress), userAmount, assetId))
690711 }
691712 }
692713
693714
694715
695716 @Callable(i)
696717 func gwxUserInfoREADONLY (userAddress) = {
697718 let gwxAmount = calcCurrentGwxAmount(userAddress)
698719 $Tuple2(nil, [gwxAmount])
699720 }
700721
701722
702723
703724 @Callable(i)
704725 func getUserGwxAmountAtHeightREADONLY (userAddress,targetHeight) = {
705726 let gwxAmount = calcUserGwxAmountAtHeight(userAddress, targetHeight)
706727 $Tuple2(nil, gwxAmount)
707728 }
729+
730+
731+
732+@Callable(i)
733+func getTotalCachedGwxREADONLY () = $Tuple2(nil, getTotalCachedGwx(true))
708734
709735
710736
711737 @Callable(i)
712738 func setManager (pendingManagerPublicKey) = {
713739 let checkCaller = mustManager(i)
714740 if ((checkCaller == checkCaller))
715741 then {
716742 let checkManagerPublicKey = fromBase58String(pendingManagerPublicKey)
717743 if ((checkManagerPublicKey == checkManagerPublicKey))
718744 then [StringEntry(keyPendingManagerPublicKey(), pendingManagerPublicKey)]
719745 else throw("Strict value is not equal to itself.")
720746 }
721747 else throw("Strict value is not equal to itself.")
722748 }
723749
724750
725751
726752 @Callable(i)
727753 func confirmManager () = {
728754 let pm = pendingManagerPublicKeyOrUnit()
729755 let hasPM = if (isDefined(pm))
730756 then true
731757 else throw("No pending manager")
732758 if ((hasPM == hasPM))
733759 then {
734760 let checkPM = if ((i.callerPublicKey == value(pm)))
735761 then true
736762 else throw("You are not pending manager")
737763 if ((checkPM == checkPM))
738764 then [StringEntry(keyManagerPublicKey(), toBase58String(value(pm))), DeleteEntry(keyPendingManagerPublicKey())]
739765 else throw("Strict value is not equal to itself.")
740766 }
741767 else throw("Strict value is not equal to itself.")
742768 }
743769
744770
745771 @Verifier(tx)
746772 func verify () = {
747773 let targetPublicKey = match managerPublicKeyOrUnit() {
748774 case pk: ByteVector =>
749775 pk
750776 case _: Unit =>
751777 tx.senderPublicKey
752778 case _ =>
753779 throw("Match error")
754780 }
755781 sigVerify(tx.bodyBytes, tx.proofs[0], targetPublicKey)
756782 }
757783

github/deemru/w8io/786bc32 
91.85 ms