tx · 5izKXppfmhfDmuwJgSTaKuoXBSKL46hU5tXYvF5K4KFn 3MyN19SDzDpXyEtabWvag2P5mkeFrdFVd4h: -0.01900000 Waves 2022.10.12 01:52 [2268311] smart account 3MyN19SDzDpXyEtabWvag2P5mkeFrdFVd4h > SELF 0.00000000 Waves
{ "type": 13, "id": "5izKXppfmhfDmuwJgSTaKuoXBSKL46hU5tXYvF5K4KFn", "fee": 1900000, "feeAssetId": null, "timestamp": 1665528833718, "version": 2, "chainId": 84, "sender": "3MyN19SDzDpXyEtabWvag2P5mkeFrdFVd4h", "senderPublicKey": "4HqqczFwZHAsxp1oNq8dQkRStfCKBL79X99icQ2B6FYn", "proofs": [ "5f17cbQobhVAPcFtg8NBswaDaGkwVgGmkE7YscL2X4DdBkFHbJo1wqp6fcZF78c298L8Fxf2vyZSQTYdrfz8PzRU" ], "script": "base64:BgIlCAISBQoDAQgIEgASABIDCgEBEgASABIAEgMKAQgSBAoCCAESAE4AC3JldmlzaW9uTnVtAgAACXNlcGFyYXRvcgICX18AA1NFUAICX18ABU1VTFQ2AMCEPQAFTVVMVDgAgMLXLwAGTVVMVFg2CQC2AgEFBU1VTFQ2AAZNVUxUWDgJALYCAQUFTVVMVDgAB01VTFRYMTgJALYCAQCAgJC7utat8A0ACVVTRE5JRFNUUgIEVVNETgAGVVNETklECQDZBAEFCVVTRE5JRFNUUgAZSWR4Q29udHJvbENmZ05ldXRyaW5vRGFwcAABABhJZHhDb250cm9sQ2ZnQXVjdGlvbkRhcHAAAgAUSWR4Q29udHJvbENmZ1JwZERhcHAAAwAVSWR4Q29udHJvbENmZ01hdGhEYXBwAAQAHElkeENvbnRyb2xDZmdMaXF1aWRhdGlvbkRhcHAABQAVSWR4Q29udHJvbENmZ1Jlc3REYXBwAAYAHUlkeENvbnRyb2xDZmdOb2RlUmVnaXN0cnlEYXBwAAcAHElkeENvbnRyb2xDZmdOc2J0U3Rha2luZ0RhcHAACAAZSWR4Q29udHJvbENmZ01lZGlhdG9yRGFwcAAJABxJZHhDb250cm9sQ2ZnU3VyZlN0YWtpbmdEYXBwAAoAIElkeENvbnRyb2xDZmdHbnNidENvbnRyb2xsZXJEYXBwAAsBD2dldFN0cmluZ09yRmFpbAIHYWRkcmVzcwNrZXkJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBQdhZGRyZXNzBQNrZXkJAKwCAgkArAICCQCsAgIJAKwCAgIKbWFuZGF0b3J5IAkApQgBBQdhZGRyZXNzAgEuBQNrZXkCDyBpcyBub3QgZGVmaW5lZAERa2V5Q29udHJvbEFkZHJlc3MAAhwlcyVzX19jb25maWdfX2NvbnRyb2xBZGRyZXNzAQ1rZXlDb250cm9sQ2ZnAAIRJXNfX2NvbnRyb2xDb25maWcBFHJlYWRDb250cm9sQ2ZnT3JGYWlsAQdjb250cm9sCQC1CQIJAQ9nZXRTdHJpbmdPckZhaWwCBQdjb250cm9sCQENa2V5Q29udHJvbENmZwAFA1NFUAEYZ2V0Q29udHJhY3RBZGRyZXNzT3JGYWlsAgpjb250cm9sQ2ZnA2lkeAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJAJEDAgUKY29udHJvbENmZwUDaWR4CQCsAgICLUNvbnRyb2wgY2ZnIGRvZXNuJ3QgY29udGFpbiBhZGRyZXNzIGF0IGluZGV4IAkApAMBBQNpZHgAD2NvbnRyb2xDb250cmFjdAkBEUBleHRyTmF0aXZlKDEwNjIpAQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzCQERa2V5Q29udHJvbEFkZHJlc3MAAiMzUDVCZmQ1OFBQZk52Qk0ySHk4UWZiY0RxTWVOdHpnN0tmUAAKY29udHJvbENmZwkBFHJlYWRDb250cm9sQ2ZnT3JGYWlsAQUPY29udHJvbENvbnRyYWN0AAxtYXRoQ29udHJhY3QJARhnZXRDb250cmFjdEFkZHJlc3NPckZhaWwCBQpjb250cm9sQ2ZnBRVJZHhDb250cm9sQ2ZnTWF0aERhcHAAEG5ldXRyaW5vQ29udHJhY3QJARhnZXRDb250cmFjdEFkZHJlc3NPckZhaWwCBQpjb250cm9sQ2ZnBRlJZHhDb250cm9sQ2ZnTmV1dHJpbm9EYXBwAA9hdWN0aW9uQ29udHJhY3QJARhnZXRDb250cmFjdEFkZHJlc3NPckZhaWwCBQpjb250cm9sQ2ZnBRhJZHhDb250cm9sQ2ZnQXVjdGlvbkRhcHABDGtleUJvbmRBc3NldAACDWJvbmRfYXNzZXRfaWQBGWtleUF1Y3Rpb25Db250cmFjdEFkZHJlc3MAAhBhdWN0aW9uX2NvbnRyYWN0ARBrZXlNaW5Mb2NrQW1vdW50AAIRJXNfX21pbkxvY2tBbW91bnQBEGtleVN0YWtlZEFzc2V0SWQAAhElc19fc3Rha2VkQXNzZXRJZAEWa2V5TG9ja1BhcmFtVXNlckFtb3VudAELdXNlckFkZHJlc3MJALkJAgkAzAgCAgYlcyVzJXMJAMwIAgILcGFyYW1CeVVzZXIJAMwIAgkApQgBBQt1c2VyQWRkcmVzcwkAzAgCAgZhbW91bnQFA25pbAUJc2VwYXJhdG9yARZrZXlMb2NrUGFyYW1TdGFydEJsb2NrAQt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBiVzJXMlcwkAzAgCAgtwYXJhbUJ5VXNlcgkAzAgCCQClCAEFC3VzZXJBZGRyZXNzCQDMCAICBXN0YXJ0BQNuaWwFCXNlcGFyYXRvcgEma2V5TG9ja1BhcmFtVm90aW5nUG93ZXJFZmZlY3RpdmVIZWlnaHQBC3VzZXJBZGRyZXNzCQC5CQIJAMwIAgIGJXMlcyVzCQDMCAICC3BhcmFtQnlVc2VyCQDMCAIJAKUIAQULdXNlckFkZHJlc3MJAMwIAgIRdnBFZmZlY3RpdmVIZWlnaHQFA25pbAUJc2VwYXJhdG9yARBrZXlIaXN0b3J5UmVjb3JkAwR0eXBlC3VzZXJBZGRyZXNzBHR4SWQJALkJAgkAzAgCAgglcyVzJXMlcwkAzAgCAgdoaXN0b3J5CQDMCAIFBHR5cGUJAMwIAgkApQgBBQt1c2VyQWRkcmVzcwkAzAgCCQDYBAEFBHR4SWQFA25pbAUJc2VwYXJhdG9yARdrZXlMb2NrUGFyYW1Ub3RhbEFtb3VudAAJALkJAgkAzAgCAgQlcyVzCQDMCAICBXN0YXRzCQDMCAICEWFjdGl2ZVRvdGFsTG9ja2VkBQNuaWwFCXNlcGFyYXRvcgESa2V5U3RhdHNMb2Nrc0NvdW50AAkAuQkCCQDMCAICBCVzJXMJAMwIAgIFc3RhdHMJAMwIAgIKbG9ja3NDb3VudAUDbmlsBQlzZXBhcmF0b3IBEmtleVN0YXRzVXNlcnNDb3VudAAJALkJAgkAzAgCAgQlcyVzCQDMCAICBXN0YXRzCQDMCAICEGFjdGl2ZVVzZXJzQ291bnQFA25pbAUJc2VwYXJhdG9yAQ1rZXlOZXh0UGVyaW9kAAIOJXNfX25leHRQZXJpb2QBGGtleVN1cHBvcnRlZFJld2FyZEFzc2V0cwACFXN1cHBvcnRlZFJld2FyZEFzc2V0cwERa2V5RGVwb3NpdE51bUxhc3QACQC5CQIJAMwIAgIGJXMlcyVzCQDMCAICA2RlcAkAzAgCAgdsYXN0TnVtBQNuaWwFCXNlcGFyYXRvcgEba2V5VXNlclJld2FyZEZyb21EZXBvc2l0TnVtAQt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBiVzJXMlcwkAzAgCAhF1c2VyUndkRnJvbURlcE51bQkAzAgCBQt1c2VyQWRkcmVzcwUDbmlsBQlzZXBhcmF0b3IBFWtleVJld2FyZFBlck5zYnRTdW1BdAIKZGVwb3NpdE51bQN0a24JALkJAgkAzAgCAgQlcyVkCQDMCAICFXJ3ZFBlck5zYnRTdW1CeURlcE51bQkAzAgCCQCkAwEFCmRlcG9zaXROdW0JAMwIAgUDdGtuBQNuaWwFCXNlcGFyYXRvcgEJa2V5UmV3YXJkAgt1c2VyQWRkcmVzcwN0a24JALkJAgkAzAgCAgYlcyVzJXMJAMwIAgIDcndkCQDMCAIFC3VzZXJBZGRyZXNzCQDMCAIFA3RrbgUDbmlsBQlzZXBhcmF0b3IBCmtleUNsYWltZWQCC3VzZXJBZGRyZXNzA3RrbgkAuQkCCQDMCAICBiVzJXMlcwkAzAgCAgNjbG0JAMwIAgULdXNlckFkZHJlc3MJAMwIAgUDdGtuBQNuaWwFCXNlcGFyYXRvcgEXa2V5Tm90RGlzdHJpYnV0ZWRSZXdhcmQBA3RrbgkAuQkCCQDMCAICBCVzJXMJAMwIAgIObm90RGlzdHJpYnV0ZWQJAMwIAgUDdGtuBQNuaWwFCXNlcGFyYXRvcgEFdG9YMTgCB29yaWdWYWwIb3JpZ011bHQJALwCAwkAtgIBBQdvcmlnVmFsBQdNVUxUWDE4BQhvcmlnTXVsdAEMZ2V0SW50T3JaZXJvAQNrZXkJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwUDa2V5AAABDGdldEludE9yRWxzZQIDa2V5CmRlZmF1bHRWYWwJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwUDa2V5BQpkZWZhdWx0VmFsAQxnZXRJbnRPckZhaWwBA2tleQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFBHRoaXMFA2tleQkArAICCQCsAgICD01hbmRhdG9yeSB0aGlzLgUDa2V5Ag8gaXMgbm90IGRlZmluZWQBDGdldFN0ck9yRWxzZQIDa2V5CmRlZmF1bHRWYWwJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwUDa2V5BQpkZWZhdWx0VmFsAQ90b0FkZHJlc3NPckZhaWwBCmFkZHJlc3NTdHIJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBBQphZGRyZXNzU3RyCQCsAgICIWNvdWxkbid0IHBhcnNlIHBhc3NlZCBhZGRyZXNzU3RyPQUKYWRkcmVzc1N0cgELdG9Bc3NldFZlY3QBCGFzc2V0U3RyAwkAAAIFCGFzc2V0U3RyBQlVU0ROSURTVFIFBHVuaXQJANkEAQUIYXNzZXRTdHIBBWFzSW50AQN2YWwEByRtYXRjaDAFA3ZhbAMJAAECBQckbWF0Y2gwAgNJbnQEBnZhbEludAUHJG1hdGNoMAUGdmFsSW50CQACAQIVZmFpbCB0byBjYXN0IGludG8gSW50ARJhc1N3YXBQYXJhbXNTVFJVQ1QBAXYEByRtYXRjaDAFAXYDCQABAgUHJG1hdGNoMAIjKEludCwgSW50LCBJbnQsIEludCwgSW50LCBJbnQsIEludCkEBnN0cnVjdAUHJG1hdGNoMAUGc3RydWN0CQACAQIVZmFpbCB0byBjYXN0IGludG8gSW50ARNmb3JtYXRIaXN0b3J5UmVjb3JkBAlvbGRBbW91bnQIb2xkU3RhcnQJbmV3QW1vdW50CG5ld1N0YXJ0CQC5CQIJAMwIAgIMJWQlZCVkJWQlZCVkCQDMCAIJAKQDAQgFCWxhc3RCbG9jawZoZWlnaHQJAMwIAgkApAMBCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAkAzAgCCQCkAwEFCW9sZEFtb3VudAkAzAgCCQCkAwEFCG9sZFN0YXJ0CQDMCAIJAKQDAQUJbmV3QW1vdW50CQDMCAIJAKQDAQUIbmV3U3RhcnQFA25pbAUJc2VwYXJhdG9yARhmb3JtYXRDbGFpbUhpc3RvcnlSZWNvcmQCBHVzZXIOY2xhaW1lZFJld2FyZHMJALkJAgkAzAgCAgglcyVkJWQlcwkAzAgCBQR1c2VyCQDMCAIJAKQDAQgFCWxhc3RCbG9jawZoZWlnaHQJAMwIAgkApAMBCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAkAzAgCBQ5jbGFpbWVkUmV3YXJkcwUDbmlsBQlzZXBhcmF0b3IBEkhpc3RvcnlSZWNvcmRFbnRyeQcEdHlwZQt1c2VyQWRkcmVzcwR0eElkCW9sZEFtb3VudAhvbGRTdGFydAluZXdBbW91bnQIbmV3U3RhcnQJAQtTdHJpbmdFbnRyeQIJARBrZXlIaXN0b3J5UmVjb3JkAwUEdHlwZQULdXNlckFkZHJlc3MFBHR4SWQJARNmb3JtYXRIaXN0b3J5UmVjb3JkBAUJb2xkQW1vdW50BQhvbGRTdGFydAUJbmV3QW1vdW50BQhuZXdTdGFydAERQ2xhaW1IaXN0b3J5RW50cnkDC3VzZXJBZGRyZXNzBHR4SWQOY2xhaW1lZFJld2FyZHMJAQtTdHJpbmdFbnRyeQIJARBrZXlIaXN0b3J5UmVjb3JkAwIFY2xhaW0FC3VzZXJBZGRyZXNzBQR0eElkCQEYZm9ybWF0Q2xhaW1IaXN0b3J5UmVjb3JkAgkApQgBBQt1c2VyQWRkcmVzcwUOY2xhaW1lZFJld2FyZHMBC1N0YXRzUmVzdWx0Aw50b3RhbExvY2tlZEluYwxsb2NrQ291bnRJbmMNdXNlcnNDb3VudEluYwQKbG9ja3NDb3VudAkBDGdldEludE9yWmVybwEJARJrZXlTdGF0c0xvY2tzQ291bnQABAp1c2Vyc0NvdW50CQEMZ2V0SW50T3JaZXJvAQkBEmtleVN0YXRzVXNlcnNDb3VudAAEC3RvdGFsQW1vdW50CQEMZ2V0SW50T3JaZXJvAQkBF2tleUxvY2tQYXJhbVRvdGFsQW1vdW50AAQOdG90YWxBbW91bnROZXcJAGQCBQt0b3RhbEFtb3VudAUOdG90YWxMb2NrZWRJbmMJAJUKAwkAzAgCCQEMSW50ZWdlckVudHJ5AgkBEmtleVN0YXRzTG9ja3NDb3VudAAJAGQCBQpsb2Nrc0NvdW50BQxsb2NrQ291bnRJbmMJAMwIAgkBDEludGVnZXJFbnRyeQIJARJrZXlTdGF0c1VzZXJzQ291bnQACQBkAgUKdXNlcnNDb3VudAUNdXNlcnNDb3VudEluYwkAzAgCCQEMSW50ZWdlckVudHJ5AgkBF2tleUxvY2tQYXJhbVRvdGFsQW1vdW50AAUOdG90YWxBbW91bnROZXcFA25pbAULdG90YWxBbW91bnQFDnRvdGFsQW1vdW50TmV3AQ9Mb2NrUGFyYW1zRW50cnkDC3VzZXJBZGRyZXNzBmFtb3VudBp2b3RpbmdQb3dlckVmZmVjdGl2ZUhlaWdodAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBFmtleUxvY2tQYXJhbVVzZXJBbW91bnQBBQt1c2VyQWRkcmVzcwUGYW1vdW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEWa2V5TG9ja1BhcmFtU3RhcnRCbG9jawEFC3VzZXJBZGRyZXNzBRp2b3RpbmdQb3dlckVmZmVjdGl2ZUhlaWdodAUDbmlsAQ9nZXRQYXJhbXNPckZhaWwACQCUCgIJANkEAQkBD2dldFN0cmluZ09yRmFpbAIFBHRoaXMJARBrZXlTdGFrZWRBc3NldElkAAkBDGdldEludE9yRmFpbAEJARBrZXlNaW5Mb2NrQW1vdW50AAEMaXNBY3RpdmVVc2VyAQt1c2VyQWRkcmVzcwkAZgIJAQxnZXRJbnRPckVsc2UCCQEWa2V5TG9ja1BhcmFtVXNlckFtb3VudAEFC3VzZXJBZGRyZXNzAAAAAAETZ2V0VXNlclBhcmFtc09yVW5pdAELdXNlckFkZHJlc3MDCQEMaXNBY3RpdmVVc2VyAQULdXNlckFkZHJlc3MJAJUKAwcJAQxnZXRJbnRPckZhaWwBCQEWa2V5TG9ja1BhcmFtVXNlckFtb3VudAEFC3VzZXJBZGRyZXNzCQEMZ2V0SW50T3JGYWlsAQkBFmtleUxvY2tQYXJhbVN0YXJ0QmxvY2sBBQt1c2VyQWRkcmVzcwUEdW5pdAETZ2V0VXNlclBhcmFtc09yRmFpbAELdXNlckFkZHJlc3MJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkBE2dldFVzZXJQYXJhbXNPclVuaXQBBQt1c2VyQWRkcmVzcwkArAICCQCsAgICBVVzZXIgCQClCAEFC3VzZXJBZGRyZXNzAg8gaXMgbm90IGRlZmluZWQAEnN1cHBvcnRlZEFzc2V0c1N0cgkBDGdldFN0ck9yRWxzZQIJARhrZXlTdXBwb3J0ZWRSZXdhcmRBc3NldHMAAgAAE3N1cHBvcnRlZEFzc2V0c0xpc3QJALUJAgUSc3VwcG9ydGVkQXNzZXRzU3RyAgFfAQpjYWxjUmV3YXJkBQt1c2VyQWRkcmVzcwdhc3NldElkDXN0YWtlZEFtb3VudFgOZGVwb3NpdE51bVVzZXIOZGVwb3NpdE51bUxhc3QEF3Jld2FyZFBlck5zYnRTdW1MYXN0S0VZCQEVa2V5UmV3YXJkUGVyTnNidFN1bUF0AgUOZGVwb3NpdE51bUxhc3QFB2Fzc2V0SWQECnN1bUxhc3RYMTgJAKcDAQkBDGdldFN0ck9yRWxzZQIJARVrZXlSZXdhcmRQZXJOc2J0U3VtQXQCBQ5kZXBvc2l0TnVtTGFzdAUHYXNzZXRJZAIBMAQKc3VtVXNlclgxOAkApwMBCQEMZ2V0U3RyT3JFbHNlAgkBFWtleVJld2FyZFBlck5zYnRTdW1BdAIFDmRlcG9zaXROdW1Vc2VyBQdhc3NldElkAgEwBBFyZXdhcmREeW5hbWljUGFydAkAoAMBCQC8AgMJALgCAgUKc3VtTGFzdFgxOAUKc3VtVXNlclgxOAUNc3Rha2VkQW1vdW50WAUHTVVMVFgxOAQTcmV3YXJkQ2FjaGVkUGFydEtFWQkBCWtleVJld2FyZAIFC3VzZXJBZGRyZXNzBQdhc3NldElkBBByZXdhcmRDYWNoZWRQYXJ0CQEMZ2V0SW50T3JFbHNlAgUTcmV3YXJkQ2FjaGVkUGFydEtFWQAACQCWCgQJAGQCBRByZXdhcmRDYWNoZWRQYXJ0BRFyZXdhcmREeW5hbWljUGFydAUQcmV3YXJkQ2FjaGVkUGFydAURcmV3YXJkRHluYW1pY1BhcnQFE3Jld2FyZENhY2hlZFBhcnRLRVkBDVJld2FyZEVudHJpZXMDCWlzTmV3VXNlcgt1c2VyQWRkcmVzcwxzdGFrZWRBbW91bnQEDXN0YWtlZEFtb3VudFgJALYCAQUMc3Rha2VkQW1vdW50BBt1c2VyUmV3YXJkRnJvbURlcG9zaXROdW1LRVkJARtrZXlVc2VyUmV3YXJkRnJvbURlcG9zaXROdW0BBQt1c2VyQWRkcmVzcwQOZGVwb3NpdE51bVVzZXIJAQxnZXRJbnRPckVsc2UCBRt1c2VyUmV3YXJkRnJvbURlcG9zaXROdW1LRVkA////////////AQQOZGVwb3NpdE51bUxhc3QJAQxnZXRJbnRPckVsc2UCCQERa2V5RGVwb3NpdE51bUxhc3QAAP///////////wEKARtmb3JFYWNoQXNzZXRDYWNoZVVzZXJSZXdhcmQCBWFjY3VtBWFzc2V0BAskdDA4Nzk3ODkzMgkBCmNhbGNSZXdhcmQFBQt1c2VyQWRkcmVzcwUFYXNzZXQFDXN0YWtlZEFtb3VudFgFDmRlcG9zaXROdW1Vc2VyBQ5kZXBvc2l0TnVtTGFzdAQLcmV3YXJkVG90YWwIBQskdDA4Nzk3ODkzMgJfMQQGY2FjaGVkCAULJHQwODc5Nzg5MzICXzIEB2R5bmFtaWMIBQskdDA4Nzk3ODkzMgJfMwQTcmV3YXJkQ2FjaGVkUGFydEtFWQgFCyR0MDg3OTc4OTMyAl80CQDNCAIFBWFjY3VtCQEMSW50ZWdlckVudHJ5AgUTcmV3YXJkQ2FjaGVkUGFydEtFWQULcmV3YXJkVG90YWwDAwkAAAIFDmRlcG9zaXROdW1MYXN0AP///////////wEJAAACBQ5kZXBvc2l0TnVtVXNlcgD///////////8BBwUDbmlsAwMJAAACBQ5kZXBvc2l0TnVtTGFzdAD///////////8BCQBmAgUOZGVwb3NpdE51bVVzZXIA////////////AQcJAAIBAi9pbnZhbGlkIGRlcG9zaXROdW1MYXN0IGFuZCBkZXBvc2l0TnVtVXNlciBzdGF0ZQMDCQBmAgUOZGVwb3NpdE51bUxhc3QA////////////AQkAZwIFDmRlcG9zaXROdW1Vc2VyAP///////////wEHAwUJaXNOZXdVc2VyCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRt1c2VyUmV3YXJkRnJvbURlcG9zaXROdW1LRVkFDmRlcG9zaXROdW1MYXN0BQNuaWwJAM0IAgoAAiRsBRNzdXBwb3J0ZWRBc3NldHNMaXN0CgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARtmb3JFYWNoQXNzZXRDYWNoZVVzZXJSZXdhcmQCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoJAQxJbnRlZ2VyRW50cnkCBRt1c2VyUmV3YXJkRnJvbURlcG9zaXROdW1LRVkFDmRlcG9zaXROdW1MYXN0CQACAQkArAICCQCsAgIJAKwCAgIkdW5jb3ZlcmVkIGNvbmRpdGlvbjogZGVwb3NpdE51bUxhc3Q9CQCkAwEFDmRlcG9zaXROdW1MYXN0AhAgZGVwb3NpdE51bVVzZXI9CQCkAwEFDmRlcG9zaXROdW1Vc2VyASJJbmNyZW1lbnROb3REaXN0cmlidXRlZFJld2FyZEVudHJ5AgN0a24JYW1vdW50SW5jBBdub3REaXN0cmlidXRlZFJld2FyZEtFWQkBF2tleU5vdERpc3RyaWJ1dGVkUmV3YXJkAQUDdGtuBBRub3REaXN0cmlidXRlZFJld2FyZAkBDGdldEludE9yRWxzZQIFF25vdERpc3RyaWJ1dGVkUmV3YXJkS0VZAAAJAMwIAgkBDEludGVnZXJFbnRyeQIFF25vdERpc3RyaWJ1dGVkUmV3YXJkS0VZCQBkAgUUbm90RGlzdHJpYnV0ZWRSZXdhcmQFCWFtb3VudEluYwUDbmlsAR9tZXJnZVZvdGluZ1Bvd2VyRWZmZWN0aXZlSGVpZ2h0BBBxdWFyYW50aW5lUGVyaW9kEXZwRWZmZWN0aXZlSGVpZ2h0CXN0YWtlZEFtdAxzdGFrZWRBbXRORVcED3JlbWFpbmluZ1RvV2FpdAkAZQIFEXZwRWZmZWN0aXZlSGVpZ2h0BQZoZWlnaHQDCQBnAgAABQ9yZW1haW5pbmdUb1dhaXQJAGQCBQZoZWlnaHQFEHF1YXJhbnRpbmVQZXJpb2QEDWFscmVhZHlXYWl0ZWQJAGUCBRBxdWFyYW50aW5lUGVyaW9kBQ9yZW1haW5pbmdUb1dhaXQEA2tYOAMJAQIhPQIFDHN0YWtlZEFtdE5FVwAACQBrAwUJc3Rha2VkQW10BQVNVUxUOAUMc3Rha2VkQW10TkVXBRF2cEVmZmVjdGl2ZUhlaWdodAkAZQIJAGQCBRBxdWFyYW50aW5lUGVyaW9kBQZoZWlnaHQJAGsDBQ1hbHJlYWR5V2FpdGVkBQNrWDgFBU1VTFQ4AQptZXJnZVN0YWtlAgt1c2VyQWRkcmVzcwthbW91bnRUb0FkZAQNJHQwMTI1MTcxMjYyNwkBC3ZhbHVlT3JFbHNlAgkBE2dldFVzZXJQYXJhbXNPclVuaXQBBQt1c2VyQWRkcmVzcwkAlQoDBgAAAAAECWlzTmV3VXNlcggFDSR0MDEyNTE3MTI2MjcCXzEEDHN0YWtlZEFtb3VudAgFDSR0MDEyNTE3MTI2MjcCXzIEEXZwRWZmZWN0aXZlSGVpZ2h0CAUNJHQwMTI1MTcxMjYyNwJfMwQPc3Rha2VkQW1vdW50TkVXAwUJaXNOZXdVc2VyBQthbW91bnRUb0FkZAkAZAIFC2Ftb3VudFRvQWRkBQxzdGFrZWRBbW91bnQEEHF1YXJhbnRpbmVQZXJpb2QJAGgCAKALAA4EFHZwRWZmZWN0aXZlSGVpZ2h0TkVXAwUJaXNOZXdVc2VyCQBkAgUQcXVhcmFudGluZVBlcmlvZAUGaGVpZ2h0CQEfbWVyZ2VWb3RpbmdQb3dlckVmZmVjdGl2ZUhlaWdodAQFEHF1YXJhbnRpbmVQZXJpb2QFEXZwRWZmZWN0aXZlSGVpZ2h0BQxzdGFrZWRBbW91bnQFD3N0YWtlZEFtb3VudE5FVwkAlwoFBQlpc05ld1VzZXIFDHN0YWtlZEFtb3VudAURdnBFZmZlY3RpdmVIZWlnaHQFD3N0YWtlZEFtb3VudE5FVwUUdnBFZmZlY3RpdmVIZWlnaHRORVcBC2NvbW1vblN0YWtlAgt1c2VyQWRkcmVzcwFpBA0kdDAxMzExMzEzMTY3CQEPZ2V0UGFyYW1zT3JGYWlsAAQNc3Rha2VkQXNzZXRJZAgFDSR0MDEzMTEzMTMxNjcCXzEEDW1pbkxvY2tBbW91bnQIBQ0kdDAxMzExMzEzMTY3Al8yAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwABCQACAQIVSW52YWxpZCBwYXltZW50cyBzaXplBAdwYXltZW50CQCRAwIIBQFpCHBheW1lbnRzAAAEBmFtb3VudAgFB3BheW1lbnQGYW1vdW50BBNpbnZhbGlkQXNzZXRNZXNzYWdlCQCsAgIJAKwCAgIPSW52YWxpZCBhc3NldC4gCQDYBAEFDXN0YWtlZEFzc2V0SWQCDCBpcyBleHBlY3RlZAQHYXNzZXRJZAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCAUHcGF5bWVudAdhc3NldElkBRNpbnZhbGlkQXNzZXRNZXNzYWdlAwkBAiE9AgUHYXNzZXRJZAUNc3Rha2VkQXNzZXRJZAkAAgEFE2ludmFsaWRBc3NldE1lc3NhZ2UEDnVzZXJBZGRyZXNzU3RyCQClCAEFC3VzZXJBZGRyZXNzBAptZXJnZWREYXRhCQEKbWVyZ2VTdGFrZQIFC3VzZXJBZGRyZXNzBQZhbW91bnQECWlzTmV3VXNlcggFCm1lcmdlZERhdGECXzEEDHN0YWtlZEFtb3VudAgFCm1lcmdlZERhdGECXzIEEXZwRWZmZWN0aXZlSGVpZ2h0CAUKbWVyZ2VkRGF0YQJfMwQPc3Rha2VkQW1vdW50TkVXCAUKbWVyZ2VkRGF0YQJfNAQUdnBFZmZlY3RpdmVIZWlnaHRORVcIBQptZXJnZWREYXRhAl81AwkAZgIFDW1pbkxvY2tBbW91bnQFD3N0YWtlZEFtb3VudE5FVwkAAgEJAKwCAgITTWluIGxvY2sgYW1vdW50IGlzIAkApAMBBQ1taW5Mb2NrQW1vdW50BA0kdDAxMzk2NjE0MDY4CQELU3RhdHNSZXN1bHQDBQZhbW91bnQAAQMFCWlzTmV3VXNlcgABAAAEDHN0YXRzRW50cmllcwgFDSR0MDEzOTY2MTQwNjgCXzEEC3RvdGFsU3Rha2VkCAUNJHQwMTM5NjYxNDA2OAJfMgQOdG90YWxTdGFrZWROZXcIBQ0kdDAxMzk2NjE0MDY4Al8zCQDOCAIJAM4IAgkAzggCCQDMCAIJARJIaXN0b3J5UmVjb3JkRW50cnkHAgVzdGFrZQULdXNlckFkZHJlc3MIBQFpDXRyYW5zYWN0aW9uSWQFDHN0YWtlZEFtb3VudAURdnBFZmZlY3RpdmVIZWlnaHQFD3N0YWtlZEFtb3VudE5FVwUUdnBFZmZlY3RpdmVIZWlnaHRORVcFA25pbAkBDVJld2FyZEVudHJpZXMDBQlpc05ld1VzZXIFDnVzZXJBZGRyZXNzU3RyBQxzdGFrZWRBbW91bnQJAQ9Mb2NrUGFyYW1zRW50cnkDBQt1c2VyQWRkcmVzcwUPc3Rha2VkQW1vdW50TkVXBRR2cEVmZmVjdGl2ZUhlaWdodE5FVwUMc3RhdHNFbnRyaWVzAQtjb21tb25DbGFpbQILdXNlckFkZHJlc3MBaQQOdXNlckFkZHJlc3NTdHIJAKUIAQULdXNlckFkZHJlc3MDCQBmAgkAkAMBCAUBaQhwYXltZW50cwAACQACAQIZcGF5bWVudHMgYXJlIG5vdCBhY2NlcHRlZAQNJHQwMTQ1NDcxNDY1MgkBC3ZhbHVlT3JFbHNlAgkBE2dldFVzZXJQYXJhbXNPclVuaXQBBQt1c2VyQWRkcmVzcwkAlQoDBgAAAAAECWlzTmV3VXNlcggFDSR0MDE0NTQ3MTQ2NTICXzEEDHN0YWtlZEFtb3VudAgFDSR0MDE0NTQ3MTQ2NTICXzIEDHN0YWtpbmdTdGFydAgFDSR0MDE0NTQ3MTQ2NTICXzMEDXN0YWtlZEFtb3VudFgJALYCAQUMc3Rha2VkQW1vdW50BBt1c2VyUmV3YXJkRnJvbURlcG9zaXROdW1LRVkJARtrZXlVc2VyUmV3YXJkRnJvbURlcG9zaXROdW0BBQ51c2VyQWRkcmVzc1N0cgQOZGVwb3NpdE51bVVzZXIJAQxnZXRJbnRPckVsc2UCBRt1c2VyUmV3YXJkRnJvbURlcG9zaXROdW1LRVkA////////////AQQOZGVwb3NpdE51bUxhc3QJAQxnZXRJbnRPckVsc2UCCQERa2V5RGVwb3NpdE51bUxhc3QAAP///////////wEKAR9mb3JFYWNoQXNzZXRDYWxjVW5jbGFpbWVkUmV3YXJkAgVhY2N1bQVhc3NldAQNJHQwMTUwMjMxNTE2MQkBCmNhbGNSZXdhcmQFBQ51c2VyQWRkcmVzc1N0cgUFYXNzZXQFDXN0YWtlZEFtb3VudFgFDmRlcG9zaXROdW1Vc2VyBQ5kZXBvc2l0TnVtTGFzdAQLcmV3YXJkVG90YWwIBQ0kdDAxNTAyMzE1MTYxAl8xBAZjYWNoZWQIBQ0kdDAxNTAyMzE1MTYxAl8yBAdkeW5hbWljCAUNJHQwMTUwMjMxNTE2MQJfMwQTcmV3YXJkQ2FjaGVkUGFydEtFWQgFDSR0MDE1MDIzMTUxNjECXzQECmNsYWltZWRLRVkJAQprZXlDbGFpbWVkAgUOdXNlckFkZHJlc3NTdHIFBWFzc2V0BA0kdDAxNTIyMTE1MjU4BQVhY2N1bQQEZGF0YQgFDSR0MDE1MjIxMTUyNTgCXzEEEWNsYWltZWRBbXRCeUFzc2V0CAUNJHQwMTUyMjExNTI1OAJfMgQHbmV3UGFydAkAuQkCCQDMCAIFBWFzc2V0CQDMCAIJAKQDAQULcmV3YXJkVG90YWwFA25pbAIBOgQUY2xhaW1lZEFtdEJ5QXNzZXROZXcJALkJAgkAzAgCBRFjbGFpbWVkQW10QnlBc3NldAkAzAgCBQduZXdQYXJ0BQNuaWwCAV8DCQBnAgAABQtyZXdhcmRUb3RhbAkAlAoCBQRkYXRhBRRjbGFpbWVkQW10QnlBc3NldE5ldwkAlAoCCQDNCAIJAM0IAgkAzQgCBQRkYXRhCQEOU2NyaXB0VHJhbnNmZXIDBQt1c2VyQWRkcmVzcwULcmV3YXJkVG90YWwJAQt0b0Fzc2V0VmVjdAEFBWFzc2V0CQEMSW50ZWdlckVudHJ5AgUKY2xhaW1lZEtFWQkAZAIJAQt2YWx1ZU9yRWxzZQIJAJ8IAQUKY2xhaW1lZEtFWQAABQtyZXdhcmRUb3RhbAkBDEludGVnZXJFbnRyeQIFE3Jld2FyZENhY2hlZFBhcnRLRVkAAAUUY2xhaW1lZEFtdEJ5QXNzZXROZXcEDSR0MDE1NzE4MTU4MzIKAAIkbAUTc3VwcG9ydGVkQXNzZXRzTGlzdAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAJAJQKAgUDbmlsAgAKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBH2ZvckVhY2hBc3NldENhbGNVbmNsYWltZWRSZXdhcmQCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoECXRyYW5zZmVycwgFDSR0MDE1NzE4MTU4MzICXzEEF2NsYWltZWRBbXRCeUFzc2V0UmVzdWx0CAUNJHQwMTU3MTgxNTgzMgJfMgMJAGcCAAAJAJADAQUJdHJhbnNmZXJzBQNuaWwJAM0IAgkAzQgCBQl0cmFuc2ZlcnMJAQxJbnRlZ2VyRW50cnkCBRt1c2VyUmV3YXJkRnJvbURlcG9zaXROdW1LRVkFDmRlcG9zaXROdW1MYXN0CQERQ2xhaW1IaXN0b3J5RW50cnkDBQt1c2VyQWRkcmVzcwgFAWkNdHJhbnNhY3Rpb25JZAkAsAICBRdjbGFpbWVkQW10QnlBc3NldFJlc3VsdAABCgFpAQtjb25zdHJ1Y3RvcgMNbWluTG9ja0Ftb3VudBVzdXBwb3J0ZWRSZXdhcmRBc3NldHMNc3Rha2VkQXNzZXRJZAMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECEVBlcm1pc3Npb24gZGVuaWVkCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEQa2V5TWluTG9ja0Ftb3VudAAFDW1pbkxvY2tBbW91bnQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBGGtleVN1cHBvcnRlZFJld2FyZEFzc2V0cwAFFXN1cHBvcnRlZFJld2FyZEFzc2V0cwkAzAgCCQELU3RyaW5nRW50cnkCCQEQa2V5U3Rha2VkQXNzZXRJZAAFDXN0YWtlZEFzc2V0SWQFA25pbAFpAQVzdGFrZQAJAQtjb21tb25TdGFrZQIIBQFpBmNhbGxlcgUBaQFpARNzdGFrZUJ5T3JpZ2luQ2FsbGVyAAkBC2NvbW1vblN0YWtlAggFAWkMb3JpZ2luQ2FsbGVyBQFpAWkBB3Vuc3Rha2UBBmFtb3VudAMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAAkAAgECI3Vuc3Rha2UgZG9lc24ndCByZXF1aXJlIGFueSBwYXltZW50BAt1c2VyQWRkcmVzcwgFAWkGY2FsbGVyBA51c2VyQWRkcmVzc1N0cgkApQgBBQt1c2VyQWRkcmVzcwQNJHQwMTY3NDExNjc5NQkBD2dldFBhcmFtc09yRmFpbAAEDXN0YWtlZEFzc2V0SWQIBQ0kdDAxNjc0MTE2Nzk1Al8xBA1taW5Mb2NrQW1vdW50CAUNJHQwMTY3NDExNjc5NQJfMgQNJHQwMTY3OTgxNjg4MgkBE2dldFVzZXJQYXJhbXNPckZhaWwBBQt1c2VyQWRkcmVzcwQJaXNOZXdVc2VyCAUNJHQwMTY3OTgxNjg4MgJfMQQMc3Rha2VkQW1vdW50CAUNJHQwMTY3OTgxNjg4MgJfMgQRdnBFZmZlY3RpdmVIZWlnaHQIBQ0kdDAxNjc5ODE2ODgyAl8zBBBzd2FwUGFyYW1zU1RSVUNUCQESYXNTd2FwUGFyYW1zU1RSVUNUAQkA/QcEBRBuZXV0cmlub0NvbnRyYWN0Ahtzd2FwUGFyYW1zQnlVc2VyU1lTUkVBRE9OTFkJAMwIAgUOdXNlckFkZHJlc3NTdHIJAMwIAgAABQNuaWwFA25pbAQUc3dhcExpbWl0U3BlbnRJblVzZG4IBRBzd2FwUGFyYW1zU1RSVUNUAl8yBA5ibGNrczJMbXRSZXNldAgFEHN3YXBQYXJhbXNTVFJVQ1QCXzMDCQBmAgUUc3dhcExpbWl0U3BlbnRJblVzZG4AAAkAAgEJAKwCAgkArAICAi1Zb3UgaGF2ZSBhbHJlYWR5IG1hZGUgYSBzd2FwIG9wZXJhdGlvbi4gV2FpdCAJAKQDAQkAZAIFBmhlaWdodAUOYmxja3MyTG10UmVzZXQCEiBoZWlnaHQgdG8gdW5zdGFrZQMJAGcCAAAFDHN0YWtlZEFtb3VudAkAAgECEk5vdGhpbmcgdG8gdW5zdGFrZQMJAGYCBQZhbW91bnQFDHN0YWtlZEFtb3VudAkAAgEJAKwCAgkArAICCQCsAgICClJlcXVlc3RlZCAJAKQDAQUGYW1vdW50AhIsIGJ1dCBzdGFrZWQgb25seSAJAKQDAQUMc3Rha2VkQW1vdW50BA9zdGFrZWRBbW91bnRORVcJAGUCBQxzdGFrZWRBbW91bnQFBmFtb3VudAQNJHQwMTc1MjAxNzY3OAkBC1N0YXRzUmVzdWx0AwkBAS0BBQZhbW91bnQDCQAAAgUGYW1vdW50BQxzdGFrZWRBbW91bnQA////////////AQAAAwkAAAIFBmFtb3VudAUMc3Rha2VkQW1vdW50AP///////////wEAAAQMc3RhdHNFbnRyaWVzCAUNJHQwMTc1MjAxNzY3OAJfMQQLdG90YWxTdGFrZWQIBQ0kdDAxNzUyMDE3Njc4Al8yBA50b3RhbFN0YWtlZE5ldwgFDSR0MDE3NTIwMTc2NzgCXzMJAM4IAgkAzggCCQDOCAIJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwULdXNlckFkZHJlc3MFBmFtb3VudAUNc3Rha2VkQXNzZXRJZAkAzAgCCQESSGlzdG9yeVJlY29yZEVudHJ5BwIHdW5zdGFrZQULdXNlckFkZHJlc3MIBQFpDXRyYW5zYWN0aW9uSWQFDHN0YWtlZEFtb3VudAURdnBFZmZlY3RpdmVIZWlnaHQFD3N0YWtlZEFtb3VudE5FVwURdnBFZmZlY3RpdmVIZWlnaHQFA25pbAkBDVJld2FyZEVudHJpZXMDBwUOdXNlckFkZHJlc3NTdHIFDHN0YWtlZEFtb3VudAkBD0xvY2tQYXJhbXNFbnRyeQMFC3VzZXJBZGRyZXNzBQ9zdGFrZWRBbW91bnRORVcFEXZwRWZmZWN0aXZlSGVpZ2h0BQxzdGF0c0VudHJpZXMBaQEHZGVwb3NpdAADCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAEJAAIBAh9leGFjdCAxIHBheW1lbnQgaXMgYWxsb3dlZCBvbmx5BANwbXQJAJEDAggFAWkIcGF5bWVudHMAAAQGYW1vdW50CAUDcG10BmFtb3VudAQKcG10QXNzZXRJZAkBC3ZhbHVlT3JFbHNlAggFA3BtdAdhc3NldElkBQZVU0ROSUQEDXBtdEFzc2V0SWRTdHIJANgEAQUKcG10QXNzZXRJZAQIcG10TXVsdFgDCQAAAgUKcG10QXNzZXRJZAUGVVNETklEBQZNVUxUWDgFBk1VTFRYNgQHYW1vdW50WAkAtgIBBQZhbW91bnQEC3RvdGFsU3Rha2VkCQEMZ2V0SW50T3JFbHNlAgkBF2tleUxvY2tQYXJhbVRvdGFsQW1vdW50AAAABAx0b3RhbFN0YWtlZFgJALYCAQULdG90YWxTdGFrZWQDCQBmAgAABQt0b3RhbFN0YWtlZAkAAgECG1RPRE86IGNhc2UgaXMgbm90IHN1cHBvcnRlZAMJAAACBQt0b3RhbFN0YWtlZAAACQEiSW5jcmVtZW50Tm90RGlzdHJpYnV0ZWRSZXdhcmRFbnRyeQIFDXBtdEFzc2V0SWRTdHIFBmFtb3VudAQQcmV3YXJkUGVyTnNidFgxOAkAvAIDBQdhbW91bnRYBQdNVUxUWDE4BQx0b3RhbFN0YWtlZFgEEWRlcG9zaXROdW1MYXN0S0VZCQERa2V5RGVwb3NpdE51bUxhc3QABA5kZXBvc2l0TnVtTGFzdAkBDGdldEludE9yRWxzZQIFEWRlcG9zaXROdW1MYXN0S0VZAP///////////wEEDWRlcG9zaXROdW1OZXcJAGQCBQ5kZXBvc2l0TnVtTGFzdAABAwkBASEBCQEIY29udGFpbnMCBRJzdXBwb3J0ZWRBc3NldHNTdHIFDXBtdEFzc2V0SWRTdHIJAAIBCQCsAgIJAKwCAgUSc3VwcG9ydGVkQXNzZXRzU3RyAhEgZG9lc24ndCBjb250YWluIAUNcG10QXNzZXRJZFN0cgoBF3JlZnJlc2hSZXdhcmRQZXJOc2J0U1VNAgVhY2N1bQluZXh0QXNzZXQEFnJld2FyZFBlck5zYnRTdW1OZXdLRVkJARVrZXlSZXdhcmRQZXJOc2J0U3VtQXQCBQ1kZXBvc2l0TnVtTmV3BQluZXh0QXNzZXQECnN1bUxhc3RTdHIJAQxnZXRTdHJPckVsc2UCCQEVa2V5UmV3YXJkUGVyTnNidFN1bUF0AgUOZGVwb3NpdE51bUxhc3QFCW5leHRBc3NldAIBMAkAzQgCBQVhY2N1bQMJAAACBQluZXh0QXNzZXQFDXBtdEFzc2V0SWRTdHIJAQtTdHJpbmdFbnRyeQIFFnJld2FyZFBlck5zYnRTdW1OZXdLRVkJAKYDAQkAtwICCQCnAwEFCnN1bUxhc3RTdHIFEHJld2FyZFBlck5zYnRYMTgJAQtTdHJpbmdFbnRyeQIFFnJld2FyZFBlck5zYnRTdW1OZXdLRVkFCnN1bUxhc3RTdHIJAM0IAgoAAiRsBRNzdXBwb3J0ZWRBc3NldHNMaXN0CgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARdyZWZyZXNoUmV3YXJkUGVyTnNidFNVTQIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgkBDEludGVnZXJFbnRyeQIFEWRlcG9zaXROdW1MYXN0S0VZBQ1kZXBvc2l0TnVtTmV3AWkBDGNsYWltUmV3YXJkcwAJAQtjb21tb25DbGFpbQIIBQFpBmNhbGxlcgUBaQFpARpjbGFpbVJld2FyZHNCeU9yaWdpbkNhbGxlcgAJAQtjb21tb25DbGFpbQIIBQFpDG9yaWdpbkNhbGxlcgUBaQFpARh1bmNsYWltZWRSZXdhcmRzUkVBRE9OTFkBDnVzZXJBZGRyZXNzU3RyCgEWZm9yRWFjaEFzc2V0WmVyb1Jld2FyZAIFYWNjdW0FYXNzZXQJAKwCAgkArAICBQVhY2N1bQkAuQkCCQDMCAIFBWFzc2V0CQDMCAICATAJAMwIAgIBMAUDbmlsAgE6AgFfBBJ1bmNsYWltZWRSZXdhcmRTdHIDCQAAAgUOdXNlckFkZHJlc3NTdHICAAoAAiRsBRNzdXBwb3J0ZWRBc3NldHNMaXN0CgACJHMJAJADAQUCJGwKAAUkYWNjMAIACgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARZmb3JFYWNoQXNzZXRaZXJvUmV3YXJkAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKBAt1c2VyQWRkcmVzcwkBEUBleHRyTmF0aXZlKDEwNjIpAQUOdXNlckFkZHJlc3NTdHIEDSR0MDIwMjUwMjAzNTUJAQt2YWx1ZU9yRWxzZQIJARNnZXRVc2VyUGFyYW1zT3JVbml0AQULdXNlckFkZHJlc3MJAJUKAwYAAAAABAlpc05ld1VzZXIIBQ0kdDAyMDI1MDIwMzU1Al8xBAxzdGFrZWRBbW91bnQIBQ0kdDAyMDI1MDIwMzU1Al8yBAxzdGFraW5nU3RhcnQIBQ0kdDAyMDI1MDIwMzU1Al8zBA1zdGFrZWRBbW91bnRYCQC2AgEFDHN0YWtlZEFtb3VudAQbdXNlclJld2FyZEZyb21EZXBvc2l0TnVtS0VZCQEba2V5VXNlclJld2FyZEZyb21EZXBvc2l0TnVtAQUOdXNlckFkZHJlc3NTdHIEDmRlcG9zaXROdW1Vc2VyCQEMZ2V0SW50T3JFbHNlAgUbdXNlclJld2FyZEZyb21EZXBvc2l0TnVtS0VZAP///////////wEEDmRlcG9zaXROdW1MYXN0CQEMZ2V0SW50T3JFbHNlAgkBEWtleURlcG9zaXROdW1MYXN0AAD///////////8BCgEfZm9yRWFjaEFzc2V0Q2FsY1VuY2xhaW1lZFJld2FyZAIFYWNjdW0FYXNzZXQEDSR0MDIwNzAxMjA4MzkJAQpjYWxjUmV3YXJkBQUOdXNlckFkZHJlc3NTdHIFBWFzc2V0BQ1zdGFrZWRBbW91bnRYBQ5kZXBvc2l0TnVtVXNlcgUOZGVwb3NpdE51bUxhc3QEC3Jld2FyZFRvdGFsCAUNJHQwMjA3MDEyMDgzOQJfMQQGY2FjaGVkCAUNJHQwMjA3MDEyMDgzOQJfMgQHZHluYW1pYwgFDSR0MDIwNzAxMjA4MzkCXzMEE3Jld2FyZENhY2hlZFBhcnRLRVkIBQ0kdDAyMDcwMTIwODM5Al80BAdjbGFpbWVkCQELdmFsdWVPckVsc2UCCQCfCAEJAQprZXlDbGFpbWVkAgUOdXNlckFkZHJlc3NTdHIFBWFzc2V0AAAJAKwCAgkArAICBQVhY2N1bQkAuQkCCQDMCAIFBWFzc2V0CQDMCAIJAKQDAQULcmV3YXJkVG90YWwJAMwIAgkApAMBBQdjbGFpbWVkBQNuaWwCAToCAV8KAAIkbAUTc3VwcG9ydGVkQXNzZXRzTGlzdAoAAiRzCQCQAwEFAiRsCgAFJGFjYzACAAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEfZm9yRWFjaEFzc2V0Q2FsY1VuY2xhaW1lZFJld2FyZAIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgkAlAoCBQNuaWwJALMCAgUSdW5jbGFpbWVkUmV3YXJkU3RyAAEBaQEWdXNkblN0YWtpbmdTWVNSRUFET05MWQIVdXNlckFkZHJlc3NTdHJPckVtcHR5CHVzZG5EaWZmBAl1c2RuVG90YWwJAQxnZXRJbnRPckVsc2UCCQEXa2V5TG9ja1BhcmFtVG90YWxBbW91bnQAAAADCQAAAgUVdXNlckFkZHJlc3NTdHJPckVtcHR5AgAJAJQKAgUDbmlsCQDMCAIAAAkAzAgCBQl1c2RuVG90YWwJAMwIAgAACQDMCAIAAAkAzAgCAAAJAMwIAgUGaGVpZ2h0CQDMCAIFBmhlaWdodAUDbmlsBAt1c2VyQWRkcmVzcwkBD3RvQWRkcmVzc09yRmFpbAEFFXVzZXJBZGRyZXNzU3RyT3JFbXB0eQQKbWVyZ2VkRGF0YQkBCm1lcmdlU3Rha2UCBQt1c2VyQWRkcmVzcwUIdXNkbkRpZmYECWlzTmV3VXNlcggFCm1lcmdlZERhdGECXzEEDHN0YWtlZEFtb3VudAgFCm1lcmdlZERhdGECXzIEEXZwRWZmZWN0aXZlSGVpZ2h0CAUKbWVyZ2VkRGF0YQJfMwQPc3Rha2VkQW1vdW50TkVXCAUKbWVyZ2VkRGF0YQJfNAQUdnBFZmZlY3RpdmVIZWlnaHRORVcIBQptZXJnZWREYXRhAl81BAh1c2RuVXNlcgUMc3Rha2VkQW1vdW50CQCUCgIFA25pbAkAzAgCBQh1c2RuVXNlcgkAzAgCBQl1c2RuVG90YWwJAMwIAgAACQDMCAIAAAkAzAgCBRF2cEVmZmVjdGl2ZUhlaWdodAkAzAgCBRR2cEVmZmVjdGl2ZUhlaWdodE5FVwUDbmlsAWkBEWNvbmZpZ1NZU1JFQURPTkxZAAQKbWluTG9ja0FtdAkBEUBleHRyTmF0aXZlKDEwNTUpAQkBEGtleU1pbkxvY2tBbW91bnQACQCUCgIFA25pbAkAzAgCBQptaW5Mb2NrQW10BQNuaWwAXx1Q8w==", "height": 2268311, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: none Next: E3yMgRXnYujy2oV8W5LDv98PeUamSkJTT1ZuDPSXTS8W Full:
Old | New | Differences | |
---|---|---|---|
1 | - | # no script | |
1 | + | {-# STDLIB_VERSION 6 #-} | |
2 | + | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | + | {-# CONTENT_TYPE DAPP #-} | |
4 | + | let revisionNum = "" | |
5 | + | ||
6 | + | let separator = "__" | |
7 | + | ||
8 | + | let SEP = "__" | |
9 | + | ||
10 | + | let MULT6 = 1000000 | |
11 | + | ||
12 | + | let MULT8 = 100000000 | |
13 | + | ||
14 | + | let MULTX6 = toBigInt(MULT6) | |
15 | + | ||
16 | + | let MULTX8 = toBigInt(MULT8) | |
17 | + | ||
18 | + | let MULTX18 = toBigInt(1000000000000000000) | |
19 | + | ||
20 | + | let USDNIDSTR = "USDN" | |
21 | + | ||
22 | + | let USDNID = fromBase58String(USDNIDSTR) | |
23 | + | ||
24 | + | let IdxControlCfgNeutrinoDapp = 1 | |
25 | + | ||
26 | + | let IdxControlCfgAuctionDapp = 2 | |
27 | + | ||
28 | + | let IdxControlCfgRpdDapp = 3 | |
29 | + | ||
30 | + | let IdxControlCfgMathDapp = 4 | |
31 | + | ||
32 | + | let IdxControlCfgLiquidationDapp = 5 | |
33 | + | ||
34 | + | let IdxControlCfgRestDapp = 6 | |
35 | + | ||
36 | + | let IdxControlCfgNodeRegistryDapp = 7 | |
37 | + | ||
38 | + | let IdxControlCfgNsbtStakingDapp = 8 | |
39 | + | ||
40 | + | let IdxControlCfgMediatorDapp = 9 | |
41 | + | ||
42 | + | let IdxControlCfgSurfStakingDapp = 10 | |
43 | + | ||
44 | + | let IdxControlCfgGnsbtControllerDapp = 11 | |
45 | + | ||
46 | + | func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), (((("mandatory " + toString(address)) + ".") + key) + " is not defined")) | |
47 | + | ||
48 | + | ||
49 | + | func keyControlAddress () = "%s%s__config__controlAddress" | |
50 | + | ||
51 | + | ||
52 | + | func keyControlCfg () = "%s__controlConfig" | |
53 | + | ||
54 | + | ||
55 | + | func readControlCfgOrFail (control) = split(getStringOrFail(control, keyControlCfg()), SEP) | |
56 | + | ||
57 | + | ||
58 | + | func getContractAddressOrFail (controlCfg,idx) = valueOrErrorMessage(addressFromString(controlCfg[idx]), ("Control cfg doesn't contain address at index " + toString(idx))) | |
59 | + | ||
60 | + | ||
61 | + | let controlContract = addressFromStringValue(valueOrElse(getString(this, keyControlAddress()), "3P5Bfd58PPfNvBM2Hy8QfbcDqMeNtzg7KfP")) | |
62 | + | ||
63 | + | let controlCfg = readControlCfgOrFail(controlContract) | |
64 | + | ||
65 | + | let mathContract = getContractAddressOrFail(controlCfg, IdxControlCfgMathDapp) | |
66 | + | ||
67 | + | let neutrinoContract = getContractAddressOrFail(controlCfg, IdxControlCfgNeutrinoDapp) | |
68 | + | ||
69 | + | let auctionContract = getContractAddressOrFail(controlCfg, IdxControlCfgAuctionDapp) | |
70 | + | ||
71 | + | func keyBondAsset () = "bond_asset_id" | |
72 | + | ||
73 | + | ||
74 | + | func keyAuctionContractAddress () = "auction_contract" | |
75 | + | ||
76 | + | ||
77 | + | func keyMinLockAmount () = "%s__minLockAmount" | |
78 | + | ||
79 | + | ||
80 | + | func keyStakedAssetId () = "%s__stakedAssetId" | |
81 | + | ||
82 | + | ||
83 | + | func keyLockParamUserAmount (userAddress) = makeString(["%s%s%s", "paramByUser", toString(userAddress), "amount"], separator) | |
84 | + | ||
85 | + | ||
86 | + | func keyLockParamStartBlock (userAddress) = makeString(["%s%s%s", "paramByUser", toString(userAddress), "start"], separator) | |
87 | + | ||
88 | + | ||
89 | + | func keyLockParamVotingPowerEffectiveHeight (userAddress) = makeString(["%s%s%s", "paramByUser", toString(userAddress), "vpEffectiveHeight"], separator) | |
90 | + | ||
91 | + | ||
92 | + | func keyHistoryRecord (type,userAddress,txId) = makeString(["%s%s%s%s", "history", type, toString(userAddress), toBase58String(txId)], separator) | |
93 | + | ||
94 | + | ||
95 | + | func keyLockParamTotalAmount () = makeString(["%s%s", "stats", "activeTotalLocked"], separator) | |
96 | + | ||
97 | + | ||
98 | + | func keyStatsLocksCount () = makeString(["%s%s", "stats", "locksCount"], separator) | |
99 | + | ||
100 | + | ||
101 | + | func keyStatsUsersCount () = makeString(["%s%s", "stats", "activeUsersCount"], separator) | |
102 | + | ||
103 | + | ||
104 | + | func keyNextPeriod () = "%s__nextPeriod" | |
105 | + | ||
106 | + | ||
107 | + | func keySupportedRewardAssets () = "supportedRewardAssets" | |
108 | + | ||
109 | + | ||
110 | + | func keyDepositNumLast () = makeString(["%s%s%s", "dep", "lastNum"], separator) | |
111 | + | ||
112 | + | ||
113 | + | func keyUserRewardFromDepositNum (userAddress) = makeString(["%s%s%s", "userRwdFromDepNum", userAddress], separator) | |
114 | + | ||
115 | + | ||
116 | + | func keyRewardPerNsbtSumAt (depositNum,tkn) = makeString(["%s%d", "rwdPerNsbtSumByDepNum", toString(depositNum), tkn], separator) | |
117 | + | ||
118 | + | ||
119 | + | func keyReward (userAddress,tkn) = makeString(["%s%s%s", "rwd", userAddress, tkn], separator) | |
120 | + | ||
121 | + | ||
122 | + | func keyClaimed (userAddress,tkn) = makeString(["%s%s%s", "clm", userAddress, tkn], separator) | |
123 | + | ||
124 | + | ||
125 | + | func keyNotDistributedReward (tkn) = makeString(["%s%s", "notDistributed", tkn], separator) | |
126 | + | ||
127 | + | ||
128 | + | func toX18 (origVal,origMult) = fraction(toBigInt(origVal), MULTX18, origMult) | |
129 | + | ||
130 | + | ||
131 | + | func getIntOrZero (key) = valueOrElse(getInteger(this, key), 0) | |
132 | + | ||
133 | + | ||
134 | + | func getIntOrElse (key,defaultVal) = valueOrElse(getInteger(this, key), defaultVal) | |
135 | + | ||
136 | + | ||
137 | + | func getIntOrFail (key) = valueOrErrorMessage(getInteger(this, key), (("Mandatory this." + key) + " is not defined")) | |
138 | + | ||
139 | + | ||
140 | + | func getStrOrElse (key,defaultVal) = valueOrElse(getString(this, key), defaultVal) | |
141 | + | ||
142 | + | ||
143 | + | func toAddressOrFail (addressStr) = valueOrErrorMessage(addressFromString(addressStr), ("couldn't parse passed addressStr=" + addressStr)) | |
144 | + | ||
145 | + | ||
146 | + | func toAssetVect (assetStr) = if ((assetStr == USDNIDSTR)) | |
147 | + | then unit | |
148 | + | else fromBase58String(assetStr) | |
149 | + | ||
150 | + | ||
151 | + | func asInt (val) = match val { | |
152 | + | case valInt: Int => | |
153 | + | valInt | |
154 | + | case _ => | |
155 | + | throw("fail to cast into Int") | |
156 | + | } | |
157 | + | ||
158 | + | ||
159 | + | func asSwapParamsSTRUCT (v) = match v { | |
160 | + | case struct: (Int, Int, Int, Int, Int, Int, Int) => | |
161 | + | struct | |
162 | + | case _ => | |
163 | + | throw("fail to cast into Int") | |
164 | + | } | |
165 | + | ||
166 | + | ||
167 | + | func formatHistoryRecord (oldAmount,oldStart,newAmount,newStart) = makeString(["%d%d%d%d%d%d", toString(lastBlock.height), toString(lastBlock.timestamp), toString(oldAmount), toString(oldStart), toString(newAmount), toString(newStart)], separator) | |
168 | + | ||
169 | + | ||
170 | + | func formatClaimHistoryRecord (user,claimedRewards) = makeString(["%s%d%d%s", user, toString(lastBlock.height), toString(lastBlock.timestamp), claimedRewards], separator) | |
171 | + | ||
172 | + | ||
173 | + | func HistoryRecordEntry (type,userAddress,txId,oldAmount,oldStart,newAmount,newStart) = StringEntry(keyHistoryRecord(type, userAddress, txId), formatHistoryRecord(oldAmount, oldStart, newAmount, newStart)) | |
174 | + | ||
175 | + | ||
176 | + | func ClaimHistoryEntry (userAddress,txId,claimedRewards) = StringEntry(keyHistoryRecord("claim", userAddress, txId), formatClaimHistoryRecord(toString(userAddress), claimedRewards)) | |
177 | + | ||
178 | + | ||
179 | + | func StatsResult (totalLockedInc,lockCountInc,usersCountInc) = { | |
180 | + | let locksCount = getIntOrZero(keyStatsLocksCount()) | |
181 | + | let usersCount = getIntOrZero(keyStatsUsersCount()) | |
182 | + | let totalAmount = getIntOrZero(keyLockParamTotalAmount()) | |
183 | + | let totalAmountNew = (totalAmount + totalLockedInc) | |
184 | + | $Tuple3([IntegerEntry(keyStatsLocksCount(), (locksCount + lockCountInc)), IntegerEntry(keyStatsUsersCount(), (usersCount + usersCountInc)), IntegerEntry(keyLockParamTotalAmount(), totalAmountNew)], totalAmount, totalAmountNew) | |
185 | + | } | |
186 | + | ||
187 | + | ||
188 | + | func LockParamsEntry (userAddress,amount,votingPowerEffectiveHeight) = [IntegerEntry(keyLockParamUserAmount(userAddress), amount), IntegerEntry(keyLockParamStartBlock(userAddress), votingPowerEffectiveHeight)] | |
189 | + | ||
190 | + | ||
191 | + | func getParamsOrFail () = $Tuple2(fromBase58String(getStringOrFail(this, keyStakedAssetId())), getIntOrFail(keyMinLockAmount())) | |
192 | + | ||
193 | + | ||
194 | + | func isActiveUser (userAddress) = (getIntOrElse(keyLockParamUserAmount(userAddress), 0) > 0) | |
195 | + | ||
196 | + | ||
197 | + | func getUserParamsOrUnit (userAddress) = if (isActiveUser(userAddress)) | |
198 | + | then $Tuple3(false, getIntOrFail(keyLockParamUserAmount(userAddress)), getIntOrFail(keyLockParamStartBlock(userAddress))) | |
199 | + | else unit | |
200 | + | ||
201 | + | ||
202 | + | func getUserParamsOrFail (userAddress) = valueOrErrorMessage(getUserParamsOrUnit(userAddress), (("User " + toString(userAddress)) + " is not defined")) | |
203 | + | ||
204 | + | ||
205 | + | let supportedAssetsStr = getStrOrElse(keySupportedRewardAssets(), "") | |
206 | + | ||
207 | + | let supportedAssetsList = split(supportedAssetsStr, "_") | |
208 | + | ||
209 | + | func calcReward (userAddress,assetId,stakedAmountX,depositNumUser,depositNumLast) = { | |
210 | + | let rewardPerNsbtSumLastKEY = keyRewardPerNsbtSumAt(depositNumLast, assetId) | |
211 | + | let sumLastX18 = parseBigIntValue(getStrOrElse(keyRewardPerNsbtSumAt(depositNumLast, assetId), "0")) | |
212 | + | let sumUserX18 = parseBigIntValue(getStrOrElse(keyRewardPerNsbtSumAt(depositNumUser, assetId), "0")) | |
213 | + | let rewardDynamicPart = toInt(fraction((sumLastX18 - sumUserX18), stakedAmountX, MULTX18)) | |
214 | + | let rewardCachedPartKEY = keyReward(userAddress, assetId) | |
215 | + | let rewardCachedPart = getIntOrElse(rewardCachedPartKEY, 0) | |
216 | + | $Tuple4((rewardCachedPart + rewardDynamicPart), rewardCachedPart, rewardDynamicPart, rewardCachedPartKEY) | |
217 | + | } | |
218 | + | ||
219 | + | ||
220 | + | func RewardEntries (isNewUser,userAddress,stakedAmount) = { | |
221 | + | let stakedAmountX = toBigInt(stakedAmount) | |
222 | + | let userRewardFromDepositNumKEY = keyUserRewardFromDepositNum(userAddress) | |
223 | + | let depositNumUser = getIntOrElse(userRewardFromDepositNumKEY, -1) | |
224 | + | let depositNumLast = getIntOrElse(keyDepositNumLast(), -1) | |
225 | + | func forEachAssetCacheUserReward (accum,asset) = { | |
226 | + | let $t087978932 = calcReward(userAddress, asset, stakedAmountX, depositNumUser, depositNumLast) | |
227 | + | let rewardTotal = $t087978932._1 | |
228 | + | let cached = $t087978932._2 | |
229 | + | let dynamic = $t087978932._3 | |
230 | + | let rewardCachedPartKEY = $t087978932._4 | |
231 | + | (accum :+ IntegerEntry(rewardCachedPartKEY, rewardTotal)) | |
232 | + | } | |
233 | + | ||
234 | + | if (if ((depositNumLast == -1)) | |
235 | + | then (depositNumUser == -1) | |
236 | + | else false) | |
237 | + | then nil | |
238 | + | else if (if ((depositNumLast == -1)) | |
239 | + | then (depositNumUser > -1) | |
240 | + | else false) | |
241 | + | then throw("invalid depositNumLast and depositNumUser state") | |
242 | + | else if (if ((depositNumLast > -1)) | |
243 | + | then (depositNumUser >= -1) | |
244 | + | else false) | |
245 | + | then if (isNewUser) | |
246 | + | then [IntegerEntry(userRewardFromDepositNumKEY, depositNumLast)] | |
247 | + | else ({ | |
248 | + | let $l = supportedAssetsList | |
249 | + | let $s = size($l) | |
250 | + | let $acc0 = nil | |
251 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
252 | + | then $a | |
253 | + | else forEachAssetCacheUserReward($a, $l[$i]) | |
254 | + | ||
255 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
256 | + | then $a | |
257 | + | else throw("List size exceeds 10") | |
258 | + | ||
259 | + | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10) | |
260 | + | } :+ IntegerEntry(userRewardFromDepositNumKEY, depositNumLast)) | |
261 | + | else throw(((("uncovered condition: depositNumLast=" + toString(depositNumLast)) + " depositNumUser=") + toString(depositNumUser))) | |
262 | + | } | |
263 | + | ||
264 | + | ||
265 | + | func IncrementNotDistributedRewardEntry (tkn,amountInc) = { | |
266 | + | let notDistributedRewardKEY = keyNotDistributedReward(tkn) | |
267 | + | let notDistributedReward = getIntOrElse(notDistributedRewardKEY, 0) | |
268 | + | [IntegerEntry(notDistributedRewardKEY, (notDistributedReward + amountInc))] | |
269 | + | } | |
270 | + | ||
271 | + | ||
272 | + | func mergeVotingPowerEffectiveHeight (quarantinePeriod,vpEffectiveHeight,stakedAmt,stakedAmtNEW) = { | |
273 | + | let remainingToWait = (vpEffectiveHeight - height) | |
274 | + | if ((0 >= remainingToWait)) | |
275 | + | then (height + quarantinePeriod) | |
276 | + | else { | |
277 | + | let alreadyWaited = (quarantinePeriod - remainingToWait) | |
278 | + | let kX8 = if ((stakedAmtNEW != 0)) | |
279 | + | then fraction(stakedAmt, MULT8, stakedAmtNEW) | |
280 | + | else vpEffectiveHeight | |
281 | + | ((quarantinePeriod + height) - fraction(alreadyWaited, kX8, MULT8)) | |
282 | + | } | |
283 | + | } | |
284 | + | ||
285 | + | ||
286 | + | func mergeStake (userAddress,amountToAdd) = { | |
287 | + | let $t01251712627 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
288 | + | let isNewUser = $t01251712627._1 | |
289 | + | let stakedAmount = $t01251712627._2 | |
290 | + | let vpEffectiveHeight = $t01251712627._3 | |
291 | + | let stakedAmountNEW = if (isNewUser) | |
292 | + | then amountToAdd | |
293 | + | else (amountToAdd + stakedAmount) | |
294 | + | let quarantinePeriod = (1440 * 14) | |
295 | + | let vpEffectiveHeightNEW = if (isNewUser) | |
296 | + | then (quarantinePeriod + height) | |
297 | + | else mergeVotingPowerEffectiveHeight(quarantinePeriod, vpEffectiveHeight, stakedAmount, stakedAmountNEW) | |
298 | + | $Tuple5(isNewUser, stakedAmount, vpEffectiveHeight, stakedAmountNEW, vpEffectiveHeightNEW) | |
299 | + | } | |
300 | + | ||
301 | + | ||
302 | + | func commonStake (userAddress,i) = { | |
303 | + | let $t01311313167 = getParamsOrFail() | |
304 | + | let stakedAssetId = $t01311313167._1 | |
305 | + | let minLockAmount = $t01311313167._2 | |
306 | + | if ((size(i.payments) != 1)) | |
307 | + | then throw("Invalid payments size") | |
308 | + | else { | |
309 | + | let payment = i.payments[0] | |
310 | + | let amount = payment.amount | |
311 | + | let invalidAssetMessage = (("Invalid asset. " + toBase58String(stakedAssetId)) + " is expected") | |
312 | + | let assetId = valueOrErrorMessage(payment.assetId, invalidAssetMessage) | |
313 | + | if ((assetId != stakedAssetId)) | |
314 | + | then throw(invalidAssetMessage) | |
315 | + | else { | |
316 | + | let userAddressStr = toString(userAddress) | |
317 | + | let mergedData = mergeStake(userAddress, amount) | |
318 | + | let isNewUser = mergedData._1 | |
319 | + | let stakedAmount = mergedData._2 | |
320 | + | let vpEffectiveHeight = mergedData._3 | |
321 | + | let stakedAmountNEW = mergedData._4 | |
322 | + | let vpEffectiveHeightNEW = mergedData._5 | |
323 | + | if ((minLockAmount > stakedAmountNEW)) | |
324 | + | then throw(("Min lock amount is " + toString(minLockAmount))) | |
325 | + | else { | |
326 | + | let $t01396614068 = StatsResult(amount, 1, if (isNewUser) | |
327 | + | then 1 | |
328 | + | else 0) | |
329 | + | let statsEntries = $t01396614068._1 | |
330 | + | let totalStaked = $t01396614068._2 | |
331 | + | let totalStakedNew = $t01396614068._3 | |
332 | + | ((([HistoryRecordEntry("stake", userAddress, i.transactionId, stakedAmount, vpEffectiveHeight, stakedAmountNEW, vpEffectiveHeightNEW)] ++ RewardEntries(isNewUser, userAddressStr, stakedAmount)) ++ LockParamsEntry(userAddress, stakedAmountNEW, vpEffectiveHeightNEW)) ++ statsEntries) | |
333 | + | } | |
334 | + | } | |
335 | + | } | |
336 | + | } | |
337 | + | ||
338 | + | ||
339 | + | func commonClaim (userAddress,i) = { | |
340 | + | let userAddressStr = toString(userAddress) | |
341 | + | if ((size(i.payments) > 0)) | |
342 | + | then throw("payments are not accepted") | |
343 | + | else { | |
344 | + | let $t01454714652 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
345 | + | let isNewUser = $t01454714652._1 | |
346 | + | let stakedAmount = $t01454714652._2 | |
347 | + | let stakingStart = $t01454714652._3 | |
348 | + | let stakedAmountX = toBigInt(stakedAmount) | |
349 | + | let userRewardFromDepositNumKEY = keyUserRewardFromDepositNum(userAddressStr) | |
350 | + | let depositNumUser = getIntOrElse(userRewardFromDepositNumKEY, -1) | |
351 | + | let depositNumLast = getIntOrElse(keyDepositNumLast(), -1) | |
352 | + | func forEachAssetCalcUnclaimedReward (accum,asset) = { | |
353 | + | let $t01502315161 = calcReward(userAddressStr, asset, stakedAmountX, depositNumUser, depositNumLast) | |
354 | + | let rewardTotal = $t01502315161._1 | |
355 | + | let cached = $t01502315161._2 | |
356 | + | let dynamic = $t01502315161._3 | |
357 | + | let rewardCachedPartKEY = $t01502315161._4 | |
358 | + | let claimedKEY = keyClaimed(userAddressStr, asset) | |
359 | + | let $t01522115258 = accum | |
360 | + | let data = $t01522115258._1 | |
361 | + | let claimedAmtByAsset = $t01522115258._2 | |
362 | + | let newPart = makeString([asset, toString(rewardTotal)], ":") | |
363 | + | let claimedAmtByAssetNew = makeString([claimedAmtByAsset, newPart], "_") | |
364 | + | if ((0 >= rewardTotal)) | |
365 | + | then $Tuple2(data, claimedAmtByAssetNew) | |
366 | + | else $Tuple2((((data :+ ScriptTransfer(userAddress, rewardTotal, toAssetVect(asset))) :+ IntegerEntry(claimedKEY, (valueOrElse(getInteger(claimedKEY), 0) + rewardTotal))) :+ IntegerEntry(rewardCachedPartKEY, 0)), claimedAmtByAssetNew) | |
367 | + | } | |
368 | + | ||
369 | + | let $t01571815832 = { | |
370 | + | let $l = supportedAssetsList | |
371 | + | let $s = size($l) | |
372 | + | let $acc0 = $Tuple2(nil, "") | |
373 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
374 | + | then $a | |
375 | + | else forEachAssetCalcUnclaimedReward($a, $l[$i]) | |
376 | + | ||
377 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
378 | + | then $a | |
379 | + | else throw("List size exceeds 10") | |
380 | + | ||
381 | + | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10) | |
382 | + | } | |
383 | + | let transfers = $t01571815832._1 | |
384 | + | let claimedAmtByAssetResult = $t01571815832._2 | |
385 | + | if ((0 >= size(transfers))) | |
386 | + | then nil | |
387 | + | else ((transfers :+ IntegerEntry(userRewardFromDepositNumKEY, depositNumLast)) :+ ClaimHistoryEntry(userAddress, i.transactionId, drop(claimedAmtByAssetResult, 1))) | |
388 | + | } | |
389 | + | } | |
390 | + | ||
391 | + | ||
392 | + | @Callable(i) | |
393 | + | func constructor (minLockAmount,supportedRewardAssets,stakedAssetId) = if ((i.caller != this)) | |
394 | + | then throw("Permission denied") | |
395 | + | else [IntegerEntry(keyMinLockAmount(), minLockAmount), StringEntry(keySupportedRewardAssets(), supportedRewardAssets), StringEntry(keyStakedAssetId(), stakedAssetId)] | |
396 | + | ||
397 | + | ||
398 | + | ||
399 | + | @Callable(i) | |
400 | + | func stake () = commonStake(i.caller, i) | |
401 | + | ||
402 | + | ||
403 | + | ||
404 | + | @Callable(i) | |
405 | + | func stakeByOriginCaller () = commonStake(i.originCaller, i) | |
406 | + | ||
407 | + | ||
408 | + | ||
409 | + | @Callable(i) | |
410 | + | func unstake (amount) = if ((size(i.payments) != 0)) | |
411 | + | then throw("unstake doesn't require any payment") | |
412 | + | else { | |
413 | + | let userAddress = i.caller | |
414 | + | let userAddressStr = toString(userAddress) | |
415 | + | let $t01674116795 = getParamsOrFail() | |
416 | + | let stakedAssetId = $t01674116795._1 | |
417 | + | let minLockAmount = $t01674116795._2 | |
418 | + | let $t01679816882 = getUserParamsOrFail(userAddress) | |
419 | + | let isNewUser = $t01679816882._1 | |
420 | + | let stakedAmount = $t01679816882._2 | |
421 | + | let vpEffectiveHeight = $t01679816882._3 | |
422 | + | let swapParamsSTRUCT = asSwapParamsSTRUCT(reentrantInvoke(neutrinoContract, "swapParamsByUserSYSREADONLY", [userAddressStr, 0], nil)) | |
423 | + | let swapLimitSpentInUsdn = swapParamsSTRUCT._2 | |
424 | + | let blcks2LmtReset = swapParamsSTRUCT._3 | |
425 | + | if ((swapLimitSpentInUsdn > 0)) | |
426 | + | then throw((("You have already made a swap operation. Wait " + toString((height + blcks2LmtReset))) + " height to unstake")) | |
427 | + | else if ((0 >= stakedAmount)) | |
428 | + | then throw("Nothing to unstake") | |
429 | + | else if ((amount > stakedAmount)) | |
430 | + | then throw(((("Requested " + toString(amount)) + ", but staked only ") + toString(stakedAmount))) | |
431 | + | else { | |
432 | + | let stakedAmountNEW = (stakedAmount - amount) | |
433 | + | let $t01752017678 = StatsResult(-(amount), if ((amount == stakedAmount)) | |
434 | + | then -1 | |
435 | + | else 0, if ((amount == stakedAmount)) | |
436 | + | then -1 | |
437 | + | else 0) | |
438 | + | let statsEntries = $t01752017678._1 | |
439 | + | let totalStaked = $t01752017678._2 | |
440 | + | let totalStakedNew = $t01752017678._3 | |
441 | + | ((([ScriptTransfer(userAddress, amount, stakedAssetId), HistoryRecordEntry("unstake", userAddress, i.transactionId, stakedAmount, vpEffectiveHeight, stakedAmountNEW, vpEffectiveHeight)] ++ RewardEntries(false, userAddressStr, stakedAmount)) ++ LockParamsEntry(userAddress, stakedAmountNEW, vpEffectiveHeight)) ++ statsEntries) | |
442 | + | } | |
443 | + | } | |
444 | + | ||
445 | + | ||
446 | + | ||
447 | + | @Callable(i) | |
448 | + | func deposit () = if ((size(i.payments) != 1)) | |
449 | + | then throw("exact 1 payment is allowed only") | |
450 | + | else { | |
451 | + | let pmt = i.payments[0] | |
452 | + | let amount = pmt.amount | |
453 | + | let pmtAssetId = valueOrElse(pmt.assetId, USDNID) | |
454 | + | let pmtAssetIdStr = toBase58String(pmtAssetId) | |
455 | + | let pmtMultX = if ((pmtAssetId == USDNID)) | |
456 | + | then MULTX8 | |
457 | + | else MULTX6 | |
458 | + | let amountX = toBigInt(amount) | |
459 | + | let totalStaked = getIntOrElse(keyLockParamTotalAmount(), 0) | |
460 | + | let totalStakedX = toBigInt(totalStaked) | |
461 | + | if ((0 > totalStaked)) | |
462 | + | then throw("TODO: case is not supported") | |
463 | + | else if ((totalStaked == 0)) | |
464 | + | then IncrementNotDistributedRewardEntry(pmtAssetIdStr, amount) | |
465 | + | else { | |
466 | + | let rewardPerNsbtX18 = fraction(amountX, MULTX18, totalStakedX) | |
467 | + | let depositNumLastKEY = keyDepositNumLast() | |
468 | + | let depositNumLast = getIntOrElse(depositNumLastKEY, -1) | |
469 | + | let depositNumNew = (depositNumLast + 1) | |
470 | + | if (!(contains(supportedAssetsStr, pmtAssetIdStr))) | |
471 | + | then throw(((supportedAssetsStr + " doesn't contain ") + pmtAssetIdStr)) | |
472 | + | else { | |
473 | + | func refreshRewardPerNsbtSUM (accum,nextAsset) = { | |
474 | + | let rewardPerNsbtSumNewKEY = keyRewardPerNsbtSumAt(depositNumNew, nextAsset) | |
475 | + | let sumLastStr = getStrOrElse(keyRewardPerNsbtSumAt(depositNumLast, nextAsset), "0") | |
476 | + | (accum :+ (if ((nextAsset == pmtAssetIdStr)) | |
477 | + | then StringEntry(rewardPerNsbtSumNewKEY, toString((parseBigIntValue(sumLastStr) + rewardPerNsbtX18))) | |
478 | + | else StringEntry(rewardPerNsbtSumNewKEY, sumLastStr))) | |
479 | + | } | |
480 | + | ||
481 | + | ({ | |
482 | + | let $l = supportedAssetsList | |
483 | + | let $s = size($l) | |
484 | + | let $acc0 = nil | |
485 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
486 | + | then $a | |
487 | + | else refreshRewardPerNsbtSUM($a, $l[$i]) | |
488 | + | ||
489 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
490 | + | then $a | |
491 | + | else throw("List size exceeds 10") | |
492 | + | ||
493 | + | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10) | |
494 | + | } :+ IntegerEntry(depositNumLastKEY, depositNumNew)) | |
495 | + | } | |
496 | + | } | |
497 | + | } | |
498 | + | ||
499 | + | ||
500 | + | ||
501 | + | @Callable(i) | |
502 | + | func claimRewards () = commonClaim(i.caller, i) | |
503 | + | ||
504 | + | ||
505 | + | ||
506 | + | @Callable(i) | |
507 | + | func claimRewardsByOriginCaller () = commonClaim(i.originCaller, i) | |
508 | + | ||
509 | + | ||
510 | + | ||
511 | + | @Callable(i) | |
512 | + | func unclaimedRewardsREADONLY (userAddressStr) = { | |
513 | + | func forEachAssetZeroReward (accum,asset) = ((accum + makeString([asset, "0", "0"], ":")) + "_") | |
514 | + | ||
515 | + | let unclaimedRewardStr = if ((userAddressStr == "")) | |
516 | + | then { | |
517 | + | let $l = supportedAssetsList | |
518 | + | let $s = size($l) | |
519 | + | let $acc0 = "" | |
520 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
521 | + | then $a | |
522 | + | else forEachAssetZeroReward($a, $l[$i]) | |
523 | + | ||
524 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
525 | + | then $a | |
526 | + | else throw("List size exceeds 10") | |
527 | + | ||
528 | + | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10) | |
529 | + | } | |
530 | + | else { | |
531 | + | let userAddress = addressFromStringValue(userAddressStr) | |
532 | + | let $t02025020355 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
533 | + | let isNewUser = $t02025020355._1 | |
534 | + | let stakedAmount = $t02025020355._2 | |
535 | + | let stakingStart = $t02025020355._3 | |
536 | + | let stakedAmountX = toBigInt(stakedAmount) | |
537 | + | let userRewardFromDepositNumKEY = keyUserRewardFromDepositNum(userAddressStr) | |
538 | + | let depositNumUser = getIntOrElse(userRewardFromDepositNumKEY, -1) | |
539 | + | let depositNumLast = getIntOrElse(keyDepositNumLast(), -1) | |
540 | + | func forEachAssetCalcUnclaimedReward (accum,asset) = { | |
541 | + | let $t02070120839 = calcReward(userAddressStr, asset, stakedAmountX, depositNumUser, depositNumLast) | |
542 | + | let rewardTotal = $t02070120839._1 | |
543 | + | let cached = $t02070120839._2 | |
544 | + | let dynamic = $t02070120839._3 | |
545 | + | let rewardCachedPartKEY = $t02070120839._4 | |
546 | + | let claimed = valueOrElse(getInteger(keyClaimed(userAddressStr, asset)), 0) | |
547 | + | ((accum + makeString([asset, toString(rewardTotal), toString(claimed)], ":")) + "_") | |
548 | + | } | |
549 | + | ||
550 | + | let $l = supportedAssetsList | |
551 | + | let $s = size($l) | |
552 | + | let $acc0 = "" | |
553 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
554 | + | then $a | |
555 | + | else forEachAssetCalcUnclaimedReward($a, $l[$i]) | |
556 | + | ||
557 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
558 | + | then $a | |
559 | + | else throw("List size exceeds 10") | |
560 | + | ||
561 | + | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10) | |
562 | + | } | |
563 | + | $Tuple2(nil, dropRight(unclaimedRewardStr, 1)) | |
564 | + | } | |
565 | + | ||
566 | + | ||
567 | + | ||
568 | + | @Callable(i) | |
569 | + | func usdnStakingSYSREADONLY (userAddressStrOrEmpty,usdnDiff) = { | |
570 | + | let usdnTotal = getIntOrElse(keyLockParamTotalAmount(), 0) | |
571 | + | if ((userAddressStrOrEmpty == "")) | |
572 | + | then $Tuple2(nil, [0, usdnTotal, 0, 0, 0, height, height]) | |
573 | + | else { | |
574 | + | let userAddress = toAddressOrFail(userAddressStrOrEmpty) | |
575 | + | let mergedData = mergeStake(userAddress, usdnDiff) | |
576 | + | let isNewUser = mergedData._1 | |
577 | + | let stakedAmount = mergedData._2 | |
578 | + | let vpEffectiveHeight = mergedData._3 | |
579 | + | let stakedAmountNEW = mergedData._4 | |
580 | + | let vpEffectiveHeightNEW = mergedData._5 | |
581 | + | let usdnUser = stakedAmount | |
582 | + | $Tuple2(nil, [usdnUser, usdnTotal, 0, 0, vpEffectiveHeight, vpEffectiveHeightNEW]) | |
583 | + | } | |
584 | + | } | |
585 | + | ||
586 | + | ||
587 | + | ||
588 | + | @Callable(i) | |
589 | + | func configSYSREADONLY () = { | |
590 | + | let minLockAmt = getIntegerValue(keyMinLockAmount()) | |
591 | + | $Tuple2(nil, [minLockAmt]) | |
592 | + | } | |
593 | + | ||
594 | + |
github/deemru/w8io/169f3d6 80.55 ms ◑