tx · 8JrUty75U58yfu7rr2J2387P6gY7SSoc5LSD9szLX2M2

3Myn55vLkduxbX3ZXfiDCZhaQsLxYp1kmCy:  -0.37000000 Waves

2023.09.07 12:36 [2744797] smart account 3Myn55vLkduxbX3ZXfiDCZhaQsLxYp1kmCy > SELF 0.00000000 Waves

{ "type": 13, "id": "8JrUty75U58yfu7rr2J2387P6gY7SSoc5LSD9szLX2M2", "fee": 37000000, "feeAssetId": null, "timestamp": 1694079404430, "version": 2, "chainId": 84, "sender": "3Myn55vLkduxbX3ZXfiDCZhaQsLxYp1kmCy", "senderPublicKey": "9W33iCCNfmFxUbiC6XZcH5x7f6xfwC7Jb3BoExT5q2PV", "proofs": [ "4xxSZMXGU3vjURwqmczbXwFNVQT6DCkmUcv6zWbWJ2iRkKergQAYLbB32Z58aNgdmgZ2wWpgt4CSw517bGev9q4i" ], "script": "base64:BgJaCAISBQoDAQgCEgMKAQESBAoCCAgSBAoCCAgSAwoBCBIDCgEIEgMKAQgSBAoCCAESAwoBCBIAEgASBQoDCAgEEgMKAQgSAwoBCBIECgIICBIECgIICBIDCgEEjwEAA1NFUAICX18ABlNDQUxFOAAIAAVNVUxUOACAwtcvAA5QT09MV0VJR0hUTVVMVAUFTVVMVDgAEGNvbnRyYWN0RmlsZW5hbWUCDWJvb3N0aW5nLnJpZGUAB1NDQUxFMTgAEgAGTVVMVDE4AICAkLu61q3wDQAITVVMVDE4QkkJALYCAQUGTVVMVDE4AA5ERUNBWV9DT05TVEFOVAAIAQd3cmFwRXJyAQNtc2cJALkJAgkAzAgCBRBjb250cmFjdEZpbGVuYW1lCQDMCAICAjogCQDMCAIFA21zZwUDbmlsAgABCHRocm93RXJyAQNtc2cJAAIBCQEHd3JhcEVycgEFA21zZwEPZ2V0U3RyaW5nT3JGYWlsAgdhZGRyZXNzA2tleQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFB2FkZHJlc3MFA2tleQkBB3dyYXBFcnIBCQCsAgIJAKwCAgIPbWFuZGF0b3J5IHRoaXMuBQNrZXkCDyBpcyBub3QgZGVmaW5lZAEMZ2V0SW50T3JaZXJvAgdhZGRyZXNzA2tleQkBC3ZhbHVlT3JFbHNlAgkAmggCBQdhZGRyZXNzBQNrZXkAAAEPZ2V0SW50T3JEZWZhdWx0AwdhZGRyZXNzA2tleQpkZWZhdWx0VmFsCQELdmFsdWVPckVsc2UCCQCaCAIFB2FkZHJlc3MFA2tleQUKZGVmYXVsdFZhbAEMZ2V0SW50T3JGYWlsAgdhZGRyZXNzA2tleQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFB2FkZHJlc3MFA2tleQkBB3dyYXBFcnIBCQCsAgIJAKwCAgIPbWFuZGF0b3J5IHRoaXMuBQNrZXkCDyBpcyBub3QgZGVmaW5lZAEDYWJzAQN2YWwDCQBmAgAABQN2YWwJAQEtAQUDdmFsBQN2YWwBDmVuc3VyZVBvc2l0aXZlAgF2AW0DCQBnAgUBdgAABQF2CQEIdGhyb3dFcnIBCQCsAgIJAQt2YWx1ZU9yRWxzZQIFAW0CBXZhbHVlAhMgc2hvdWxkIGJlIHBvc2l0aXZlARtrZXlSZWZlcnJhbHNDb250cmFjdEFkZHJlc3MACQC5CQIJAMwIAgIEJXMlcwkAzAgCAgZjb25maWcJAMwIAgIYcmVmZXJyYWxzQ29udHJhY3RBZGRyZXNzBQNuaWwFA1NFUAAecmVmZXJyYWxzQ29udHJhY3RBZGRyZXNzT3JGYWlsCQERQGV4dHJOYXRpdmUoMTA2MikBCQEPZ2V0U3RyaW5nT3JGYWlsAgUEdGhpcwkBG2tleVJlZmVycmFsc0NvbnRyYWN0QWRkcmVzcwAAFmtleVJlZmVycmFsUHJvZ3JhbU5hbWUJALkJAgkAzAgCAgQlcyVzCQDMCAICCHJlZmVycmFsCQDMCAICC3Byb2dyYW1OYW1lBQNuaWwFA1NFUAAacmVmZXJyYWxQcm9ncmFtTmFtZURlZmF1bHQCBnd4bG9jawATcmVmZXJyYWxQcm9ncmFtTmFtZQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzBRZrZXlSZWZlcnJhbFByb2dyYW1OYW1lBRpyZWZlcnJhbFByb2dyYW1OYW1lRGVmYXVsdAERa2V5RmFjdG9yeUFkZHJlc3MAAhwlcyVzX19jb25maWdfX2ZhY3RvcnlBZGRyZXNzABhJZHhGYWN0b3J5Q2ZnU3Rha2luZ0RhcHAAAQAZSWR4RmFjdG9yeUNmZ0Jvb3N0aW5nRGFwcAACABRJZHhGYWN0b3J5Q2ZnSWRvRGFwcAADABVJZHhGYWN0b3J5Q2ZnVGVhbURhcHAABAAZSWR4RmFjdG9yeUNmZ0VtaXNzaW9uRGFwcAAFABVJZHhGYWN0b3J5Q2ZnUmVzdERhcHAABgAZSWR4RmFjdG9yeUNmZ1NsaXBwYWdlRGFwcAAHABRJZHhGYWN0b3J5Q2ZnRGFvRGFwcAAIABpJZHhGYWN0b3J5Q2ZnTWFya2V0aW5nRGFwcAAJABpJZHhGYWN0b3J5Q2ZnR3d4UmV3YXJkRGFwcAAKABZJZHhGYWN0b3J5Q2ZnQmlyZHNEYXBwAAsBDWtleUZhY3RvcnlDZmcAAhElc19fZmFjdG9yeUNvbmZpZwEma2V5RmFjdG9yeUxwQXNzZXRUb1Bvb2xDb250cmFjdEFkZHJlc3MBCmxwQXNzZXRTdHIJALkJAgkAzAgCAgYlcyVzJXMJAMwIAgUKbHBBc3NldFN0cgkAzAgCAh5tYXBwaW5nc19fbHBBc3NldDJQb29sQ29udHJhY3QFA25pbAUDU0VQARRrZXlGYWN0b3J5UG9vbFdlaWdodAEPY29udHJhY3RBZGRyZXNzCQC5CQIJAMwIAgIEJXMlcwkAzAgCAgpwb29sV2VpZ2h0CQDMCAIFD2NvbnRyYWN0QWRkcmVzcwUDbmlsBQNTRVABG2tleUZhY3RvcnlQb29sV2VpZ2h0SGlzdG9yeQILcG9vbEFkZHJlc3MDbnVtCQCsAgIJAKwCAgkArAICAhIlcyVzX19wb29sV2VpZ2h0X18FC3Bvb2xBZGRyZXNzAgJfXwkApAMBBQNudW0BGHJlYWRGYWN0b3J5QWRkcmVzc09yRmFpbAAJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAQ9nZXRTdHJpbmdPckZhaWwCBQR0aGlzCQERa2V5RmFjdG9yeUFkZHJlc3MAARRyZWFkRmFjdG9yeUNmZ09yRmFpbAEHZmFjdG9yeQkAtQkCCQEPZ2V0U3RyaW5nT3JGYWlsAgUHZmFjdG9yeQkBDWtleUZhY3RvcnlDZmcABQNTRVABGGdldEJvb3N0aW5nQWRkcmVzc09yRmFpbAEKZmFjdG9yeUNmZwkBEUBleHRyTmF0aXZlKDEwNjIpAQkAkQMCBQpmYWN0b3J5Q2ZnBRlJZHhGYWN0b3J5Q2ZnQm9vc3RpbmdEYXBwARhnZXRFbWlzc2lvbkFkZHJlc3NPckZhaWwBCmZhY3RvcnlDZmcJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAJEDAgUKZmFjdG9yeUNmZwUZSWR4RmFjdG9yeUNmZ0VtaXNzaW9uRGFwcAEXZ2V0U3Rha2luZ0FkZHJlc3NPckZhaWwBCmZhY3RvcnlDZmcJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAJEDAgUKZmFjdG9yeUNmZwUYSWR4RmFjdG9yeUNmZ1N0YWtpbmdEYXBwARlnZXRHd3hSZXdhcmRBZGRyZXNzT3JGYWlsAQpmYWN0b3J5Q2ZnCQERQGV4dHJOYXRpdmUoMTA2MikBCQCRAwIFCmZhY3RvcnlDZmcFGklkeEZhY3RvcnlDZmdHd3hSZXdhcmREYXBwARNrZXlNYW5hZ2VyUHVibGljS2V5AAIUJXNfX21hbmFnZXJQdWJsaWNLZXkBFmtleU1hbmFnZXJWYXVsdEFkZHJlc3MAAhclc19fbWFuYWdlclZhdWx0QWRkcmVzcwEea2V5RW1pc3Npb25SYXRlUGVyQmxvY2tDdXJyZW50AAIbJXMlc19fcmF0ZVBlckJsb2NrX19jdXJyZW50ASFrZXlFbWlzc2lvblJhdGVQZXJCbG9ja01heEN1cnJlbnQAAh4lcyVzX19yYXRlUGVyQmxvY2tNYXhfX2N1cnJlbnQBFWtleUVtaXNzaW9uU3RhcnRCbG9jawACGiVzJXNfX2VtaXNzaW9uX19zdGFydEJsb2NrAR1rZXlCb29zdGluZ1YyTGFzdFVwZGF0ZUhlaWdodAACHCVzJXNfX2Jvb3N0aW5nVjJfX3N0YXJ0QmxvY2sBFWtleUJvb3N0aW5nVjJJbnRlZ3JhbAACGiVzJXNfX2Jvb3N0aW5nVjJfX2ludGVncmFsARtrZXlFbWlzc2lvbkR1cmF0aW9uSW5CbG9ja3MAAhglcyVzX19lbWlzc2lvbl9fZHVyYXRpb24BE2tleUVtaXNzaW9uRW5kQmxvY2sAAhglcyVzX19lbWlzc2lvbl9fZW5kQmxvY2sADUlkeENmZ0Fzc2V0SWQAAQATSWR4Q2ZnTWluTG9ja0Ftb3VudAACABVJZHhDZmdNaW5Mb2NrRHVyYXRpb24AAwAVSWR4Q2ZnTWF4TG9ja0R1cmF0aW9uAAQAEklkeENmZ01hdGhDb250cmFjdAAFABRJZHhDZmdCbG9ja3NJblBlcmlvZAAGABRJZHhDZmdMb2NrU3RlcEJsb2NrcwAHAQlrZXlDb25maWcAAgolc19fY29uZmlnARVyZWFkQ29uZmlnQXJyYXlPckZhaWwACQC1CQIJAQ9nZXRTdHJpbmdPckZhaWwCBQR0aGlzCQEJa2V5Q29uZmlnAAUDU0VQAAhjZmdBcnJheQkBFXJlYWRDb25maWdBcnJheU9yRmFpbAAAB2Fzc2V0SWQJANkEAQkAkQMCBQhjZmdBcnJheQUNSWR4Q2ZnQXNzZXRJZAANbWluTG9ja0Ftb3VudAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEJAJEDAgUIY2ZnQXJyYXkFE0lkeENmZ01pbkxvY2tBbW91bnQJAQd3cmFwRXJyAQIXaW52YWxpZCBtaW4gbG9jayBhbW91bnQAD21pbkxvY2tEdXJhdGlvbgkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEJAJEDAgUIY2ZnQXJyYXkFFUlkeENmZ01pbkxvY2tEdXJhdGlvbgkBB3dyYXBFcnIBAhlpbnZhbGlkIG1pbiBsb2NrIGR1cmF0aW9uAA9tYXhMb2NrRHVyYXRpb24JARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAtgkBCQCRAwIFCGNmZ0FycmF5BRVJZHhDZmdNYXhMb2NrRHVyYXRpb24JAQd3cmFwRXJyAQIZaW52YWxpZCBtYXggbG9jayBkdXJhdGlvbgAMbWF0aENvbnRyYWN0CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkAkQMCBQhjZmdBcnJheQUSSWR4Q2ZnTWF0aENvbnRyYWN0CQEHd3JhcEVycgECHWludmFsaWQgbWF0aCBjb250cmFjdCBhZGRyZXNzAA5ibG9ja3NJblBlcmlvZAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEJAJEDAgUIY2ZnQXJyYXkFFElkeENmZ0Jsb2Nrc0luUGVyaW9kCQEHd3JhcEVycgECGGludmFsaWQgYmxvY2tzIGluIHBlcmlvZAAObG9ja1N0ZXBCbG9ja3MJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAtgkBCQCRAwIFCGNmZ0FycmF5BRRJZHhDZmdMb2NrU3RlcEJsb2NrcwkBB3dyYXBFcnIBAhhpbnZhbGlkIGxvY2sgc3RlcCBibG9ja3MADWtleVN1c3BlbnNpb24CDiVzX19zdXNwZW5zaW9uAAtpc1N1c3BlbmRlZAkBC3ZhbHVlT3JFbHNlAgkAmwgCBQR0aGlzBQ1rZXlTdXNwZW5zaW9uBwEQdGhyb3dJZlN1c3BlbmRlZAADCQEBIQEFC2lzU3VzcGVuZGVkBgkBCHRocm93RXJyAQIJc3VzcGVuZGVkARxnZXRNYW5hZ2VyVmF1bHRBZGRyZXNzT3JUaGlzAAQHJG1hdGNoMAkAoggBCQEWa2V5TWFuYWdlclZhdWx0QWRkcmVzcwADCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFzBQckbWF0Y2gwCQERQGV4dHJOYXRpdmUoMTA2MikBBQFzBQR0aGlzARZtYW5hZ2VyUHVibGljS2V5T3JVbml0AAQTbWFuYWdlclZhdWx0QWRkcmVzcwkBHGdldE1hbmFnZXJWYXVsdEFkZHJlc3NPclRoaXMABAckbWF0Y2gwCQCdCAIFE21hbmFnZXJWYXVsdEFkZHJlc3MJARNrZXlNYW5hZ2VyUHVibGljS2V5AAMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAXMFByRtYXRjaDAJANkEAQUBcwMJAAECBQckbWF0Y2gwAgRVbml0BQR1bml0CQACAQILTWF0Y2ggZXJyb3IBC211c3RNYW5hZ2VyAQFpBAJwZAkBCHRocm93RXJyAQIRUGVybWlzc2lvbiBkZW5pZWQEByRtYXRjaDAJARZtYW5hZ2VyUHVibGljS2V5T3JVbml0AAMJAAECBQckbWF0Y2gwAgpCeXRlVmVjdG9yBAJwawUHJG1hdGNoMAMJAAACCAUBaQ9jYWxsZXJQdWJsaWNLZXkFAnBrBgUCcGQDCQABAgUHJG1hdGNoMAIEVW5pdAMJAAACCAUBaQZjYWxsZXIFBHRoaXMGBQJwZAkAAgECC01hdGNoIGVycm9yAA1JZHhMb2NrQW1vdW50AAEADElkeExvY2tTdGFydAACAA9JZHhMb2NrRHVyYXRpb24AAwAaSWR4TG9ja0xhc3RVcGRhdGVUaW1lc3RhbXAABAAQSWR4TG9ja0d3eEFtb3VudAAFABBJZHhMb2NrV3hDbGFpbWVkAAYBE2tleUxvY2tQYXJhbXNSZWNvcmQCC3VzZXJBZGRyZXNzBHR4SWQJALkJAgkAzAgCAgwlcyVzJXNfX2xvY2sJAMwIAgkApQgBBQt1c2VyQWRkcmVzcwkAzAgCBAckbWF0Y2gwBQR0eElkAwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEAWIFByRtYXRjaDAJANgEAQUBYgMJAAECBQckbWF0Y2gwAgRVbml0AgZsZWdhY3kJAAIBAgtNYXRjaCBlcnJvcgUDbmlsBQNTRVABGnJlYWRMb2NrUGFyYW1zUmVjb3JkT3JGYWlsAgt1c2VyQWRkcmVzcwR0eElkCQC1CQIJAQ9nZXRTdHJpbmdPckZhaWwCBQR0aGlzCQETa2V5TG9ja1BhcmFtc1JlY29yZAIFC3VzZXJBZGRyZXNzBQR0eElkBQNTRVABFWtleVVzZXJHd3hBbW91bnRUb3RhbAELdXNlckFkZHJlc3MJALkJAgkAzAgCAhQlcyVzX19nd3hBbW91bnRUb3RhbAkAzAgCCQClCAEFC3VzZXJBZGRyZXNzBQNuaWwFA1NFUAEWZm9ybWF0TG9ja1BhcmFtc1JlY29yZAUGYW1vdW50BXN0YXJ0CGR1cmF0aW9uCWd3eEFtb3VudAl3eENsYWltZWQJALkJAgkAzAgCAgwlZCVkJWQlZCVkJWQJAMwIAgkApAMBBQZhbW91bnQJAMwIAgkApAMBBQVzdGFydAkAzAgCCQCkAwEFCGR1cmF0aW9uCQDMCAIJAKQDAQgFCWxhc3RCbG9jawl0aW1lc3RhbXAJAMwIAgkApAMBBQlnd3hBbW91bnQJAMwIAgkApAMBBQl3eENsYWltZWQFA25pbAUDU0VQAQ5rZXlOZXh0VXNlck51bQACDyVzX19uZXh0VXNlck51bQESa2V5VXNlcjJOdW1NYXBwaW5nAQt1c2VyQWRkcmVzcwkAuQkCCQDMCAICGSVzJXMlc19fbWFwcGluZ19fdXNlcjJudW0JAMwIAgULdXNlckFkZHJlc3MFA25pbAUDU0VQARJrZXlOdW0yVXNlck1hcHBpbmcBA251bQkAuQkCCQDMCAICGSVzJXMlc19fbWFwcGluZ19fbnVtMnVzZXIJAMwIAgUDbnVtBQNuaWwFA1NFUAEXa2V5TG9ja1BhcmFtVG90YWxBbW91bnQAAh4lcyVzX19zdGF0c19fYWN0aXZlVG90YWxMb2NrZWQBIGtleVN0YXRzTG9ja3NEdXJhdGlvblN1bUluQmxvY2tzAAIlJXMlc19fc3RhdHNfX2xvY2tzRHVyYXRpb25TdW1JbkJsb2NrcwESa2V5U3RhdHNMb2Nrc0NvdW50AAIXJXMlc19fc3RhdHNfX2xvY2tzQ291bnQBEmtleVN0YXRzVXNlcnNDb3VudAACHSVzJXNfX3N0YXRzX19hY3RpdmVVc2Vyc0NvdW50ASBrZXlVc2VyQm9vc3RFbWlzc2lvbkxhc3RJTlRFR1JBTAEHdXNlck51bQkAuQkCCQDMCAICICVzJWRfX3VzZXJCb29zdEVtaXNzaW9uTGFzdEludFYyCQDMCAIJAKQDAQUHdXNlck51bQUDbmlsBQNTRVABImtleVVzZXJMcEJvb3N0RW1pc3Npb25MYXN0SU5URUdSQUwCB3VzZXJOdW0JbHBBc3NldElkCQC5CQIJAMwIAgIgJXMlZF9fdXNlckJvb3N0RW1pc3Npb25MYXN0SW50VjIJAMwIAgkApAMBBQd1c2VyTnVtCQDMCAIFCWxwQXNzZXRJZAUDbmlsBQNTRVABF2tleVVzZXJNYXhCb29zdElOVEVHUkFMAQd1c2VyTnVtCQC5CQIJAMwIAgIRJXMlZF9fbWF4Qm9vc3RJbnQJAMwIAgkApAMBBQd1c2VyTnVtBQNuaWwFA1NFUAEYa2V5VG90YWxNYXhCb29zdElOVEVHUkFMAAIYJXMlc19fbWF4Qm9vc3RJbnRfX3RvdGFsASFrZXlVc2VyQm9vc3RBdmFsYWlibGVUb0NsYWltVG90YWwBB3VzZXJOdW0JALkJAgkAzAgCAiQlcyVkX191c2VyQm9vc3RBdmFsaWFibGVUb0NsYWltVG90YWwJAMwIAgkApAMBBQd1c2VyTnVtBQNuaWwFA1NFUAETa2V5VXNlckJvb3N0Q2xhaW1lZAEHdXNlck51bQkAuQkCCQDMCAICFiVzJWRfX3VzZXJCb29zdENsYWltZWQJAMwIAgkApAMBBQd1c2VyTnVtBQNuaWwFA1NFUAELa2V5R3d4VG90YWwAAhAlcyVzX19nd3hfX3RvdGFsAQdrZXlWb3RlBA1hbW91bnRBc3NldElkDHByaWNlQXNzZXRJZAdhZGRyZXNzBWVwb2NoCQC5CQIJAMwIAgIKJXMlcyVzJXMlZAkAzAgCAgR2b3RlCQDMCAIFDWFtb3VudEFzc2V0SWQJAMwIAgUMcHJpY2VBc3NldElkCQDMCAIJAKUIAQUHYWRkcmVzcwkAzAgCCQCkAwEFBWVwb2NoBQNuaWwFA1NFUAEVa2V5U3RhcnRIZWlnaHRCeUVwb2NoAQVlcG9jaAkAuQkCCQDMCAICBCVzJWQJAMwIAgILc3RhcnRIZWlnaHQJAMwIAgkApAMBBQVlcG9jaAUDbmlsBQNTRVABEWtleUN1cnJlbnRFcG9jaFVpAAkAuQkCCQDMCAICAiVzCQDMCAICDmN1cnJlbnRFcG9jaFVpBQNuaWwFA1NFUAEVa2V5Vm90aW5nUmVzdWx0U3Rha2VkAgxscEFzc2V0SWRTdHIFZXBvY2gJALkJAgkAzAgCAgYlcyVzJWQJAMwIAgISdm90aW5nUmVzdWx0U3Rha2VkCQDMCAIFDGxwQXNzZXRJZFN0cgkAzAgCCQCkAwEFBWVwb2NoBQNuaWwFA1NFUAEda2V5Vm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWwCDGxwQXNzZXRJZFN0cgVlcG9jaAkAuQkCCQDMCAICBiVzJXMlZAkAzAgCAhp2b3RpbmdSZXN1bHRTdGFrZWRJbnRlZ3JhbAkAzAgCBQxscEFzc2V0SWRTdHIJAMwIAgkApAMBBQVlcG9jaAUDbmlsBQNTRVABJWtleVZvdGluZ1Jlc3VsdFN0YWtlZExhc3RVcGRhdGVIZWlnaHQCDGxwQXNzZXRJZFN0cgVlcG9jaAkAuQkCCQDMCAICBiVzJXMlZAkAzAgCAip2b3RpbmdSZXN1bHRTdGFrZWRJbnRlZ3JhbExhc3RVcGRhdGVIZWlnaHQJAMwIAgUMbHBBc3NldElkU3RyCQDMCAIJAKQDAQUFZXBvY2gFA25pbAUDU0VQASFrZXlWb3RpbmdSZXN1bHRTdGFrZWRJbnRlZ3JhbExhc3QDDGxwQXNzZXRJZFN0cgdhZGRyZXNzBWVwb2NoCQC5CQIJAMwIAgIIJXMlcyVzJWQJAMwIAgIedm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWxMYXN0CQDMCAIFDGxwQXNzZXRJZFN0cgkAzAgCCQClCAEFB2FkZHJlc3MJAMwIAgkApAMBBQVlcG9jaAUDbmlsBQNTRVABFWtleVZvdGVTdGFrZWRJbnRlZ3JhbAMMbHBBc3NldElkU3RyB2FkZHJlc3MFZXBvY2gJALkJAgkAzAgCAgglcyVzJXMlZAkAzAgCAhJ2b3RlU3Rha2VkSW50ZWdyYWwJAMwIAgUMbHBBc3NldElkU3RyCQDMCAIJAKUIAQUHYWRkcmVzcwkAzAgCCQCkAwEFBWVwb2NoBQNuaWwFA1NFUAEda2V5Vm90ZVN0YWtlZExhc3RVcGRhdGVIZWlnaHQDDGxwQXNzZXRJZFN0cgdhZGRyZXNzBWVwb2NoCQC5CQIJAMwIAgIIJXMlcyVzJWQJAMwIAgIidm90ZVN0YWtlZEludGVncmFsTGFzdFVwZGF0ZUhlaWdodAkAzAgCBQxscEFzc2V0SWRTdHIJAMwIAgkApQgBBQdhZGRyZXNzCQDMCAIJAKQDAQUFZXBvY2gFA25pbAUDU0VQARlrZXlWb3RlU3Rha2VkSW50ZWdyYWxMYXN0AwxscEFzc2V0SWRTdHIHYWRkcmVzcwVlcG9jaAkAuQkCCQDMCAICCCVzJXMlcyVkCQDMCAICFnZvdGVTdGFrZWRJbnRlZ3JhbExhc3QJAMwIAgUMbHBBc3NldElkU3RyCQDMCAIJAKUIAQUHYWRkcmVzcwkAzAgCCQCkAwEFBWVwb2NoBQNuaWwFA1NFUAEPa2V5U3Rha2VkQnlVc2VyAg51c2VyQWRkcmVzc1N0cgxscEFzc2V0SWRTdHIJALkJAgkAzAgCAgYlcyVzJXMJAMwIAgIGc3Rha2VkCQDMCAIFDnVzZXJBZGRyZXNzU3RyCQDMCAIFDGxwQXNzZXRJZFN0cgUDbmlsBQNTRVAAD2ZhY3RvcnlDb250cmFjdAkBGHJlYWRGYWN0b3J5QWRkcmVzc09yRmFpbAAACmZhY3RvcnlDZmcJARRyZWFkRmFjdG9yeUNmZ09yRmFpbAEFD2ZhY3RvcnlDb250cmFjdAAQZW1pc3Npb25Db250cmFjdAkBGGdldEVtaXNzaW9uQWRkcmVzc09yRmFpbAEFCmZhY3RvcnlDZmcAD3N0YWtpbmdDb250cmFjdAkBF2dldFN0YWtpbmdBZGRyZXNzT3JGYWlsAQUKZmFjdG9yeUNmZwARZ3d4UmV3YXJkQ29udHJhY3QJARlnZXRHd3hSZXdhcmRBZGRyZXNzT3JGYWlsAQUKZmFjdG9yeUNmZwAWbHBTdGFraW5nUG9vbHNDb250cmFjdAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQC5CQIJAMwIAgICJXMJAMwIAgIWbHBTdGFraW5nUG9vbHNDb250cmFjdAUDbmlsBQNTRVAJAQd3cmFwRXJyAQIubHBfc3Rha2luZ19wb29scyBjb250cmFjdCBhZGRyZXNzIGlzIHVuZGVmaW5lZAkBB3dyYXBFcnIBAilpbnZhbGlkIGxwX3N0YWtpbmdfcG9vbHMgY29udHJhY3QgYWRkcmVzcwAZa2V5Vm90aW5nRW1pc3Npb25Db250cmFjdAkAuQkCCQDMCAICAiVzCQDMCAICFnZvdGluZ0VtaXNzaW9uQ29udHJhY3QFA25pbAUDU0VQABZ2b3RpbmdFbWlzc2lvbkNvbnRyYWN0CQERQGV4dHJOYXRpdmUoMTA2MikBCQERQGV4dHJOYXRpdmUoMTA1MykCBQ9mYWN0b3J5Q29udHJhY3QFGWtleVZvdGluZ0VtaXNzaW9uQ29udHJhY3QAHWtleVZvdGluZ0VtaXNzaW9uUmF0ZUNvbnRyYWN0CQC5CQIJAMwIAgICJXMJAMwIAgIadm90aW5nRW1pc3Npb25SYXRlQ29udHJhY3QFA25pbAUDU0VQAApib29zdENvZWZmCgABQAkA/AcEBRBlbWlzc2lvbkNvbnRyYWN0AhVnZXRCb29zdENvZWZmUkVBRE9OTFkFA25pbAUDbmlsAwkAAQIFAUACA0ludAUBQAkAAgEJAKwCAgkAAwEFAUACGCBjb3VsZG4ndCBiZSBjYXN0IHRvIEludAEZdXNlck51bWJlckJ5QWRkcmVzc09yRmFpbAELdXNlckFkZHJlc3MEByRtYXRjaDAJAJ0IAgUEdGhpcwkBEmtleVVzZXIyTnVtTWFwcGluZwEJAKUIAQULdXNlckFkZHJlc3MDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFzBQckbWF0Y2gwCQETdmFsdWVPckVycm9yTWVzc2FnZQIJALYJAQUBcwkBB3dyYXBFcnIBAhNpbnZhbGlkIHVzZXIgbnVtYmVyAwkAAQIFByRtYXRjaDACBFVuaXQJAQh0aHJvd0VycgECDGludmFsaWQgdXNlcgkAAgECC01hdGNoIGVycm9yARFnZXRHd3hBbW91bnRUb3RhbAAJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBC2tleUd3eFRvdGFsAAAAARJnZXRMb2NrZWRHd3hBbW91bnQBC3VzZXJBZGRyZXNzBAxmdW5jdGlvbk5hbWUCEmdldExvY2tlZEd3eEFtb3VudAQadm90aW5nRW1pc3Npb25SYXRlQ29udHJhY3QJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgQHJG1hdGNoMAkAnQgCBRZ2b3RpbmdFbWlzc2lvbkNvbnRyYWN0BR1rZXlWb3RpbmdFbWlzc2lvblJhdGVDb250cmFjdAMJAAECBQckbWF0Y2gwAgRVbml0BQR1bml0AwkAAQIFByRtYXRjaDACBlN0cmluZwQBcwUHJG1hdGNoMAkApggBBQFzCQACAQILTWF0Y2ggZXJyb3IJAQd3cmFwRXJyAQIkaW52YWxpZCB2b3RpbmcgZW1pc3Npb24gcmF0ZSBhZGRyZXNzBBhsb2NrZWRWb3RpbmdFbWlzc2lvblJhdGUKAAFACQD8BwQFFnZvdGluZ0VtaXNzaW9uQ29udHJhY3QFDGZ1bmN0aW9uTmFtZQkAzAgCCQClCAEFC3VzZXJBZGRyZXNzBQNuaWwFA25pbAMJAAECBQFAAgNJbnQFAUAJAAIBCQCsAgIJAAMBBQFAAhggY291bGRuJ3QgYmUgY2FzdCB0byBJbnQEFGxvY2tlZFZvdGluZ0VtaXNzaW9uCgABQAkA/AcEBRp2b3RpbmdFbWlzc2lvblJhdGVDb250cmFjdAUMZnVuY3Rpb25OYW1lCQDMCAIJAKUIAQULdXNlckFkZHJlc3MFA25pbAUDbmlsAwkAAQIFAUACA0ludAUBQAkAAgEJAKwCAgkAAwEFAUACGCBjb3VsZG4ndCBiZSBjYXN0IHRvIEludAQGbG9ja2VkCQCWAwEJAMwIAgUYbG9ja2VkVm90aW5nRW1pc3Npb25SYXRlCQDMCAIFFGxvY2tlZFZvdGluZ0VtaXNzaW9uBQNuaWwFBmxvY2tlZAEMSGlzdG9yeUVudHJ5BwR0eXBlBHVzZXIGYW1vdW50CWxvY2tTdGFydAhkdXJhdGlvbglnd3hBbW91bnQBaQQKaGlzdG9yeUtFWQkAuQkCCQDMCAICESVzJXMlcyVzX19oaXN0b3J5CQDMCAIFBHR5cGUJAMwIAgUEdXNlcgkAzAgCCQDYBAEIBQFpDXRyYW5zYWN0aW9uSWQFA25pbAUDU0VQBAtoaXN0b3J5REFUQQkAuQkCCQDMCAICDiVkJWQlZCVkJWQlZCVkCQDMCAIJAKQDAQgFCWxhc3RCbG9jawZoZWlnaHQJAMwIAgkApAMBCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAkAzAgCCQCkAwEFBmFtb3VudAkAzAgCCQCkAwEFCWxvY2tTdGFydAkAzAgCCQCkAwEFCGR1cmF0aW9uCQDMCAIJAKQDAQUJZ3d4QW1vdW50BQNuaWwFA1NFUAkBC1N0cmluZ0VudHJ5AgUKaGlzdG9yeUtFWQULaGlzdG9yeURBVEEBClN0YXRzRW50cnkEDnRvdGFsTG9ja2VkSW5jC2R1cmF0aW9uSW5jDGxvY2tDb3VudEluYw11c2Vyc0NvdW50SW5jBBtsb2Nrc0R1cmF0aW9uU3VtSW5CbG9ja3NLRVkJASBrZXlTdGF0c0xvY2tzRHVyYXRpb25TdW1JbkJsb2NrcwAEDWxvY2tzQ291bnRLRVkJARJrZXlTdGF0c0xvY2tzQ291bnQABA11c2Vyc0NvdW50S0VZCQESa2V5U3RhdHNVc2Vyc0NvdW50AAQOdG90YWxBbW91bnRLRVkJARdrZXlMb2NrUGFyYW1Ub3RhbEFtb3VudAAEGGxvY2tzRHVyYXRpb25TdW1JbkJsb2NrcwkBDGdldEludE9yWmVybwIFBHRoaXMFG2xvY2tzRHVyYXRpb25TdW1JbkJsb2Nrc0tFWQQKbG9ja3NDb3VudAkBDGdldEludE9yWmVybwIFBHRoaXMFDWxvY2tzQ291bnRLRVkECnVzZXJzQ291bnQJAQxnZXRJbnRPclplcm8CBQR0aGlzBQ11c2Vyc0NvdW50S0VZBAt0b3RhbEFtb3VudAkBDGdldEludE9yWmVybwIFBHRoaXMFDnRvdGFsQW1vdW50S0VZCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRtsb2Nrc0R1cmF0aW9uU3VtSW5CbG9ja3NLRVkJAGQCBRhsb2Nrc0R1cmF0aW9uU3VtSW5CbG9ja3MFC2R1cmF0aW9uSW5jCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ1sb2Nrc0NvdW50S0VZCQBkAgUKbG9ja3NDb3VudAUMbG9ja0NvdW50SW5jCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ11c2Vyc0NvdW50S0VZCQBkAgUKdXNlcnNDb3VudAUNdXNlcnNDb3VudEluYwkAzAgCCQEMSW50ZWdlckVudHJ5AgUOdG90YWxBbW91bnRLRVkJAGQCBQt0b3RhbEFtb3VudAUOdG90YWxMb2NrZWRJbmMFA25pbAEPTG9ja1BhcmFtc0VudHJ5Bwt1c2VyQWRkcmVzcwR0eElkBmFtb3VudAVzdGFydAhkdXJhdGlvbglnd3hBbW91bnQJd3hDbGFpbWVkCQDMCAIJAQtTdHJpbmdFbnRyeQIJARNrZXlMb2NrUGFyYW1zUmVjb3JkAgULdXNlckFkZHJlc3MFBHR4SWQJARZmb3JtYXRMb2NrUGFyYW1zUmVjb3JkBQUGYW1vdW50BQVzdGFydAUIZHVyYXRpb24FCWd3eEFtb3VudAUJd3hDbGFpbWVkBQNuaWwBImV4dHJhY3RPcHRpb25hbFBheW1lbnRBbW91bnRPckZhaWwCAWkPZXhwZWN0ZWRBc3NldElkAwkAZgIJAJADAQgFAWkIcGF5bWVudHMAAQkBCHRocm93RXJyAQIbb25seSBvbmUgcGF5bWVudCBpcyBhbGxvd2VkAwkAAAIJAJADAQgFAWkIcGF5bWVudHMAAAAABANwbXQJAJEDAggFAWkIcGF5bWVudHMAAAMJAQIhPQIJAQV2YWx1ZQEIBQNwbXQHYXNzZXRJZAUPZXhwZWN0ZWRBc3NldElkCQEIdGhyb3dFcnIBAhtpbnZhbGlkIGFzc2V0IGlkIGluIHBheW1lbnQIBQNwbXQGYW1vdW50ARVnZXRVc2VyR3d4QW1vdW50VG90YWwBC3VzZXJBZGRyZXNzCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJARVrZXlVc2VyR3d4QW1vdW50VG90YWwBBQt1c2VyQWRkcmVzcwAAARpnZXRWb3RpbmdFbWlzc2lvbkVwb2NoSW5mbwAEDSR0MDE0Njg2MTQ5NzYEDmN1cnJlbnRFcG9jaFVpCQEFdmFsdWUBCQCaCAIFFnZvdGluZ0VtaXNzaW9uQ29udHJhY3QJARFrZXlDdXJyZW50RXBvY2hVaQAEEmxhc3RGaW5hbGl6ZWRFcG9jaAkAZQIFDmN1cnJlbnRFcG9jaFVpAAEDCQBmAgAABRJsYXN0RmluYWxpemVkRXBvY2gJAQh0aHJvd0VycgECDWludmFsaWQgZXBvY2gJAJQKAgUOY3VycmVudEVwb2NoVWkFEmxhc3RGaW5hbGl6ZWRFcG9jaAQOY3VycmVudEVwb2NoVWkIBQ0kdDAxNDY4NjE0OTc2Al8xBBJsYXN0RmluYWxpemVkRXBvY2gIBQ0kdDAxNDY4NjE0OTc2Al8yBBdjdXJyZW50RXBvY2hTdGFydEhlaWdodAkBBXZhbHVlAQkAmggCBRZ2b3RpbmdFbWlzc2lvbkNvbnRyYWN0CQEVa2V5U3RhcnRIZWlnaHRCeUVwb2NoAQUOY3VycmVudEVwb2NoVWkJAJQKAgUSbGFzdEZpbmFsaXplZEVwb2NoBRdjdXJyZW50RXBvY2hTdGFydEhlaWdodAEYZ2V0UG9vbEFzc2V0c0J5THBBc3NldElkAQxscEFzc2V0SWRTdHIEEGlkeEFtb3VudEFzc2V0SWQABAQPaWR4UHJpY2VBc3NldElkAAUEB3Bvb2xDZmcKAAFACQD8BwQFD2ZhY3RvcnlDb250cmFjdAIgZ2V0UG9vbENvbmZpZ0J5THBBc3NldElkUkVBRE9OTFkJAMwIAgUMbHBBc3NldElkU3RyBQNuaWwFA25pbAMJAAECBQFAAglMaXN0W0FueV0FAUAJAAIBCQCsAgIJAAMBBQFAAh4gY291bGRuJ3QgYmUgY2FzdCB0byBMaXN0W0FueV0EDWFtb3VudEFzc2V0SWQKAAFACQCRAwIFB3Bvb2xDZmcFEGlkeEFtb3VudEFzc2V0SWQDCQABAgUBQAIGU3RyaW5nBQFACQACAQkArAICCQADAQUBQAIbIGNvdWxkbid0IGJlIGNhc3QgdG8gU3RyaW5nBAxwcmljZUFzc2V0SWQKAAFACQCRAwIFB3Bvb2xDZmcFD2lkeFByaWNlQXNzZXRJZAMJAAECBQFAAgZTdHJpbmcFAUAJAAIBCQCsAgIJAAMBBQFAAhsgY291bGRuJ3QgYmUgY2FzdCB0byBTdHJpbmcJAJQKAgUNYW1vdW50QXNzZXRJZAUMcHJpY2VBc3NldElkARRnZXRVc2VyVm90ZUZpbmFsaXplZAIMbHBBc3NldElkU3RyDnVzZXJBZGRyZXNzU3RyBAt1c2VyQWRkcmVzcwkBEUBleHRyTmF0aXZlKDEwNjIpAQUOdXNlckFkZHJlc3NTdHIEDSR0MDE1NjY3MTU3NDcJARpnZXRWb3RpbmdFbWlzc2lvbkVwb2NoSW5mbwAEEmxhc3RGaW5hbGl6ZWRFcG9jaAgFDSR0MDE1NjY3MTU3NDcCXzEEF2N1cnJlbnRFcG9jaFN0YXJ0SGVpZ2h0CAUNJHQwMTU2NjcxNTc0NwJfMgQNJHQwMTU3NTAxNTgyNQkBGGdldFBvb2xBc3NldHNCeUxwQXNzZXRJZAEFDGxwQXNzZXRJZFN0cgQNYW1vdW50QXNzZXRJZAgFDSR0MDE1NzUwMTU4MjUCXzEEDHByaWNlQXNzZXRJZAgFDSR0MDE1NzUwMTU4MjUCXzIEC3VzZXJWb3RlS2V5CQEHa2V5Vm90ZQQFDWFtb3VudEFzc2V0SWQFDHByaWNlQXNzZXRJZAULdXNlckFkZHJlc3MFEmxhc3RGaW5hbGl6ZWRFcG9jaAQIdXNlclZvdGUJAQt2YWx1ZU9yRWxzZQIJAJoIAgUWdm90aW5nRW1pc3Npb25Db250cmFjdAULdXNlclZvdGVLZXkAAAUIdXNlclZvdGUBEWdldFVzZXJWb3RlU3Rha2VkAgxscEFzc2V0SWRTdHIOdXNlckFkZHJlc3NTdHIEDHN0YWtlZEJ5VXNlcgkBC3ZhbHVlT3JFbHNlAgkAmggCBQ9zdGFraW5nQ29udHJhY3QJAQ9rZXlTdGFrZWRCeVVzZXICBQ51c2VyQWRkcmVzc1N0cgUMbHBBc3NldElkU3RyAAAECHVzZXJWb3RlCQEUZ2V0VXNlclZvdGVGaW5hbGl6ZWQCBQxscEFzc2V0SWRTdHIFDnVzZXJBZGRyZXNzU3RyAwkAAAIFDHN0YWtlZEJ5VXNlcgAAAAAFCHVzZXJWb3RlARVnZXRWb3RpbmdSZXN1bHRTdGFrZWQBDGxwQXNzZXRJZFN0cgQNJHQwMTYzNjkxNjQ0OQkBGmdldFZvdGluZ0VtaXNzaW9uRXBvY2hJbmZvAAQSbGFzdEZpbmFsaXplZEVwb2NoCAUNJHQwMTYzNjkxNjQ0OQJfMQQXY3VycmVudEVwb2NoU3RhcnRIZWlnaHQIBQ0kdDAxNjM2OTE2NDQ5Al8yBBd2b3RpbmdSZXN1bHRTdGFrZWRTdGFydAkBC3ZhbHVlT3JFbHNlAgkAmggCBRZ2b3RpbmdFbWlzc2lvbkNvbnRyYWN0CQEVa2V5Vm90aW5nUmVzdWx0U3Rha2VkAgUMbHBBc3NldElkU3RyBRJsYXN0RmluYWxpemVkRXBvY2gAAAQSdm90aW5nUmVzdWx0U3Rha2VkCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJARVrZXlWb3RpbmdSZXN1bHRTdGFrZWQCBQxscEFzc2V0SWRTdHIFEmxhc3RGaW5hbGl6ZWRFcG9jaAUXdm90aW5nUmVzdWx0U3Rha2VkU3RhcnQFEnZvdGluZ1Jlc3VsdFN0YWtlZAEdZ2V0Vm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWwBDGxwQXNzZXRJZFN0cgQNJHQwMTY4MTExNjg5MQkBGmdldFZvdGluZ0VtaXNzaW9uRXBvY2hJbmZvAAQSbGFzdEZpbmFsaXplZEVwb2NoCAUNJHQwMTY4MTExNjg5MQJfMQQXY3VycmVudEVwb2NoU3RhcnRIZWlnaHQIBQ0kdDAxNjgxMTE2ODkxAl8yBBJ2b3RpbmdSZXN1bHRTdGFrZWQJARVnZXRWb3RpbmdSZXN1bHRTdGFrZWQBBQxscEFzc2V0SWRTdHIEHnZvdGluZ1Jlc3VsdFN0YWtlZEludGVncmFsUHJldgkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEda2V5Vm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWwCBQxscEFzc2V0SWRTdHIFEmxhc3RGaW5hbGl6ZWRFcG9jaAAABCJ2b3RpbmdSZXN1bHRTdGFrZWRMYXN0VXBkYXRlSGVpZ2h0CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJASVrZXlWb3RpbmdSZXN1bHRTdGFrZWRMYXN0VXBkYXRlSGVpZ2h0AgUMbHBBc3NldElkU3RyBRJsYXN0RmluYWxpemVkRXBvY2gFF2N1cnJlbnRFcG9jaFN0YXJ0SGVpZ2h0BBx2b3RpbmdSZXN1bHRTdGFrZWRJbnRlZ3JhbERoCQBlAgUGaGVpZ2h0BSJ2b3RpbmdSZXN1bHRTdGFrZWRMYXN0VXBkYXRlSGVpZ2h0BBp2b3RpbmdSZXN1bHRTdGFrZWRJbnRlZ3JhbAkAZAIJAGgCBRx2b3RpbmdSZXN1bHRTdGFrZWRJbnRlZ3JhbERoBRJ2b3RpbmdSZXN1bHRTdGFrZWQFHnZvdGluZ1Jlc3VsdFN0YWtlZEludGVncmFsUHJldgUadm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWwBIXJlZnJlc2hWb3RpbmdSZXN1bHRTdGFrZWRJbnRlZ3JhbAIMbHBBc3NldElkU3RyD3N0YWtlZFZvdGVEZWx0YQQNJHQwMTc3MjgxNzgwOAkBGmdldFZvdGluZ0VtaXNzaW9uRXBvY2hJbmZvAAQSbGFzdEZpbmFsaXplZEVwb2NoCAUNJHQwMTc3MjgxNzgwOAJfMQQXY3VycmVudEVwb2NoU3RhcnRIZWlnaHQIBQ0kdDAxNzcyODE3ODA4Al8yBBJ2b3RpbmdSZXN1bHRTdGFrZWQJARVnZXRWb3RpbmdSZXN1bHRTdGFrZWQBBQxscEFzc2V0SWRTdHIEFXZvdGluZ1Jlc3VsdFN0YWtlZE5ldwkAZAIFEnZvdGluZ1Jlc3VsdFN0YWtlZAUPc3Rha2VkVm90ZURlbHRhBBp2b3RpbmdSZXN1bHRTdGFrZWRJbnRlZ3JhbAkBHWdldFZvdGluZ1Jlc3VsdFN0YWtlZEludGVncmFsAQUMbHBBc3NldElkU3RyCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEVa2V5Vm90aW5nUmVzdWx0U3Rha2VkAgUMbHBBc3NldElkU3RyBRJsYXN0RmluYWxpemVkRXBvY2gFFXZvdGluZ1Jlc3VsdFN0YWtlZE5ldwkAzAgCCQEMSW50ZWdlckVudHJ5AgkBJWtleVZvdGluZ1Jlc3VsdFN0YWtlZExhc3RVcGRhdGVIZWlnaHQCBQxscEFzc2V0SWRTdHIFEmxhc3RGaW5hbGl6ZWRFcG9jaAUGaGVpZ2h0CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEda2V5Vm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWwCBQxscEFzc2V0SWRTdHIFEmxhc3RGaW5hbGl6ZWRFcG9jaAUadm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWwFA25pbAEZZ2V0VXNlclZvdGVTdGFrZWRJbnRlZ3JhbAIMbHBBc3NldElkU3RyDnVzZXJBZGRyZXNzU3RyBA0kdDAxODQxOTE4NDk5CQEaZ2V0Vm90aW5nRW1pc3Npb25FcG9jaEluZm8ABBJsYXN0RmluYWxpemVkRXBvY2gIBQ0kdDAxODQxOTE4NDk5Al8xBBdjdXJyZW50RXBvY2hTdGFydEhlaWdodAgFDSR0MDE4NDE5MTg0OTkCXzIEC3VzZXJBZGRyZXNzCQERQGV4dHJOYXRpdmUoMTA2MikBBQ51c2VyQWRkcmVzc1N0cgQOdXNlclZvdGVTdGFrZWQJARFnZXRVc2VyVm90ZVN0YWtlZAIFDGxwQXNzZXRJZFN0cgUOdXNlckFkZHJlc3NTdHIEGnVzZXJWb3RlU3Rha2VkSW50ZWdyYWxQcmV2CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJARVrZXlWb3RlU3Rha2VkSW50ZWdyYWwDBQxscEFzc2V0SWRTdHIFC3VzZXJBZGRyZXNzBRJsYXN0RmluYWxpemVkRXBvY2gAAAQedXNlclZvdGVTdGFrZWRMYXN0VXBkYXRlSGVpZ2h0CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAR1rZXlWb3RlU3Rha2VkTGFzdFVwZGF0ZUhlaWdodAMFDGxwQXNzZXRJZFN0cgULdXNlckFkZHJlc3MFEmxhc3RGaW5hbGl6ZWRFcG9jaAUXY3VycmVudEVwb2NoU3RhcnRIZWlnaHQEGHVzZXJWb3RlU3Rha2VkSW50ZWdyYWxEaAkAZQIFBmhlaWdodAUedXNlclZvdGVTdGFrZWRMYXN0VXBkYXRlSGVpZ2h0BBZ1c2VyVm90ZVN0YWtlZEludGVncmFsCQBkAgkAaAIFGHVzZXJWb3RlU3Rha2VkSW50ZWdyYWxEaAUOdXNlclZvdGVTdGFrZWQFGnVzZXJWb3RlU3Rha2VkSW50ZWdyYWxQcmV2BRZ1c2VyVm90ZVN0YWtlZEludGVncmFsARlyZWZyZXNoVm90ZVN0YWtlZEludGVncmFsAwxscEFzc2V0SWRTdHIOdXNlckFkZHJlc3NTdHIEZWRnZQQNJHQwMTkyODcxOTM2NwkBGmdldFZvdGluZ0VtaXNzaW9uRXBvY2hJbmZvAAQSbGFzdEZpbmFsaXplZEVwb2NoCAUNJHQwMTkyODcxOTM2NwJfMQQXY3VycmVudEVwb2NoU3RhcnRIZWlnaHQIBQ0kdDAxOTI4NzE5MzY3Al8yBAt1c2VyQWRkcmVzcwkBEUBleHRyTmF0aXZlKDEwNjIpAQUOdXNlckFkZHJlc3NTdHIEEXVzZXJWb3RlRmluYWxpemVkCQEUZ2V0VXNlclZvdGVGaW5hbGl6ZWQCBQxscEFzc2V0SWRTdHIFDnVzZXJBZGRyZXNzU3RyBAdhY3Rpb25zAwkAAAIFEXVzZXJWb3RlRmluYWxpemVkAAAFA25pbAQPc3Rha2VkVm90ZURlbHRhAwUEZWRnZQURdXNlclZvdGVGaW5hbGl6ZWQJAQEtAQURdXNlclZvdGVGaW5hbGl6ZWQEE3ZvdGluZ1Jlc3VsdEFjdGlvbnMJASFyZWZyZXNoVm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWwCBQxscEFzc2V0SWRTdHIFD3N0YWtlZFZvdGVEZWx0YQQWdXNlclZvdGVTdGFrZWRJbnRlZ3JhbAkBGWdldFVzZXJWb3RlU3Rha2VkSW50ZWdyYWwCBQxscEFzc2V0SWRTdHIFDnVzZXJBZGRyZXNzU3RyBAt2b3RlQWN0aW9ucwkAzAgCCQEMSW50ZWdlckVudHJ5AgkBHWtleVZvdGVTdGFrZWRMYXN0VXBkYXRlSGVpZ2h0AwUMbHBBc3NldElkU3RyBQt1c2VyQWRkcmVzcwUSbGFzdEZpbmFsaXplZEVwb2NoBQZoZWlnaHQJAMwIAgkBDEludGVnZXJFbnRyeQIJARVrZXlWb3RlU3Rha2VkSW50ZWdyYWwDBQxscEFzc2V0SWRTdHIFC3VzZXJBZGRyZXNzBRJsYXN0RmluYWxpemVkRXBvY2gFFnVzZXJWb3RlU3Rha2VkSW50ZWdyYWwFA25pbAkAzggCBRN2b3RpbmdSZXN1bHRBY3Rpb25zBQt2b3RlQWN0aW9ucwUHYWN0aW9ucwEbZ2V0U3Rha2VkVm90ZXNJbnRlZ3JhbHNEaWZmAgxscEFzc2V0SWRTdHIOdXNlckFkZHJlc3NTdHIEDSR0MDIwMjIxMjAzMDEJARpnZXRWb3RpbmdFbWlzc2lvbkVwb2NoSW5mbwAEEmxhc3RGaW5hbGl6ZWRFcG9jaAgFDSR0MDIwMjIxMjAzMDECXzEEF2N1cnJlbnRFcG9jaFN0YXJ0SGVpZ2h0CAUNJHQwMjAyMjEyMDMwMQJfMgQLdXNlckFkZHJlc3MJARFAZXh0ck5hdGl2ZSgxMDYyKQEFDnVzZXJBZGRyZXNzU3RyBB11c2VyVm90ZVN0YWtlZEludGVncmFsTGFzdEtleQkBGWtleVZvdGVTdGFrZWRJbnRlZ3JhbExhc3QDBQxscEFzc2V0SWRTdHIFC3VzZXJBZGRyZXNzBRJsYXN0RmluYWxpemVkRXBvY2gEGnVzZXJWb3RlU3Rha2VkSW50ZWdyYWxMYXN0CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFHXVzZXJWb3RlU3Rha2VkSW50ZWdyYWxMYXN0S2V5AAAEIXZvdGluZ1Jlc3VsdFN0YWtlZEludGVncmFsTGFzdEtleQkBIWtleVZvdGluZ1Jlc3VsdFN0YWtlZEludGVncmFsTGFzdAMFDGxwQXNzZXRJZFN0cgULdXNlckFkZHJlc3MFEmxhc3RGaW5hbGl6ZWRFcG9jaAQedm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWxMYXN0CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFIXZvdGluZ1Jlc3VsdFN0YWtlZEludGVncmFsTGFzdEtleQAABBZ1c2VyVm90ZVN0YWtlZEludGVncmFsCQEZZ2V0VXNlclZvdGVTdGFrZWRJbnRlZ3JhbAIFDGxwQXNzZXRJZFN0cgUOdXNlckFkZHJlc3NTdHIEGnZvdGluZ1Jlc3VsdFN0YWtlZEludGVncmFsCQEdZ2V0Vm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWwBBQxscEFzc2V0SWRTdHIEGnVzZXJWb3RlU3Rha2VkSW50ZWdyYWxEaWZmCQBlAgUWdXNlclZvdGVTdGFrZWRJbnRlZ3JhbAUadXNlclZvdGVTdGFrZWRJbnRlZ3JhbExhc3QEHnZvdGluZ1Jlc3VsdFN0YWtlZEludGVncmFsRGlmZgkAZQIFGnZvdGluZ1Jlc3VsdFN0YWtlZEludGVncmFsBR52b3RpbmdSZXN1bHRTdGFrZWRJbnRlZ3JhbExhc3QJAJUKAwkAzAgCCQEMSW50ZWdlckVudHJ5AgUddXNlclZvdGVTdGFrZWRJbnRlZ3JhbExhc3RLZXkFFnVzZXJWb3RlU3Rha2VkSW50ZWdyYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFIXZvdGluZ1Jlc3VsdFN0YWtlZEludGVncmFsTGFzdEtleQUadm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWwFA25pbAUadXNlclZvdGVTdGFrZWRJbnRlZ3JhbERpZmYFHnZvdGluZ1Jlc3VsdFN0YWtlZEludGVncmFsRGlmZgEccmVmcmVzaEJvb3N0RW1pc3Npb25JbnRlZ3JhbAAEEnd4RW1pc3Npb25QZXJCbG9jawkBDGdldEludE9yRmFpbAIFEGVtaXNzaW9uQ29udHJhY3QJAR5rZXlFbWlzc2lvblJhdGVQZXJCbG9ja0N1cnJlbnQABCBib29zdGluZ1YyTGFzdFVwZGF0ZUhlaWdodE9wdGlvbgkAmggCBQR0aGlzCQEda2V5Qm9vc3RpbmdWMkxhc3RVcGRhdGVIZWlnaHQABBhib29zdGluZ1YySW5nZXJnYWxPcHRpb24JAJoIAgUEdGhpcwkBFWtleUJvb3N0aW5nVjJJbnRlZ3JhbAAEC2VtaXNzaW9uRW5kCQEMZ2V0SW50T3JGYWlsAgUQZW1pc3Npb25Db250cmFjdAkBE2tleUVtaXNzaW9uRW5kQmxvY2sABAFoAwkAZgIFBmhlaWdodAULZW1pc3Npb25FbmQFC2VtaXNzaW9uRW5kBQZoZWlnaHQEAmRoBAckbWF0Y2gwBSBib29zdGluZ1YyTGFzdFVwZGF0ZUhlaWdodE9wdGlvbgMJAAECBQckbWF0Y2gwAgNJbnQEEGxhc3RVcGRhdGVIZWlnaHQFByRtYXRjaDAJAJYDAQkAzAgCCQBlAgUBaAUQbGFzdFVwZGF0ZUhlaWdodAkAzAgCAAAFA25pbAMJAAECBQckbWF0Y2gwAgRVbml0AAAJAAIBAgtNYXRjaCBlcnJvcgQVYm9vc3RFbWlzc2lvblBlckJsb2NrCQBpAgkAaAIFEnd4RW1pc3Npb25QZXJCbG9jawkAZQIFCmJvb3N0Q29lZmYAAQUKYm9vc3RDb2VmZgQZYm9vc3RFbWlzc2lvbkludGVncmFsUHJldgkBC3ZhbHVlT3JFbHNlAgUYYm9vc3RpbmdWMkluZ2VyZ2FsT3B0aW9uAAAEFWJvb3N0RW1pc3Npb25JbnRlZ3JhbAkAZAIJAGgCBRVib29zdEVtaXNzaW9uUGVyQmxvY2sFAmRoBRlib29zdEVtaXNzaW9uSW50ZWdyYWxQcmV2CQCUCgIJAMwIAgkBDEludGVnZXJFbnRyeQIJARVrZXlCb29zdGluZ1YySW50ZWdyYWwABRVib29zdEVtaXNzaW9uSW50ZWdyYWwJAMwIAgkBDEludGVnZXJFbnRyeQIJAR1rZXlCb29zdGluZ1YyTGFzdFVwZGF0ZUhlaWdodAAFBmhlaWdodAUDbmlsBRVib29zdEVtaXNzaW9uSW50ZWdyYWwBFGludGVybmFsQ2xhaW1XeEJvb3N0AwxscEFzc2V0SWRTdHIOdXNlckFkZHJlc3NTdHIIcmVhZE9ubHkEC3VzZXJBZGRyZXNzCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQUOdXNlckFkZHJlc3NTdHIJAQd3cmFwRXJyAQIUaW52YWxpZCB1c2VyIGFkZHJlc3MEB3VzZXJOdW0JARl1c2VyTnVtYmVyQnlBZGRyZXNzT3JGYWlsAQULdXNlckFkZHJlc3MDCQAAAgUHdXNlck51bQUHdXNlck51bQQIRU1QVFlTVFICBWVtcHR5BApwb29sV2VpZ2h0AwkBAiE9AgUMbHBBc3NldElkU3RyBQhFTVBUWVNUUgQOcG9vbEFkZHJlc3NTdHIJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBQ9mYWN0b3J5Q29udHJhY3QJASZrZXlGYWN0b3J5THBBc3NldFRvUG9vbENvbnRyYWN0QWRkcmVzcwEFDGxwQXNzZXRJZFN0cgkBB3dyYXBFcnIBCQCsAgICFXVuc3VwcG9ydGVkIGxwIGFzc2V0IAUMbHBBc3NldElkU3RyCQERQGV4dHJOYXRpdmUoMTA1MCkCBQ9mYWN0b3J5Q29udHJhY3QJARRrZXlGYWN0b3J5UG9vbFdlaWdodAEFDnBvb2xBZGRyZXNzU3RyAwUIcmVhZE9ubHkAAAkBCHRocm93RXJyAQkArAICAihub3QgcmVhZG9ubHkgbW9kZTogdW5zdXBwb3J0ZWQgbHAgYXNzZXQgBQxscEFzc2V0SWRTdHIEInVzZXJMcEJvb3N0RW1pc3Npb25MYXN0SW50ZWdyYWxLRVkJASJrZXlVc2VyTHBCb29zdEVtaXNzaW9uTGFzdElOVEVHUkFMAgUHdXNlck51bQUMbHBBc3NldElkU3RyBCB1c2VyQm9vc3RFbWlzc2lvbkxhc3RJbnRlZ3JhbEtFWQkBIGtleVVzZXJCb29zdEVtaXNzaW9uTGFzdElOVEVHUkFMAQUHdXNlck51bQQddXNlckJvb3N0RW1pc3Npb25MYXN0SW50ZWdyYWwJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwUidXNlckxwQm9vc3RFbWlzc2lvbkxhc3RJbnRlZ3JhbEtFWQkBDGdldEludE9yWmVybwIFBHRoaXMFIHVzZXJCb29zdEVtaXNzaW9uTGFzdEludGVncmFsS0VZBBVib29zdEVtaXNzaW9uSW50ZWdyYWwICQEccmVmcmVzaEJvb3N0RW1pc3Npb25JbnRlZ3JhbAACXzIEGXVzZXJCb29zdEVtaXNzaW9uSW50ZWdyYWwJAGUCBRVib29zdEVtaXNzaW9uSW50ZWdyYWwFHXVzZXJCb29zdEVtaXNzaW9uTGFzdEludGVncmFsAwkAZgIAAAUZdXNlckJvb3N0RW1pc3Npb25JbnRlZ3JhbAkBCHRocm93RXJyAQISd3JvbmcgY2FsY3VsYXRpb25zBA0kdDAyMzg0MzIzOTgyCQEbZ2V0U3Rha2VkVm90ZXNJbnRlZ3JhbHNEaWZmAgUMbHBBc3NldElkU3RyBQ51c2VyQWRkcmVzc1N0cgQbc3Rha2VkVm90ZXNJbnRlZ3JhbHNBY3Rpb25zCAUNJHQwMjM4NDMyMzk4MgJfMQQUdXNlclZvdGVJbnRlZ3JhbERpZmYIBQ0kdDAyMzg0MzIzOTgyAl8yBBZ0b3RhbFZvdGVzSW50ZWdyYWxEaWZmCAUNJHQwMjM4NDMyMzk4MgJfMwQdcG9vbFVzZXJCb29zdEVtaXNzaW9uSW50ZWdyYWwJAGsDBRl1c2VyQm9vc3RFbWlzc2lvbkludGVncmFsBQpwb29sV2VpZ2h0BQ5QT09MV0VJR0hUTVVMVAQhdXNlckJvb3N0QXZhbGlhYmxlVG9DbGFpbVRvdGFsTmV3AwkAAAIFFnRvdGFsVm90ZXNJbnRlZ3JhbERpZmYAAAAACQBrAwUdcG9vbFVzZXJCb29zdEVtaXNzaW9uSW50ZWdyYWwFFHVzZXJWb3RlSW50ZWdyYWxEaWZmBRZ0b3RhbFZvdGVzSW50ZWdyYWxEaWZmBAlkYXRhU3RhdGUJAM4IAgkAzAgCCQEMSW50ZWdlckVudHJ5AgUidXNlckxwQm9vc3RFbWlzc2lvbkxhc3RJbnRlZ3JhbEtFWQUVYm9vc3RFbWlzc2lvbkludGVncmFsBQNuaWwFG3N0YWtlZFZvdGVzSW50ZWdyYWxzQWN0aW9ucwQFZGVidWcJALkJAgkAzAgCCQCkAwEFHXVzZXJCb29zdEVtaXNzaW9uTGFzdEludGVncmFsCQDMCAIJAKQDAQUZdXNlckJvb3N0RW1pc3Npb25JbnRlZ3JhbAkAzAgCCQCkAwEFCnBvb2xXZWlnaHQJAMwIAgkApAMBBRR1c2VyVm90ZUludGVncmFsRGlmZgkAzAgCCQCkAwEFFnRvdGFsVm90ZXNJbnRlZ3JhbERpZmYFA25pbAIBOgkAlQoDBSF1c2VyQm9vc3RBdmFsaWFibGVUb0NsYWltVG90YWxOZXcFCWRhdGFTdGF0ZQUFZGVidWcJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BC2xvY2tBY3Rpb25zAgFpCGR1cmF0aW9uBAphc3NldElkU3RyCQDYBAEFB2Fzc2V0SWQDCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAEJAQh0aHJvd0VycgECNGludmFsaWQgcGF5bWVudCAtIGV4YWN0IG9uZSBwYXltZW50IG11c3QgYmUgYXR0YWNoZWQEA3BtdAkAkQMCCAUBaQhwYXltZW50cwAABAlwbXRBbW91bnQIBQNwbXQGYW1vdW50AwkBAiE9AgUHYXNzZXRJZAkBBXZhbHVlAQgFA3BtdAdhc3NldElkCQEIdGhyb3dFcnIBCQCsAgIJAKwCAgIeaW52YWxpZCBhc3NldCBpcyBpbiBwYXltZW50IC0gBQphc3NldElkU3RyAgwgaXMgZXhwZWN0ZWQEDm5leHRVc2VyTnVtS0VZCQEOa2V5TmV4dFVzZXJOdW0ABAt1c2VyQWRkcmVzcwgFAWkGY2FsbGVyBA51c2VyQWRkcmVzc1N0cgkApQgBBQt1c2VyQWRkcmVzcwQOdXNlcklzRXhpc3RpbmcJAQlpc0RlZmluZWQBCQCiCAEJARJrZXlVc2VyMk51bU1hcHBpbmcBBQ51c2VyQWRkcmVzc1N0cgQKdXNlck51bVN0cgMFDnVzZXJJc0V4aXN0aW5nCQEFdmFsdWUBCQCiCAEJARJrZXlVc2VyMk51bU1hcHBpbmcBBQ51c2VyQWRkcmVzc1N0cgkApAMBCQEMZ2V0SW50T3JGYWlsAgUEdGhpcwUObmV4dFVzZXJOdW1LRVkEB3VzZXJOdW0JAQ1wYXJzZUludFZhbHVlAQUKdXNlck51bVN0cgQJbG9ja1N0YXJ0BQZoZWlnaHQDAwkAZgIFDW1pbkxvY2tBbW91bnQFCXBtdEFtb3VudAkBAiE9AgULdXNlckFkZHJlc3MFFmxwU3Rha2luZ1Bvb2xzQ29udHJhY3QHCQEIdGhyb3dFcnIBCQCsAgICImFtb3VudCBpcyBsZXNzIHRoZW4gbWluTG9ja0Ftb3VudD0JAKQDAQUNbWluTG9ja0Ftb3VudAMJAGYCBQ9taW5Mb2NrRHVyYXRpb24FCGR1cmF0aW9uCQEIdGhyb3dFcnIBCQCsAgICLXBhc3NlZCBkdXJhdGlvbiBpcyBsZXNzIHRoYW4gbWluTG9ja0R1cmF0aW9uPQkApAMBBQ9taW5Mb2NrRHVyYXRpb24DCQBmAgUIZHVyYXRpb24FD21heExvY2tEdXJhdGlvbgkBCHRocm93RXJyAQkArAICAjBwYXNzZWQgZHVyYXRpb24gaXMgZ3JlYXRlciB0aGFuIG1heExvY2tEdXJhdGlvbj0JAKQDAQUPbWF4TG9ja0R1cmF0aW9uAwkBAiE9AgkAagIFCGR1cmF0aW9uBQ5sb2NrU3RlcEJsb2NrcwAACQEIdGhyb3dFcnIBCQCsAgICLGR1cmF0aW9uIG11c3QgYmUgbXVsdGlwbGUgb2YgbG9ja1N0ZXBCbG9ja3M9CQCkAwEFDmxvY2tTdGVwQmxvY2tzBA5nV3hBbW91bnRTdGFydAkAawMFCXBtdEFtb3VudAUIZHVyYXRpb24FD21heExvY2tEdXJhdGlvbgQOZ3d4QW1vdW50VG90YWwJARFnZXRHd3hBbW91bnRUb3RhbAAEIHVzZXJCb29zdEVtaXNzaW9uTGFzdEludGVncmFsS0VZCQEga2V5VXNlckJvb3N0RW1pc3Npb25MYXN0SU5URUdSQUwBBQd1c2VyTnVtBBVib29zdEVtaXNzaW9uSW50ZWdyYWwICQEccmVmcmVzaEJvb3N0RW1pc3Npb25JbnRlZ3JhbAACXzIEEnVzZXJHd3hBbW91bnRUb3RhbAkBFWdldFVzZXJHd3hBbW91bnRUb3RhbAEFC3VzZXJBZGRyZXNzBAxnd3hSZXdhcmRJbnYJAPwHBAURZ3d4UmV3YXJkQ29udHJhY3QCEXJlZnJlc2hVc2VyUmV3YXJkCQDMCAIIBQt1c2VyQWRkcmVzcwVieXRlcwkAzAgCBQd1c2VyTnVtBQNuaWwFA25pbAMJAAACBQxnd3hSZXdhcmRJbnYFDGd3eFJld2FyZEludgQDYXJyAwUOdXNlcklzRXhpc3RpbmcFA25pbAkAzAgCCQEMSW50ZWdlckVudHJ5AgUObmV4dFVzZXJOdW1LRVkJAGQCBQd1c2VyTnVtAAEJAMwIAgkBC1N0cmluZ0VudHJ5AgkBEmtleVVzZXIyTnVtTWFwcGluZwEFDnVzZXJBZGRyZXNzU3RyBQp1c2VyTnVtU3RyCQDMCAIJAQtTdHJpbmdFbnRyeQIJARJrZXlOdW0yVXNlck1hcHBpbmcBBQp1c2VyTnVtU3RyBQ51c2VyQWRkcmVzc1N0cgUDbmlsCQCUCgIJAM4IAgkAzQgCCQDOCAIJAM4IAgUDYXJyCQEPTG9ja1BhcmFtc0VudHJ5BwULdXNlckFkZHJlc3MIBQFpDXRyYW5zYWN0aW9uSWQFCXBtdEFtb3VudAUJbG9ja1N0YXJ0BQhkdXJhdGlvbgUOZ1d4QW1vdW50U3RhcnQAAAkBClN0YXRzRW50cnkEBQlwbXRBbW91bnQFCGR1cmF0aW9uAAEDBQ51c2VySXNFeGlzdGluZwAAAAEJAQxIaXN0b3J5RW50cnkHAgRsb2NrBQ51c2VyQWRkcmVzc1N0cgUJcG10QW1vdW50BQlsb2NrU3RhcnQFCGR1cmF0aW9uBQ5nV3hBbW91bnRTdGFydAUBaQkAzAgCCQEMSW50ZWdlckVudHJ5AgUgdXNlckJvb3N0RW1pc3Npb25MYXN0SW50ZWdyYWxLRVkFFWJvb3N0RW1pc3Npb25JbnRlZ3JhbAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBC2tleUd3eFRvdGFsAAkAZAIFDmd3eEFtb3VudFRvdGFsBQ5nV3hBbW91bnRTdGFydAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBFWtleVVzZXJHd3hBbW91bnRUb3RhbAEFC3VzZXJBZGRyZXNzCQBkAgUSdXNlckd3eEFtb3VudFRvdGFsBQ5nV3hBbW91bnRTdGFydAUDbmlsBQ5nV3hBbW91bnRTdGFydAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgERZ2V0V3hXaXRoZHJhd2FibGUCC3VzZXJBZGRyZXNzCnR4SWRPcHRpb24ED3VzZXJSZWNvcmRBcnJheQkBGnJlYWRMb2NrUGFyYW1zUmVjb3JkT3JGYWlsAgULdXNlckFkZHJlc3MFCnR4SWRPcHRpb24ECnVzZXJBbW91bnQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQ91c2VyUmVjb3JkQXJyYXkFDUlkeExvY2tBbW91bnQECWxvY2tTdGFydAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFD3VzZXJSZWNvcmRBcnJheQUMSWR4TG9ja1N0YXJ0BAxsb2NrRHVyYXRpb24JAQ1wYXJzZUludFZhbHVlAQkAkQMCBQ91c2VyUmVjb3JkQXJyYXkFD0lkeExvY2tEdXJhdGlvbgQHbG9ja0VuZAkAZAIFCWxvY2tTdGFydAUMbG9ja0R1cmF0aW9uBAl3eENsYWltZWQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQ91c2VyUmVjb3JkQXJyYXkFEElkeExvY2tXeENsYWltZWQEAXQJAGkCCQBlAgUGaGVpZ2h0BQlsb2NrU3RhcnQFDmJsb2Nrc0luUGVyaW9kBAhleHBvbmVudAkAvAIDCQC2AgEFAXQJALkCAgkAtgIBCQBoAgUOREVDQVlfQ09OU1RBTlQFDmJsb2Nrc0luUGVyaW9kBQhNVUxUMThCSQkAtgIBBQxsb2NrRHVyYXRpb24EE3d4V2l0aGRyYXdhYmxlVG90YWwDCQBmAgUGaGVpZ2h0BQdsb2NrRW5kBQp1c2VyQW1vdW50CQCgAwEJALwCAwkAtgIBBQp1c2VyQW1vdW50CQC4AgIFCE1VTFQxOEJJCQB2BgkAtgIBAAUAAQUIZXhwb25lbnQFB1NDQUxFMTgFB1NDQUxFMTgFBERPV04FCE1VTFQxOEJJBA53eFdpdGhkcmF3YWJsZQkAZQIFE3d4V2l0aGRyYXdhYmxlVG90YWwFCXd4Q2xhaW1lZAUOd3hXaXRoZHJhd2FibGURAWkBB2xvY2tSZWYDCGR1cmF0aW9uD3JlZmVycmVyQWRkcmVzcwlzaWduYXR1cmUED3N1c3BlbnNpb25DaGVjawkBEHRocm93SWZTdXNwZW5kZWQAAwkAAAIFD3N1c3BlbnNpb25DaGVjawUPc3VzcGVuc2lvbkNoZWNrBA0kdDAyODQwMDI4NDY1CQELbG9ja0FjdGlvbnMCBQFpBQhkdXJhdGlvbgQRbG9ja0FjdGlvbnNSZXN1bHQIBQ0kdDAyODQwMDI4NDY1Al8xBA5nV3hBbW91bnRTdGFydAgFDSR0MDI4NDAwMjg0NjUCXzIED3JlZmVycmFsQWRkcmVzcwkApQgBCAUBaQZjYWxsZXIEBnJlZkludgMDCQAAAgUPcmVmZXJyZXJBZGRyZXNzAgAGCQAAAgUJc2lnbmF0dXJlAQAFBHVuaXQJAPwHBAUecmVmZXJyYWxzQ29udHJhY3RBZGRyZXNzT3JGYWlsAgpjcmVhdGVQYWlyCQDMCAIFE3JlZmVycmFsUHJvZ3JhbU5hbWUJAMwIAgUPcmVmZXJyZXJBZGRyZXNzCQDMCAIFD3JlZmVycmFsQWRkcmVzcwkAzAgCBQlzaWduYXR1cmUFA25pbAUDbmlsAwkAAAIFBnJlZkludgUGcmVmSW52BBF1cGRhdGVSZWZBY3Rpdml0eQkA/AcEBQxtYXRoQ29udHJhY3QCFnVwZGF0ZVJlZmVycmFsQWN0aXZpdHkJAMwIAgkApQgBCAUBaQZjYWxsZXIJAMwIAgUOZ1d4QW1vdW50U3RhcnQFA25pbAUDbmlsAwkAAAIFEXVwZGF0ZVJlZkFjdGl2aXR5BRF1cGRhdGVSZWZBY3Rpdml0eQkAlAoCBRFsb2NrQWN0aW9uc1Jlc3VsdAUEdW5pdAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQRsb2NrAQhkdXJhdGlvbgQPc3VzcGVuc2lvbkNoZWNrCQEQdGhyb3dJZlN1c3BlbmRlZAADCQAAAgUPc3VzcGVuc2lvbkNoZWNrBQ9zdXNwZW5zaW9uQ2hlY2sEDSR0MDI4OTY5MjkwMzQJAQtsb2NrQWN0aW9ucwIFAWkFCGR1cmF0aW9uBBFsb2NrQWN0aW9uc1Jlc3VsdAgFDSR0MDI4OTY5MjkwMzQCXzEEDmdXeEFtb3VudFN0YXJ0CAUNJHQwMjg5NjkyOTAzNAJfMgQRdXBkYXRlUmVmQWN0aXZpdHkJAPwHBAUMbWF0aENvbnRyYWN0AhZ1cGRhdGVSZWZlcnJhbEFjdGl2aXR5CQDMCAIJAKUIAQgFAWkGY2FsbGVyCQDMCAIFDmdXeEFtb3VudFN0YXJ0BQNuaWwFA25pbAMJAAACBRF1cGRhdGVSZWZBY3Rpdml0eQURdXBkYXRlUmVmQWN0aXZpdHkJAJQKAgURbG9ja0FjdGlvbnNSZXN1bHQFBHVuaXQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEMY2xhaW1XeEJvb3N0AgxscEFzc2V0SWRTdHIOdXNlckFkZHJlc3NTdHIED3N1c3BlbnNpb25DaGVjawkBEHRocm93SWZTdXNwZW5kZWQAAwkAAAIFD3N1c3BlbnNpb25DaGVjawUPc3VzcGVuc2lvbkNoZWNrAwkBAiE9AgUPc3Rha2luZ0NvbnRyYWN0CAUBaQZjYWxsZXIJAQh0aHJvd0VycgECEnBlcm1pc3Npb25zIGRlbmllZAQNJHQwMjkzOTAyOTQ5MgkBFGludGVybmFsQ2xhaW1XeEJvb3N0AwUMbHBBc3NldElkU3RyBQ51c2VyQWRkcmVzc1N0cgcEEnVzZXJCb29zdEF2YWlsYWJsZQgFDSR0MDI5MzkwMjk0OTICXzEECWRhdGFTdGF0ZQgFDSR0MDI5MzkwMjk0OTICXzIEBWRlYnVnCAUNJHQwMjkzOTAyOTQ5MgJfMwkAlAoCBQlkYXRhU3RhdGUJAMwIAgUSdXNlckJvb3N0QXZhaWxhYmxlBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEUY2xhaW1XeEJvb3N0UkVBRE9OTFkCDGxwQXNzZXRJZFN0cg51c2VyQWRkcmVzc1N0cgQNJHQwMjk2MjQyOTcyNQkBFGludGVybmFsQ2xhaW1XeEJvb3N0AwUMbHBBc3NldElkU3RyBQ51c2VyQWRkcmVzc1N0cgYEEnVzZXJCb29zdEF2YWlsYWJsZQgFDSR0MDI5NjI0Mjk3MjUCXzEECWRhdGFTdGF0ZQgFDSR0MDI5NjI0Mjk3MjUCXzIEBWRlYnVnCAUNJHQwMjk2MjQyOTcyNQJfMwkAlAoCBQNuaWwJAMwIAgUSdXNlckJvb3N0QXZhaWxhYmxlCQDMCAIFBWRlYnVnBQNuaWwBaQEGdW5sb2NrAQd0eElkU3RyBA9zdXNwZW5zaW9uQ2hlY2sJARB0aHJvd0lmU3VzcGVuZGVkAAMJAAACBQ9zdXNwZW5zaW9uQ2hlY2sFD3N1c3BlbnNpb25DaGVjawQLdXNlckFkZHJlc3MIBQFpBmNhbGxlcgQOdXNlckFkZHJlc3NTdHIJAKUIAQULdXNlckFkZHJlc3MECnR4SWRPcHRpb24DCQAAAgUHdHhJZFN0cgIABQR1bml0CQDZBAEFB3R4SWRTdHIED3VzZXJSZWNvcmRBcnJheQkBGnJlYWRMb2NrUGFyYW1zUmVjb3JkT3JGYWlsAgULdXNlckFkZHJlc3MFCnR4SWRPcHRpb24ECnVzZXJBbW91bnQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQ91c2VyUmVjb3JkQXJyYXkFDUlkeExvY2tBbW91bnQECWxvY2tTdGFydAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFD3VzZXJSZWNvcmRBcnJheQUMSWR4TG9ja1N0YXJ0BAxsb2NrRHVyYXRpb24JAQ1wYXJzZUludFZhbHVlAQkAkQMCBQ91c2VyUmVjb3JkQXJyYXkFD0lkeExvY2tEdXJhdGlvbgQJd3hDbGFpbWVkCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUPdXNlclJlY29yZEFycmF5BRBJZHhMb2NrV3hDbGFpbWVkBAlnd3hBbW91bnQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQ91c2VyUmVjb3JkQXJyYXkFEElkeExvY2tHd3hBbW91bnQEAXQJAGkCCQBlAgUGaGVpZ2h0BQlsb2NrU3RhcnQFDmJsb2Nrc0luUGVyaW9kBA53eFdpdGhkcmF3YWJsZQkBEWdldFd4V2l0aGRyYXdhYmxlAgULdXNlckFkZHJlc3MFCnR4SWRPcHRpb24ECWd3eEJ1cm5lZAkAlwMBCQDMCAIJAGsDBQ53eFdpdGhkcmF3YWJsZQUMbG9ja0R1cmF0aW9uBQ9tYXhMb2NrRHVyYXRpb24JAMwIAgUJZ3d4QW1vdW50BQNuaWwEDGd3eFJlbWFpbmluZwkBDmVuc3VyZVBvc2l0aXZlAgkAZQIFCWd3eEFtb3VudAUJZ3d4QnVybmVkAgxnd3hSZW1haW5pbmcED2xvY2tlZEd3eEFtb3VudAkBEmdldExvY2tlZEd3eEFtb3VudAEFC3VzZXJBZGRyZXNzAwkAZwIAAAUOd3hXaXRoZHJhd2FibGUJAQh0aHJvd0VycgECEW5vdGhpbmcgdG8gdW5sb2NrBA5nd3hBbW91bnRUb3RhbAkBEWdldEd3eEFtb3VudFRvdGFsAAQSdXNlckd3eEFtb3VudFRvdGFsCQEVZ2V0VXNlckd3eEFtb3VudFRvdGFsAQULdXNlckFkZHJlc3MEFXVzZXJHd3hBbW91bnRUb3RhbE5ldwkBDmVuc3VyZVBvc2l0aXZlAgkAZQIFEnVzZXJHd3hBbW91bnRUb3RhbAUJZ3d4QnVybmVkAhV1c2VyR3d4QW1vdW50VG90YWxOZXcDCQBmAgUPbG9ja2VkR3d4QW1vdW50BRV1c2VyR3d4QW1vdW50VG90YWxOZXcJAQh0aHJvd0VycgEJAKwCAgITbG9ja2VkIGd3eCBhbW91bnQ6IAkApAMBBQ9sb2NrZWRHd3hBbW91bnQEB3VzZXJOdW0JAQ1wYXJzZUludFZhbHVlAQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCiCAEJARJrZXlVc2VyMk51bU1hcHBpbmcBBQ51c2VyQWRkcmVzc1N0cgkBB3dyYXBFcnIBAhNpbnZhbGlkIHVzZXIgbnVtYmVyBAxnd3hSZXdhcmRJbnYJAPwHBAURZ3d4UmV3YXJkQ29udHJhY3QCEXJlZnJlc2hVc2VyUmV3YXJkCQDMCAIIBQt1c2VyQWRkcmVzcwVieXRlcwkAzAgCBQd1c2VyTnVtBQNuaWwFA25pbAMJAAACBQxnd3hSZXdhcmRJbnYFDGd3eFJld2FyZEludgkAzggCCQDNCAIJAM0IAgkAzggCCQEPTG9ja1BhcmFtc0VudHJ5BwULdXNlckFkZHJlc3MFCnR4SWRPcHRpb24FCnVzZXJBbW91bnQFCWxvY2tTdGFydAUMbG9ja0R1cmF0aW9uBQxnd3hSZW1haW5pbmcJAGQCBQl3eENsYWltZWQFDnd4V2l0aGRyYXdhYmxlCQEKU3RhdHNFbnRyeQQJAQEtAQUOd3hXaXRoZHJhd2FibGUAAAAAAAAJAQxIaXN0b3J5RW50cnkHAgZ1bmxvY2sFDnVzZXJBZGRyZXNzU3RyBQ53eFdpdGhkcmF3YWJsZQUJbG9ja1N0YXJ0BQxsb2NrRHVyYXRpb24FCWd3eEJ1cm5lZAUBaQkBDlNjcmlwdFRyYW5zZmVyAwULdXNlckFkZHJlc3MFDnd4V2l0aGRyYXdhYmxlBQdhc3NldElkCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQELa2V5R3d4VG90YWwACQEOZW5zdXJlUG9zaXRpdmUCCQBlAgUOZ3d4QW1vdW50VG90YWwFCWd3eEJ1cm5lZAIIZ3d4VG90YWwJAMwIAgkBDEludGVnZXJFbnRyeQIJARVrZXlVc2VyR3d4QW1vdW50VG90YWwBBQt1c2VyQWRkcmVzcwUVdXNlckd3eEFtb3VudFRvdGFsTmV3BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQETZ3d4VXNlckluZm9SRUFET05MWQEOdXNlckFkZHJlc3NTdHIEC3VzZXJBZGRyZXNzCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQUOdXNlckFkZHJlc3NTdHIJAQd3cmFwRXJyAQIUaW52YWxpZCB1c2VyIGFkZHJlc3MECWd3eEFtb3VudAkBFWdldFVzZXJHd3hBbW91bnRUb3RhbAEFC3VzZXJBZGRyZXNzCQCUCgIFA25pbAkAzAgCBQlnd3hBbW91bnQFA25pbAFpARd1c2VyTWF4RHVyYXRpb25SRUFET05MWQEOdXNlckFkZHJlc3NTdHIJAJQKAgUDbmlsCQCUCgICBGxvY2sFD21heExvY2tEdXJhdGlvbgFpASBnZXRVc2VyR3d4QW1vdW50QXRIZWlnaHRSRUFET05MWQIOdXNlckFkZHJlc3NTdHIMdGFyZ2V0SGVpZ2h0BAt1c2VyQWRkcmVzcwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEFDnVzZXJBZGRyZXNzU3RyCQEHd3JhcEVycgECFGludmFsaWQgdXNlciBhZGRyZXNzBAlnd3hBbW91bnQJARVnZXRVc2VyR3d4QW1vdW50VG90YWwBBQt1c2VyQWRkcmVzcwkAlAoCBQNuaWwFCWd3eEFtb3VudAFpARBnZXRVc2VyR3d4QW1vdW50AQ51c2VyQWRkcmVzc1N0cgQLdXNlckFkZHJlc3MJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBBQ51c2VyQWRkcmVzc1N0cgkBB3dyYXBFcnIBAhRpbnZhbGlkIHVzZXIgYWRkcmVzcwQJZ3d4QW1vdW50CQEVZ2V0VXNlckd3eEFtb3VudFRvdGFsAQULdXNlckFkZHJlc3MJAJQKAgUDbmlsBQlnd3hBbW91bnQBaQETZ2V0R3d4VG90YWxSRUFET05MWQAJAJQKAgUDbmlsCQERZ2V0R3d4QW1vdW50VG90YWwAAWkBFW9uQm9vc3RFbWlzc2lvblVwZGF0ZQAED3N1c3BlbnNpb25DaGVjawkBEHRocm93SWZTdXNwZW5kZWQAAwkAAAIFD3N1c3BlbnNpb25DaGVjawUPc3VzcGVuc2lvbkNoZWNrBAtjaGVja0NhbGxlcgMJAAACCAUBaQZjYWxsZXIFEGVtaXNzaW9uQ29udHJhY3QGCQELbXVzdE1hbmFnZXIBBQFpAwkAAAIFC2NoZWNrQ2FsbGVyBQtjaGVja0NhbGxlcgkBHHJlZnJlc2hCb29zdEVtaXNzaW9uSW50ZWdyYWwACQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBEm9uU3Rha2VkVm90ZVVwZGF0ZQMMbHBBc3NldElkU3RyDnVzZXJBZGRyZXNzU3RyBGVkZ2UED3N1c3BlbnNpb25DaGVjawkBEHRocm93SWZTdXNwZW5kZWQAAwkAAAIFD3N1c3BlbnNpb25DaGVjawUPc3VzcGVuc2lvbkNoZWNrBAtjaGVja0NhbGxlcgMJAAACCAUBaQZjYWxsZXIFD3N0YWtpbmdDb250cmFjdAYJAQttdXN0TWFuYWdlcgEFAWkDCQAAAgULY2hlY2tDYWxsZXIFC2NoZWNrQ2FsbGVyBAdhY3Rpb25zCQEZcmVmcmVzaFZvdGVTdGFrZWRJbnRlZ3JhbAMFDGxwQXNzZXRJZFN0cgUOdXNlckFkZHJlc3NTdHIFBGVkZ2UJAJQKAgUHYWN0aW9ucwUEdW5pdAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAR1nZXRWb3RpbmdSZXN1bHRTdGFrZWRSRUFET05MWQEMbHBBc3NldElkU3RyCQCUCgIFA25pbAkBFWdldFZvdGluZ1Jlc3VsdFN0YWtlZAEFDGxwQXNzZXRJZFN0cgFpASVnZXRWb3RpbmdSZXN1bHRTdGFrZWRJbnRlZ3JhbFJFQURPTkxZAQxscEFzc2V0SWRTdHIJAJQKAgUDbmlsCQEdZ2V0Vm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWwBBQxscEFzc2V0SWRTdHIBaQEcZ2V0VXNlclZvdGVGaW5hbGl6ZWRSRUFET05MWQIMbHBBc3NldElkU3RyDnVzZXJBZGRyZXNzU3RyCQCUCgIFA25pbAkBFGdldFVzZXJWb3RlRmluYWxpemVkAgUMbHBBc3NldElkU3RyBQ51c2VyQWRkcmVzc1N0cgFpASFnZXRVc2VyVm90ZVN0YWtlZEludGVncmFsUkVBRE9OTFkCDGxwQXNzZXRJZFN0cg51c2VyQWRkcmVzc1N0cgkAlAoCBQNuaWwJARlnZXRVc2VyVm90ZVN0YWtlZEludGVncmFsAgUMbHBBc3NldElkU3RyBQ51c2VyQWRkcmVzc1N0cgFpAQdzdXNwZW5kAQF2BAtjaGVja0NhbGxlcgkBC211c3RNYW5hZ2VyAQUBaQMJAAACBQtjaGVja0NhbGxlcgULY2hlY2tDYWxsZXIJAJQKAgkAzAgCCQEMQm9vbGVhbkVudHJ5AgUNa2V5U3VzcGVuc2lvbgUBdgUDbmlsBQF2CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAQJ0eAEGdmVyaWZ5AAQPdGFyZ2V0UHVibGljS2V5BAckbWF0Y2gwCQEWbWFuYWdlclB1YmxpY0tleU9yVW5pdAADCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQCcGsFByRtYXRjaDAFAnBrAwkAAQIFByRtYXRjaDACBFVuaXQIBQJ0eA9zZW5kZXJQdWJsaWNLZXkJAAIBAgtNYXRjaCBlcnJvcgkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAAUPdGFyZ2V0UHVibGljS2V5Vb8vjQ==", "height": 2744797, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: HAKq5ZPxuNdEToBdxVMkftzGhJnyUaW8BhJUy82p8QWi Next: D4ajEzGWvhoHAR9C2TnuhtZpS99tu1nZV3VNcZK2t2uC Diff:
OldNewDifferences
99
1010 let POOLWEIGHTMULT = MULT8
1111
12-func wrapErr (msg) = makeString(["boosting.ride:", msg], " ")
12+let contractFilename = "boosting.ride"
13+
14+let SCALE18 = 18
15+
16+let MULT18 = 1000000000000000000
17+
18+let MULT18BI = toBigInt(MULT18)
19+
20+let DECAY_CONSTANT = 8
21+
22+func wrapErr (msg) = makeString([contractFilename, ": ", msg], "")
1323
1424
1525 func throwErr (msg) = throw(wrapErr(msg))
1626
1727
18-func strf (address,key) = valueOrErrorMessage(getString(address, key), wrapErr((("mandatory this." + key) + " is not defined")))
28+func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), wrapErr((("mandatory this." + key) + " is not defined")))
1929
2030
21-func ioz (address,key) = valueOrElse(getInteger(address, key), 0)
31+func getIntOrZero (address,key) = valueOrElse(getInteger(address, key), 0)
2232
2333
24-func iod (address,key,defaultVal) = valueOrElse(getInteger(address, key), defaultVal)
34+func getIntOrDefault (address,key,defaultVal) = valueOrElse(getInteger(address, key), defaultVal)
2535
2636
27-func iof (address,key) = valueOrErrorMessage(getInteger(address, key), wrapErr((("mandatory this." + key) + " is not defined")))
37+func getIntOrFail (address,key) = valueOrErrorMessage(getInteger(address, key), wrapErr((("mandatory this." + key) + " is not defined")))
2838
2939
3040 func abs (val) = if ((0 > val))
3242 else val
3343
3444
35-func aal (val) = match val {
36- case valAnyLyst: List[Any] =>
37- valAnyLyst
38- case _ =>
39- throwErr("fail to cast into List[Any]")
40-}
41-
42-
43-func ai (val) = match val {
44- case valInt: Int =>
45- valInt
46- case _ =>
47- throwErr("fail to cast into Int")
48-}
45+func ensurePositive (v,m) = if ((v >= 0))
46+ then v
47+ else throwErr((valueOrElse(m, "value") + " should be positive"))
4948
5049
5150 func keyReferralsContractAddress () = makeString(["%s%s", "config", "referralsContractAddress"], SEP)
5251
5352
54-let referralsContractAddressOrFail = addressFromStringValue(strf(this, keyReferralsContractAddress()))
53+let referralsContractAddressOrFail = addressFromStringValue(getStringOrFail(this, keyReferralsContractAddress()))
5554
5655 let keyReferralProgramName = makeString(["%s%s", "referral", "programName"], SEP)
5756
8786 func keyFactoryCfg () = "%s__factoryConfig"
8887
8988
90-func keyFactoryLpList () = "%s__lpTokensList"
91-
92-
9389 func keyFactoryLpAssetToPoolContractAddress (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP)
9490
9591
9995 func keyFactoryPoolWeightHistory (poolAddress,num) = ((("%s%s__poolWeight__" + poolAddress) + "__") + toString(num))
10096
10197
102-func readFactoryAddressOrFail () = addressFromStringValue(strf(this, keyFactoryAddress()))
98+func readFactoryAddressOrFail () = addressFromStringValue(getStringOrFail(this, keyFactoryAddress()))
10399
104100
105-func readLpList () = split(valueOrElse(getString(readFactoryAddressOrFail(), keyFactoryLpList()), ""), SEP)
106-
107-
108-func readFactoryCfgOrFail (factory) = split(strf(factory, keyFactoryCfg()), SEP)
101+func readFactoryCfgOrFail (factory) = split(getStringOrFail(factory, keyFactoryCfg()), SEP)
109102
110103
111104 func getBoostingAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgBoostingDapp])
147140 func keyEmissionEndBlock () = "%s%s__emission__endBlock"
148141
149142
150-func keyNextPeriod () = "%s__nextPeriod"
151-
152-
153-func keyGwxRewardEmissionStartHeight () = "%s%s__gwxRewardEmissionPart__startHeight"
154-
155-
156143 let IdxCfgAssetId = 1
157144
158145 let IdxCfgMinLockAmount = 2
163150
164151 let IdxCfgMathContract = 5
165152
153+let IdxCfgBlocksInPeriod = 6
154+
155+let IdxCfgLockStepBlocks = 7
156+
166157 func keyConfig () = "%s__config"
167158
168159
169-func readConfigArrayOrFail () = split(strf(this, keyConfig()), SEP)
160+func readConfigArrayOrFail () = split(getStringOrFail(this, keyConfig()), SEP)
170161
171162
172-let mathContract = addressFromStringValue(readConfigArrayOrFail()[IdxCfgMathContract])
163+let cfgArray = readConfigArrayOrFail()
173164
174-func formatConfigS (assetId,minLockAmount,minLockDuration,maxLockDuration,mathContract) = makeString(["%s%d%d%d", assetId, minLockAmount, minLockDuration, maxLockDuration, mathContract], SEP)
165+let assetId = fromBase58String(cfgArray[IdxCfgAssetId])
175166
167+let minLockAmount = valueOrErrorMessage(parseInt(cfgArray[IdxCfgMinLockAmount]), wrapErr("invalid min lock amount"))
176168
177-func formatConfig (assetId,minLockAmount,minLockDuration,maxLockDuration,mathContract) = formatConfigS(assetId, toString(minLockAmount), toString(minLockDuration), toString(maxLockDuration), mathContract)
169+let minLockDuration = valueOrErrorMessage(parseInt(cfgArray[IdxCfgMinLockDuration]), wrapErr("invalid min lock duration"))
170+
171+let maxLockDuration = valueOrErrorMessage(parseInt(cfgArray[IdxCfgMaxLockDuration]), wrapErr("invalid max lock duration"))
172+
173+let mathContract = valueOrErrorMessage(addressFromString(cfgArray[IdxCfgMathContract]), wrapErr("invalid math contract address"))
174+
175+let blocksInPeriod = valueOrErrorMessage(parseInt(cfgArray[IdxCfgBlocksInPeriod]), wrapErr("invalid blocks in period"))
176+
177+let lockStepBlocks = valueOrErrorMessage(parseInt(cfgArray[IdxCfgLockStepBlocks]), wrapErr("invalid lock step blocks"))
178+
179+let keySuspension = "%s__suspension"
180+
181+let isSuspended = valueOrElse(getBoolean(this, keySuspension), false)
182+
183+func throwIfSuspended () = if (!(isSuspended))
184+ then true
185+ else throwErr("suspended")
178186
179187
180188 func getManagerVaultAddressOrThis () = match getString(keyManagerVaultAddress()) {
215223 }
216224
217225
218-let IdxLockUserNum = 1
226+let IdxLockAmount = 1
219227
220-let IdxLockAmount = 2
228+let IdxLockStart = 2
221229
222-let IdxLockStart = 3
230+let IdxLockDuration = 3
223231
224-let IdxLockDuration = 4
232+let IdxLockLastUpdateTimestamp = 4
225233
226-let IdxLockParamK = 5
234+let IdxLockGwxAmount = 5
227235
228-let IdxLockParamB = 6
236+let IdxLockWxClaimed = 6
229237
230-func keyLockParamsRecord (userAddress) = makeString(["%s%s__lock", userAddress], SEP)
238+func keyLockParamsRecord (userAddress,txId) = makeString(["%s%s%s__lock", toString(userAddress), match txId {
239+ case b: ByteVector =>
240+ toBase58String(b)
241+ case _: Unit =>
242+ "legacy"
243+ case _ =>
244+ throw("Match error")
245+}], SEP)
231246
232247
233-func readLockParamsRecordOrFail (userAddress) = split(strf(this, keyLockParamsRecord(userAddress)), SEP)
248+func readLockParamsRecordOrFail (userAddress,txId) = split(getStringOrFail(this, keyLockParamsRecord(userAddress, txId)), SEP)
234249
235250
236-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)
251+func keyUserGwxAmountTotal (userAddress) = makeString(["%s%s__gwxAmountTotal", toString(userAddress)], SEP)
237252
238253
239-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))
254+func formatLockParamsRecord (amount,start,duration,gwxAmount,wxClaimed) = makeString(["%d%d%d%d%d%d", toString(amount), toString(start), toString(duration), toString(lastBlock.timestamp), toString(gwxAmount), toString(wxClaimed)], SEP)
240255
241256
242257 func keyNextUserNum () = "%s__nextUserNum"
246261
247262
248263 func keyNum2UserMapping (num) = makeString(["%s%s%s__mapping__num2user", num], SEP)
249-
250-
251-func keyLockParamUserAmount (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "amount"], SEP)
252-
253-
254-func keyLockParamStartBlock (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "start"], SEP)
255-
256-
257-func keyLockParamDuration (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "duration"], SEP)
258-
259-
260-func keyLockParamK (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "k"], SEP)
261-
262-
263-func keyLockParamB (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "b"], SEP)
264-
265-
266-func keyLockParamByPeriodK (userNum,period) = makeString(["%s%d%s%d__paramByPeriod", userNum, "k", period], SEP)
267-
268-
269-func keyLockParamByPeriodB (userNum,period) = makeString(["%s%d%s%d__paramByPeriod", userNum, "b", period], SEP)
270264
271265
272266 func keyLockParamTotalAmount () = "%s%s__stats__activeTotalLocked"
281275 func keyStatsUsersCount () = "%s%s__stats__activeUsersCount"
282276
283277
284-func keyUserBoostEmissionLastINTEGRAL (userNum) = makeString(["%s%d__userBoostEmissionLastIntV2", userNum], SEP)
278+func keyUserBoostEmissionLastINTEGRAL (userNum) = makeString(["%s%d__userBoostEmissionLastIntV2", toString(userNum)], SEP)
285279
286280
287-func keyUserLpBoostEmissionLastINTEGRAL (userNum,lpAssetId) = makeString(["%s%d__userBoostEmissionLastIntV2", userNum, lpAssetId], SEP)
281+func keyUserLpBoostEmissionLastINTEGRAL (userNum,lpAssetId) = makeString(["%s%d__userBoostEmissionLastIntV2", toString(userNum), lpAssetId], SEP)
288282
289283
290-func keyUserMaxBoostINTEGRAL (userNum) = makeString(["%s%d__maxBoostInt", userNum], SEP)
284+func keyUserMaxBoostINTEGRAL (userNum) = makeString(["%s%d__maxBoostInt", toString(userNum)], SEP)
291285
292286
293287 func keyTotalMaxBoostINTEGRAL () = "%s%s__maxBoostInt__total"
294288
295289
296-func keyUserBoostAvalaibleToClaimTotal (userNum) = makeString(["%s%d__userBoostAvaliableToClaimTotal", userNum], SEP)
290+func keyUserBoostAvalaibleToClaimTotal (userNum) = makeString(["%s%d__userBoostAvaliableToClaimTotal", toString(userNum)], SEP)
297291
298292
299-func keyUserBoostClaimed (userNum) = makeString(["%s%d__userBoostClaimed", userNum], SEP)
293+func keyUserBoostClaimed (userNum) = makeString(["%s%d__userBoostClaimed", toString(userNum)], SEP)
300294
301295
302-func keyTotalCachedGwx () = "%s%s__gwxCached__total"
303-
304-
305-func keyTotalCachedGwxCorrective () = "%s__gwxCachedTotalCorrective"
296+func keyGwxTotal () = "%s%s__gwx__total"
306297
307298
308299 func keyVote (amountAssetId,priceAssetId,address,epoch) = makeString(["%s%s%s%s%d", "vote", amountAssetId, priceAssetId, toString(address), toString(epoch)], SEP)
354345
355346 let votingEmissionContract = addressFromStringValue(getStringValue(factoryContract, keyVotingEmissionContract))
356347
348+let keyVotingEmissionRateContract = makeString(["%s", "votingEmissionRateContract"], SEP)
349+
357350 let boostCoeff = {
358351 let @ = invoke(emissionContract, "getBoostCoeffREADONLY", nil, nil)
359352 if ($isInstanceOf(@, "Int"))
361354 else throw(($getType(@) + " couldn't be cast to Int"))
362355 }
363356
364-func getTotalCachedGwx (correct) = {
365- let currentEpochUi = getIntegerValue(votingEmissionContract, keyCurrentEpochUi())
366- let keyTargetEpoch = makeString(["%s%s", "totalCachedGwxCorrection__activationEpoch"], SEP)
367- let targetEpochOption = getInteger(this, keyTargetEpoch)
368- let totalCachedGwxRaw = valueOrElse(getInteger(this, keyTotalCachedGwx()), 0)
369- let isCorrectionActivated = if (isDefined(targetEpochOption))
370- then (currentEpochUi >= value(targetEpochOption))
371- else false
372- let corrective = if (if (isCorrectionActivated)
373- then correct
374- else false)
375- then valueOrElse(getInteger(this, keyTotalCachedGwxCorrective()), 0)
376- else 0
377- max([0, (totalCachedGwxRaw + corrective)])
357+func userNumberByAddressOrFail (userAddress) = match getString(this, keyUser2NumMapping(toString(userAddress))) {
358+ case s: String =>
359+ valueOrErrorMessage(parseInt(s), wrapErr("invalid user number"))
360+ case _: Unit =>
361+ throwErr("invalid user")
362+ case _ =>
363+ throw("Match error")
364+}
365+
366+
367+func getGwxAmountTotal () = valueOrElse(getInteger(this, keyGwxTotal()), 0)
368+
369+
370+func getLockedGwxAmount (userAddress) = {
371+ let functionName = "getLockedGwxAmount"
372+ let votingEmissionRateContract = valueOrErrorMessage( match getString(votingEmissionContract, keyVotingEmissionRateContract) {
373+ case _: Unit =>
374+ unit
375+ case s: String =>
376+ addressFromString(s)
377+ case _ =>
378+ throw("Match error")
379+ }, wrapErr("invalid voting emission rate address"))
380+ let lockedVotingEmissionRate = {
381+ let @ = invoke(votingEmissionContract, functionName, [toString(userAddress)], nil)
382+ if ($isInstanceOf(@, "Int"))
383+ then @
384+ else throw(($getType(@) + " couldn't be cast to Int"))
385+ }
386+ let lockedVotingEmission = {
387+ let @ = invoke(votingEmissionRateContract, functionName, [toString(userAddress)], nil)
388+ if ($isInstanceOf(@, "Int"))
389+ then @
390+ else throw(($getType(@) + " couldn't be cast to Int"))
391+ }
392+ let locked = max([lockedVotingEmissionRate, lockedVotingEmission])
393+ locked
378394 }
379395
380396
381-func HistoryEntry (type,user,amount,lockStart,duration,k,b,i) = {
397+func HistoryEntry (type,user,amount,lockStart,duration,gwxAmount,i) = {
382398 let historyKEY = makeString(["%s%s%s%s__history", type, user, toBase58String(i.transactionId)], SEP)
383- 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)
399+ let historyDATA = makeString(["%d%d%d%d%d%d%d", toString(lastBlock.height), toString(lastBlock.timestamp), toString(amount), toString(lockStart), toString(duration), toString(gwxAmount)], SEP)
384400 StringEntry(historyKEY, historyDATA)
385401 }
386402
390406 let locksCountKEY = keyStatsLocksCount()
391407 let usersCountKEY = keyStatsUsersCount()
392408 let totalAmountKEY = keyLockParamTotalAmount()
393- let locksDurationSumInBlocks = ioz(this, locksDurationSumInBlocksKEY)
394- let locksCount = ioz(this, locksCountKEY)
395- let usersCount = ioz(this, usersCountKEY)
396- let totalAmount = ioz(this, totalAmountKEY)
409+ let locksDurationSumInBlocks = getIntOrZero(this, locksDurationSumInBlocksKEY)
410+ let locksCount = getIntOrZero(this, locksCountKEY)
411+ let usersCount = getIntOrZero(this, usersCountKEY)
412+ let totalAmount = getIntOrZero(this, totalAmountKEY)
397413 [IntegerEntry(locksDurationSumInBlocksKEY, (locksDurationSumInBlocks + durationInc)), IntegerEntry(locksCountKEY, (locksCount + lockCountInc)), IntegerEntry(usersCountKEY, (usersCount + usersCountInc)), IntegerEntry(totalAmountKEY, (totalAmount + totalLockedInc))]
398414 }
399415
400416
401-func calcGwxAmount (kRaw,bRaw,h) = {
402- let SCALE = 1000
403- (((kRaw * h) + bRaw) / SCALE)
404- }
405-
406-
407-func LockParamsEntry (userAddress,userNum,amount,start,duration,k,b,period) = {
408- let userAmountKEY = keyLockParamUserAmount(userNum)
409- let startBlockKEY = keyLockParamStartBlock(userNum)
410- let durationKEY = keyLockParamDuration(userNum)
411- let kKEY = keyLockParamK(userNum)
412- let bKEY = keyLockParamB(userNum)
413- let kByPeriodKEY = keyLockParamByPeriodK(userNum, period)
414- let bByPeriodKEY = keyLockParamByPeriodB(userNum, period)
415- let gwxAmount = calcGwxAmount(k, b, height)
416-[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))]
417- }
417+func LockParamsEntry (userAddress,txId,amount,start,duration,gwxAmount,wxClaimed) = [StringEntry(keyLockParamsRecord(userAddress, txId), formatLockParamsRecord(amount, start, duration, gwxAmount, wxClaimed))]
418418
419419
420420 func extractOptionalPaymentAmountOrFail (i,expectedAssetId) = if ((size(i.payments) > 1))
429429 }
430430
431431
432-func calcUserGwxAmountAtHeight (userAddress,targetHeight) = {
433- let EMPTY = "empty"
434- let user2NumMappingKEY = keyUser2NumMapping(userAddress)
435- let userNum = valueOrElse(getString(user2NumMappingKEY), EMPTY)
436- let k = valueOrElse(getInteger(keyLockParamK(userNum)), 0)
437- let b = valueOrElse(getInteger(keyLockParamB(userNum)), 0)
438- let gwxAmountCalc = calcGwxAmount(k, b, targetHeight)
439- let gwxAmount = if ((0 > gwxAmountCalc))
440- then 0
441- else gwxAmountCalc
442- gwxAmount
443- }
444-
445-
446-func calcCurrentGwxAmount (userAddress) = calcUserGwxAmountAtHeight(userAddress, height)
432+func getUserGwxAmountTotal (userAddress) = valueOrElse(getInteger(this, keyUserGwxAmountTotal(userAddress)), 0)
447433
448434
449435 func getVotingEmissionEpochInfo () = {
450- let $t01718617476 = {
436+ let $t01468614976 = {
451437 let currentEpochUi = value(getInteger(votingEmissionContract, keyCurrentEpochUi()))
452438 let lastFinalizedEpoch = (currentEpochUi - 1)
453439 if ((0 > lastFinalizedEpoch))
454440 then throwErr("invalid epoch")
455441 else $Tuple2(currentEpochUi, lastFinalizedEpoch)
456442 }
457- let currentEpochUi = $t01718617476._1
458- let lastFinalizedEpoch = $t01718617476._2
443+ let currentEpochUi = $t01468614976._1
444+ let lastFinalizedEpoch = $t01468614976._2
459445 let currentEpochStartHeight = value(getInteger(votingEmissionContract, keyStartHeightByEpoch(currentEpochUi)))
460446 $Tuple2(lastFinalizedEpoch, currentEpochStartHeight)
461447 }
488474
489475 func getUserVoteFinalized (lpAssetIdStr,userAddressStr) = {
490476 let userAddress = addressFromStringValue(userAddressStr)
491- let $t01816718247 = getVotingEmissionEpochInfo()
492- let lastFinalizedEpoch = $t01816718247._1
493- let currentEpochStartHeight = $t01816718247._2
494- let $t01825018325 = getPoolAssetsByLpAssetId(lpAssetIdStr)
495- let amountAssetId = $t01825018325._1
496- let priceAssetId = $t01825018325._2
477+ let $t01566715747 = getVotingEmissionEpochInfo()
478+ let lastFinalizedEpoch = $t01566715747._1
479+ let currentEpochStartHeight = $t01566715747._2
480+ let $t01575015825 = getPoolAssetsByLpAssetId(lpAssetIdStr)
481+ let amountAssetId = $t01575015825._1
482+ let priceAssetId = $t01575015825._2
497483 let userVoteKey = keyVote(amountAssetId, priceAssetId, userAddress, lastFinalizedEpoch)
498484 let userVote = valueOrElse(getInteger(votingEmissionContract, userVoteKey), 0)
499485 userVote
510496
511497
512498 func getVotingResultStaked (lpAssetIdStr) = {
513- let $t01886918949 = getVotingEmissionEpochInfo()
514- let lastFinalizedEpoch = $t01886918949._1
515- let currentEpochStartHeight = $t01886918949._2
499+ let $t01636916449 = getVotingEmissionEpochInfo()
500+ let lastFinalizedEpoch = $t01636916449._1
501+ let currentEpochStartHeight = $t01636916449._2
516502 let votingResultStakedStart = valueOrElse(getInteger(votingEmissionContract, keyVotingResultStaked(lpAssetIdStr, lastFinalizedEpoch)), 0)
517503 let votingResultStaked = valueOrElse(getInteger(this, keyVotingResultStaked(lpAssetIdStr, lastFinalizedEpoch)), votingResultStakedStart)
518504 votingResultStaked
520506
521507
522508 func getVotingResultStakedIntegral (lpAssetIdStr) = {
523- let $t01931119391 = getVotingEmissionEpochInfo()
524- let lastFinalizedEpoch = $t01931119391._1
525- let currentEpochStartHeight = $t01931119391._2
509+ let $t01681116891 = getVotingEmissionEpochInfo()
510+ let lastFinalizedEpoch = $t01681116891._1
511+ let currentEpochStartHeight = $t01681116891._2
526512 let votingResultStaked = getVotingResultStaked(lpAssetIdStr)
527513 let votingResultStakedIntegralPrev = valueOrElse(getInteger(this, keyVotingResultStakedIntegral(lpAssetIdStr, lastFinalizedEpoch)), 0)
528514 let votingResultStakedLastUpdateHeight = valueOrElse(getInteger(this, keyVotingResultStakedLastUpdateHeight(lpAssetIdStr, lastFinalizedEpoch)), currentEpochStartHeight)
533519
534520
535521 func refreshVotingResultStakedIntegral (lpAssetIdStr,stakedVoteDelta) = {
536- let $t02022820308 = getVotingEmissionEpochInfo()
537- let lastFinalizedEpoch = $t02022820308._1
538- let currentEpochStartHeight = $t02022820308._2
522+ let $t01772817808 = getVotingEmissionEpochInfo()
523+ let lastFinalizedEpoch = $t01772817808._1
524+ let currentEpochStartHeight = $t01772817808._2
539525 let votingResultStaked = getVotingResultStaked(lpAssetIdStr)
540526 let votingResultStakedNew = (votingResultStaked + stakedVoteDelta)
541527 let votingResultStakedIntegral = getVotingResultStakedIntegral(lpAssetIdStr)
544530
545531
546532 func getUserVoteStakedIntegral (lpAssetIdStr,userAddressStr) = {
547- let $t02091920999 = getVotingEmissionEpochInfo()
548- let lastFinalizedEpoch = $t02091920999._1
549- let currentEpochStartHeight = $t02091920999._2
533+ let $t01841918499 = getVotingEmissionEpochInfo()
534+ let lastFinalizedEpoch = $t01841918499._1
535+ let currentEpochStartHeight = $t01841918499._2
550536 let userAddress = addressFromStringValue(userAddressStr)
551537 let userVoteStaked = getUserVoteStaked(lpAssetIdStr, userAddressStr)
552538 let userVoteStakedIntegralPrev = valueOrElse(getInteger(this, keyVoteStakedIntegral(lpAssetIdStr, userAddress, lastFinalizedEpoch)), 0)
558544
559545
560546 func refreshVoteStakedIntegral (lpAssetIdStr,userAddressStr,edge) = {
561- let $t02178721867 = getVotingEmissionEpochInfo()
562- let lastFinalizedEpoch = $t02178721867._1
563- let currentEpochStartHeight = $t02178721867._2
547+ let $t01928719367 = getVotingEmissionEpochInfo()
548+ let lastFinalizedEpoch = $t01928719367._1
549+ let currentEpochStartHeight = $t01928719367._2
564550 let userAddress = addressFromStringValue(userAddressStr)
565551 let userVoteFinalized = getUserVoteFinalized(lpAssetIdStr, userAddressStr)
566552 let actions = if ((userVoteFinalized == 0))
579565
580566
581567 func getStakedVotesIntegralsDiff (lpAssetIdStr,userAddressStr) = {
582- let $t02272122801 = getVotingEmissionEpochInfo()
583- let lastFinalizedEpoch = $t02272122801._1
584- let currentEpochStartHeight = $t02272122801._2
568+ let $t02022120301 = getVotingEmissionEpochInfo()
569+ let lastFinalizedEpoch = $t02022120301._1
570+ let currentEpochStartHeight = $t02022120301._2
585571 let userAddress = addressFromStringValue(userAddressStr)
586572 let userVoteStakedIntegralLastKey = keyVoteStakedIntegralLast(lpAssetIdStr, userAddress, lastFinalizedEpoch)
587573 let userVoteStakedIntegralLast = valueOrElse(getInteger(this, userVoteStakedIntegralLastKey), 0)
596582
597583
598584 func refreshBoostEmissionIntegral () = {
599- let wxEmissionPerBlock = iof(emissionContract, keyEmissionRatePerBlockCurrent())
585+ let wxEmissionPerBlock = getIntOrFail(emissionContract, keyEmissionRatePerBlockCurrent())
600586 let boostingV2LastUpdateHeightOption = getInteger(this, keyBoostingV2LastUpdateHeight())
601587 let boostingV2IngergalOption = getInteger(this, keyBoostingV2Integral())
602- let emissionEnd = iof(emissionContract, keyEmissionEndBlock())
588+ let emissionEnd = getIntOrFail(emissionContract, keyEmissionEndBlock())
603589 let h = if ((height > emissionEnd))
604590 then emissionEnd
605591 else height
619605
620606
621607 func internalClaimWxBoost (lpAssetIdStr,userAddressStr,readOnly) = {
622- let userRecordOption = getString(this, keyLockParamsRecord(userAddressStr))
623- if ((userRecordOption == unit))
624- then $Tuple3(0, nil, "userRecord::is::empty")
625- else {
626- let userRecordArray = split(value(userRecordOption), SEP)
627- let userNumStr = userRecordArray[IdxLockUserNum]
608+ let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid user address"))
609+ let userNum = userNumberByAddressOrFail(userAddress)
610+ if ((userNum == userNum))
611+ then {
628612 let EMPTYSTR = "empty"
629613 let poolWeight = if ((lpAssetIdStr != EMPTYSTR))
630614 then {
634618 else if (readOnly)
635619 then 0
636620 else throwErr(("not readonly mode: unsupported lp asset " + lpAssetIdStr))
637- let userLpBoostEmissionLastIntegralKEY = keyUserLpBoostEmissionLastINTEGRAL(userNumStr, lpAssetIdStr)
638- let userBoostEmissionLastIntegralKEY = keyUserBoostEmissionLastINTEGRAL(userNumStr)
639- let userBoostEmissionLastIntegral = valueOrElse(getInteger(this, userLpBoostEmissionLastIntegralKEY), ioz(this, userBoostEmissionLastIntegralKEY))
621+ let userLpBoostEmissionLastIntegralKEY = keyUserLpBoostEmissionLastINTEGRAL(userNum, lpAssetIdStr)
622+ let userBoostEmissionLastIntegralKEY = keyUserBoostEmissionLastINTEGRAL(userNum)
623+ let userBoostEmissionLastIntegral = valueOrElse(getInteger(this, userLpBoostEmissionLastIntegralKEY), getIntOrZero(this, userBoostEmissionLastIntegralKEY))
640624 let boostEmissionIntegral = refreshBoostEmissionIntegral()._2
641625 let userBoostEmissionIntegral = (boostEmissionIntegral - userBoostEmissionLastIntegral)
642626 if ((0 > userBoostEmissionIntegral))
643627 then throwErr("wrong calculations")
644628 else {
645- let $t02642026559 = getStakedVotesIntegralsDiff(lpAssetIdStr, userAddressStr)
646- let stakedVotesIntegralsActions = $t02642026559._1
647- let userVoteIntegralDiff = $t02642026559._2
648- let totalVotesIntegralDiff = $t02642026559._3
629+ let $t02384323982 = getStakedVotesIntegralsDiff(lpAssetIdStr, userAddressStr)
630+ let stakedVotesIntegralsActions = $t02384323982._1
631+ let userVoteIntegralDiff = $t02384323982._2
632+ let totalVotesIntegralDiff = $t02384323982._3
649633 let poolUserBoostEmissionIntegral = fraction(userBoostEmissionIntegral, poolWeight, POOLWEIGHTMULT)
650634 let userBoostAvaliableToClaimTotalNew = if ((totalVotesIntegralDiff == 0))
651635 then 0
655639 $Tuple3(userBoostAvaliableToClaimTotalNew, dataState, debug)
656640 }
657641 }
642+ else throw("Strict value is not equal to itself.")
658643 }
659644
660645
661646 func lockActions (i,duration) = {
662- let cfgArray = readConfigArrayOrFail()
663- let assetIdStr = cfgArray[IdxCfgAssetId]
664- let assetId = fromBase58String(assetIdStr)
665- let minLockAmount = parseIntValue(cfgArray[IdxCfgMinLockAmount])
666- let minLockDuration = parseIntValue(cfgArray[IdxCfgMinLockDuration])
667- let maxLockDuration = parseIntValue(cfgArray[IdxCfgMaxLockDuration])
647+ let assetIdStr = toBase58String(assetId)
668648 if ((size(i.payments) != 1))
669649 then throwErr("invalid payment - exact one payment must be attached")
670650 else {
674654 then throwErr((("invalid asset is in payment - " + assetIdStr) + " is expected"))
675655 else {
676656 let nextUserNumKEY = keyNextUserNum()
677- let userAddressStr = toString(i.caller)
657+ let userAddress = i.caller
658+ let userAddressStr = toString(userAddress)
678659 let userIsExisting = isDefined(getString(keyUser2NumMapping(userAddressStr)))
679660 let userNumStr = if (userIsExisting)
680661 then value(getString(keyUser2NumMapping(userAddressStr)))
681- else toString(iof(this, nextUserNumKEY))
662+ else toString(getIntOrFail(this, nextUserNumKEY))
682663 let userNum = parseIntValue(userNumStr)
683664 let lockStart = height
684- let startBlockKEY = keyLockParamStartBlock(userNumStr)
685- let durationKEY = keyLockParamDuration(userNumStr)
686- let userAmountKEY = keyLockParamUserAmount(userNumStr)
687665 if (if ((minLockAmount > pmtAmount))
688- then (i.caller != lpStakingPoolsContract)
666+ then (userAddress != lpStakingPoolsContract)
689667 else false)
690668 then throwErr(("amount is less then minLockAmount=" + toString(minLockAmount)))
691669 else if ((minLockDuration > duration))
692- then throwErr(("passed duration is less then minLockDuration=" + toString(minLockDuration)))
670+ then throwErr(("passed duration is less than minLockDuration=" + toString(minLockDuration)))
693671 else if ((duration > maxLockDuration))
694- then throwErr(("passed duration is greater then maxLockDuration=" + toString(maxLockDuration)))
695- else if (if (userIsExisting)
696- then ((iof(this, startBlockKEY) + iof(this, durationKEY)) >= lockStart)
697- else false)
698- then throwErr("there is an active lock - consider to use increaseLock")
699- else if ((ioz(this, userAmountKEY) > 0))
700- then throwErr(("there are locked WXs - consider to use increaseLock " + userAmountKEY))
701- else {
702- let coeffX8 = fraction(duration, MULT8, maxLockDuration)
703- let gWxAmountStart = fraction(pmtAmount, coeffX8, MULT8)
704- let gWxParamsResultList = aal(invoke(mathContract, "calcGwxParamsREADONLY", [gWxAmountStart, lockStart, duration], nil))
705- let k = ai(gWxParamsResultList[0])
706- let b = ai(gWxParamsResultList[1])
707- let period = toString(ai(gWxParamsResultList[2]))
708- let totalCachedGwxRaw = getTotalCachedGwx(false)
709- let userBoostEmissionLastIntegralKEY = keyUserBoostEmissionLastINTEGRAL(userNumStr)
710- let boostEmissionIntegral = refreshBoostEmissionIntegral()._2
711- let arr = if (userIsExisting)
712- then nil
713- else [IntegerEntry(nextUserNumKEY, (userNum + 1)), StringEntry(keyUser2NumMapping(userAddressStr), userNumStr), StringEntry(keyNum2UserMapping(userNumStr), userAddressStr)]
714- $Tuple2(((((arr ++ LockParamsEntry(userAddressStr, userNumStr, pmtAmount, lockStart, duration, k, b, period)) ++ StatsEntry(pmtAmount, duration, 1, if (userIsExisting)
715- then 0
716- else 1)) :+ HistoryEntry("lock", userAddressStr, pmtAmount, lockStart, duration, k, b, i)) ++ [IntegerEntry(userBoostEmissionLastIntegralKEY, boostEmissionIntegral), IntegerEntry(keyTotalCachedGwx(), (totalCachedGwxRaw + gWxAmountStart))]), gWxAmountStart)
717- }
672+ then throwErr(("passed duration is greater than maxLockDuration=" + toString(maxLockDuration)))
673+ else if (((duration % lockStepBlocks) != 0))
674+ then throwErr(("duration must be multiple of lockStepBlocks=" + toString(lockStepBlocks)))
675+ else {
676+ let gWxAmountStart = fraction(pmtAmount, duration, maxLockDuration)
677+ let gwxAmountTotal = getGwxAmountTotal()
678+ let userBoostEmissionLastIntegralKEY = keyUserBoostEmissionLastINTEGRAL(userNum)
679+ let boostEmissionIntegral = refreshBoostEmissionIntegral()._2
680+ let userGwxAmountTotal = getUserGwxAmountTotal(userAddress)
681+ let gwxRewardInv = invoke(gwxRewardContract, "refreshUserReward", [userAddress.bytes, userNum], nil)
682+ if ((gwxRewardInv == gwxRewardInv))
683+ then {
684+ let arr = if (userIsExisting)
685+ then nil
686+ else [IntegerEntry(nextUserNumKEY, (userNum + 1)), StringEntry(keyUser2NumMapping(userAddressStr), userNumStr), StringEntry(keyNum2UserMapping(userNumStr), userAddressStr)]
687+ $Tuple2(((((arr ++ LockParamsEntry(userAddress, i.transactionId, pmtAmount, lockStart, duration, gWxAmountStart, 0)) ++ StatsEntry(pmtAmount, duration, 1, if (userIsExisting)
688+ then 0
689+ else 1)) :+ HistoryEntry("lock", userAddressStr, pmtAmount, lockStart, duration, gWxAmountStart, i)) ++ [IntegerEntry(userBoostEmissionLastIntegralKEY, boostEmissionIntegral), IntegerEntry(keyGwxTotal(), (gwxAmountTotal + gWxAmountStart)), IntegerEntry(keyUserGwxAmountTotal(userAddress), (userGwxAmountTotal + gWxAmountStart))]), gWxAmountStart)
690+ }
691+ else throw("Strict value is not equal to itself.")
692+ }
718693 }
719694 }
720695 }
721696
722697
698+func getWxWithdrawable (userAddress,txIdOption) = {
699+ let userRecordArray = readLockParamsRecordOrFail(userAddress, txIdOption)
700+ let userAmount = parseIntValue(userRecordArray[IdxLockAmount])
701+ let lockStart = parseIntValue(userRecordArray[IdxLockStart])
702+ let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
703+ let lockEnd = (lockStart + lockDuration)
704+ let wxClaimed = parseIntValue(userRecordArray[IdxLockWxClaimed])
705+ let t = ((height - lockStart) / blocksInPeriod)
706+ let exponent = fraction(toBigInt(t), (toBigInt((DECAY_CONSTANT * blocksInPeriod)) * MULT18BI), toBigInt(lockDuration))
707+ let wxWithdrawableTotal = if ((height > lockEnd))
708+ then userAmount
709+ else toInt(fraction(toBigInt(userAmount), (MULT18BI - pow(toBigInt(5), 1, exponent, SCALE18, SCALE18, DOWN)), MULT18BI))
710+ let wxWithdrawable = (wxWithdrawableTotal - wxClaimed)
711+ wxWithdrawable
712+ }
713+
714+
723715 @Callable(i)
724-func constructor (factoryAddressStr,lockAssetIdStr,minLockAmount,minDuration,maxDuration,mathContract) = {
725- let checkCaller = mustManager(i)
726- if ((checkCaller == checkCaller))
727- then ([IntegerEntry(keyNextUserNum(), 0), StringEntry(keyConfig(), formatConfig(lockAssetIdStr, minLockAmount, minDuration, maxDuration, mathContract)), StringEntry(keyFactoryAddress(), factoryAddressStr)] ++ StatsEntry(0, 0, 0, 0))
716+func lockRef (duration,referrerAddress,signature) = {
717+ let suspensionCheck = throwIfSuspended()
718+ if ((suspensionCheck == suspensionCheck))
719+ then {
720+ let $t02840028465 = lockActions(i, duration)
721+ let lockActionsResult = $t02840028465._1
722+ let gWxAmountStart = $t02840028465._2
723+ let referralAddress = toString(i.caller)
724+ let refInv = if (if ((referrerAddress == ""))
725+ then true
726+ else (signature == base58''))
727+ then unit
728+ else invoke(referralsContractAddressOrFail, "createPair", [referralProgramName, referrerAddress, referralAddress, signature], nil)
729+ if ((refInv == refInv))
730+ then {
731+ let updateRefActivity = invoke(mathContract, "updateReferralActivity", [toString(i.caller), gWxAmountStart], nil)
732+ if ((updateRefActivity == updateRefActivity))
733+ then $Tuple2(lockActionsResult, unit)
734+ else throw("Strict value is not equal to itself.")
735+ }
736+ else throw("Strict value is not equal to itself.")
737+ }
728738 else throw("Strict value is not equal to itself.")
729739 }
730740
731741
732742
733743 @Callable(i)
734-func lockRef (duration,referrerAddress,signature) = {
735- let $t03117031235 = lockActions(i, duration)
736- let lockActionsResult = $t03117031235._1
737- let gWxAmountStart = $t03117031235._2
738- let referralAddress = toString(i.caller)
739- let refInv = if (if ((referrerAddress == ""))
740- then true
741- else (signature == base58''))
742- then unit
743- else invoke(referralsContractAddressOrFail, "createPair", [referralProgramName, referrerAddress, referralAddress, signature], nil)
744- if ((refInv == refInv))
744+func lock (duration) = {
745+ let suspensionCheck = throwIfSuspended()
746+ if ((suspensionCheck == suspensionCheck))
745747 then {
748+ let $t02896929034 = lockActions(i, duration)
749+ let lockActionsResult = $t02896929034._1
750+ let gWxAmountStart = $t02896929034._2
746751 let updateRefActivity = invoke(mathContract, "updateReferralActivity", [toString(i.caller), gWxAmountStart], nil)
747752 if ((updateRefActivity == updateRefActivity))
748753 then $Tuple2(lockActionsResult, unit)
754759
755760
756761 @Callable(i)
757-func lock (duration) = {
758- let $t03169331758 = lockActions(i, duration)
759- let lockActionsResult = $t03169331758._1
760- let gWxAmountStart = $t03169331758._2
761- let updateRefActivity = invoke(mathContract, "updateReferralActivity", [toString(i.caller), gWxAmountStart], nil)
762- if ((updateRefActivity == updateRefActivity))
763- then $Tuple2(lockActionsResult, unit)
762+func claimWxBoost (lpAssetIdStr,userAddressStr) = {
763+ let suspensionCheck = throwIfSuspended()
764+ if ((suspensionCheck == suspensionCheck))
765+ then if ((stakingContract != i.caller))
766+ then throwErr("permissions denied")
767+ else {
768+ let $t02939029492 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, false)
769+ let userBoostAvailable = $t02939029492._1
770+ let dataState = $t02939029492._2
771+ let debug = $t02939029492._3
772+ $Tuple2(dataState, [userBoostAvailable])
773+ }
764774 else throw("Strict value is not equal to itself.")
765775 }
766776
767777
768778
769779 @Callable(i)
770-func increaseLock (deltaDuration) = {
771- let cfgArray = readConfigArrayOrFail()
772- let assetIdStr = cfgArray[IdxCfgAssetId]
773- let assetId = fromBase58String(assetIdStr)
774- let minLockDuration = parseIntValue(cfgArray[IdxCfgMinLockDuration])
775- let maxLockDuration = parseIntValue(cfgArray[IdxCfgMaxLockDuration])
776- let pmtAmount = extractOptionalPaymentAmountOrFail(i, assetId)
777- let userAddressStr = toString(i.caller)
778- let userRecordArray = readLockParamsRecordOrFail(userAddressStr)
779- let userNumStr = userRecordArray[IdxLockUserNum]
780- let userAmount = parseIntValue(userRecordArray[IdxLockAmount])
781- let lockStart = parseIntValue(userRecordArray[IdxLockStart])
782- let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
783- let lockEnd = (lockStart + lockDuration)
784- let remainingDuration = max([(lockEnd - height), 0])
785- let userAmountNew = (userAmount + pmtAmount)
786- let lockDurationNew = (remainingDuration + deltaDuration)
787- if ((0 > deltaDuration))
788- then throwErr("duration is less then zero")
789- else if ((minLockDuration > lockDurationNew))
790- then throwErr(("lockDurationNew is less then minLockDuration=" + toString(minLockDuration)))
791- else if ((lockDurationNew > maxLockDuration))
792- then throwErr(("deltaDuration + existedLockDuration is greater then maxLockDuration=" + toString(maxLockDuration)))
793- else {
794- let coeffX8 = fraction(lockDurationNew, MULT8, maxLockDuration)
795- let gWxAmountStart = fraction(userAmountNew, coeffX8, MULT8)
796- let updateRefActivity = invoke(mathContract, "updateReferralActivity", [toString(i.caller), gWxAmountStart], nil)
797- if ((updateRefActivity == updateRefActivity))
798- then {
799- let lockStartNew = height
800- let gWxParamsResultList = aal(invoke(mathContract, "calcGwxParamsREADONLY", [gWxAmountStart, lockStartNew, lockDurationNew], nil))
801- let k = ai(gWxParamsResultList[0])
802- let b = ai(gWxParamsResultList[1])
803- let period = toString(ai(gWxParamsResultList[2]))
804- let currUserGwx = calcCurrentGwxAmount(userAddressStr)
805- let gwxDiff = (gWxAmountStart - currUserGwx)
806- if ((0 > gwxDiff))
807- then throwErr(("gwxDiff is less then 0: " + toString(gwxDiff)))
808- else {
809- let totalCachedGwxRaw = getTotalCachedGwx(false)
810- let totalCachedGwxCorrected = getTotalCachedGwx(true)
811- (((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))])
812- }
813- }
814- else throw("Strict value is not equal to itself.")
815- }
816- }
817-
818-
819-
820-@Callable(i)
821-func claimWxBoost (lpAssetIdStr,userAddressStr) = if ((stakingContract != i.caller))
822- then throwErr("permissions denied")
823- else {
824- let $t03486334965 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, false)
825- let userBoostAvailable = $t03486334965._1
826- let dataState = $t03486334965._2
827- let debug = $t03486334965._3
828- $Tuple2(dataState, [userBoostAvailable])
829- }
830-
831-
832-
833-@Callable(i)
834780 func claimWxBoostREADONLY (lpAssetIdStr,userAddressStr) = {
835- let $t03509735198 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, true)
836- let userBoostAvailable = $t03509735198._1
837- let dataState = $t03509735198._2
838- let debug = $t03509735198._3
781+ let $t02962429725 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, true)
782+ let userBoostAvailable = $t02962429725._1
783+ let dataState = $t02962429725._2
784+ let debug = $t02962429725._3
839785 $Tuple2(nil, [userBoostAvailable, debug])
840786 }
841787
842788
843789
844790 @Callable(i)
845-func unlock (userAddress) = {
846- let userRecordArray = readLockParamsRecordOrFail(userAddress)
847- let userNumStr = userRecordArray[IdxLockUserNum]
848- let userAmount = parseIntValue(userRecordArray[IdxLockAmount])
849- let lockStart = parseIntValue(userRecordArray[IdxLockStart])
850- let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
851- let lockEnd = (lockStart + lockDuration)
852- let cfgArray = readConfigArrayOrFail()
853- let assetId = fromBase58String(cfgArray[IdxCfgAssetId])
854- if ((lockEnd >= height))
855- then throwErr((("wait " + toString(lockEnd)) + " to unlock"))
856- else if ((0 >= userAmount))
857- then throwErr("nothing to unlock")
858- else {
859- let period = valueOrElse(getInteger(mathContract, keyNextPeriod()), 0)
860- (((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))
861- }
791+func unlock (txIdStr) = {
792+ let suspensionCheck = throwIfSuspended()
793+ if ((suspensionCheck == suspensionCheck))
794+ then {
795+ let userAddress = i.caller
796+ let userAddressStr = toString(userAddress)
797+ let txIdOption = if ((txIdStr == ""))
798+ then unit
799+ else fromBase58String(txIdStr)
800+ let userRecordArray = readLockParamsRecordOrFail(userAddress, txIdOption)
801+ let userAmount = parseIntValue(userRecordArray[IdxLockAmount])
802+ let lockStart = parseIntValue(userRecordArray[IdxLockStart])
803+ let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
804+ let wxClaimed = parseIntValue(userRecordArray[IdxLockWxClaimed])
805+ let gwxAmount = parseIntValue(userRecordArray[IdxLockGwxAmount])
806+ let t = ((height - lockStart) / blocksInPeriod)
807+ let wxWithdrawable = getWxWithdrawable(userAddress, txIdOption)
808+ let gwxBurned = min([fraction(wxWithdrawable, lockDuration, maxLockDuration), gwxAmount])
809+ let gwxRemaining = ensurePositive((gwxAmount - gwxBurned), "gwxRemaining")
810+ let lockedGwxAmount = getLockedGwxAmount(userAddress)
811+ if ((0 >= wxWithdrawable))
812+ then throwErr("nothing to unlock")
813+ else {
814+ let gwxAmountTotal = getGwxAmountTotal()
815+ let userGwxAmountTotal = getUserGwxAmountTotal(userAddress)
816+ let userGwxAmountTotalNew = ensurePositive((userGwxAmountTotal - gwxBurned), "userGwxAmountTotalNew")
817+ if ((lockedGwxAmount > userGwxAmountTotalNew))
818+ then throwErr(("locked gwx amount: " + toString(lockedGwxAmount)))
819+ else {
820+ let userNum = parseIntValue(valueOrErrorMessage(getString(keyUser2NumMapping(userAddressStr)), wrapErr("invalid user number")))
821+ let gwxRewardInv = invoke(gwxRewardContract, "refreshUserReward", [userAddress.bytes, userNum], nil)
822+ if ((gwxRewardInv == gwxRewardInv))
823+ then ((((LockParamsEntry(userAddress, txIdOption, userAmount, lockStart, lockDuration, gwxRemaining, (wxClaimed + wxWithdrawable)) ++ StatsEntry(-(wxWithdrawable), 0, 0, 0)) :+ HistoryEntry("unlock", userAddressStr, wxWithdrawable, lockStart, lockDuration, gwxBurned, i)) :+ ScriptTransfer(userAddress, wxWithdrawable, assetId)) ++ [IntegerEntry(keyGwxTotal(), ensurePositive((gwxAmountTotal - gwxBurned), "gwxTotal")), IntegerEntry(keyUserGwxAmountTotal(userAddress), userGwxAmountTotalNew)])
824+ else throw("Strict value is not equal to itself.")
825+ }
826+ }
827+ }
828+ else throw("Strict value is not equal to itself.")
862829 }
863830
864831
865832
866833 @Callable(i)
867-func gwxUserInfoREADONLY (userAddress) = {
868- let gwxAmount = calcCurrentGwxAmount(userAddress)
834+func gwxUserInfoREADONLY (userAddressStr) = {
835+ let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid user address"))
836+ let gwxAmount = getUserGwxAmountTotal(userAddress)
869837 $Tuple2(nil, [gwxAmount])
870838 }
871839
872840
873841
874842 @Callable(i)
875-func userMaxDurationREADONLY (userAddressStr) = {
876- let cfgArray = readConfigArrayOrFail()
877- let maxLockDuration = parseIntValue(cfgArray[IdxCfgMaxLockDuration])
878- let userRecordOption = getString(this, keyLockParamsRecord(userAddressStr))
879- if ((userRecordOption == unit))
880- then $Tuple2(nil, $Tuple2("lock", maxLockDuration))
881- else {
882- let userRecordArray = split(value(userRecordOption), SEP)
883- let lockStart = parseIntValue(userRecordArray[IdxLockStart])
884- let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
885- let lockEnd = (lockStart + lockDuration)
886- let remainingDuration = max([(lockEnd - height), 0])
887- let maxDeltaDuration = (maxLockDuration - remainingDuration)
888- $Tuple2(nil, $Tuple2("increaseLock", maxDeltaDuration))
889- }
890- }
843+func userMaxDurationREADONLY (userAddressStr) = $Tuple2(nil, $Tuple2("lock", maxLockDuration))
891844
892845
893846
894847 @Callable(i)
895-func getUserGwxAmountAtHeightREADONLY (userAddress,targetHeight) = {
896- let gwxAmount = calcUserGwxAmountAtHeight(userAddress, targetHeight)
848+func getUserGwxAmountAtHeightREADONLY (userAddressStr,targetHeight) = {
849+ let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid user address"))
850+ let gwxAmount = getUserGwxAmountTotal(userAddress)
897851 $Tuple2(nil, gwxAmount)
898852 }
899853
900854
901855
902856 @Callable(i)
903-func getTotalCachedGwxREADONLY () = $Tuple2(nil, getTotalCachedGwx(true))
857+func getUserGwxAmount (userAddressStr) = {
858+ let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid user address"))
859+ let gwxAmount = getUserGwxAmountTotal(userAddress)
860+ $Tuple2(nil, gwxAmount)
861+ }
862+
863+
864+
865+@Callable(i)
866+func getGwxTotalREADONLY () = $Tuple2(nil, getGwxAmountTotal())
904867
905868
906869
907870 @Callable(i)
908871 func onBoostEmissionUpdate () = {
909- let checkCaller = if ((i.caller == emissionContract))
910- then true
911- else mustManager(i)
912- if ((checkCaller == checkCaller))
913- then refreshBoostEmissionIntegral()
872+ let suspensionCheck = throwIfSuspended()
873+ if ((suspensionCheck == suspensionCheck))
874+ then {
875+ let checkCaller = if ((i.caller == emissionContract))
876+ then true
877+ else mustManager(i)
878+ if ((checkCaller == checkCaller))
879+ then refreshBoostEmissionIntegral()
880+ else throw("Strict value is not equal to itself.")
881+ }
914882 else throw("Strict value is not equal to itself.")
915883 }
916884
918886
919887 @Callable(i)
920888 func onStakedVoteUpdate (lpAssetIdStr,userAddressStr,edge) = {
921- let checkCaller = if ((i.caller == stakingContract))
922- then true
923- else mustManager(i)
924- if ((checkCaller == checkCaller))
889+ let suspensionCheck = throwIfSuspended()
890+ if ((suspensionCheck == suspensionCheck))
925891 then {
926- let actions = refreshVoteStakedIntegral(lpAssetIdStr, userAddressStr, edge)
927- $Tuple2(actions, unit)
892+ let checkCaller = if ((i.caller == stakingContract))
893+ then true
894+ else mustManager(i)
895+ if ((checkCaller == checkCaller))
896+ then {
897+ let actions = refreshVoteStakedIntegral(lpAssetIdStr, userAddressStr, edge)
898+ $Tuple2(actions, unit)
899+ }
900+ else throw("Strict value is not equal to itself.")
928901 }
929902 else throw("Strict value is not equal to itself.")
930903 }
950923 func getUserVoteStakedIntegralREADONLY (lpAssetIdStr,userAddressStr) = $Tuple2(nil, getUserVoteStakedIntegral(lpAssetIdStr, userAddressStr))
951924
952925
926+
927+@Callable(i)
928+func suspend (v) = {
929+ let checkCaller = mustManager(i)
930+ if ((checkCaller == checkCaller))
931+ then $Tuple2([BooleanEntry(keySuspension, v)], v)
932+ else throw("Strict value is not equal to itself.")
933+ }
934+
935+
953936 @Verifier(tx)
954937 func verify () = {
955938 let targetPublicKey = match managerPublicKeyOrUnit() {
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
12-func wrapErr (msg) = makeString(["boosting.ride:", msg], " ")
12+let contractFilename = "boosting.ride"
13+
14+let SCALE18 = 18
15+
16+let MULT18 = 1000000000000000000
17+
18+let MULT18BI = toBigInt(MULT18)
19+
20+let DECAY_CONSTANT = 8
21+
22+func wrapErr (msg) = makeString([contractFilename, ": ", msg], "")
1323
1424
1525 func throwErr (msg) = throw(wrapErr(msg))
1626
1727
18-func strf (address,key) = valueOrErrorMessage(getString(address, key), wrapErr((("mandatory this." + key) + " is not defined")))
28+func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), wrapErr((("mandatory this." + key) + " is not defined")))
1929
2030
21-func ioz (address,key) = valueOrElse(getInteger(address, key), 0)
31+func getIntOrZero (address,key) = valueOrElse(getInteger(address, key), 0)
2232
2333
24-func iod (address,key,defaultVal) = valueOrElse(getInteger(address, key), defaultVal)
34+func getIntOrDefault (address,key,defaultVal) = valueOrElse(getInteger(address, key), defaultVal)
2535
2636
27-func iof (address,key) = valueOrErrorMessage(getInteger(address, key), wrapErr((("mandatory this." + key) + " is not defined")))
37+func getIntOrFail (address,key) = valueOrErrorMessage(getInteger(address, key), wrapErr((("mandatory this." + key) + " is not defined")))
2838
2939
3040 func abs (val) = if ((0 > val))
3141 then -(val)
3242 else val
3343
3444
35-func aal (val) = match val {
36- case valAnyLyst: List[Any] =>
37- valAnyLyst
38- case _ =>
39- throwErr("fail to cast into List[Any]")
40-}
41-
42-
43-func ai (val) = match val {
44- case valInt: Int =>
45- valInt
46- case _ =>
47- throwErr("fail to cast into Int")
48-}
45+func ensurePositive (v,m) = if ((v >= 0))
46+ then v
47+ else throwErr((valueOrElse(m, "value") + " should be positive"))
4948
5049
5150 func keyReferralsContractAddress () = makeString(["%s%s", "config", "referralsContractAddress"], SEP)
5251
5352
54-let referralsContractAddressOrFail = addressFromStringValue(strf(this, keyReferralsContractAddress()))
53+let referralsContractAddressOrFail = addressFromStringValue(getStringOrFail(this, keyReferralsContractAddress()))
5554
5655 let keyReferralProgramName = makeString(["%s%s", "referral", "programName"], SEP)
5756
5857 let referralProgramNameDefault = "wxlock"
5958
6059 let referralProgramName = valueOrElse(getString(this, keyReferralProgramName), referralProgramNameDefault)
6160
6261 func keyFactoryAddress () = "%s%s__config__factoryAddress"
6362
6463
6564 let IdxFactoryCfgStakingDapp = 1
6665
6766 let IdxFactoryCfgBoostingDapp = 2
6867
6968 let IdxFactoryCfgIdoDapp = 3
7069
7170 let IdxFactoryCfgTeamDapp = 4
7271
7372 let IdxFactoryCfgEmissionDapp = 5
7473
7574 let IdxFactoryCfgRestDapp = 6
7675
7776 let IdxFactoryCfgSlippageDapp = 7
7877
7978 let IdxFactoryCfgDaoDapp = 8
8079
8180 let IdxFactoryCfgMarketingDapp = 9
8281
8382 let IdxFactoryCfgGwxRewardDapp = 10
8483
8584 let IdxFactoryCfgBirdsDapp = 11
8685
8786 func keyFactoryCfg () = "%s__factoryConfig"
8887
8988
90-func keyFactoryLpList () = "%s__lpTokensList"
91-
92-
9389 func keyFactoryLpAssetToPoolContractAddress (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP)
9490
9591
9692 func keyFactoryPoolWeight (contractAddress) = makeString(["%s%s", "poolWeight", contractAddress], SEP)
9793
9894
9995 func keyFactoryPoolWeightHistory (poolAddress,num) = ((("%s%s__poolWeight__" + poolAddress) + "__") + toString(num))
10096
10197
102-func readFactoryAddressOrFail () = addressFromStringValue(strf(this, keyFactoryAddress()))
98+func readFactoryAddressOrFail () = addressFromStringValue(getStringOrFail(this, keyFactoryAddress()))
10399
104100
105-func readLpList () = split(valueOrElse(getString(readFactoryAddressOrFail(), keyFactoryLpList()), ""), SEP)
106-
107-
108-func readFactoryCfgOrFail (factory) = split(strf(factory, keyFactoryCfg()), SEP)
101+func readFactoryCfgOrFail (factory) = split(getStringOrFail(factory, keyFactoryCfg()), SEP)
109102
110103
111104 func getBoostingAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgBoostingDapp])
112105
113106
114107 func getEmissionAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgEmissionDapp])
115108
116109
117110 func getStakingAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgStakingDapp])
118111
119112
120113 func getGwxRewardAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgGwxRewardDapp])
121114
122115
123116 func keyManagerPublicKey () = "%s__managerPublicKey"
124117
125118
126119 func keyManagerVaultAddress () = "%s__managerVaultAddress"
127120
128121
129122 func keyEmissionRatePerBlockCurrent () = "%s%s__ratePerBlock__current"
130123
131124
132125 func keyEmissionRatePerBlockMaxCurrent () = "%s%s__ratePerBlockMax__current"
133126
134127
135128 func keyEmissionStartBlock () = "%s%s__emission__startBlock"
136129
137130
138131 func keyBoostingV2LastUpdateHeight () = "%s%s__boostingV2__startBlock"
139132
140133
141134 func keyBoostingV2Integral () = "%s%s__boostingV2__integral"
142135
143136
144137 func keyEmissionDurationInBlocks () = "%s%s__emission__duration"
145138
146139
147140 func keyEmissionEndBlock () = "%s%s__emission__endBlock"
148141
149142
150-func keyNextPeriod () = "%s__nextPeriod"
151-
152-
153-func keyGwxRewardEmissionStartHeight () = "%s%s__gwxRewardEmissionPart__startHeight"
154-
155-
156143 let IdxCfgAssetId = 1
157144
158145 let IdxCfgMinLockAmount = 2
159146
160147 let IdxCfgMinLockDuration = 3
161148
162149 let IdxCfgMaxLockDuration = 4
163150
164151 let IdxCfgMathContract = 5
165152
153+let IdxCfgBlocksInPeriod = 6
154+
155+let IdxCfgLockStepBlocks = 7
156+
166157 func keyConfig () = "%s__config"
167158
168159
169-func readConfigArrayOrFail () = split(strf(this, keyConfig()), SEP)
160+func readConfigArrayOrFail () = split(getStringOrFail(this, keyConfig()), SEP)
170161
171162
172-let mathContract = addressFromStringValue(readConfigArrayOrFail()[IdxCfgMathContract])
163+let cfgArray = readConfigArrayOrFail()
173164
174-func formatConfigS (assetId,minLockAmount,minLockDuration,maxLockDuration,mathContract) = makeString(["%s%d%d%d", assetId, minLockAmount, minLockDuration, maxLockDuration, mathContract], SEP)
165+let assetId = fromBase58String(cfgArray[IdxCfgAssetId])
175166
167+let minLockAmount = valueOrErrorMessage(parseInt(cfgArray[IdxCfgMinLockAmount]), wrapErr("invalid min lock amount"))
176168
177-func formatConfig (assetId,minLockAmount,minLockDuration,maxLockDuration,mathContract) = formatConfigS(assetId, toString(minLockAmount), toString(minLockDuration), toString(maxLockDuration), mathContract)
169+let minLockDuration = valueOrErrorMessage(parseInt(cfgArray[IdxCfgMinLockDuration]), wrapErr("invalid min lock duration"))
170+
171+let maxLockDuration = valueOrErrorMessage(parseInt(cfgArray[IdxCfgMaxLockDuration]), wrapErr("invalid max lock duration"))
172+
173+let mathContract = valueOrErrorMessage(addressFromString(cfgArray[IdxCfgMathContract]), wrapErr("invalid math contract address"))
174+
175+let blocksInPeriod = valueOrErrorMessage(parseInt(cfgArray[IdxCfgBlocksInPeriod]), wrapErr("invalid blocks in period"))
176+
177+let lockStepBlocks = valueOrErrorMessage(parseInt(cfgArray[IdxCfgLockStepBlocks]), wrapErr("invalid lock step blocks"))
178+
179+let keySuspension = "%s__suspension"
180+
181+let isSuspended = valueOrElse(getBoolean(this, keySuspension), false)
182+
183+func throwIfSuspended () = if (!(isSuspended))
184+ then true
185+ else throwErr("suspended")
178186
179187
180188 func getManagerVaultAddressOrThis () = match getString(keyManagerVaultAddress()) {
181189 case s: String =>
182190 addressFromStringValue(s)
183191 case _ =>
184192 this
185193 }
186194
187195
188196 func managerPublicKeyOrUnit () = {
189197 let managerVaultAddress = getManagerVaultAddressOrThis()
190198 match getString(managerVaultAddress, keyManagerPublicKey()) {
191199 case s: String =>
192200 fromBase58String(s)
193201 case _: Unit =>
194202 unit
195203 case _ =>
196204 throw("Match error")
197205 }
198206 }
199207
200208
201209 func mustManager (i) = {
202210 let pd = throwErr("Permission denied")
203211 match managerPublicKeyOrUnit() {
204212 case pk: ByteVector =>
205213 if ((i.callerPublicKey == pk))
206214 then true
207215 else pd
208216 case _: Unit =>
209217 if ((i.caller == this))
210218 then true
211219 else pd
212220 case _ =>
213221 throw("Match error")
214222 }
215223 }
216224
217225
218-let IdxLockUserNum = 1
226+let IdxLockAmount = 1
219227
220-let IdxLockAmount = 2
228+let IdxLockStart = 2
221229
222-let IdxLockStart = 3
230+let IdxLockDuration = 3
223231
224-let IdxLockDuration = 4
232+let IdxLockLastUpdateTimestamp = 4
225233
226-let IdxLockParamK = 5
234+let IdxLockGwxAmount = 5
227235
228-let IdxLockParamB = 6
236+let IdxLockWxClaimed = 6
229237
230-func keyLockParamsRecord (userAddress) = makeString(["%s%s__lock", userAddress], SEP)
238+func keyLockParamsRecord (userAddress,txId) = makeString(["%s%s%s__lock", toString(userAddress), match txId {
239+ case b: ByteVector =>
240+ toBase58String(b)
241+ case _: Unit =>
242+ "legacy"
243+ case _ =>
244+ throw("Match error")
245+}], SEP)
231246
232247
233-func readLockParamsRecordOrFail (userAddress) = split(strf(this, keyLockParamsRecord(userAddress)), SEP)
248+func readLockParamsRecordOrFail (userAddress,txId) = split(getStringOrFail(this, keyLockParamsRecord(userAddress, txId)), SEP)
234249
235250
236-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)
251+func keyUserGwxAmountTotal (userAddress) = makeString(["%s%s__gwxAmountTotal", toString(userAddress)], SEP)
237252
238253
239-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))
254+func formatLockParamsRecord (amount,start,duration,gwxAmount,wxClaimed) = makeString(["%d%d%d%d%d%d", toString(amount), toString(start), toString(duration), toString(lastBlock.timestamp), toString(gwxAmount), toString(wxClaimed)], SEP)
240255
241256
242257 func keyNextUserNum () = "%s__nextUserNum"
243258
244259
245260 func keyUser2NumMapping (userAddress) = makeString(["%s%s%s__mapping__user2num", userAddress], SEP)
246261
247262
248263 func keyNum2UserMapping (num) = makeString(["%s%s%s__mapping__num2user", num], SEP)
249-
250-
251-func keyLockParamUserAmount (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "amount"], SEP)
252-
253-
254-func keyLockParamStartBlock (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "start"], SEP)
255-
256-
257-func keyLockParamDuration (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "duration"], SEP)
258-
259-
260-func keyLockParamK (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "k"], SEP)
261-
262-
263-func keyLockParamB (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "b"], SEP)
264-
265-
266-func keyLockParamByPeriodK (userNum,period) = makeString(["%s%d%s%d__paramByPeriod", userNum, "k", period], SEP)
267-
268-
269-func keyLockParamByPeriodB (userNum,period) = makeString(["%s%d%s%d__paramByPeriod", userNum, "b", period], SEP)
270264
271265
272266 func keyLockParamTotalAmount () = "%s%s__stats__activeTotalLocked"
273267
274268
275269 func keyStatsLocksDurationSumInBlocks () = "%s%s__stats__locksDurationSumInBlocks"
276270
277271
278272 func keyStatsLocksCount () = "%s%s__stats__locksCount"
279273
280274
281275 func keyStatsUsersCount () = "%s%s__stats__activeUsersCount"
282276
283277
284-func keyUserBoostEmissionLastINTEGRAL (userNum) = makeString(["%s%d__userBoostEmissionLastIntV2", userNum], SEP)
278+func keyUserBoostEmissionLastINTEGRAL (userNum) = makeString(["%s%d__userBoostEmissionLastIntV2", toString(userNum)], SEP)
285279
286280
287-func keyUserLpBoostEmissionLastINTEGRAL (userNum,lpAssetId) = makeString(["%s%d__userBoostEmissionLastIntV2", userNum, lpAssetId], SEP)
281+func keyUserLpBoostEmissionLastINTEGRAL (userNum,lpAssetId) = makeString(["%s%d__userBoostEmissionLastIntV2", toString(userNum), lpAssetId], SEP)
288282
289283
290-func keyUserMaxBoostINTEGRAL (userNum) = makeString(["%s%d__maxBoostInt", userNum], SEP)
284+func keyUserMaxBoostINTEGRAL (userNum) = makeString(["%s%d__maxBoostInt", toString(userNum)], SEP)
291285
292286
293287 func keyTotalMaxBoostINTEGRAL () = "%s%s__maxBoostInt__total"
294288
295289
296-func keyUserBoostAvalaibleToClaimTotal (userNum) = makeString(["%s%d__userBoostAvaliableToClaimTotal", userNum], SEP)
290+func keyUserBoostAvalaibleToClaimTotal (userNum) = makeString(["%s%d__userBoostAvaliableToClaimTotal", toString(userNum)], SEP)
297291
298292
299-func keyUserBoostClaimed (userNum) = makeString(["%s%d__userBoostClaimed", userNum], SEP)
293+func keyUserBoostClaimed (userNum) = makeString(["%s%d__userBoostClaimed", toString(userNum)], SEP)
300294
301295
302-func keyTotalCachedGwx () = "%s%s__gwxCached__total"
303-
304-
305-func keyTotalCachedGwxCorrective () = "%s__gwxCachedTotalCorrective"
296+func keyGwxTotal () = "%s%s__gwx__total"
306297
307298
308299 func keyVote (amountAssetId,priceAssetId,address,epoch) = makeString(["%s%s%s%s%d", "vote", amountAssetId, priceAssetId, toString(address), toString(epoch)], SEP)
309300
310301
311302 func keyStartHeightByEpoch (epoch) = makeString(["%s%d", "startHeight", toString(epoch)], SEP)
312303
313304
314305 func keyCurrentEpochUi () = makeString(["%s", "currentEpochUi"], SEP)
315306
316307
317308 func keyVotingResultStaked (lpAssetIdStr,epoch) = makeString(["%s%s%d", "votingResultStaked", lpAssetIdStr, toString(epoch)], SEP)
318309
319310
320311 func keyVotingResultStakedIntegral (lpAssetIdStr,epoch) = makeString(["%s%s%d", "votingResultStakedIntegral", lpAssetIdStr, toString(epoch)], SEP)
321312
322313
323314 func keyVotingResultStakedLastUpdateHeight (lpAssetIdStr,epoch) = makeString(["%s%s%d", "votingResultStakedIntegralLastUpdateHeight", lpAssetIdStr, toString(epoch)], SEP)
324315
325316
326317 func keyVotingResultStakedIntegralLast (lpAssetIdStr,address,epoch) = makeString(["%s%s%s%d", "votingResultStakedIntegralLast", lpAssetIdStr, toString(address), toString(epoch)], SEP)
327318
328319
329320 func keyVoteStakedIntegral (lpAssetIdStr,address,epoch) = makeString(["%s%s%s%d", "voteStakedIntegral", lpAssetIdStr, toString(address), toString(epoch)], SEP)
330321
331322
332323 func keyVoteStakedLastUpdateHeight (lpAssetIdStr,address,epoch) = makeString(["%s%s%s%d", "voteStakedIntegralLastUpdateHeight", lpAssetIdStr, toString(address), toString(epoch)], SEP)
333324
334325
335326 func keyVoteStakedIntegralLast (lpAssetIdStr,address,epoch) = makeString(["%s%s%s%d", "voteStakedIntegralLast", lpAssetIdStr, toString(address), toString(epoch)], SEP)
336327
337328
338329 func keyStakedByUser (userAddressStr,lpAssetIdStr) = makeString(["%s%s%s", "staked", userAddressStr, lpAssetIdStr], SEP)
339330
340331
341332 let factoryContract = readFactoryAddressOrFail()
342333
343334 let factoryCfg = readFactoryCfgOrFail(factoryContract)
344335
345336 let emissionContract = getEmissionAddressOrFail(factoryCfg)
346337
347338 let stakingContract = getStakingAddressOrFail(factoryCfg)
348339
349340 let gwxRewardContract = getGwxRewardAddressOrFail(factoryCfg)
350341
351342 let lpStakingPoolsContract = valueOrErrorMessage(addressFromString(valueOrErrorMessage(getString(makeString(["%s", "lpStakingPoolsContract"], SEP)), wrapErr("lp_staking_pools contract address is undefined"))), wrapErr("invalid lp_staking_pools contract address"))
352343
353344 let keyVotingEmissionContract = makeString(["%s", "votingEmissionContract"], SEP)
354345
355346 let votingEmissionContract = addressFromStringValue(getStringValue(factoryContract, keyVotingEmissionContract))
356347
348+let keyVotingEmissionRateContract = makeString(["%s", "votingEmissionRateContract"], SEP)
349+
357350 let boostCoeff = {
358351 let @ = invoke(emissionContract, "getBoostCoeffREADONLY", nil, nil)
359352 if ($isInstanceOf(@, "Int"))
360353 then @
361354 else throw(($getType(@) + " couldn't be cast to Int"))
362355 }
363356
364-func getTotalCachedGwx (correct) = {
365- let currentEpochUi = getIntegerValue(votingEmissionContract, keyCurrentEpochUi())
366- let keyTargetEpoch = makeString(["%s%s", "totalCachedGwxCorrection__activationEpoch"], SEP)
367- let targetEpochOption = getInteger(this, keyTargetEpoch)
368- let totalCachedGwxRaw = valueOrElse(getInteger(this, keyTotalCachedGwx()), 0)
369- let isCorrectionActivated = if (isDefined(targetEpochOption))
370- then (currentEpochUi >= value(targetEpochOption))
371- else false
372- let corrective = if (if (isCorrectionActivated)
373- then correct
374- else false)
375- then valueOrElse(getInteger(this, keyTotalCachedGwxCorrective()), 0)
376- else 0
377- max([0, (totalCachedGwxRaw + corrective)])
357+func userNumberByAddressOrFail (userAddress) = match getString(this, keyUser2NumMapping(toString(userAddress))) {
358+ case s: String =>
359+ valueOrErrorMessage(parseInt(s), wrapErr("invalid user number"))
360+ case _: Unit =>
361+ throwErr("invalid user")
362+ case _ =>
363+ throw("Match error")
364+}
365+
366+
367+func getGwxAmountTotal () = valueOrElse(getInteger(this, keyGwxTotal()), 0)
368+
369+
370+func getLockedGwxAmount (userAddress) = {
371+ let functionName = "getLockedGwxAmount"
372+ let votingEmissionRateContract = valueOrErrorMessage( match getString(votingEmissionContract, keyVotingEmissionRateContract) {
373+ case _: Unit =>
374+ unit
375+ case s: String =>
376+ addressFromString(s)
377+ case _ =>
378+ throw("Match error")
379+ }, wrapErr("invalid voting emission rate address"))
380+ let lockedVotingEmissionRate = {
381+ let @ = invoke(votingEmissionContract, functionName, [toString(userAddress)], nil)
382+ if ($isInstanceOf(@, "Int"))
383+ then @
384+ else throw(($getType(@) + " couldn't be cast to Int"))
385+ }
386+ let lockedVotingEmission = {
387+ let @ = invoke(votingEmissionRateContract, functionName, [toString(userAddress)], nil)
388+ if ($isInstanceOf(@, "Int"))
389+ then @
390+ else throw(($getType(@) + " couldn't be cast to Int"))
391+ }
392+ let locked = max([lockedVotingEmissionRate, lockedVotingEmission])
393+ locked
378394 }
379395
380396
381-func HistoryEntry (type,user,amount,lockStart,duration,k,b,i) = {
397+func HistoryEntry (type,user,amount,lockStart,duration,gwxAmount,i) = {
382398 let historyKEY = makeString(["%s%s%s%s__history", type, user, toBase58String(i.transactionId)], SEP)
383- 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)
399+ let historyDATA = makeString(["%d%d%d%d%d%d%d", toString(lastBlock.height), toString(lastBlock.timestamp), toString(amount), toString(lockStart), toString(duration), toString(gwxAmount)], SEP)
384400 StringEntry(historyKEY, historyDATA)
385401 }
386402
387403
388404 func StatsEntry (totalLockedInc,durationInc,lockCountInc,usersCountInc) = {
389405 let locksDurationSumInBlocksKEY = keyStatsLocksDurationSumInBlocks()
390406 let locksCountKEY = keyStatsLocksCount()
391407 let usersCountKEY = keyStatsUsersCount()
392408 let totalAmountKEY = keyLockParamTotalAmount()
393- let locksDurationSumInBlocks = ioz(this, locksDurationSumInBlocksKEY)
394- let locksCount = ioz(this, locksCountKEY)
395- let usersCount = ioz(this, usersCountKEY)
396- let totalAmount = ioz(this, totalAmountKEY)
409+ let locksDurationSumInBlocks = getIntOrZero(this, locksDurationSumInBlocksKEY)
410+ let locksCount = getIntOrZero(this, locksCountKEY)
411+ let usersCount = getIntOrZero(this, usersCountKEY)
412+ let totalAmount = getIntOrZero(this, totalAmountKEY)
397413 [IntegerEntry(locksDurationSumInBlocksKEY, (locksDurationSumInBlocks + durationInc)), IntegerEntry(locksCountKEY, (locksCount + lockCountInc)), IntegerEntry(usersCountKEY, (usersCount + usersCountInc)), IntegerEntry(totalAmountKEY, (totalAmount + totalLockedInc))]
398414 }
399415
400416
401-func calcGwxAmount (kRaw,bRaw,h) = {
402- let SCALE = 1000
403- (((kRaw * h) + bRaw) / SCALE)
404- }
405-
406-
407-func LockParamsEntry (userAddress,userNum,amount,start,duration,k,b,period) = {
408- let userAmountKEY = keyLockParamUserAmount(userNum)
409- let startBlockKEY = keyLockParamStartBlock(userNum)
410- let durationKEY = keyLockParamDuration(userNum)
411- let kKEY = keyLockParamK(userNum)
412- let bKEY = keyLockParamB(userNum)
413- let kByPeriodKEY = keyLockParamByPeriodK(userNum, period)
414- let bByPeriodKEY = keyLockParamByPeriodB(userNum, period)
415- let gwxAmount = calcGwxAmount(k, b, height)
416-[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))]
417- }
417+func LockParamsEntry (userAddress,txId,amount,start,duration,gwxAmount,wxClaimed) = [StringEntry(keyLockParamsRecord(userAddress, txId), formatLockParamsRecord(amount, start, duration, gwxAmount, wxClaimed))]
418418
419419
420420 func extractOptionalPaymentAmountOrFail (i,expectedAssetId) = if ((size(i.payments) > 1))
421421 then throwErr("only one payment is allowed")
422422 else if ((size(i.payments) == 0))
423423 then 0
424424 else {
425425 let pmt = i.payments[0]
426426 if ((value(pmt.assetId) != expectedAssetId))
427427 then throwErr("invalid asset id in payment")
428428 else pmt.amount
429429 }
430430
431431
432-func calcUserGwxAmountAtHeight (userAddress,targetHeight) = {
433- let EMPTY = "empty"
434- let user2NumMappingKEY = keyUser2NumMapping(userAddress)
435- let userNum = valueOrElse(getString(user2NumMappingKEY), EMPTY)
436- let k = valueOrElse(getInteger(keyLockParamK(userNum)), 0)
437- let b = valueOrElse(getInteger(keyLockParamB(userNum)), 0)
438- let gwxAmountCalc = calcGwxAmount(k, b, targetHeight)
439- let gwxAmount = if ((0 > gwxAmountCalc))
440- then 0
441- else gwxAmountCalc
442- gwxAmount
443- }
444-
445-
446-func calcCurrentGwxAmount (userAddress) = calcUserGwxAmountAtHeight(userAddress, height)
432+func getUserGwxAmountTotal (userAddress) = valueOrElse(getInteger(this, keyUserGwxAmountTotal(userAddress)), 0)
447433
448434
449435 func getVotingEmissionEpochInfo () = {
450- let $t01718617476 = {
436+ let $t01468614976 = {
451437 let currentEpochUi = value(getInteger(votingEmissionContract, keyCurrentEpochUi()))
452438 let lastFinalizedEpoch = (currentEpochUi - 1)
453439 if ((0 > lastFinalizedEpoch))
454440 then throwErr("invalid epoch")
455441 else $Tuple2(currentEpochUi, lastFinalizedEpoch)
456442 }
457- let currentEpochUi = $t01718617476._1
458- let lastFinalizedEpoch = $t01718617476._2
443+ let currentEpochUi = $t01468614976._1
444+ let lastFinalizedEpoch = $t01468614976._2
459445 let currentEpochStartHeight = value(getInteger(votingEmissionContract, keyStartHeightByEpoch(currentEpochUi)))
460446 $Tuple2(lastFinalizedEpoch, currentEpochStartHeight)
461447 }
462448
463449
464450 func getPoolAssetsByLpAssetId (lpAssetIdStr) = {
465451 let idxAmountAssetId = 4
466452 let idxPriceAssetId = 5
467453 let poolCfg = {
468454 let @ = invoke(factoryContract, "getPoolConfigByLpAssetIdREADONLY", [lpAssetIdStr], nil)
469455 if ($isInstanceOf(@, "List[Any]"))
470456 then @
471457 else throw(($getType(@) + " couldn't be cast to List[Any]"))
472458 }
473459 let amountAssetId = {
474460 let @ = poolCfg[idxAmountAssetId]
475461 if ($isInstanceOf(@, "String"))
476462 then @
477463 else throw(($getType(@) + " couldn't be cast to String"))
478464 }
479465 let priceAssetId = {
480466 let @ = poolCfg[idxPriceAssetId]
481467 if ($isInstanceOf(@, "String"))
482468 then @
483469 else throw(($getType(@) + " couldn't be cast to String"))
484470 }
485471 $Tuple2(amountAssetId, priceAssetId)
486472 }
487473
488474
489475 func getUserVoteFinalized (lpAssetIdStr,userAddressStr) = {
490476 let userAddress = addressFromStringValue(userAddressStr)
491- let $t01816718247 = getVotingEmissionEpochInfo()
492- let lastFinalizedEpoch = $t01816718247._1
493- let currentEpochStartHeight = $t01816718247._2
494- let $t01825018325 = getPoolAssetsByLpAssetId(lpAssetIdStr)
495- let amountAssetId = $t01825018325._1
496- let priceAssetId = $t01825018325._2
477+ let $t01566715747 = getVotingEmissionEpochInfo()
478+ let lastFinalizedEpoch = $t01566715747._1
479+ let currentEpochStartHeight = $t01566715747._2
480+ let $t01575015825 = getPoolAssetsByLpAssetId(lpAssetIdStr)
481+ let amountAssetId = $t01575015825._1
482+ let priceAssetId = $t01575015825._2
497483 let userVoteKey = keyVote(amountAssetId, priceAssetId, userAddress, lastFinalizedEpoch)
498484 let userVote = valueOrElse(getInteger(votingEmissionContract, userVoteKey), 0)
499485 userVote
500486 }
501487
502488
503489 func getUserVoteStaked (lpAssetIdStr,userAddressStr) = {
504490 let stakedByUser = valueOrElse(getInteger(stakingContract, keyStakedByUser(userAddressStr, lpAssetIdStr)), 0)
505491 let userVote = getUserVoteFinalized(lpAssetIdStr, userAddressStr)
506492 if ((stakedByUser == 0))
507493 then 0
508494 else userVote
509495 }
510496
511497
512498 func getVotingResultStaked (lpAssetIdStr) = {
513- let $t01886918949 = getVotingEmissionEpochInfo()
514- let lastFinalizedEpoch = $t01886918949._1
515- let currentEpochStartHeight = $t01886918949._2
499+ let $t01636916449 = getVotingEmissionEpochInfo()
500+ let lastFinalizedEpoch = $t01636916449._1
501+ let currentEpochStartHeight = $t01636916449._2
516502 let votingResultStakedStart = valueOrElse(getInteger(votingEmissionContract, keyVotingResultStaked(lpAssetIdStr, lastFinalizedEpoch)), 0)
517503 let votingResultStaked = valueOrElse(getInteger(this, keyVotingResultStaked(lpAssetIdStr, lastFinalizedEpoch)), votingResultStakedStart)
518504 votingResultStaked
519505 }
520506
521507
522508 func getVotingResultStakedIntegral (lpAssetIdStr) = {
523- let $t01931119391 = getVotingEmissionEpochInfo()
524- let lastFinalizedEpoch = $t01931119391._1
525- let currentEpochStartHeight = $t01931119391._2
509+ let $t01681116891 = getVotingEmissionEpochInfo()
510+ let lastFinalizedEpoch = $t01681116891._1
511+ let currentEpochStartHeight = $t01681116891._2
526512 let votingResultStaked = getVotingResultStaked(lpAssetIdStr)
527513 let votingResultStakedIntegralPrev = valueOrElse(getInteger(this, keyVotingResultStakedIntegral(lpAssetIdStr, lastFinalizedEpoch)), 0)
528514 let votingResultStakedLastUpdateHeight = valueOrElse(getInteger(this, keyVotingResultStakedLastUpdateHeight(lpAssetIdStr, lastFinalizedEpoch)), currentEpochStartHeight)
529515 let votingResultStakedIntegralDh = (height - votingResultStakedLastUpdateHeight)
530516 let votingResultStakedIntegral = ((votingResultStakedIntegralDh * votingResultStaked) + votingResultStakedIntegralPrev)
531517 votingResultStakedIntegral
532518 }
533519
534520
535521 func refreshVotingResultStakedIntegral (lpAssetIdStr,stakedVoteDelta) = {
536- let $t02022820308 = getVotingEmissionEpochInfo()
537- let lastFinalizedEpoch = $t02022820308._1
538- let currentEpochStartHeight = $t02022820308._2
522+ let $t01772817808 = getVotingEmissionEpochInfo()
523+ let lastFinalizedEpoch = $t01772817808._1
524+ let currentEpochStartHeight = $t01772817808._2
539525 let votingResultStaked = getVotingResultStaked(lpAssetIdStr)
540526 let votingResultStakedNew = (votingResultStaked + stakedVoteDelta)
541527 let votingResultStakedIntegral = getVotingResultStakedIntegral(lpAssetIdStr)
542528 [IntegerEntry(keyVotingResultStaked(lpAssetIdStr, lastFinalizedEpoch), votingResultStakedNew), IntegerEntry(keyVotingResultStakedLastUpdateHeight(lpAssetIdStr, lastFinalizedEpoch), height), IntegerEntry(keyVotingResultStakedIntegral(lpAssetIdStr, lastFinalizedEpoch), votingResultStakedIntegral)]
543529 }
544530
545531
546532 func getUserVoteStakedIntegral (lpAssetIdStr,userAddressStr) = {
547- let $t02091920999 = getVotingEmissionEpochInfo()
548- let lastFinalizedEpoch = $t02091920999._1
549- let currentEpochStartHeight = $t02091920999._2
533+ let $t01841918499 = getVotingEmissionEpochInfo()
534+ let lastFinalizedEpoch = $t01841918499._1
535+ let currentEpochStartHeight = $t01841918499._2
550536 let userAddress = addressFromStringValue(userAddressStr)
551537 let userVoteStaked = getUserVoteStaked(lpAssetIdStr, userAddressStr)
552538 let userVoteStakedIntegralPrev = valueOrElse(getInteger(this, keyVoteStakedIntegral(lpAssetIdStr, userAddress, lastFinalizedEpoch)), 0)
553539 let userVoteStakedLastUpdateHeight = valueOrElse(getInteger(this, keyVoteStakedLastUpdateHeight(lpAssetIdStr, userAddress, lastFinalizedEpoch)), currentEpochStartHeight)
554540 let userVoteStakedIntegralDh = (height - userVoteStakedLastUpdateHeight)
555541 let userVoteStakedIntegral = ((userVoteStakedIntegralDh * userVoteStaked) + userVoteStakedIntegralPrev)
556542 userVoteStakedIntegral
557543 }
558544
559545
560546 func refreshVoteStakedIntegral (lpAssetIdStr,userAddressStr,edge) = {
561- let $t02178721867 = getVotingEmissionEpochInfo()
562- let lastFinalizedEpoch = $t02178721867._1
563- let currentEpochStartHeight = $t02178721867._2
547+ let $t01928719367 = getVotingEmissionEpochInfo()
548+ let lastFinalizedEpoch = $t01928719367._1
549+ let currentEpochStartHeight = $t01928719367._2
564550 let userAddress = addressFromStringValue(userAddressStr)
565551 let userVoteFinalized = getUserVoteFinalized(lpAssetIdStr, userAddressStr)
566552 let actions = if ((userVoteFinalized == 0))
567553 then nil
568554 else {
569555 let stakedVoteDelta = if (edge)
570556 then userVoteFinalized
571557 else -(userVoteFinalized)
572558 let votingResultActions = refreshVotingResultStakedIntegral(lpAssetIdStr, stakedVoteDelta)
573559 let userVoteStakedIntegral = getUserVoteStakedIntegral(lpAssetIdStr, userAddressStr)
574560 let voteActions = [IntegerEntry(keyVoteStakedLastUpdateHeight(lpAssetIdStr, userAddress, lastFinalizedEpoch), height), IntegerEntry(keyVoteStakedIntegral(lpAssetIdStr, userAddress, lastFinalizedEpoch), userVoteStakedIntegral)]
575561 (votingResultActions ++ voteActions)
576562 }
577563 actions
578564 }
579565
580566
581567 func getStakedVotesIntegralsDiff (lpAssetIdStr,userAddressStr) = {
582- let $t02272122801 = getVotingEmissionEpochInfo()
583- let lastFinalizedEpoch = $t02272122801._1
584- let currentEpochStartHeight = $t02272122801._2
568+ let $t02022120301 = getVotingEmissionEpochInfo()
569+ let lastFinalizedEpoch = $t02022120301._1
570+ let currentEpochStartHeight = $t02022120301._2
585571 let userAddress = addressFromStringValue(userAddressStr)
586572 let userVoteStakedIntegralLastKey = keyVoteStakedIntegralLast(lpAssetIdStr, userAddress, lastFinalizedEpoch)
587573 let userVoteStakedIntegralLast = valueOrElse(getInteger(this, userVoteStakedIntegralLastKey), 0)
588574 let votingResultStakedIntegralLastKey = keyVotingResultStakedIntegralLast(lpAssetIdStr, userAddress, lastFinalizedEpoch)
589575 let votingResultStakedIntegralLast = valueOrElse(getInteger(this, votingResultStakedIntegralLastKey), 0)
590576 let userVoteStakedIntegral = getUserVoteStakedIntegral(lpAssetIdStr, userAddressStr)
591577 let votingResultStakedIntegral = getVotingResultStakedIntegral(lpAssetIdStr)
592578 let userVoteStakedIntegralDiff = (userVoteStakedIntegral - userVoteStakedIntegralLast)
593579 let votingResultStakedIntegralDiff = (votingResultStakedIntegral - votingResultStakedIntegralLast)
594580 $Tuple3([IntegerEntry(userVoteStakedIntegralLastKey, userVoteStakedIntegral), IntegerEntry(votingResultStakedIntegralLastKey, votingResultStakedIntegral)], userVoteStakedIntegralDiff, votingResultStakedIntegralDiff)
595581 }
596582
597583
598584 func refreshBoostEmissionIntegral () = {
599- let wxEmissionPerBlock = iof(emissionContract, keyEmissionRatePerBlockCurrent())
585+ let wxEmissionPerBlock = getIntOrFail(emissionContract, keyEmissionRatePerBlockCurrent())
600586 let boostingV2LastUpdateHeightOption = getInteger(this, keyBoostingV2LastUpdateHeight())
601587 let boostingV2IngergalOption = getInteger(this, keyBoostingV2Integral())
602- let emissionEnd = iof(emissionContract, keyEmissionEndBlock())
588+ let emissionEnd = getIntOrFail(emissionContract, keyEmissionEndBlock())
603589 let h = if ((height > emissionEnd))
604590 then emissionEnd
605591 else height
606592 let dh = match boostingV2LastUpdateHeightOption {
607593 case lastUpdateHeight: Int =>
608594 max([(h - lastUpdateHeight), 0])
609595 case _: Unit =>
610596 0
611597 case _ =>
612598 throw("Match error")
613599 }
614600 let boostEmissionPerBlock = ((wxEmissionPerBlock * (boostCoeff - 1)) / boostCoeff)
615601 let boostEmissionIntegralPrev = valueOrElse(boostingV2IngergalOption, 0)
616602 let boostEmissionIntegral = ((boostEmissionPerBlock * dh) + boostEmissionIntegralPrev)
617603 $Tuple2([IntegerEntry(keyBoostingV2Integral(), boostEmissionIntegral), IntegerEntry(keyBoostingV2LastUpdateHeight(), height)], boostEmissionIntegral)
618604 }
619605
620606
621607 func internalClaimWxBoost (lpAssetIdStr,userAddressStr,readOnly) = {
622- let userRecordOption = getString(this, keyLockParamsRecord(userAddressStr))
623- if ((userRecordOption == unit))
624- then $Tuple3(0, nil, "userRecord::is::empty")
625- else {
626- let userRecordArray = split(value(userRecordOption), SEP)
627- let userNumStr = userRecordArray[IdxLockUserNum]
608+ let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid user address"))
609+ let userNum = userNumberByAddressOrFail(userAddress)
610+ if ((userNum == userNum))
611+ then {
628612 let EMPTYSTR = "empty"
629613 let poolWeight = if ((lpAssetIdStr != EMPTYSTR))
630614 then {
631615 let poolAddressStr = valueOrErrorMessage(getString(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetIdStr)), wrapErr(("unsupported lp asset " + lpAssetIdStr)))
632616 getIntegerValue(factoryContract, keyFactoryPoolWeight(poolAddressStr))
633617 }
634618 else if (readOnly)
635619 then 0
636620 else throwErr(("not readonly mode: unsupported lp asset " + lpAssetIdStr))
637- let userLpBoostEmissionLastIntegralKEY = keyUserLpBoostEmissionLastINTEGRAL(userNumStr, lpAssetIdStr)
638- let userBoostEmissionLastIntegralKEY = keyUserBoostEmissionLastINTEGRAL(userNumStr)
639- let userBoostEmissionLastIntegral = valueOrElse(getInteger(this, userLpBoostEmissionLastIntegralKEY), ioz(this, userBoostEmissionLastIntegralKEY))
621+ let userLpBoostEmissionLastIntegralKEY = keyUserLpBoostEmissionLastINTEGRAL(userNum, lpAssetIdStr)
622+ let userBoostEmissionLastIntegralKEY = keyUserBoostEmissionLastINTEGRAL(userNum)
623+ let userBoostEmissionLastIntegral = valueOrElse(getInteger(this, userLpBoostEmissionLastIntegralKEY), getIntOrZero(this, userBoostEmissionLastIntegralKEY))
640624 let boostEmissionIntegral = refreshBoostEmissionIntegral()._2
641625 let userBoostEmissionIntegral = (boostEmissionIntegral - userBoostEmissionLastIntegral)
642626 if ((0 > userBoostEmissionIntegral))
643627 then throwErr("wrong calculations")
644628 else {
645- let $t02642026559 = getStakedVotesIntegralsDiff(lpAssetIdStr, userAddressStr)
646- let stakedVotesIntegralsActions = $t02642026559._1
647- let userVoteIntegralDiff = $t02642026559._2
648- let totalVotesIntegralDiff = $t02642026559._3
629+ let $t02384323982 = getStakedVotesIntegralsDiff(lpAssetIdStr, userAddressStr)
630+ let stakedVotesIntegralsActions = $t02384323982._1
631+ let userVoteIntegralDiff = $t02384323982._2
632+ let totalVotesIntegralDiff = $t02384323982._3
649633 let poolUserBoostEmissionIntegral = fraction(userBoostEmissionIntegral, poolWeight, POOLWEIGHTMULT)
650634 let userBoostAvaliableToClaimTotalNew = if ((totalVotesIntegralDiff == 0))
651635 then 0
652636 else fraction(poolUserBoostEmissionIntegral, userVoteIntegralDiff, totalVotesIntegralDiff)
653637 let dataState = ([IntegerEntry(userLpBoostEmissionLastIntegralKEY, boostEmissionIntegral)] ++ stakedVotesIntegralsActions)
654638 let debug = makeString([toString(userBoostEmissionLastIntegral), toString(userBoostEmissionIntegral), toString(poolWeight), toString(userVoteIntegralDiff), toString(totalVotesIntegralDiff)], ":")
655639 $Tuple3(userBoostAvaliableToClaimTotalNew, dataState, debug)
656640 }
657641 }
642+ else throw("Strict value is not equal to itself.")
658643 }
659644
660645
661646 func lockActions (i,duration) = {
662- let cfgArray = readConfigArrayOrFail()
663- let assetIdStr = cfgArray[IdxCfgAssetId]
664- let assetId = fromBase58String(assetIdStr)
665- let minLockAmount = parseIntValue(cfgArray[IdxCfgMinLockAmount])
666- let minLockDuration = parseIntValue(cfgArray[IdxCfgMinLockDuration])
667- let maxLockDuration = parseIntValue(cfgArray[IdxCfgMaxLockDuration])
647+ let assetIdStr = toBase58String(assetId)
668648 if ((size(i.payments) != 1))
669649 then throwErr("invalid payment - exact one payment must be attached")
670650 else {
671651 let pmt = i.payments[0]
672652 let pmtAmount = pmt.amount
673653 if ((assetId != value(pmt.assetId)))
674654 then throwErr((("invalid asset is in payment - " + assetIdStr) + " is expected"))
675655 else {
676656 let nextUserNumKEY = keyNextUserNum()
677- let userAddressStr = toString(i.caller)
657+ let userAddress = i.caller
658+ let userAddressStr = toString(userAddress)
678659 let userIsExisting = isDefined(getString(keyUser2NumMapping(userAddressStr)))
679660 let userNumStr = if (userIsExisting)
680661 then value(getString(keyUser2NumMapping(userAddressStr)))
681- else toString(iof(this, nextUserNumKEY))
662+ else toString(getIntOrFail(this, nextUserNumKEY))
682663 let userNum = parseIntValue(userNumStr)
683664 let lockStart = height
684- let startBlockKEY = keyLockParamStartBlock(userNumStr)
685- let durationKEY = keyLockParamDuration(userNumStr)
686- let userAmountKEY = keyLockParamUserAmount(userNumStr)
687665 if (if ((minLockAmount > pmtAmount))
688- then (i.caller != lpStakingPoolsContract)
666+ then (userAddress != lpStakingPoolsContract)
689667 else false)
690668 then throwErr(("amount is less then minLockAmount=" + toString(minLockAmount)))
691669 else if ((minLockDuration > duration))
692- then throwErr(("passed duration is less then minLockDuration=" + toString(minLockDuration)))
670+ then throwErr(("passed duration is less than minLockDuration=" + toString(minLockDuration)))
693671 else if ((duration > maxLockDuration))
694- then throwErr(("passed duration is greater then maxLockDuration=" + toString(maxLockDuration)))
695- else if (if (userIsExisting)
696- then ((iof(this, startBlockKEY) + iof(this, durationKEY)) >= lockStart)
697- else false)
698- then throwErr("there is an active lock - consider to use increaseLock")
699- else if ((ioz(this, userAmountKEY) > 0))
700- then throwErr(("there are locked WXs - consider to use increaseLock " + userAmountKEY))
701- else {
702- let coeffX8 = fraction(duration, MULT8, maxLockDuration)
703- let gWxAmountStart = fraction(pmtAmount, coeffX8, MULT8)
704- let gWxParamsResultList = aal(invoke(mathContract, "calcGwxParamsREADONLY", [gWxAmountStart, lockStart, duration], nil))
705- let k = ai(gWxParamsResultList[0])
706- let b = ai(gWxParamsResultList[1])
707- let period = toString(ai(gWxParamsResultList[2]))
708- let totalCachedGwxRaw = getTotalCachedGwx(false)
709- let userBoostEmissionLastIntegralKEY = keyUserBoostEmissionLastINTEGRAL(userNumStr)
710- let boostEmissionIntegral = refreshBoostEmissionIntegral()._2
711- let arr = if (userIsExisting)
712- then nil
713- else [IntegerEntry(nextUserNumKEY, (userNum + 1)), StringEntry(keyUser2NumMapping(userAddressStr), userNumStr), StringEntry(keyNum2UserMapping(userNumStr), userAddressStr)]
714- $Tuple2(((((arr ++ LockParamsEntry(userAddressStr, userNumStr, pmtAmount, lockStart, duration, k, b, period)) ++ StatsEntry(pmtAmount, duration, 1, if (userIsExisting)
715- then 0
716- else 1)) :+ HistoryEntry("lock", userAddressStr, pmtAmount, lockStart, duration, k, b, i)) ++ [IntegerEntry(userBoostEmissionLastIntegralKEY, boostEmissionIntegral), IntegerEntry(keyTotalCachedGwx(), (totalCachedGwxRaw + gWxAmountStart))]), gWxAmountStart)
717- }
672+ then throwErr(("passed duration is greater than maxLockDuration=" + toString(maxLockDuration)))
673+ else if (((duration % lockStepBlocks) != 0))
674+ then throwErr(("duration must be multiple of lockStepBlocks=" + toString(lockStepBlocks)))
675+ else {
676+ let gWxAmountStart = fraction(pmtAmount, duration, maxLockDuration)
677+ let gwxAmountTotal = getGwxAmountTotal()
678+ let userBoostEmissionLastIntegralKEY = keyUserBoostEmissionLastINTEGRAL(userNum)
679+ let boostEmissionIntegral = refreshBoostEmissionIntegral()._2
680+ let userGwxAmountTotal = getUserGwxAmountTotal(userAddress)
681+ let gwxRewardInv = invoke(gwxRewardContract, "refreshUserReward", [userAddress.bytes, userNum], nil)
682+ if ((gwxRewardInv == gwxRewardInv))
683+ then {
684+ let arr = if (userIsExisting)
685+ then nil
686+ else [IntegerEntry(nextUserNumKEY, (userNum + 1)), StringEntry(keyUser2NumMapping(userAddressStr), userNumStr), StringEntry(keyNum2UserMapping(userNumStr), userAddressStr)]
687+ $Tuple2(((((arr ++ LockParamsEntry(userAddress, i.transactionId, pmtAmount, lockStart, duration, gWxAmountStart, 0)) ++ StatsEntry(pmtAmount, duration, 1, if (userIsExisting)
688+ then 0
689+ else 1)) :+ HistoryEntry("lock", userAddressStr, pmtAmount, lockStart, duration, gWxAmountStart, i)) ++ [IntegerEntry(userBoostEmissionLastIntegralKEY, boostEmissionIntegral), IntegerEntry(keyGwxTotal(), (gwxAmountTotal + gWxAmountStart)), IntegerEntry(keyUserGwxAmountTotal(userAddress), (userGwxAmountTotal + gWxAmountStart))]), gWxAmountStart)
690+ }
691+ else throw("Strict value is not equal to itself.")
692+ }
718693 }
719694 }
720695 }
721696
722697
698+func getWxWithdrawable (userAddress,txIdOption) = {
699+ let userRecordArray = readLockParamsRecordOrFail(userAddress, txIdOption)
700+ let userAmount = parseIntValue(userRecordArray[IdxLockAmount])
701+ let lockStart = parseIntValue(userRecordArray[IdxLockStart])
702+ let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
703+ let lockEnd = (lockStart + lockDuration)
704+ let wxClaimed = parseIntValue(userRecordArray[IdxLockWxClaimed])
705+ let t = ((height - lockStart) / blocksInPeriod)
706+ let exponent = fraction(toBigInt(t), (toBigInt((DECAY_CONSTANT * blocksInPeriod)) * MULT18BI), toBigInt(lockDuration))
707+ let wxWithdrawableTotal = if ((height > lockEnd))
708+ then userAmount
709+ else toInt(fraction(toBigInt(userAmount), (MULT18BI - pow(toBigInt(5), 1, exponent, SCALE18, SCALE18, DOWN)), MULT18BI))
710+ let wxWithdrawable = (wxWithdrawableTotal - wxClaimed)
711+ wxWithdrawable
712+ }
713+
714+
723715 @Callable(i)
724-func constructor (factoryAddressStr,lockAssetIdStr,minLockAmount,minDuration,maxDuration,mathContract) = {
725- let checkCaller = mustManager(i)
726- if ((checkCaller == checkCaller))
727- then ([IntegerEntry(keyNextUserNum(), 0), StringEntry(keyConfig(), formatConfig(lockAssetIdStr, minLockAmount, minDuration, maxDuration, mathContract)), StringEntry(keyFactoryAddress(), factoryAddressStr)] ++ StatsEntry(0, 0, 0, 0))
716+func lockRef (duration,referrerAddress,signature) = {
717+ let suspensionCheck = throwIfSuspended()
718+ if ((suspensionCheck == suspensionCheck))
719+ then {
720+ let $t02840028465 = lockActions(i, duration)
721+ let lockActionsResult = $t02840028465._1
722+ let gWxAmountStart = $t02840028465._2
723+ let referralAddress = toString(i.caller)
724+ let refInv = if (if ((referrerAddress == ""))
725+ then true
726+ else (signature == base58''))
727+ then unit
728+ else invoke(referralsContractAddressOrFail, "createPair", [referralProgramName, referrerAddress, referralAddress, signature], nil)
729+ if ((refInv == refInv))
730+ then {
731+ let updateRefActivity = invoke(mathContract, "updateReferralActivity", [toString(i.caller), gWxAmountStart], nil)
732+ if ((updateRefActivity == updateRefActivity))
733+ then $Tuple2(lockActionsResult, unit)
734+ else throw("Strict value is not equal to itself.")
735+ }
736+ else throw("Strict value is not equal to itself.")
737+ }
728738 else throw("Strict value is not equal to itself.")
729739 }
730740
731741
732742
733743 @Callable(i)
734-func lockRef (duration,referrerAddress,signature) = {
735- let $t03117031235 = lockActions(i, duration)
736- let lockActionsResult = $t03117031235._1
737- let gWxAmountStart = $t03117031235._2
738- let referralAddress = toString(i.caller)
739- let refInv = if (if ((referrerAddress == ""))
740- then true
741- else (signature == base58''))
742- then unit
743- else invoke(referralsContractAddressOrFail, "createPair", [referralProgramName, referrerAddress, referralAddress, signature], nil)
744- if ((refInv == refInv))
744+func lock (duration) = {
745+ let suspensionCheck = throwIfSuspended()
746+ if ((suspensionCheck == suspensionCheck))
745747 then {
748+ let $t02896929034 = lockActions(i, duration)
749+ let lockActionsResult = $t02896929034._1
750+ let gWxAmountStart = $t02896929034._2
746751 let updateRefActivity = invoke(mathContract, "updateReferralActivity", [toString(i.caller), gWxAmountStart], nil)
747752 if ((updateRefActivity == updateRefActivity))
748753 then $Tuple2(lockActionsResult, unit)
749754 else throw("Strict value is not equal to itself.")
750755 }
751756 else throw("Strict value is not equal to itself.")
752757 }
753758
754759
755760
756761 @Callable(i)
757-func lock (duration) = {
758- let $t03169331758 = lockActions(i, duration)
759- let lockActionsResult = $t03169331758._1
760- let gWxAmountStart = $t03169331758._2
761- let updateRefActivity = invoke(mathContract, "updateReferralActivity", [toString(i.caller), gWxAmountStart], nil)
762- if ((updateRefActivity == updateRefActivity))
763- then $Tuple2(lockActionsResult, unit)
762+func claimWxBoost (lpAssetIdStr,userAddressStr) = {
763+ let suspensionCheck = throwIfSuspended()
764+ if ((suspensionCheck == suspensionCheck))
765+ then if ((stakingContract != i.caller))
766+ then throwErr("permissions denied")
767+ else {
768+ let $t02939029492 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, false)
769+ let userBoostAvailable = $t02939029492._1
770+ let dataState = $t02939029492._2
771+ let debug = $t02939029492._3
772+ $Tuple2(dataState, [userBoostAvailable])
773+ }
764774 else throw("Strict value is not equal to itself.")
765775 }
766776
767777
768778
769779 @Callable(i)
770-func increaseLock (deltaDuration) = {
771- let cfgArray = readConfigArrayOrFail()
772- let assetIdStr = cfgArray[IdxCfgAssetId]
773- let assetId = fromBase58String(assetIdStr)
774- let minLockDuration = parseIntValue(cfgArray[IdxCfgMinLockDuration])
775- let maxLockDuration = parseIntValue(cfgArray[IdxCfgMaxLockDuration])
776- let pmtAmount = extractOptionalPaymentAmountOrFail(i, assetId)
777- let userAddressStr = toString(i.caller)
778- let userRecordArray = readLockParamsRecordOrFail(userAddressStr)
779- let userNumStr = userRecordArray[IdxLockUserNum]
780- let userAmount = parseIntValue(userRecordArray[IdxLockAmount])
781- let lockStart = parseIntValue(userRecordArray[IdxLockStart])
782- let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
783- let lockEnd = (lockStart + lockDuration)
784- let remainingDuration = max([(lockEnd - height), 0])
785- let userAmountNew = (userAmount + pmtAmount)
786- let lockDurationNew = (remainingDuration + deltaDuration)
787- if ((0 > deltaDuration))
788- then throwErr("duration is less then zero")
789- else if ((minLockDuration > lockDurationNew))
790- then throwErr(("lockDurationNew is less then minLockDuration=" + toString(minLockDuration)))
791- else if ((lockDurationNew > maxLockDuration))
792- then throwErr(("deltaDuration + existedLockDuration is greater then maxLockDuration=" + toString(maxLockDuration)))
793- else {
794- let coeffX8 = fraction(lockDurationNew, MULT8, maxLockDuration)
795- let gWxAmountStart = fraction(userAmountNew, coeffX8, MULT8)
796- let updateRefActivity = invoke(mathContract, "updateReferralActivity", [toString(i.caller), gWxAmountStart], nil)
797- if ((updateRefActivity == updateRefActivity))
798- then {
799- let lockStartNew = height
800- let gWxParamsResultList = aal(invoke(mathContract, "calcGwxParamsREADONLY", [gWxAmountStart, lockStartNew, lockDurationNew], nil))
801- let k = ai(gWxParamsResultList[0])
802- let b = ai(gWxParamsResultList[1])
803- let period = toString(ai(gWxParamsResultList[2]))
804- let currUserGwx = calcCurrentGwxAmount(userAddressStr)
805- let gwxDiff = (gWxAmountStart - currUserGwx)
806- if ((0 > gwxDiff))
807- then throwErr(("gwxDiff is less then 0: " + toString(gwxDiff)))
808- else {
809- let totalCachedGwxRaw = getTotalCachedGwx(false)
810- let totalCachedGwxCorrected = getTotalCachedGwx(true)
811- (((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))])
812- }
813- }
814- else throw("Strict value is not equal to itself.")
815- }
816- }
817-
818-
819-
820-@Callable(i)
821-func claimWxBoost (lpAssetIdStr,userAddressStr) = if ((stakingContract != i.caller))
822- then throwErr("permissions denied")
823- else {
824- let $t03486334965 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, false)
825- let userBoostAvailable = $t03486334965._1
826- let dataState = $t03486334965._2
827- let debug = $t03486334965._3
828- $Tuple2(dataState, [userBoostAvailable])
829- }
830-
831-
832-
833-@Callable(i)
834780 func claimWxBoostREADONLY (lpAssetIdStr,userAddressStr) = {
835- let $t03509735198 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, true)
836- let userBoostAvailable = $t03509735198._1
837- let dataState = $t03509735198._2
838- let debug = $t03509735198._3
781+ let $t02962429725 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, true)
782+ let userBoostAvailable = $t02962429725._1
783+ let dataState = $t02962429725._2
784+ let debug = $t02962429725._3
839785 $Tuple2(nil, [userBoostAvailable, debug])
840786 }
841787
842788
843789
844790 @Callable(i)
845-func unlock (userAddress) = {
846- let userRecordArray = readLockParamsRecordOrFail(userAddress)
847- let userNumStr = userRecordArray[IdxLockUserNum]
848- let userAmount = parseIntValue(userRecordArray[IdxLockAmount])
849- let lockStart = parseIntValue(userRecordArray[IdxLockStart])
850- let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
851- let lockEnd = (lockStart + lockDuration)
852- let cfgArray = readConfigArrayOrFail()
853- let assetId = fromBase58String(cfgArray[IdxCfgAssetId])
854- if ((lockEnd >= height))
855- then throwErr((("wait " + toString(lockEnd)) + " to unlock"))
856- else if ((0 >= userAmount))
857- then throwErr("nothing to unlock")
858- else {
859- let period = valueOrElse(getInteger(mathContract, keyNextPeriod()), 0)
860- (((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))
861- }
791+func unlock (txIdStr) = {
792+ let suspensionCheck = throwIfSuspended()
793+ if ((suspensionCheck == suspensionCheck))
794+ then {
795+ let userAddress = i.caller
796+ let userAddressStr = toString(userAddress)
797+ let txIdOption = if ((txIdStr == ""))
798+ then unit
799+ else fromBase58String(txIdStr)
800+ let userRecordArray = readLockParamsRecordOrFail(userAddress, txIdOption)
801+ let userAmount = parseIntValue(userRecordArray[IdxLockAmount])
802+ let lockStart = parseIntValue(userRecordArray[IdxLockStart])
803+ let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
804+ let wxClaimed = parseIntValue(userRecordArray[IdxLockWxClaimed])
805+ let gwxAmount = parseIntValue(userRecordArray[IdxLockGwxAmount])
806+ let t = ((height - lockStart) / blocksInPeriod)
807+ let wxWithdrawable = getWxWithdrawable(userAddress, txIdOption)
808+ let gwxBurned = min([fraction(wxWithdrawable, lockDuration, maxLockDuration), gwxAmount])
809+ let gwxRemaining = ensurePositive((gwxAmount - gwxBurned), "gwxRemaining")
810+ let lockedGwxAmount = getLockedGwxAmount(userAddress)
811+ if ((0 >= wxWithdrawable))
812+ then throwErr("nothing to unlock")
813+ else {
814+ let gwxAmountTotal = getGwxAmountTotal()
815+ let userGwxAmountTotal = getUserGwxAmountTotal(userAddress)
816+ let userGwxAmountTotalNew = ensurePositive((userGwxAmountTotal - gwxBurned), "userGwxAmountTotalNew")
817+ if ((lockedGwxAmount > userGwxAmountTotalNew))
818+ then throwErr(("locked gwx amount: " + toString(lockedGwxAmount)))
819+ else {
820+ let userNum = parseIntValue(valueOrErrorMessage(getString(keyUser2NumMapping(userAddressStr)), wrapErr("invalid user number")))
821+ let gwxRewardInv = invoke(gwxRewardContract, "refreshUserReward", [userAddress.bytes, userNum], nil)
822+ if ((gwxRewardInv == gwxRewardInv))
823+ then ((((LockParamsEntry(userAddress, txIdOption, userAmount, lockStart, lockDuration, gwxRemaining, (wxClaimed + wxWithdrawable)) ++ StatsEntry(-(wxWithdrawable), 0, 0, 0)) :+ HistoryEntry("unlock", userAddressStr, wxWithdrawable, lockStart, lockDuration, gwxBurned, i)) :+ ScriptTransfer(userAddress, wxWithdrawable, assetId)) ++ [IntegerEntry(keyGwxTotal(), ensurePositive((gwxAmountTotal - gwxBurned), "gwxTotal")), IntegerEntry(keyUserGwxAmountTotal(userAddress), userGwxAmountTotalNew)])
824+ else throw("Strict value is not equal to itself.")
825+ }
826+ }
827+ }
828+ else throw("Strict value is not equal to itself.")
862829 }
863830
864831
865832
866833 @Callable(i)
867-func gwxUserInfoREADONLY (userAddress) = {
868- let gwxAmount = calcCurrentGwxAmount(userAddress)
834+func gwxUserInfoREADONLY (userAddressStr) = {
835+ let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid user address"))
836+ let gwxAmount = getUserGwxAmountTotal(userAddress)
869837 $Tuple2(nil, [gwxAmount])
870838 }
871839
872840
873841
874842 @Callable(i)
875-func userMaxDurationREADONLY (userAddressStr) = {
876- let cfgArray = readConfigArrayOrFail()
877- let maxLockDuration = parseIntValue(cfgArray[IdxCfgMaxLockDuration])
878- let userRecordOption = getString(this, keyLockParamsRecord(userAddressStr))
879- if ((userRecordOption == unit))
880- then $Tuple2(nil, $Tuple2("lock", maxLockDuration))
881- else {
882- let userRecordArray = split(value(userRecordOption), SEP)
883- let lockStart = parseIntValue(userRecordArray[IdxLockStart])
884- let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
885- let lockEnd = (lockStart + lockDuration)
886- let remainingDuration = max([(lockEnd - height), 0])
887- let maxDeltaDuration = (maxLockDuration - remainingDuration)
888- $Tuple2(nil, $Tuple2("increaseLock", maxDeltaDuration))
889- }
890- }
843+func userMaxDurationREADONLY (userAddressStr) = $Tuple2(nil, $Tuple2("lock", maxLockDuration))
891844
892845
893846
894847 @Callable(i)
895-func getUserGwxAmountAtHeightREADONLY (userAddress,targetHeight) = {
896- let gwxAmount = calcUserGwxAmountAtHeight(userAddress, targetHeight)
848+func getUserGwxAmountAtHeightREADONLY (userAddressStr,targetHeight) = {
849+ let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid user address"))
850+ let gwxAmount = getUserGwxAmountTotal(userAddress)
897851 $Tuple2(nil, gwxAmount)
898852 }
899853
900854
901855
902856 @Callable(i)
903-func getTotalCachedGwxREADONLY () = $Tuple2(nil, getTotalCachedGwx(true))
857+func getUserGwxAmount (userAddressStr) = {
858+ let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid user address"))
859+ let gwxAmount = getUserGwxAmountTotal(userAddress)
860+ $Tuple2(nil, gwxAmount)
861+ }
862+
863+
864+
865+@Callable(i)
866+func getGwxTotalREADONLY () = $Tuple2(nil, getGwxAmountTotal())
904867
905868
906869
907870 @Callable(i)
908871 func onBoostEmissionUpdate () = {
909- let checkCaller = if ((i.caller == emissionContract))
910- then true
911- else mustManager(i)
912- if ((checkCaller == checkCaller))
913- then refreshBoostEmissionIntegral()
872+ let suspensionCheck = throwIfSuspended()
873+ if ((suspensionCheck == suspensionCheck))
874+ then {
875+ let checkCaller = if ((i.caller == emissionContract))
876+ then true
877+ else mustManager(i)
878+ if ((checkCaller == checkCaller))
879+ then refreshBoostEmissionIntegral()
880+ else throw("Strict value is not equal to itself.")
881+ }
914882 else throw("Strict value is not equal to itself.")
915883 }
916884
917885
918886
919887 @Callable(i)
920888 func onStakedVoteUpdate (lpAssetIdStr,userAddressStr,edge) = {
921- let checkCaller = if ((i.caller == stakingContract))
922- then true
923- else mustManager(i)
924- if ((checkCaller == checkCaller))
889+ let suspensionCheck = throwIfSuspended()
890+ if ((suspensionCheck == suspensionCheck))
925891 then {
926- let actions = refreshVoteStakedIntegral(lpAssetIdStr, userAddressStr, edge)
927- $Tuple2(actions, unit)
892+ let checkCaller = if ((i.caller == stakingContract))
893+ then true
894+ else mustManager(i)
895+ if ((checkCaller == checkCaller))
896+ then {
897+ let actions = refreshVoteStakedIntegral(lpAssetIdStr, userAddressStr, edge)
898+ $Tuple2(actions, unit)
899+ }
900+ else throw("Strict value is not equal to itself.")
928901 }
929902 else throw("Strict value is not equal to itself.")
930903 }
931904
932905
933906
934907 @Callable(i)
935908 func getVotingResultStakedREADONLY (lpAssetIdStr) = $Tuple2(nil, getVotingResultStaked(lpAssetIdStr))
936909
937910
938911
939912 @Callable(i)
940913 func getVotingResultStakedIntegralREADONLY (lpAssetIdStr) = $Tuple2(nil, getVotingResultStakedIntegral(lpAssetIdStr))
941914
942915
943916
944917 @Callable(i)
945918 func getUserVoteFinalizedREADONLY (lpAssetIdStr,userAddressStr) = $Tuple2(nil, getUserVoteFinalized(lpAssetIdStr, userAddressStr))
946919
947920
948921
949922 @Callable(i)
950923 func getUserVoteStakedIntegralREADONLY (lpAssetIdStr,userAddressStr) = $Tuple2(nil, getUserVoteStakedIntegral(lpAssetIdStr, userAddressStr))
951924
952925
926+
927+@Callable(i)
928+func suspend (v) = {
929+ let checkCaller = mustManager(i)
930+ if ((checkCaller == checkCaller))
931+ then $Tuple2([BooleanEntry(keySuspension, v)], v)
932+ else throw("Strict value is not equal to itself.")
933+ }
934+
935+
953936 @Verifier(tx)
954937 func verify () = {
955938 let targetPublicKey = match managerPublicKeyOrUnit() {
956939 case pk: ByteVector =>
957940 pk
958941 case _: Unit =>
959942 tx.senderPublicKey
960943 case _ =>
961944 throw("Match error")
962945 }
963946 sigVerify(tx.bodyBytes, tx.proofs[0], targetPublicKey)
964947 }
965948

github/deemru/w8io/3ef1775 
266.90 ms