tx · 2YTUDVy5c9WEf2XUhRfABTXnpMgw11i9VWM6xBZivQZx

3N9be2mwrA52WJho6DiesZkk4351GvpnWuj:  -0.04000000 Waves

2022.08.23 14:58 [2197101] smart account 3N9be2mwrA52WJho6DiesZkk4351GvpnWuj > SELF 0.00000000 Waves

{ "type": 13, "id": "2YTUDVy5c9WEf2XUhRfABTXnpMgw11i9VWM6xBZivQZx", "fee": 4000000, "feeAssetId": null, "timestamp": 1661256044342, "version": 1, "sender": "3N9be2mwrA52WJho6DiesZkk4351GvpnWuj", "senderPublicKey": "6mzmbCza9iqbzxMEELcEA4Xc9NeF4CYpbTtz1zMK3C7x", "proofs": [ "2V2z8cievbPeEHWzv92KTEALj7fcvp1TeKXPzWppy3yK8iBu4ZGff3q2qVnYyRkkmjKaL3yPvcWnMVJ9i76ktWUD", "iobcyHP3he3RdFjBhwoTPuQmgRQipKf5oxbCSrenaK3TbfFaNPNiQdkPPD9FnwHLYgByLhVBaB9x5V97vQom1tZ", "52BArtFQWrNzoUGL4URq3juMryFi6VQqKtB32aM4ucRFZN4AV9Z2PCM4qBUSWwydMNqrn873VRELPNdY8umbRudm" ], "script": "base64:BgJOCAISDgoMCAgICAgIAQEBAQEBEgUKAwgIARIAEgASBQoDCAEIEgMKAQESBAoCAQgSABIECgIIARIECgIBARIECgIIARIFCgMIAQESABIApQEBD2dldFN0cmluZ09yRmFpbAIHYWRkcmVzcwNrZXkJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBQdhZGRyZXNzBQNrZXkJALkJAgkAzAgCAgptYW5kYXRvcnkgCQDMCAIJAKUIAQUHYWRkcmVzcwkAzAgCAgEuCQDMCAIFA2tleQkAzAgCAg8gaXMgbm90IGRlZmluZWQFA25pbAIAAQVsY2FsYwEBbAkAuQgBBQFsAQ5nZXROdW1iZXJCeUtleQEDa2V5CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFA2tleQAAAQ5nZXRTdHJpbmdCeUtleQEDa2V5CQELdmFsdWVPckVsc2UCCQCdCAIFBHRoaXMFA2tleQIAAQxnZXRCb29sQnlLZXkBA2tleQkBC3ZhbHVlT3JFbHNlAgkAmwgCBQR0aGlzBQNrZXkHARhnZXROdW1iZXJCeUFkZHJlc3NBbmRLZXkCB2FkZHJlc3MDa2V5CQELdmFsdWVPckVsc2UCCQCaCAIFB2FkZHJlc3MFA2tleQAAARhnZXRTdHJpbmdCeUFkZHJlc3NBbmRLZXkCB2FkZHJlc3MDa2V5CQELdmFsdWVPckVsc2UCCQCdCAIJARFAZXh0ck5hdGl2ZSgxMDYyKQEFB2FkZHJlc3MFA2tleQIAARZnZXRCb29sQnlBZGRyZXNzQW5kS2V5AgdhZGRyZXNzA2tleQkBC3ZhbHVlT3JFbHNlAgkAmwgCBQdhZGRyZXNzBQNrZXkHAQlhc0FueUxpc3QBAXYEByRtYXRjaDAFAXYDCQABAgUHJG1hdGNoMAIJTGlzdFtBbnldBAFsBQckbWF0Y2gwBQFsCQACAQIbZmFpbCB0byBjYXN0IGludG8gTGlzdFtBbnldAQhhc1N0cmluZwEBdgQHJG1hdGNoMAUBdgMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAXMFByRtYXRjaDAFAXMJAAIBAhhmYWlsIHRvIGNhc3QgaW50byBTdHJpbmcBBWFzSW50AQF2BAckbWF0Y2gwBQF2AwkAAQIFByRtYXRjaDACA0ludAQBaQUHJG1hdGNoMAUBaQkAAgECFWZhaWwgdG8gY2FzdCBpbnRvIEludAEHYXNCeXRlcwEDdmFsBAckbWF0Y2gwBQN2YWwDCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQHdmFsQnl0ZQUHJG1hdGNoMAUHdmFsQnl0ZQkAAgECHGZhaWwgdG8gY2FzdCBpbnRvIEJ5dGVWZWN0b3IBCWFzUGF5bWVudAEBdgQHJG1hdGNoMAUBdgMJAAECBQckbWF0Y2gwAg9BdHRhY2hlZFBheW1lbnQEAXAFByRtYXRjaDAFAXAJAAIBAiFmYWlsIHRvIGNhc3QgaW50byBBdHRhY2hlZFBheW1lbnQBEmFzU3dhcFBhcmFtc1NUUlVDVAEBdgQHJG1hdGNoMAUBdgMJAAECBQckbWF0Y2gwAiMoSW50LCBJbnQsIEludCwgSW50LCBJbnQsIEludCwgSW50KQQGc3RydWN0BQckbWF0Y2gwBQZzdHJ1Y3QJAAIBAh1mYWlsIHRvIGNhc3QgaW50byBUdXBsZTUgaW50cwADU0VQAgJfXwAHV0FWRUxFVACAwtcvAAVQQVVMSQDAhD0ACFBSSUNFTEVUAMCEPQAOREVGQVVMVFNXQVBGRUUAoJwBAAtCUlBST1RFQ1RFRACgjQYADElkeE5ldEFtb3VudAAAAAxJZHhGZWVBbW91bnQAAQAOSWR4R3Jvc3NBbW91bnQAAgAZSWR4Q29udHJvbENmZ05ldXRyaW5vRGFwcAABABhJZHhDb250cm9sQ2ZnQXVjdGlvbkRhcHAAAgAUSWR4Q29udHJvbENmZ1JwZERhcHAAAwAVSWR4Q29udHJvbENmZ01hdGhEYXBwAAQAHElkeENvbnRyb2xDZmdMaXF1aWRhdGlvbkRhcHAABQAVSWR4Q29udHJvbENmZ1Jlc3REYXBwAAYAHUlkeENvbnRyb2xDZmdOb2RlUmVnaXN0cnlEYXBwAAcAHElkeENvbnRyb2xDZmdOc2J0U3Rha2luZ0RhcHAACAAZSWR4Q29udHJvbENmZ01lZGlhdG9yRGFwcAAJABxJZHhDb250cm9sQ2ZnU3VyZlN0YWtpbmdEYXBwAAoAIElkeENvbnRyb2xDZmdHbnNidENvbnRyb2xsZXJEYXBwAAsBEWtleUNvbnRyb2xBZGRyZXNzAAIcJXMlc19fY29uZmlnX19jb250cm9sQWRkcmVzcwENa2V5Q29udHJvbENmZwACESVzX19jb250cm9sQ29uZmlnARRyZWFkQ29udHJvbENmZ09yRmFpbAEHY29udHJvbAkAtQkCCQEPZ2V0U3RyaW5nT3JGYWlsAgUHY29udHJvbAkBDWtleUNvbnRyb2xDZmcABQNTRVABGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAIKY29udHJvbENmZwNpZHgJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQCRAwIFCmNvbnRyb2xDZmcFA2lkeAkArAICAi1Db250cm9sIGNmZyBkb2Vzbid0IGNvbnRhaW4gYWRkcmVzcyBhdCBpbmRleCAJAKQDAQUDaWR4AA9jb250cm9sQ29udHJhY3QJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwkBEWtleUNvbnRyb2xBZGRyZXNzAAIjM040TlM3ZDRKbzlhNkYxNExpRlVLS1lWZFVra2YyZVA0WngACmNvbnRyb2xDZmcJARRyZWFkQ29udHJvbENmZ09yRmFpbAEFD2NvbnRyb2xDb250cmFjdAAMbWF0aENvbnRyYWN0CQEYZ2V0Q29udHJhY3RBZGRyZXNzT3JGYWlsAgUKY29udHJvbENmZwUVSWR4Q29udHJvbENmZ01hdGhEYXBwABNuc2J0U3Rha2luZ0NvbnRyYWN0CQEYZ2V0Q29udHJhY3RBZGRyZXNzT3JGYWlsAgUKY29udHJvbENmZwUcSWR4Q29udHJvbENmZ05zYnRTdGFraW5nRGFwcAATc3VyZlN0YWtpbmdDb250cmFjdAkBGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAIFCmNvbnRyb2xDZmcFHElkeENvbnRyb2xDZmdTdXJmU3Rha2luZ0RhcHAAF2duc2J0Q29udHJvbGxlckNvbnRyYWN0CQEYZ2V0Q29udHJhY3RBZGRyZXNzT3JGYWlsAgUKY29udHJvbENmZwUgSWR4Q29udHJvbENmZ0duc2J0Q29udHJvbGxlckRhcHAAD2F1Y3Rpb25Db250cmFjdAkBGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAIFCmNvbnRyb2xDZmcFGElkeENvbnRyb2xDZmdBdWN0aW9uRGFwcAASTmV1dHJpbm9Bc3NldElkS2V5AhFuZXV0cmlub19hc3NldF9pZAAOQm9uZEFzc2V0SWRLZXkCDWJvbmRfYXNzZXRfaWQAEkF1Y3Rpb25Db250cmFjdEtleQIQYXVjdGlvbl9jb250cmFjdAAWTnNidFN0YWtpbmdDb250cmFjdEtleQITbnNidFN0YWtpbmdDb250cmFjdAAWTGlxdWlkYXRpb25Db250cmFjdEtleQIUbGlxdWlkYXRpb25fY29udHJhY3QADlJQRENvbnRyYWN0S2V5AgxycGRfY29udHJhY3QAEUNvbnRvbENvbnRyYWN0S2V5AhBjb250cm9sX2NvbnRyYWN0AA9NYXRoQ29udHJhY3RLZXkCDW1hdGhfY29udHJhY3QAG0JhbGFuY2VXYXZlc0xvY2tJbnRlcnZhbEtleQIbYmFsYW5jZV93YXZlc19sb2NrX2ludGVydmFsAB5CYWxhbmNlTmV1dHJpbm9Mb2NrSW50ZXJ2YWxLZXkCHmJhbGFuY2VfbmV1dHJpbm9fbG9ja19pbnRlcnZhbAAVTWluV2F2ZXNTd2FwQW1vdW50S2V5AhVtaW5fd2F2ZXNfc3dhcF9hbW91bnQAGE1pbk5ldXRyaW5vU3dhcEFtb3VudEtleQIYbWluX25ldXRyaW5vX3N3YXBfYW1vdW50ABtOb2RlT3JhY2xlUHJvdmlkZXJQdWJLZXlLZXkCFG5vZGVfb3JhY2xlX3Byb3ZpZGVyABVOZXV0cmlub091dEZlZVBhcnRLZXkCGG5ldXRyaW5vT3V0X3N3YXBfZmVlUGFydAASV2F2ZXNPdXRGZWVQYXJ0S2V5AhV3YXZlc091dF9zd2FwX2ZlZVBhcnQBD2tleU5vZGVSZWdpc3RyeQEHYWRkcmVzcwkArAICAgQlc19fBQdhZGRyZXNzAAhQcmljZUtleQIFcHJpY2UADVByaWNlSW5kZXhLZXkCC3ByaWNlX2luZGV4AAxJc0Jsb2NrZWRLZXkCCmlzX2Jsb2NrZWQBEmdldFByaWNlSGlzdG9yeUtleQEFYmxvY2sJAKwCAgkArAICBQhQcmljZUtleQIBXwkApAMBBQVibG9jawEYZ2V0SGVpZ2h0UHJpY2VCeUluZGV4S2V5AQVpbmRleAkArAICCQCsAgIFDVByaWNlSW5kZXhLZXkCAV8JAKQDAQUFaW5kZXgBFWdldFN0YWtpbmdOb2RlQnlJbmRleAEDaWR4CQEOZ2V0U3RyaW5nQnlLZXkBCQC5CQIJAMwIAgIGJXMlZCVzCQDMCAICBWxlYXNlCQDMCAIJAKQDAQUDaWR4CQDMCAICC25vZGVBZGRyZXNzBQNuaWwFA1NFUAEcZ2V0U3Rha2luZ05vZGVBZGRyZXNzQnlJbmRleAEDaWR4CQERQGV4dHJOYXRpdmUoMTA2MikBCQEVZ2V0U3Rha2luZ05vZGVCeUluZGV4AQUDaWR4AR9nZXRSZXNlcnZlZEFtb3VudEZvclNwb25zb3JzaGlwAAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQC5CQIJAMwIAgIEJXMlcwkAzAgCAgVsZWFzZQkAzAgCAhdzcG9uc29yc2hpcFdhdmVzUmVzZXJ2ZQUDbmlsBQNTRVAJAGgCAOgHBQdXQVZFTEVUARhnZXRCYWxhbmNlVW5sb2NrQmxvY2tLZXkBBW93bmVyCQCsAgICFWJhbGFuY2VfdW5sb2NrX2Jsb2NrXwUFb3duZXIBDWdldExlYXNlSWRLZXkBCW5vZGVJbmRleAkAuQkCCQDMCAICBiVzJWQlcwkAzAgCAgVsZWFzZQkAzAgCCQCkAwEFCW5vZGVJbmRleAkAzAgCAgJpZAUDbmlsBQNTRVABFmdldExlYXNlSWRCeUFkZHJlc3NLZXkBC25vZGVBZGRyZXNzCQC5CQIJAMwIAgIGJXMlcyVzCQDMCAICDmxlYXNlQnlBZGRyZXNzCQDMCAIFC25vZGVBZGRyZXNzCQDMCAICAmlkBQNuaWwFA1NFUAERZ2V0TGVhc2VBbW91bnRLZXkBCW5vZGVJbmRleAkAuQkCCQDMCAICBiVzJWQlcwkAzAgCAgVsZWFzZQkAzAgCCQCkAwEFCW5vZGVJbmRleAkAzAgCAgZhbW91bnQFA25pbAUDU0VQARpnZXRMZWFzZUFtb3VudEJ5QWRkcmVzc0tleQELbm9kZUFkZHJlc3MJALkJAgkAzAgCAgYlcyVzJXMJAMwIAgIObGVhc2VCeUFkZHJlc3MJAMwIAgULbm9kZUFkZHJlc3MJAMwIAgIGYW1vdW50BQNuaWwFA1NFUAEYZ2V0TGVhc2VHcm91cE5vZGVMaXN0S2V5AQhncm91cE51bQkAuQkCCQDMCAICBiVzJWQlcwkAzAgCAgpsZWFzZUdyb3VwCQDMCAIJAKQDAQUIZ3JvdXBOdW0JAMwIAgIIbm9kZUxpc3QFA25pbAUDU0VQARBtaW5Td2FwQW1vdW50S0VZAQhzd2FwVHlwZQkArAICCQCsAgICBG1pbl8FCHN3YXBUeXBlAgxfc3dhcF9hbW91bnQBDnRvdGFsTG9ja2VkS0VZAQhzd2FwVHlwZQkArAICAg1iYWxhbmNlX2xvY2tfBQhzd2FwVHlwZQEUdG90YWxMb2NrZWRCeVVzZXJLRVkCCHN3YXBUeXBlBW93bmVyCQC5CQIJAMwIAgIMYmFsYW5jZV9sb2NrCQDMCAIFCHN3YXBUeXBlCQDMCAIFBW93bmVyBQNuaWwCAV8BFmJhbGFuY2VMb2NrSW50ZXJ2YWxLRVkBCHN3YXBUeXBlCQCsAgIJAKwCAgIIYmFsYW5jZV8FCHN3YXBUeXBlAg5fbG9ja19pbnRlcnZhbAEabm9kZUJhbGFuY2VMb2NrSW50ZXJ2YWxLRVkAAhpiYWxhbmNlX25vZGVfbG9ja19pbnRlcnZhbAENb3V0RmVlUGFydEtFWQEIc3dhcFR5cGUJAKwCAgUIc3dhcFR5cGUCEE91dF9zd2FwX2ZlZVBhcnQBEXN3YXBzVGltZWZyYW1lS0VZAAIPc3dhcHNfdGltZWZyYW1lAQ5iclByb3RlY3RlZEtFWQACF21pbl9CUl9wcm90ZWN0aW9uX2xldmVsARFtaW5Td2FwQW1vdW50UkVBRAEIc3dhcFR5cGUJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBEG1pblN3YXBBbW91bnRLRVkBBQhzd2FwVHlwZQAAARJzd2Fwc1RpbWVmcmFtZVJFQUQACQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJARFzd2Fwc1RpbWVmcmFtZUtFWQAAoAsBD3RvdGFsTG9ja2VkUkVBRAEIc3dhcFR5cGUJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBDnRvdGFsTG9ja2VkS0VZAQUIc3dhcFR5cGUAAAEVdG90YWxMb2NrZWRCeVVzZXJSRUFEAghzd2FwVHlwZQVvd25lcgkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEUdG90YWxMb2NrZWRCeVVzZXJLRVkCBQhzd2FwVHlwZQUFb3duZXIAAAEXYmFsYW5jZUxvY2tJbnRlcnZhbFJFQUQBCHN3YXBUeXBlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJARZiYWxhbmNlTG9ja0ludGVydmFsS0VZAQUIc3dhcFR5cGUAoAsBG25vZGVCYWxhbmNlTG9ja0ludGVydmFsUkVBRAAJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBGm5vZGVCYWxhbmNlTG9ja0ludGVydmFsS0VZAAABARhrZXlTd2FwVXNlclNwZW50SW5QZXJpb2QBC3VzZXJBZGRyZXNzCQC5CQIJAMwIAgIEJXMlcwkAzAgCAhVzd2FwVXNlclNwZW50SW5QZXJpb2QJAMwIAgULdXNlckFkZHJlc3MFA25pbAUDU0VQARVrZXlVc2VyTGFzdFN3YXBIZWlnaHQBC3VzZXJBZGRyZXNzCQC5CQIJAMwIAgIEJXMlcwkAzAgCAhJ1c2VyTGFzdFN3YXBIZWlnaHQJAMwIAgULdXNlckFkZHJlc3MFA25pbAUDU0VQARZjb252ZXJ0TmV1dHJpbm9Ub1dhdmVzAgZhbW91bnQFcHJpY2UJAGsDCQBrAwUGYW1vdW50BQhQUklDRUxFVAUFcHJpY2UFB1dBVkVMRVQFBVBBVUxJARZjb252ZXJ0V2F2ZXNUb05ldXRyaW5vAgZhbW91bnQFcHJpY2UJAGsDCQBrAwUGYW1vdW50BQVwcmljZQUIUFJJQ0VMRVQFBVBBVUxJBQdXQVZFTEVUARJjb252ZXJ0V2F2ZXNUb0JvbmQCBmFtb3VudAVwcmljZQkBFmNvbnZlcnRXYXZlc1RvTmV1dHJpbm8CBQZhbW91bnQFBXByaWNlARZjb252ZXJ0SnNvbkFycmF5VG9MaXN0AQlqc29uQXJyYXkJALUJAgUJanNvbkFycmF5AgEsARFtaW5Td2FwQW1vdW50RkFJTAIIc3dhcFR5cGUNbWluU3dhcEFtb3VudAkAAgEJAKwCAgkArAICCQCsAgICGFRoZSBzcGVjaWZpZWQgYW1vdW50IGluIAUIc3dhcFR5cGUCKyBzd2FwIGlzIGxlc3MgdGhhbiB0aGUgcmVxdWlyZWQgbWluaW11bSBvZiAJAKQDAQUNbWluU3dhcEFtb3VudAEVZW1lcmdlbmN5U2h1dGRvd25GQUlMAAkAAgECWmNvbnRyYWN0IGlzIGJsb2NrZWQgYnkgRU1FUkdFTkNZIFNIVVRET1dOIGFjdGlvbnMgdW50aWxsIHJlYWN0aXZhdGlvbiBieSBlbWVyZ2VuY3kgb3JhY2xlcwEOcHJpY2VJbmRleEZBSUwFBWluZGV4CnByaWNlSW5kZXgLaW5kZXhIZWlnaHQMdW5sb2NrSGVpZ2h0D3ByZXZJbmRleEhlaWdodAkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgICI2ludmFsaWQgcHJpY2UgaGlzdG9yeSBpbmRleDogaW5kZXg9CQCkAwEFBWluZGV4AgwgcHJpY2VJbmRleD0JAKQDAQUKcHJpY2VJbmRleAINIGluZGV4SGVpZ2h0PQkApAMBBQtpbmRleEhlaWdodAIOIHVubG9ja0hlaWdodD0JAKQDAQUMdW5sb2NrSGVpZ2h0AhEgcHJldkluZGV4SGVpZ2h0PQkApAMBBQ9wcmV2SW5kZXhIZWlnaHQAD25ldXRyaW5vQXNzZXRJZAkA2QQBCQEOZ2V0U3RyaW5nQnlLZXkBBRJOZXV0cmlub0Fzc2V0SWRLZXkACnByaWNlSW5kZXgJARhnZXROdW1iZXJCeUFkZHJlc3NBbmRLZXkCBQ9jb250cm9sQ29udHJhY3QFDVByaWNlSW5kZXhLZXkACWlzQmxvY2tlZAkBFmdldEJvb2xCeUFkZHJlc3NBbmRLZXkCBQ9jb250cm9sQ29udHJhY3QFDElzQmxvY2tlZEtleQAYbm9kZU9yYWNsZVByb3ZpZGVyUHViS2V5CQDZBAEJAQ5nZXRTdHJpbmdCeUtleQEFG05vZGVPcmFjbGVQcm92aWRlclB1YktleUtleQALYm9uZEFzc2V0SWQJANkEAQIsRjNpYXh6cnVGZUt1amZWZllTWkVrZWpwamg2N3dtUmZQQ1JIaU5tV0twM1oAFWRlcHJlY2F0ZWRCb25kQXNzZXRJZAkA2QQBAiw5NzVha1pCZm5NajUxM1U3TVphSEt6UXJtc0V4NWFFM3dkV0tUckhCaGJqRgAQbmV1dHJpbm9Db250cmFjdAUEdGhpcwAMY3VycmVudFByaWNlCQEYZ2V0TnVtYmVyQnlBZGRyZXNzQW5kS2V5AgUPY29udHJvbENvbnRyYWN0BQhQcmljZUtleQEbY2hlY2tJc1ZhbGlkTWluU3BvbnNvcmVkRmVlAQJ0eAQOTUlOVFJBTlNGRVJGRUUAoI0GBBZTcG9uc29yZWRGZWVVcHBlckJvdW5kAOgHBA9yZWFsTmV1dHJpbm9GZWUJARZjb252ZXJ0V2F2ZXNUb05ldXRyaW5vAgUOTUlOVFJBTlNGRVJGRUUFDGN1cnJlbnRQcmljZQQObWluTmV1dHJpbm9GZWUJAGgCBQ9yZWFsTmV1dHJpbm9GZWUAAgQObWF4TmV1dHJpbm9GZWUJAGsDBQ9yZWFsTmV1dHJpbm9GZWUFFlNwb25zb3JlZEZlZVVwcGVyQm91bmQAZAQIaW5wdXRGZWUJAQV2YWx1ZQEIBQJ0eBRtaW5TcG9uc29yZWRBc3NldEZlZQMDCQBnAgUIaW5wdXRGZWUFDm1pbk5ldXRyaW5vRmVlCQBnAgUObWF4TmV1dHJpbm9GZWUFCGlucHV0RmVlBwkAAAIIBQJ0eAdhc3NldElkBQ9uZXV0cmlub0Fzc2V0SWQHAQ9nZXRQcmljZUhpc3RvcnkBBWJsb2NrCQEYZ2V0TnVtYmVyQnlBZGRyZXNzQW5kS2V5AgUPY29udHJvbENvbnRyYWN0CQESZ2V0UHJpY2VIaXN0b3J5S2V5AQUFYmxvY2sBFWdldEhlaWdodFByaWNlQnlJbmRleAEFaW5kZXgJARhnZXROdW1iZXJCeUFkZHJlc3NBbmRLZXkCBQ9jb250cm9sQ29udHJhY3QJARhnZXRIZWlnaHRQcmljZUJ5SW5kZXhLZXkBBQVpbmRleAEWa2V5TG9ja1BhcmFtVXNlckFtb3VudAELdXNlckFkZHJlc3MJALkJAgkAzAgCAgYlcyVzJXMJAMwIAgILcGFyYW1CeVVzZXIJAMwIAgULdXNlckFkZHJlc3MJAMwIAgIGYW1vdW50BQNuaWwFA1NFUAAMc0lkeFN3YXBUeXBlAAEACnNJZHhTdGF0dXMAAgAMc0lkeEluQW1vdW50AAMACXNJZHhQcmljZQAEABBzSWR4T3V0TmV0QW1vdW50AAUAEHNJZHhPdXRGZWVBbW91bnQABgAPc0lkeFN0YXJ0SGVpZ2h0AAcAEnNJZHhTdGFydFRpbWVzdGFtcAAIAA1zSWR4RW5kSGVpZ2h0AAkAEHNJZHhFbmRUaW1lc3RhbXAACgAUc0lkeFNlbGZVbmxvY2tIZWlnaHQACwAUc0lkeFJhbmRVbmxvY2tIZWlnaHQADAAJc0lkeEluZGV4AA0AEHNJZHhXaXRoZHJhd1R4SWQADgALc0lkeE1pblJhbmQADwALc0lkeE1heFJhbmQAEAEHc3dhcEtFWQILdXNlckFkZHJlc3MEdHhJZAkAuQkCCQDMCAICBCVzJXMJAMwIAgULdXNlckFkZHJlc3MJAMwIAgUEdHhJZAUDbmlsBQNTRVABC3N0clN3YXBEQVRBEAhzd2FwVHlwZQZzdGF0dXMIaW5BbW91bnQFcHJpY2UMb3V0TmV0QW1vdW50DG91dEZlZUFtb3VudAtzdGFydEhlaWdodA5zdGFydFRpbWVzdGFtcAllbmRIZWlnaHQMZW5kVGltZXN0YW1wEHNlbGZVbmxvY2tIZWlnaHQQcmFuZFVubG9ja0hlaWdodAVpbmRleAx3aXRoZHJhd1R4SWQHcmFuZE1pbgdyYW5kTWF4CQC5CQIJAMwIAgIcJXMlcyVkJWQlZCVkJWQlZCVkJWQlZCVkJWQlcwkAzAgCBQhzd2FwVHlwZQkAzAgCBQZzdGF0dXMJAMwIAgUIaW5BbW91bnQJAMwIAgUFcHJpY2UJAMwIAgUMb3V0TmV0QW1vdW50CQDMCAIFDG91dEZlZUFtb3VudAkAzAgCBQtzdGFydEhlaWdodAkAzAgCBQ5zdGFydFRpbWVzdGFtcAkAzAgCBQllbmRIZWlnaHQJAMwIAgUMZW5kVGltZXN0YW1wCQDMCAIFEHNlbGZVbmxvY2tIZWlnaHQJAMwIAgUQcmFuZFVubG9ja0hlaWdodAkAzAgCBQVpbmRleAkAzAgCBQx3aXRoZHJhd1R4SWQJAMwIAgUHcmFuZE1pbgkAzAgCBQdyYW5kTWF4BQNuaWwFA1NFUAEPcGVuZGluZ1N3YXBEQVRBAwhzd2FwVHlwZQ1pbkFzc2V0QW1vdW50EHNlbGZVbmxvY2tIZWlnaHQJAQtzdHJTd2FwREFUQRAFCHN3YXBUeXBlAgdQRU5ESU5HCQCkAwEFDWluQXNzZXRBbW91bnQCATACATACATAJAKQDAQUGaGVpZ2h0CQCkAwEIBQlsYXN0QmxvY2sJdGltZXN0YW1wAgEwAgEwCQCkAwEFEHNlbGZVbmxvY2tIZWlnaHQCATACATACBE5VTEwCATACATABDmZpbmlzaFN3YXBEQVRBBwlkYXRhQXJyYXkFcHJpY2UMb3V0TmV0QW1vdW50DG91dEZlZUFtb3VudBByYW5kVW5sb2NrSGVpZ2h0BWluZGV4DHdpdGhkcmF3VHhJZAkBC3N0clN3YXBEQVRBEAkAkQMCBQlkYXRhQXJyYXkFDHNJZHhTd2FwVHlwZQIIRklOSVNIRUQJAJEDAgUJZGF0YUFycmF5BQxzSWR4SW5BbW91bnQJAKQDAQUFcHJpY2UJAKQDAQUMb3V0TmV0QW1vdW50CQCkAwEFDG91dEZlZUFtb3VudAkAkQMCBQlkYXRhQXJyYXkFD3NJZHhTdGFydEhlaWdodAkAkQMCBQlkYXRhQXJyYXkFEnNJZHhTdGFydFRpbWVzdGFtcAkApAMBBQZoZWlnaHQJAKQDAQgFCWxhc3RCbG9jawl0aW1lc3RhbXAJAJEDAgUJZGF0YUFycmF5BRRzSWR4U2VsZlVubG9ja0hlaWdodAkApAMBBRByYW5kVW5sb2NrSGVpZ2h0CQCkAwEFBWluZGV4BQx3aXRoZHJhd1R4SWQJAJEDAgUJZGF0YUFycmF5BQtzSWR4TWluUmFuZAkAkQMCBQlkYXRhQXJyYXkFC3NJZHhNYXhSYW5kARJzd2FwRGF0YUZhaWxPclJFQUQCC3VzZXJBZGRyZXNzCHN3YXBUeElkBAdzd2FwS2V5CQEHc3dhcEtFWQIFC3VzZXJBZGRyZXNzBQhzd2FwVHhJZAkAtQkCCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ0IAgUEdGhpcwUHc3dhcEtleQkArAICAhFubyBzd2FwIGRhdGEgZm9yIAUHc3dhcEtleQUDU0VQAQlhcHBseUZlZXMDDmFtb3VudE91dEdyb3NzC2luQW10VG9TVVJGB2ZlZVBhcnQECWZlZUFtb3VudAkAawMFDmFtb3VudE91dEdyb3NzBQdmZWVQYXJ0BQVQQVVMSQkAzAgCCQBlAgUOYW1vdW50T3V0R3Jvc3MFCWZlZUFtb3VudAkAzAgCBQlmZWVBbW91bnQFA25pbAEDYWJzAQF4AwkAZgIAAAUBeAkBAS0BBQF4BQF4AQpzZWxlY3ROb2RlAQ11bmxlYXNlQW1vdW50BA1hbW91bnRUb0xlYXNlCQBlAgkAZQIICQDvBwEFEG5ldXRyaW5vQ29udHJhY3QJYXZhaWxhYmxlBQ11bmxlYXNlQW1vdW50CQEfZ2V0UmVzZXJ2ZWRBbW91bnRGb3JTcG9uc29yc2hpcAAECm9sZExlYXNlZDAJAQ5nZXROdW1iZXJCeUtleQEJARFnZXRMZWFzZUFtb3VudEtleQEAAAQKb2xkTGVhc2VkMQkBDmdldE51bWJlckJ5S2V5AQkBEWdldExlYXNlQW1vdW50S2V5AQABBApuZXdMZWFzZWQwCQBkAgUNYW1vdW50VG9MZWFzZQUKb2xkTGVhc2VkMAQKbmV3TGVhc2VkMQkAZAIFDWFtb3VudFRvTGVhc2UFCm9sZExlYXNlZDEDAwkAZgIFCm5ld0xlYXNlZDAAAAYJAGYCBQpuZXdMZWFzZWQxAAAEBmRlbHRhMAkBA2FicwEJAGUCBQpuZXdMZWFzZWQwBQpvbGRMZWFzZWQxBAZkZWx0YTEJAQNhYnMBCQBlAgUKbmV3TGVhc2VkMQUKb2xkTGVhc2VkMAMJAGcCBQZkZWx0YTEFBmRlbHRhMAkAlAoCAAAFCm5ld0xlYXNlZDAJAJQKAgABBQpuZXdMZWFzZWQxCQCUCgIA////////////AQAAAQh0aGlzT25seQEBaQMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECLVBlcm1pc3Npb24gZGVuaWVkOiB0aGlzIGNvbnRyYWN0IG9ubHkgYWxsb3dlZAYBFnByZXBhcmVVbmxlYXNlQW5kTGVhc2UBDXVubGVhc2VBbW91bnQECW5vZGVUdXBsZQkBCnNlbGVjdE5vZGUBBQ11bmxlYXNlQW1vdW50BAlub2RlSW5kZXgIBQlub2RlVHVwbGUCXzEEDm5ld0xlYXNlQW1vdW50CAUJbm9kZVR1cGxlAl8yAwkAZgIFDm5ld0xlYXNlQW1vdW50AAAECmxlYXNlSWRLZXkJAQ1nZXRMZWFzZUlkS2V5AQUJbm9kZUluZGV4BAhvbGRMZWFzZQkAnAgCBQR0aGlzBQpsZWFzZUlkS2V5BA51bmxlYXNlT3JFbXB0eQMJAQlpc0RlZmluZWQBBQhvbGRMZWFzZQkAzAgCCQELTGVhc2VDYW5jZWwBCQEFdmFsdWUBBQhvbGRMZWFzZQUDbmlsBQNuaWwEDmxlYXNlQW1vdW50S2V5CQERZ2V0TGVhc2VBbW91bnRLZXkBBQlub2RlSW5kZXgEBWxlYXNlCQDECAIJARxnZXRTdGFraW5nTm9kZUFkZHJlc3NCeUluZGV4AQUJbm9kZUluZGV4BQ5uZXdMZWFzZUFtb3VudAkAzggCBQ51bmxlYXNlT3JFbXB0eQkAzAgCBQVsZWFzZQkAzAgCCQELQmluYXJ5RW50cnkCBQpsZWFzZUlkS2V5CQEFbGNhbGMBBQVsZWFzZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBEWdldExlYXNlQW1vdW50S2V5AQUJbm9kZUluZGV4BQ5uZXdMZWFzZUFtb3VudAUDbmlsBQNuaWwBDHJlYWROb2RlSW5mbwEHbm9kZUlkeAQLbm9kZUFkZHJlc3MJARxnZXRTdGFraW5nTm9kZUFkZHJlc3NCeUluZGV4AQUHbm9kZUlkeAQMbGVhc2VkQW10S0VZCQERZ2V0TGVhc2VBbW91bnRLZXkBBQdub2RlSWR4BAlsZWFzZWRBbXQJAQ5nZXROdW1iZXJCeUtleQEFDGxlYXNlZEFtdEtFWQQKbGVhc2VJZEtFWQkBDWdldExlYXNlSWRLZXkBBQdub2RlSWR4BAdsZWFzZUlkCQEFdmFsdWUBCQCcCAIFBHRoaXMFCmxlYXNlSWRLRVkJAJcKBQULbm9kZUFkZHJlc3MFDGxlYXNlZEFtdEtFWQUJbGVhc2VkQW10BQpsZWFzZUlkS0VZBQdsZWFzZUlkAQpjb21tb25Td2FwBQhzd2FwVHlwZQlwbXRBbW91bnQOdXNlckFkZHJlc3NTdHIGdHhJZDU4G3N3YXBQYXJhbXNCeVVzZXJTWVNSRUFET05MWQQOc3dhcExpbWl0U3BlbnQIBRtzd2FwUGFyYW1zQnlVc2VyU1lTUkVBRE9OTFkCXzIEDmJsY2tzMkxtdFJlc2V0CAUbc3dhcFBhcmFtc0J5VXNlclNZU1JFQURPTkxZAl8zBBF3YXZlc1N3YXBMaW1pdE1heAgFG3N3YXBQYXJhbXNCeVVzZXJTWVNSRUFET05MWQJfNgQQdXNkblN3YXBMaW1pdE1heAgFG3N3YXBQYXJhbXNCeVVzZXJTWVNSRUFET05MWQJfNwQNbWluU3dhcEFtb3VudAkBEW1pblN3YXBBbW91bnRSRUFEAQUIc3dhcFR5cGUEC3RvdGFsTG9ja2VkCQEPdG90YWxMb2NrZWRSRUFEAQUIc3dhcFR5cGUEEXRvdGFsTG9ja2VkQnlVc2VyCQEVdG90YWxMb2NrZWRCeVVzZXJSRUFEAgUIc3dhcFR5cGUFDnVzZXJBZGRyZXNzU3RyBAtub2RlQWRkcmVzcwkBFWdldFN0YWtpbmdOb2RlQnlJbmRleAEAAAQMcHJpY2VCeUluZGV4CQEPZ2V0UHJpY2VIaXN0b3J5AQkBFWdldEhlaWdodFByaWNlQnlJbmRleAEFCnByaWNlSW5kZXgEDGlzU3dhcEJ5Tm9kZQkAAAIFC25vZGVBZGRyZXNzBQ51c2VyQWRkcmVzc1N0cgQWYmFsYW5jZUxvY2tNYXhJbnRlcnZhbAMFDGlzU3dhcEJ5Tm9kZQkBG25vZGVCYWxhbmNlTG9ja0ludGVydmFsUkVBRAAJARdiYWxhbmNlTG9ja0ludGVydmFsUkVBRAEFCHN3YXBUeXBlBBBzZWxmVW5sb2NrSGVpZ2h0CQBkAgUGaGVpZ2h0BRZiYWxhbmNlTG9ja01heEludGVydmFsBA5zd2FwVXNkblZvbHVtZQMJAAACBQhzd2FwVHlwZQIIbmV1dHJpbm8FCXBtdEFtb3VudAkBFmNvbnZlcnRXYXZlc1RvTmV1dHJpbm8CBQlwbXRBbW91bnQFDHByaWNlQnlJbmRleAQMc3dhcExpbWl0TWF4AwkAAAIFCHN3YXBUeXBlAghuZXV0cmlubwUQdXNkblN3YXBMaW1pdE1heAkBFmNvbnZlcnRXYXZlc1RvTmV1dHJpbm8CBRF3YXZlc1N3YXBMaW1pdE1heAUMcHJpY2VCeUluZGV4AwkAZgIFDW1pblN3YXBBbW91bnQFCXBtdEFtb3VudAkBEW1pblN3YXBBbW91bnRGQUlMAgUIc3dhcFR5cGUFDW1pblN3YXBBbW91bnQDAwkBASEBBQxpc1N3YXBCeU5vZGUJAGYCBQ5zd2FwTGltaXRTcGVudAAABwkAAgEJAKwCAgI6WW91IGhhdmUgZXhjZWVkZWQgc3dhcCBsaW1pdCEgTmV4dCBhbGxvd2VkIHN3YXAgaGVpZ2h0IGlzIAkApAMBCQBkAgUGaGVpZ2h0BQ5ibGNrczJMbXRSZXNldAMDCQEBIQEFDGlzU3dhcEJ5Tm9kZQkAZgIFDnN3YXBVc2RuVm9sdW1lBQxzd2FwTGltaXRNYXgHCQACAQkArAICCQCsAgIJAKwCAgIuWW91IGhhdmUgZXhjZWVkZWQgeW91ciBzd2FwIGxpbWl0ISBSZXF1ZXN0ZWQ6IAkApAMBBQ5zd2FwVXNkblZvbHVtZQINLCBhdmFpbGFibGU6IAkApAMBBQxzd2FwTGltaXRNYXgDBQlpc0Jsb2NrZWQJARVlbWVyZ2VuY3lTaHV0ZG93bkZBSUwABAlsZWFzZVBhcnQDCQAAAgUIc3dhcFR5cGUCBXdhdmVzCQEWcHJlcGFyZVVubGVhc2VBbmRMZWFzZQEAAAUDbmlsCQCUCgIJAM4IAgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBGGtleVN3YXBVc2VyU3BlbnRJblBlcmlvZAEFDnVzZXJBZGRyZXNzU3RyBQ5zd2FwVXNkblZvbHVtZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBFWtleVVzZXJMYXN0U3dhcEhlaWdodAEFDnVzZXJBZGRyZXNzU3RyBQZoZWlnaHQJAMwIAgkBDEludGVnZXJFbnRyeQIJARR0b3RhbExvY2tlZEJ5VXNlcktFWQIFCHN3YXBUeXBlBQ51c2VyQWRkcmVzc1N0cgkAZAIFEXRvdGFsTG9ja2VkQnlVc2VyBQlwbXRBbW91bnQJAMwIAgkBDEludGVnZXJFbnRyeQIJARhnZXRCYWxhbmNlVW5sb2NrQmxvY2tLZXkBBQ51c2VyQWRkcmVzc1N0cgUQc2VsZlVubG9ja0hlaWdodAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvdGFsTG9ja2VkS0VZAQUIc3dhcFR5cGUJAGQCBQt0b3RhbExvY2tlZAUJcG10QW1vdW50CQDMCAIJAQtTdHJpbmdFbnRyeQIJAQdzd2FwS0VZAgUOdXNlckFkZHJlc3NTdHIFBnR4SWQ1OAkBD3BlbmRpbmdTd2FwREFUQQMFCHN3YXBUeXBlBQlwbXRBbW91bnQFEHNlbGZVbmxvY2tIZWlnaHQFA25pbAUJbGVhc2VQYXJ0BQR1bml0AA9uTWV0cmljSWR4UHJpY2UAAAAbbk1ldHJpY0lkeFVzZG5Mb2NrZWRCYWxhbmNlAAEAHG5NZXRyaWNJZHhXYXZlc0xvY2tlZEJhbGFuY2UAAgARbk1ldHJpY0lkeFJlc2VydmUAAwAXbk1ldHJpY0lkeFJlc2VydmVJblVzZG4ABAAUbk1ldHJpY0lkeFVzZG5TdXBwbHkABQARbk1ldHJpY0lkeFN1cnBsdXMABgAYbk1ldHJpY0lkeFN1cnBsdXNQZXJjZW50AAcADG5NZXRyaWNJZHhCUgAIABRuTWV0cmljSWR4TnNidFN1cHBseQAJABduTWV0cmljSWR4TWF4TnNidFN1cHBseQAKABRuTWV0cmljSWR4U3VyZlN1cHBseQALAAxiRnVuY0lkeFN1cmYAAAANYkZ1bmNJZHhXYXZlcwABAAxiRnVuY0lkeFVzZG4AAgAUYkZ1bmNJZHhSZXNlcnZlU3RhcnQAAwATYkZ1bmNJZHhTdXBwbHlTdGFydAAEAA9iRnVuY0lkeEJSU3RhcnQABQASYkZ1bmNJZHhSZXNlcnZlRW5kAAYAEWJGdW5jSWR4U3VwcGx5RW5kAAcADWJGdW5jSWR4QlJFbmQACAAMYkZ1bmNJZHhSZXN0AAkAEmJGdW5jSWR4V2F2ZXNQcmljZQAKAQ9jYWxjV2l0aGRyYXdXMlUCB3dhdmVzSW4FcHJpY2UEC291dEFtdEdyb3NzCQEWY29udmVydFdhdmVzVG9OZXV0cmlubwIFB3dhdmVzSW4FBXByaWNlCQCbCgkFC291dEFtdEdyb3NzBQ9uZXV0cmlub0Fzc2V0SWQAAAUEdW5pdAAABQd3YXZlc0luAAAAAAAAAQ9jYWxjV2l0aGRyYXdVMlcFBnVzZG5JbgVwcmljZQJicg5yZXNlcnZlc0luVXNkbgp1c2RuU3VwcGx5BAticlByb3RlY3RlZAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEOYnJQcm90ZWN0ZWRLRVkABQtCUlBST1RFQ1RFRAQZbWF4QWxsb3dlZFVzZG5CZWZvcmVNaW5CcgMJAGcCBQticlByb3RlY3RlZAUCYnIAAAkAawMJAGUCBQ5yZXNlcnZlc0luVXNkbgkAawMFC2JyUHJvdGVjdGVkBQp1c2RuU3VwcGx5BQVQQVVMSQUFUEFVTEkJAGUCBQVQQVVMSQULYnJQcm90ZWN0ZWQEFmFsbG93ZWRVc2RuQmVmb3JlTWluQnIDCQBmAgUGdXNkbkluBRltYXhBbGxvd2VkVXNkbkJlZm9yZU1pbkJyBRltYXhBbGxvd2VkVXNkbkJlZm9yZU1pbkJyBQZ1c2RuSW4EFWFsbG93ZWRVc2RuQWZ0ZXJNaW5CcgMJAGYCBQZ1c2RuSW4FGW1heEFsbG93ZWRVc2RuQmVmb3JlTWluQnIJAGsDCQBlAgUGdXNkbkluBRltYXhBbGxvd2VkVXNkbkJlZm9yZU1pbkJyBQJicgUFUEFVTEkAAAQLYWxsb3dlZFVzZG4JAGQCBRZhbGxvd2VkVXNkbkJlZm9yZU1pbkJyBRVhbGxvd2VkVXNkbkFmdGVyTWluQnIECXVzZG4yU1VSRgkAZQIFBnVzZG5JbgULYWxsb3dlZFVzZG4EC291dEFtdEdyb3NzCQEWY29udmVydE5ldXRyaW5vVG9XYXZlcwIFC2FsbG93ZWRVc2RuBQVwcmljZQkAmwoJBQtvdXRBbXRHcm9zcwUEdW5pdAUJdXNkbjJTVVJGBQ9uZXV0cmlub0Fzc2V0SWQFC291dEFtdEdyb3NzBQthbGxvd2VkVXNkbgUZbWF4QWxsb3dlZFVzZG5CZWZvcmVNaW5CcgUWYWxsb3dlZFVzZG5CZWZvcmVNaW5CcgUVYWxsb3dlZFVzZG5BZnRlck1pbkJyAQxjYWxjV2l0aGRyYXcDCHN3YXBUeXBlCGluQW1vdW50BXByaWNlBApvdXRGZWVQYXJ0CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQ1vdXRGZWVQYXJ0S0VZAQUIc3dhcFR5cGUFDkRFRkFVTFRTV0FQRkVFAwMJAGYCAAAFCm91dEZlZVBhcnQGCQBnAgUKb3V0RmVlUGFydAUFUEFVTEkJAAIBCQCsAgIJAKwCAgkArAICAh5pbnZhbGlkIG91dEZlZVBhcnQgY29uZmlnIGZvciAFCHN3YXBUeXBlAhIgc3dhcDogb3V0RmVlUGFydD0JAKQDAQUKb3V0RmVlUGFydAQLYnJQcm90ZWN0ZWQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBDmJyUHJvdGVjdGVkS0VZAAULQlJQUk9URUNURUQED25ldXRyaW5vTWV0cmljcwkBCWFzQW55TGlzdAEJAPwHBAUMbWF0aENvbnRyYWN0AhpjYWxjTmV1dGlub01ldHJpY3NSRUFET05MWQUDbmlsBQNuaWwEAkJSCQEFYXNJbnQBCQCRAwIFD25ldXRyaW5vTWV0cmljcwUMbk1ldHJpY0lkeEJSBA5yZXNlcnZlc0luVXNkbgkBBWFzSW50AQkAkQMCBQ9uZXV0cmlub01ldHJpY3MFF25NZXRyaWNJZHhSZXNlcnZlSW5Vc2RuBAp1c2RuU3VwcGx5CQEFYXNJbnQBCQCRAwIFD25ldXRyaW5vTWV0cmljcwUUbk1ldHJpY0lkeFVzZG5TdXBwbHkEDG91dERhdGFUdXBsZQMJAAACBQhzd2FwVHlwZQIFd2F2ZXMJAQ9jYWxjV2l0aGRyYXdXMlUCBQhpbkFtb3VudAUFcHJpY2UDCQAAAgUIc3dhcFR5cGUCCG5ldXRyaW5vCQEPY2FsY1dpdGhkcmF3VTJXBQUIaW5BbW91bnQFBXByaWNlBQJCUgUOcmVzZXJ2ZXNJblVzZG4FCnVzZG5TdXBwbHkJAAIBCQCsAgICFlVuc3VwcG9ydGVkIHN3YXAgdHlwZSAFCHN3YXBUeXBlBAtvdXRBbXRHcm9zcwgFDG91dERhdGFUdXBsZQJfMQQKb3V0QXNzZXRJZAgFDG91dERhdGFUdXBsZQJfMgQPaW5BbXRUb1N1cmZQYXJ0CAUMb3V0RGF0YVR1cGxlAl8zBAlpbkFzc2V0SWQIBQxvdXREYXRhVHVwbGUCXzQECnVubGVhc2VBbXQIBQxvdXREYXRhVHVwbGUCXzUEDHBheW91dHNBcnJheQkBCWFwcGx5RmVlcwMFC291dEFtdEdyb3NzBQ9pbkFtdFRvU3VyZlBhcnQFCm91dEZlZVBhcnQECW91dE5ldEFtdAkAkQMCBQxwYXlvdXRzQXJyYXkFDElkeE5ldEFtb3VudAQJb3V0RmVlQW10CQCRAwIFDHBheW91dHNBcnJheQUMSWR4RmVlQW1vdW50BApvdXRTdXJmQW10AwkAZwIAAAUPaW5BbXRUb1N1cmZQYXJ0AAAECnN1cmZSZXN1bHQJAQlhc0FueUxpc3QBCQD8BwQFDG1hdGhDb250cmFjdAIUc3VyZkZ1bmN0aW9uUkVBRE9OTFkJAMwIAgUPaW5BbXRUb1N1cmZQYXJ0CQDMCAIFCWluQXNzZXRJZAUDbmlsBQNuaWwJAQVhc0ludAEJAJEDAgUKc3VyZlJlc3VsdAUMYkZ1bmNJZHhTdXJmCQCZCgcFCW91dE5ldEFtdAUKb3V0QXNzZXRJZAUKb3V0U3VyZkFtdAUPaW5BbXRUb1N1cmZQYXJ0BQp1bmxlYXNlQW10BQlvdXRGZWVBbXQFC291dEFtdEdyb3NzAQ5jb21tb25XaXRoZHJhdwQHYWNjb3VudAVpbmRleAhzd2FwVHhJZAx3aXRoZHJhd1R4SWQEC3VzZXJBZGRyZXNzCQERQGV4dHJOYXRpdmUoMTA2MikBBQdhY2NvdW50BAlkYXRhQXJyYXkJARJzd2FwRGF0YUZhaWxPclJFQUQCBQdhY2NvdW50BQhzd2FwVHhJZAQQc2VsZlVubG9ja0hlaWdodAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCWRhdGFBcnJheQUUc0lkeFNlbGZVbmxvY2tIZWlnaHQECHN3YXBUeXBlCQCRAwIFCWRhdGFBcnJheQUMc0lkeFN3YXBUeXBlBAhpbkFtb3VudAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCWRhdGFBcnJheQUMc0lkeEluQW1vdW50BApzd2FwU3RhdHVzCQCRAwIFCWRhdGFBcnJheQUKc0lkeFN0YXR1cwQLc3RhcnRIZWlnaHQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQlkYXRhQXJyYXkFD3NJZHhTdGFydEhlaWdodAQKb3V0RmVlUGFydAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQENb3V0RmVlUGFydEtFWQEFCHN3YXBUeXBlBQ5ERUZBVUxUU1dBUEZFRQQLdG90YWxMb2NrZWQJAQ90b3RhbExvY2tlZFJFQUQBBQhzd2FwVHlwZQQRdG90YWxMb2NrZWRCeVVzZXIJARV0b3RhbExvY2tlZEJ5VXNlclJFQUQCBQhzd2FwVHlwZQUHYWNjb3VudAQMdW5sb2NrSGVpZ2h0BRBzZWxmVW5sb2NrSGVpZ2h0BAtpbmRleEhlaWdodAkBFWdldEhlaWdodFByaWNlQnlJbmRleAEFBWluZGV4BA9wcmV2SW5kZXhIZWlnaHQJARVnZXRIZWlnaHRQcmljZUJ5SW5kZXgBCQBlAgUFaW5kZXgAAQQMcHJpY2VCeUluZGV4CQEPZ2V0UHJpY2VIaXN0b3J5AQULaW5kZXhIZWlnaHQDBQlpc0Jsb2NrZWQJARVlbWVyZ2VuY3lTaHV0ZG93bkZBSUwAAwkBAiE9AgUKc3dhcFN0YXR1cwIHUEVORElORwkAAgECH3N3YXAgaGFzIGJlZW4gYWxyZWFkeSBwcm9jZXNzZWQDCQBmAgUMdW5sb2NrSGVpZ2h0BQZoZWlnaHQJAAIBCQCsAgIJAKwCAgIRcGxlYXNlIHdhaXQgZm9yOiAJAKQDAQUMdW5sb2NrSGVpZ2h0Ah8gYmxvY2sgaGVpZ2h0IHRvIHdpdGhkcmF3IGZ1bmRzAwMDCQBmAgUFaW5kZXgFCnByaWNlSW5kZXgGCQBmAgUMdW5sb2NrSGVpZ2h0BQtpbmRleEhlaWdodAYDCQECIT0CBQ9wcmV2SW5kZXhIZWlnaHQAAAkAZwIFD3ByZXZJbmRleEhlaWdodAUMdW5sb2NrSGVpZ2h0BwkBDnByaWNlSW5kZXhGQUlMBQUFaW5kZXgFCnByaWNlSW5kZXgFC2luZGV4SGVpZ2h0BQx1bmxvY2tIZWlnaHQFD3ByZXZJbmRleEhlaWdodAQNd2l0aGRyYXdUdXBsZQkBDGNhbGNXaXRoZHJhdwMFCHN3YXBUeXBlBQhpbkFtb3VudAUMcHJpY2VCeUluZGV4BAxvdXROZXRBbW91bnQIBQ13aXRoZHJhd1R1cGxlAl8xBApvdXRBc3NldElkCAUNd2l0aGRyYXdUdXBsZQJfMgQKb3V0U3VyZkFtdAgFDXdpdGhkcmF3VHVwbGUCXzMED2luQW10VG9TdXJmUGFydAgFDXdpdGhkcmF3VHVwbGUCXzQECnVubGVhc2VBbXQIBQ13aXRoZHJhd1R1cGxlAl81BAxvdXRGZWVBbW91bnQIBQ13aXRoZHJhd1R1cGxlAl82BAtvdXRBbXRHcm9zcwgFDXdpdGhkcmF3VHVwbGUCXzcDCQBnAgAABQtvdXRBbXRHcm9zcwkAAgECE2JhbGFuY2UgZXF1YWxzIHplcm8EBXN0YXRlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEUdG90YWxMb2NrZWRCeVVzZXJLRVkCBQhzd2FwVHlwZQUHYWNjb3VudAkAZQIFEXRvdGFsTG9ja2VkQnlVc2VyBQhpbkFtb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvdGFsTG9ja2VkS0VZAQUIc3dhcFR5cGUJAGUCBQt0b3RhbExvY2tlZAUIaW5BbW91bnQJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwULdXNlckFkZHJlc3MFDG91dE5ldEFtb3VudAUKb3V0QXNzZXRJZAkAzAgCCQELU3RyaW5nRW50cnkCCQEHc3dhcEtFWQIFB2FjY291bnQFCHN3YXBUeElkCQEOZmluaXNoU3dhcERBVEEHBQlkYXRhQXJyYXkFDHByaWNlQnlJbmRleAUMb3V0TmV0QW1vdW50BQxvdXRGZWVBbW91bnQFDHVubG9ja0hlaWdodAUFaW5kZXgFDHdpdGhkcmF3VHhJZAUDbmlsBA1zdXJmQ29uZGl0aW9uAwkAZgIFCm91dFN1cmZBbXQAAAQLaXNzdWVSZXN1bHQJAPwHBAUPYXVjdGlvbkNvbnRyYWN0Aglpc3N1ZVN1cmYJAMwIAgUKb3V0U3VyZkFtdAkAzAgCBQdhY2NvdW50BQNuaWwFA25pbAMJAAACBQtpc3N1ZVJlc3VsdAULaXNzdWVSZXN1bHQAAAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgAAAwkAAAIFDXN1cmZDb25kaXRpb24FDXN1cmZDb25kaXRpb24JAJUKAwUFc3RhdGUJAQ9BdHRhY2hlZFBheW1lbnQCBQpvdXRBc3NldElkBQxvdXRGZWVBbW91bnQFCnVubGVhc2VBbXQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4OAWkBC2NvbnN0cnVjdG9yDBJuZXV0cmlub0Fzc2V0SWRQcm0OYm9uZEFzc2V0SWRQcm0SYXVjdGlvbkNvbnRyYWN0UHJtFmxpcXVpZGF0aW9uQ29udHJhY3RQcm0OcnBkQ29udHJhY3RQcm0bbm9kZU9yYWNsZVByb3ZpZGVyUHViS2V5UHJtG2JhbGFuY2VXYXZlc0xvY2tJbnRlcnZhbFBybR5iYWxhbmNlTmV1dHJpbm9Mb2NrSW50ZXJ2YWxQcm0VbWluV2F2ZXNTd2FwQW1vdW50UHJtGG1pbk5ldXRyaW5vU3dhcEFtb3VudFBybRVuZXV0cmlub091dEZlZVBhcnRQcm0Sd2F2ZXNPdXRGZWVQYXJ0UHJtBAtjaGVja0NhbGxlcgkBCHRoaXNPbmx5AQUBaQMJAAACBQtjaGVja0NhbGxlcgULY2hlY2tDYWxsZXIDCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAAJAAIBAhNubyBwYXltZW50cyBhbGxvd2VkCQDMCAIJAQtTdHJpbmdFbnRyeQIFEk5ldXRyaW5vQXNzZXRJZEtleQUSbmV1dHJpbm9Bc3NldElkUHJtCQDMCAIJAQtTdHJpbmdFbnRyeQIFDkJvbmRBc3NldElkS2V5BQ5ib25kQXNzZXRJZFBybQkAzAgCCQELU3RyaW5nRW50cnkCBRJBdWN0aW9uQ29udHJhY3RLZXkFEmF1Y3Rpb25Db250cmFjdFBybQkAzAgCCQELU3RyaW5nRW50cnkCBRZMaXF1aWRhdGlvbkNvbnRyYWN0S2V5BRZsaXF1aWRhdGlvbkNvbnRyYWN0UHJtCQDMCAIJAQtTdHJpbmdFbnRyeQIFDlJQRENvbnRyYWN0S2V5BQ5ycGRDb250cmFjdFBybQkAzAgCCQELU3RyaW5nRW50cnkCBRtOb2RlT3JhY2xlUHJvdmlkZXJQdWJLZXlLZXkFG25vZGVPcmFjbGVQcm92aWRlclB1YktleVBybQkAzAgCCQEMSW50ZWdlckVudHJ5AgUbQmFsYW5jZVdhdmVzTG9ja0ludGVydmFsS2V5BRtiYWxhbmNlV2F2ZXNMb2NrSW50ZXJ2YWxQcm0JAMwIAgkBDEludGVnZXJFbnRyeQIFHkJhbGFuY2VOZXV0cmlub0xvY2tJbnRlcnZhbEtleQUeYmFsYW5jZU5ldXRyaW5vTG9ja0ludGVydmFsUHJtCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRVNaW5XYXZlc1N3YXBBbW91bnRLZXkFFW1pbldhdmVzU3dhcEFtb3VudFBybQkAzAgCCQEMSW50ZWdlckVudHJ5AgUYTWluTmV1dHJpbm9Td2FwQW1vdW50S2V5BRhtaW5OZXV0cmlub1N3YXBBbW91bnRQcm0JAMwIAgkBDEludGVnZXJFbnRyeQIFFU5ldXRyaW5vT3V0RmVlUGFydEtleQUVbmV1dHJpbm9PdXRGZWVQYXJ0UHJtCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRJXYXZlc091dEZlZVBhcnRLZXkFEndhdmVzT3V0RmVlUGFydFBybQUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDWNvbnN0cnVjdG9yVjIDDG1hdGhDb250cmFjdBNuc2J0U3Rha2luZ0NvbnRyYWN0FHN3YXBzVGltZWZyYW1lQmxvY2tzBAtjaGVja0NhbGxlcgkBCHRoaXNPbmx5AQUBaQMJAAACBQtjaGVja0NhbGxlcgULY2hlY2tDYWxsZXIDCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAAJAAIBAhNubyBwYXltZW50cyBhbGxvd2VkCQDMCAIJAQtTdHJpbmdFbnRyeQIFD01hdGhDb250cmFjdEtleQUMbWF0aENvbnRyYWN0CQDMCAIJAQtTdHJpbmdFbnRyeQIFFk5zYnRTdGFraW5nQ29udHJhY3RLZXkFE25zYnRTdGFraW5nQ29udHJhY3QJAMwIAgkBDEludGVnZXJFbnRyeQIJARFzd2Fwc1RpbWVmcmFtZUtFWQAFFHN3YXBzVGltZWZyYW1lQmxvY2tzBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQETc3dhcFdhdmVzVG9OZXV0cmlubwADCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAEJAAIBAixzd2FwV2F2ZXNUb05ldXRyaW5vIHJlcXVpcmUgb25seSBvbmUgcGF5bWVudAQDcG10CQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAADCQEJaXNEZWZpbmVkAQgFA3BtdAdhc3NldElkCQACAQIpT25seSBXYXZlcyB0b2tlbiBpcyBhbGxvd2VkIGZvciBzd2FwcGluZy4EC3VzZXJBZGRyZXNzCQClCAEIBQFpBmNhbGxlcgQGdHhJZDU4CQDYBAEIBQFpDXRyYW5zYWN0aW9uSWQEEHN3YXBQYXJhbXNTVFJVQ1QJARJhc1N3YXBQYXJhbXNTVFJVQ1QBCQD8BwQFBHRoaXMCG3N3YXBQYXJhbXNCeVVzZXJTWVNSRUFET05MWQkAzAgCBQt1c2VyQWRkcmVzcwkAzAgCAAAFA25pbAUDbmlsBBBjb21tb25Td2FwUmVzdWx0CQEKY29tbW9uU3dhcAUCBXdhdmVzCAUDcG10BmFtb3VudAULdXNlckFkZHJlc3MFBnR4SWQ1OAUQc3dhcFBhcmFtc1NUUlVDVAUQY29tbW9uU3dhcFJlc3VsdAFpARNzd2FwTmV1dHJpbm9Ub1dhdmVzAAMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAQkAAgECLHN3YXBOZXV0cmlub1RvV2F2ZXMgcmVxdWlyZSBvbmx5IG9uZSBwYXltZW50BANwbXQJAQV2YWx1ZQEJAJEDAggFAWkIcGF5bWVudHMAAAMJAQIhPQIIBQNwbXQHYXNzZXRJZAUPbmV1dHJpbm9Bc3NldElkCQACAQI6T25seSBhcHByb3ByaWF0ZSBOZXV0cmlubyB0b2tlbnMgYXJlIGFsbG93ZWQgZm9yIHN3YXBwaW5nLgQLdXNlckFkZHJlc3MJAKUIAQgFAWkGY2FsbGVyBAZ0eElkNTgJANgEAQgFAWkNdHJhbnNhY3Rpb25JZAQQc3dhcFBhcmFtc1NUUlVDVAkBEmFzU3dhcFBhcmFtc1NUUlVDVAEJAPwHBAUEdGhpcwIbc3dhcFBhcmFtc0J5VXNlclNZU1JFQURPTkxZCQDMCAIFC3VzZXJBZGRyZXNzCQDMCAIAAAUDbmlsBQNuaWwEEGNvbW1vblN3YXBSZXN1bHQJAQpjb21tb25Td2FwBQIIbmV1dHJpbm8IBQNwbXQGYW1vdW50BQt1c2VyQWRkcmVzcwUGdHhJZDU4BRBzd2FwUGFyYW1zU1RSVUNUBRBjb21tb25Td2FwUmVzdWx0AWkBCHdpdGhkcmF3AwdhY2NvdW50BWluZGV4CHN3YXBUeElkBAR0eElkCQDYBAEIBQFpDXRyYW5zYWN0aW9uSWQDCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAAJAAIBAhNubyBwYXltZW50cyBhbGxvd2VkBAtjb21tb25UdXBsZQkBDmNvbW1vbldpdGhkcmF3BAUHYWNjb3VudAUFaW5kZXgFCHN3YXBUeElkBQR0eElkBAVzdGF0ZQgFC2NvbW1vblR1cGxlAl8xBANmZWUIBQtjb21tb25UdXBsZQJfMgQKdW5sZWFzZUFtdAgFC2NvbW1vblR1cGxlAl8zBBF1bmxlYXNlSW52T3JFbXB0eQkA/AcEBQR0aGlzAhdpbnRlcm5hbFVubGVhc2VBbmRMZWFzZQkAzAgCBQp1bmxlYXNlQW10BQNuaWwFA25pbAMJAAACBRF1bmxlYXNlSW52T3JFbXB0eQURdW5sZWFzZUludk9yRW1wdHkECWduc2J0RGF0YQkBCWFzQW55TGlzdAEJAPwHBAUXZ25zYnRDb250cm9sbGVyQ29udHJhY3QCFGduc2J0SW5mb1NZU1JFQURPTkxZCQDMCAICAAkAzAgCAAAJAMwIAgAABQNuaWwFA25pbAQNZ25zYnRBbXRUb3RhbAkBBWFzSW50AQkAkQMCBQlnbnNidERhdGEAAQQVZ25zYnRBbXRGcm9tU3VyZlRvdGFsCQEFYXNJbnQBCQCRAwIJAQlhc0FueUxpc3QBCQCRAwIFCWduc2J0RGF0YQADAAMECnN1cmZGZWVBbXQDCQECIT0CBQ1nbnNidEFtdFRvdGFsAAAJAGsDCAUDZmVlBmFtb3VudAUVZ25zYnRBbXRGcm9tU3VyZlRvdGFsBQ1nbnNidEFtdFRvdGFsAAAECm5zYnRGZWVBbXQJAGUCCAUDZmVlBmFtb3VudAUKc3VyZkZlZUFtdAQLc3VyZkRlcG9zaXQDCQBmAgUKc3VyZkZlZUFtdAAABAdzdXJmSW52CQD8BwQFE3N1cmZTdGFraW5nQ29udHJhY3QCB2RlcG9zaXQFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AggFA2ZlZQdhc3NldElkBQpzdXJmRmVlQW10BQNuaWwDCQAAAgUHc3VyZkludgUHc3VyZkludgUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgULc3VyZkRlcG9zaXQFC3N1cmZEZXBvc2l0BAtuc2J0RGVwb3NpdAMJAGYCBQpuc2J0RmVlQW10AAAEB25zYnRJbnYJAPwHBAUTbnNidFN0YWtpbmdDb250cmFjdAIHZGVwb3NpdAUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCAUDZmVlB2Fzc2V0SWQFCm5zYnRGZWVBbXQFA25pbAMJAAACBQduc2J0SW52BQduc2J0SW52BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBQtuc2J0RGVwb3NpdAULbnNidERlcG9zaXQFBXN0YXRlCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBF2ludGVybmFsVW5sZWFzZUFuZExlYXNlAQ11bmxlYXNlQW1vdW50AwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIsaW50ZXJuYWxVbmxlYXNlQW5kTGVhc2UgaXMgbm90IHB1YmxpYyBtZXRob2QJARZwcmVwYXJlVW5sZWFzZUFuZExlYXNlAQUNdW5sZWFzZUFtb3VudAFpARJ0cmFuc2ZlclVzZG5Ub1VzZXICBmFtb3VudARhZGRyAwkBAiE9AggFAWkGY2FsbGVyBQ9hdWN0aW9uQ29udHJhY3QJAAIBAiNPbmx5IGF1Y3Rpb24gY29udHJhY3QgaXMgYXV0aG9yaXplZAkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCQERQGV4dHJOYXRpdmUoMTA2MikBBQRhZGRyBQZhbW91bnQFD25ldXRyaW5vQXNzZXRJZAUDbmlsAWkBC2FjY2VwdFdhdmVzAAMJAQIhPQIIBQFpBmNhbGxlcgUPYXVjdGlvbkNvbnRyYWN0CQACAQIyQ3VycmVudGx5IG9ubHkgYXVjdGlvbiBjb250cmFjdCBpcyBhbGxvd2VkIHRvIGNhbGwJAJQKAgkBFnByZXBhcmVVbmxlYXNlQW5kTGVhc2UBAAACB3N1Y2Nlc3MBaQEPYXBwcm92ZUxlYXNpbmdzAgZuTGlzdFMIZ3JvdXBOdW0EBGxBbXQJAGgCADIFB1dBVkVMRVQEBW5JZHhzCQDMCAIAAAkAzAgCAAEJAMwIAgACCQDMCAIAAwkAzAgCAAQJAMwIAgAFCQDMCAIABgkAzAgCAAcFA25pbAQHbW5nUHViUwkBC3ZhbHVlT3JFbHNlAgkAoggBAhwlcyVzX19jZmdfX2xlYXNpbmdNYW5hZ2VyUHViAiw3QVVNWDU0dWtZTVl2UG1tYTd5b0ZmNU5qWmhzNEJ1NW56M0V6OUVWOHN1cgQGbW5nUHViCQDZBAEFB21uZ1B1YlMEDm5vZGVSZWdBZGRyU3RyCQELdmFsdWVPckVsc2UCCQCiCAECHyVzJXNfX2NmZ19fbm9kZXNSZWdpc3RyeUFkZHJlc3MCIzNQOXZLcVFLalVkbXBYQWZpV2F1OGtyUkVZQVkxWHI2OXBFBAtub2RlUmVnQWRkcgkBEUBleHRyTmF0aXZlKDEwNjIpAQUObm9kZVJlZ0FkZHJTdHIEEWxHcm91cE5vZGVMaXN0S0VZCQEYZ2V0TGVhc2VHcm91cE5vZGVMaXN0S2V5AQUIZ3JvdXBOdW0ECmxHck5vZGVPcHQJAJ0IAgUEdGhpcwURbEdyb3VwTm9kZUxpc3RLRVkDCQEJaXNEZWZpbmVkAQUKbEdyTm9kZU9wdAkAAgEJAKwCAgkArAICAgZncm91cCAJAKQDAQUIZ3JvdXBOdW0CFCBhbHJlYWR5IGluaXRpYWxpemVkBAVuTGlzdAkAtQkCBQZuTGlzdFMFA1NFUAQIZXhwQ291bnQJAJADAQUFbklkeHMDCQECIT0CCAUBaQ9jYWxsZXJQdWJsaWNLZXkFBm1uZ1B1YgkAAgECHmFwcHJvdmVMZWFzaW5ncyBub3QgYXV0aG9yaXplZAQNJHQwMzM2MzkzMzcwMQkBDHJlYWROb2RlSW5mbwEAAAQGbkFkZHIwCAUNJHQwMzM2MzkzMzcwMQJfMQQIbEFtdEtFWTAIBQ0kdDAzMzYzOTMzNzAxAl8yBAVsQW10MAgFDSR0MDMzNjM5MzM3MDECXzMEB2xJZEtFWTAIBQ0kdDAzMzYzOTMzNzAxAl80BARsSWQwCAUNJHQwMzM2MzkzMzcwMQJfNQQNJHQwMzM3MDQzMzc2NgkBDHJlYWROb2RlSW5mbwEAAQQGbkFkZHIxCAUNJHQwMzM3MDQzMzc2NgJfMQQIbEFtdEtFWTEIBQ0kdDAzMzcwNDMzNzY2Al8yBAVsQW10MQgFDSR0MDMzNzA0MzM3NjYCXzMEB2xJZEtFWTEIBQ0kdDAzMzcwNDMzNzY2Al80BARsSWQxCAUNJHQwMzM3MDQzMzc2NgJfNQQFbmV3TDAJAMQIAgUGbkFkZHIwCQBlAgUFbEFtdDAJAGkCCQBoAgUEbEFtdAUIZXhwQ291bnQAAgQFbmV3TDEJAMQIAgUGbkFkZHIxCQBlAgUFbEFtdDEJAGkCCQBoAgUEbEFtdAUIZXhwQ291bnQAAgQKdmFsaWRhdGlvbgkA/AcEBQtub2RlUmVnQWRkcgIadmFsaWRhdGVBbmRBcHByb3ZlTGVhc2luZ3MJAMwIAgUGbkxpc3RTBQNuaWwFA25pbAMJAAACBQp2YWxpZGF0aW9uBQp2YWxpZGF0aW9uCgEjZm9yRWFjaE5vZGVWYWxpZGF0ZUFuZEdlbmVyYXRlTGVhc2UCAWEBaQQEbm9kZQkAkQMCBQVuTGlzdAUBaQQCbGEJAMQIAgkBEUBleHRyTmF0aXZlKDEwNjIpAQUEbm9kZQUEbEFtdAkAzggCBQFhCQDMCAIFAmxhCQDMCAIJAQtCaW5hcnlFbnRyeQIJARZnZXRMZWFzZUlkQnlBZGRyZXNzS2V5AQUEbm9kZQkBBWxjYWxjAQUCbGEJAMwIAgkBDEludGVnZXJFbnRyeQIJARpnZXRMZWFzZUFtb3VudEJ5QWRkcmVzc0tleQEFBG5vZGUFBGxBbXQFA25pbAkAzggCCQDMCAIJAQtTdHJpbmdFbnRyeQIFEWxHcm91cE5vZGVMaXN0S0VZBQZuTGlzdFMJAMwIAgkBC0JpbmFyeUVudHJ5AgUHbElkS0VZMAkBBWxjYWxjAQUFbmV3TDAJAMwIAgkBC0JpbmFyeUVudHJ5AgUHbElkS0VZMQkBBWxjYWxjAQUFbmV3TDEJAMwIAgkBDEludGVnZXJFbnRyeQIFCGxBbXRLRVkwCAUFbmV3TDAGYW1vdW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCBQhsQW10S0VZMQgFBW5ld0wxBmFtb3VudAkAzAgCCQELTGVhc2VDYW5jZWwBBQRsSWQwCQDMCAIJAQtMZWFzZUNhbmNlbAEFBGxJZDEJAMwIAgUFbmV3TDAJAMwIAgUFbmV3TDEFA25pbAoAAiRsBQVuSWR4cwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEjZm9yRWFjaE5vZGVWYWxpZGF0ZUFuZEdlbmVyYXRlTGVhc2UCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECE0xpc3Qgc2l6ZSBleGNlZWRzIDgJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAICQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBEXJlYmFsYW5jZUxlYXNpbmdzAgZhbW91bnQIZ3JvdXBOdW0EBW5JZHhzCQDMCAIAAAkAzAgCAAEJAMwIAgACCQDMCAIAAwkAzAgCAAQJAMwIAgAFCQDMCAIABgkAzAgCAAcFA25pbAQHbW5nUHViUwkBC3ZhbHVlT3JFbHNlAgkAoggBAhwlcyVzX19jZmdfX2xlYXNpbmdNYW5hZ2VyUHViAiw3QVVNWDU0dWtZTVl2UG1tYTd5b0ZmNU5qWmhzNEJ1NW56M0V6OUVWOHN1cgQGbW5nUHViCQDZBAEFB21uZ1B1YlMEEWxHcm91cE5vZGVMaXN0S0VZCQEYZ2V0TGVhc2VHcm91cE5vZGVMaXN0S2V5AQUIZ3JvdXBOdW0EBm5MaXN0UwkBD2dldFN0cmluZ09yRmFpbAIFBHRoaXMFEWxHcm91cE5vZGVMaXN0S0VZBAVuTGlzdAkAtQkCBQZuTGlzdFMFA1NFUAMJAQIhPQIIBQFpD2NhbGxlclB1YmxpY0tleQUGbW5nUHViCQACAQIgcmViYWxhbmNlTGVhc2luZ3Mgbm90IGF1dGhvcml6ZWQECnVubGVhc2VBbXQJAGQCCQBpAgUGYW1vdW50CQCQAwEFBW5MaXN0AAEEDSR0MDM1MTgzMzUyNDUJAQxyZWFkTm9kZUluZm8BAAAEBm5BZGRyMAgFDSR0MDM1MTgzMzUyNDUCXzEECGxBbXRLRVkwCAUNJHQwMzUxODMzNTI0NQJfMgQFbEFtdDAIBQ0kdDAzNTE4MzM1MjQ1Al8zBAdsSWRLRVkwCAUNJHQwMzUxODMzNTI0NQJfNAQEbElkMAgFDSR0MDM1MTgzMzUyNDUCXzUEBW5ld0wwCQDECAIFBm5BZGRyMAkAZAIFBWxBbXQwCQBoAgUKdW5sZWFzZUFtdAkAkAMBBQVuTGlzdAoBFGZvckVhY2hOb2RlRG9VbmxlYXNlAgFhAWkEBG5vZGUJAJEDAgUFbkxpc3QFAWkEBmxJZEtFWQkBFmdldExlYXNlSWRCeUFkZHJlc3NLZXkBBQRub2RlBANsSWQJARFAZXh0ck5hdGl2ZSgxMDUyKQIFBHRoaXMFBmxJZEtFWQQHbEFtdEtFWQkBGmdldExlYXNlQW1vdW50QnlBZGRyZXNzS2V5AQUEbm9kZQQEbEFtdAkBEUBleHRyTmF0aXZlKDEwNTApAgUEdGhpcwUHbEFtdEtFWQQDdWxhCQELTGVhc2VDYW5jZWwBCQEFdmFsdWUBBQNsSWQEAmxhCQDECAIJARFAZXh0ck5hdGl2ZSgxMDYyKQEFBG5vZGUJAGUCBQRsQW10BQp1bmxlYXNlQW10CQDOCAIFAWEJAMwIAgkBC0xlYXNlQ2FuY2VsAQkBBXZhbHVlAQUDbElkCQDMCAIFAmxhCQDMCAIJAQtCaW5hcnlFbnRyeQIFBmxJZEtFWQkBBWxjYWxjAQUCbGEJAMwIAgkBDEludGVnZXJFbnRyeQIFB2xBbXRLRVkIBQJsYQZhbW91bnQFA25pbAkAzggCCgACJGwFBW5JZHhzCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARRmb3JFYWNoTm9kZURvVW5sZWFzZQIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQITTGlzdCBzaXplIGV4Y2VlZHMgOAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgJAMwIAgkBC0JpbmFyeUVudHJ5AgUHbElkS0VZMAkBBWxjYWxjAQUFbmV3TDAJAMwIAgkBDEludGVnZXJFbnRyeQIFCGxBbXRLRVkwCAUFbmV3TDAGYW1vdW50CQDMCAIJAQtMZWFzZUNhbmNlbAEFBGxJZDAJAMwIAgUFbmV3TDAFA25pbAFpARtzd2FwUGFyYW1zQnlVc2VyU1lTUkVBRE9OTFkCDnVzZXJBZGRyZXNzU3RyCWduc2J0RGlmZgQJZ25zYnREYXRhCQEJYXNBbnlMaXN0AQkA/AcEBRdnbnNidENvbnRyb2xsZXJDb250cmFjdAIUZ25zYnRJbmZvU1lTUkVBRE9OTFkJAMwIAgUOdXNlckFkZHJlc3NTdHIJAMwIAgAACQDMCAIAAAUDbmlsBQNuaWwECGduc2J0QW10CQBkAgkBBWFzSW50AQkAkQMCBQlnbnNidERhdGEAAAUJZ25zYnREaWZmBA1nbnNidEFtdFRvdGFsCQBkAgkBBWFzSW50AQkAkQMCBQlnbnNidERhdGEAAQUJZ25zYnREaWZmBA1zd2FwTGltaXREYXRhCQEJYXNBbnlMaXN0AQkA/AcEBQxtYXRoQ29udHJhY3QCFWNhbGNTd2FwTGltaXRSRUFET05MWQkAzAgCBQhnbnNidEFtdAUDbmlsBQNuaWwEF3dhdmVzU3dhcExpbWl0SW5Vc2RuTWF4CQEFYXNJbnQBCQCRAwIFDXN3YXBMaW1pdERhdGEAAAQRd2F2ZXNTd2FwTGltaXRNYXgJAQVhc0ludAEJAJEDAgUNc3dhcExpbWl0RGF0YQABBBB1c2RuU3dhcExpbWl0TWF4CQEFYXNJbnQBCQCRAwIFDXN3YXBMaW1pdERhdGEAAgQObGFzdFN3YXBIZWlnaHQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBFWtleVVzZXJMYXN0U3dhcEhlaWdodAEFDnVzZXJBZGRyZXNzU3RyAAAEF3N3YXBMaW1pdFRpbWVsaWZlQmxvY2tzCQESc3dhcHNUaW1lZnJhbWVSRUFEAAQZcGFzc2VkQmxvY2tzQWZ0ZXJMYXN0U3dhcAkAZQIFBmhlaWdodAUObGFzdFN3YXBIZWlnaHQEEWlzU3dhcFRpbWVsaWZlTmV3CQBnAgUZcGFzc2VkQmxvY2tzQWZ0ZXJMYXN0U3dhcAUXc3dhcExpbWl0VGltZWxpZmVCbG9ja3MEFHN3YXBMaW1pdFNwZW50SW5Vc2RuAwURaXNTd2FwVGltZWxpZmVOZXcAAAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEYa2V5U3dhcFVzZXJTcGVudEluUGVyaW9kAQUOdXNlckFkZHJlc3NTdHIAAAQOYmxja3MyTG10UmVzZXQDBRFpc1N3YXBUaW1lbGlmZU5ldwAACQBlAgUXc3dhcExpbWl0VGltZWxpZmVCbG9ja3MFGXBhc3NlZEJsb2Nrc0FmdGVyTGFzdFN3YXAJAJQKAgUDbmlsCQCZCgcFF3dhdmVzU3dhcExpbWl0SW5Vc2RuTWF4BRRzd2FwTGltaXRTcGVudEluVXNkbgUOYmxja3MyTG10UmVzZXQFCGduc2J0QW10BQ1nbnNidEFtdFRvdGFsBRF3YXZlc1N3YXBMaW1pdE1heAUQdXNkblN3YXBMaW1pdE1heAFpAR1jYWxjV2l0aGRyYXdSZXN1bHRTWVNSRUFET05MWQMIc3dhcFR5cGUIaW5BbW91bnQFcHJpY2UJAJQKAgUDbmlsCQEMY2FsY1dpdGhkcmF3AwUIc3dhcFR5cGUFCGluQW1vdW50BQVwcmljZQFpAR91cGRhdGVSZXNlcnZlc0FuZE5ldXRyaW5vU3VwcGx5AAoBFmdldE51bWJlckJ5S2V5SW50ZXJuYWwBA2tleQQHJG1hdGNoMAkAmggCBQR0aGlzBQNrZXkDCQABAgUHJG1hdGNoMAIDSW50BAFhBQckbWF0Y2gwBQFhAAAEB25NZXRyaXgJAQlhc0FueUxpc3QBCQD8BwQFDG1hdGhDb250cmFjdAIaY2FsY05ldXRpbm9NZXRyaWNzUkVBRE9OTFkFA25pbAUDbmlsBANpZHgJARZnZXROdW1iZXJCeUtleUludGVybmFsAQIidXBkYXRlUmVzZXJ2ZXNBbmROZXV0cmlub1N1cHBseUlkeAQGbmV3SWR4CQBkAgUDaWR4AAEJAMwIAgkBDEludGVnZXJFbnRyeQICInVwZGF0ZVJlc2VydmVzQW5kTmV1dHJpbm9TdXBwbHlJZHgFBm5ld0lkeAkAzAgCCQEMSW50ZWdlckVudHJ5AgIHcmVzZXJ2ZQkBBWFzSW50AQkAkQMCBQduTWV0cml4AAMJAMwIAgkBDEludGVnZXJFbnRyeQICDm5ldXRyaW5vU3VwcGx5CQEFYXNJbnQBCQCRAwIFB25NZXRyaXgABQkAzAgCCQEMSW50ZWdlckVudHJ5AgIOcmVzZXJ2ZXNJblVzZG4JARZjb252ZXJ0V2F2ZXNUb05ldXRyaW5vAgkBBWFzSW50AQkAkQMCBQduTWV0cml4AAMJAQVhc0ludAEJAJEDAgUHbk1ldHJpeAAACQDMCAIJAQxJbnRlZ2VyRW50cnkCAgdzdXJwbHVzCQEFYXNJbnQBCQCRAwIFB25NZXRyaXgABgkAzAgCCQEMSW50ZWdlckVudHJ5AgIHZGVmaWNpdAkBAS0BCQEFYXNJbnQBCQCRAwIFB25NZXRyaXgABgUDbmlsAWkBFndhdmVzQmFsYW5jZXNWc1BheW1lbnQABAFiCQDvBwEFBHRoaXMJAMwIAgkBDEludGVnZXJFbnRyeQICFndhdmVzQmFsYW5jZV9hdmFpbGFibGUIBQFiCWF2YWlsYWJsZQkAzAgCCQEMSW50ZWdlckVudHJ5AgIUd2F2ZXNCYWxhbmNlX3JlZ3VsYXIIBQFiB3JlZ3VsYXIJAMwIAgkBDEludGVnZXJFbnRyeQICF3dhdmVzQmFsYW5jZV9nZW5lcmF0aW5nCAUBYgpnZW5lcmF0aW5nCQDMCAIJAQxJbnRlZ2VyRW50cnkCAhZ3YXZlc0JhbGFuY2VfZWZmZWN0aXZlCAUBYgllZmZlY3RpdmUJAMwIAgkBDEludGVnZXJFbnRyeQICDXdhdmVzX3BheW1lbnQICQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50BQNuaWwBAnR4AQZ2ZXJpZnkABAJpZAkA2AQBCAUCdHgCaWQEE3B1YktleUFkbWluc0xpc3RTdHIJALkJAgkAzAgCAixFeHRFRUsxOW5tS2o5bUNwbld5dkVFSkZZQVRMTWNWRU12b2hoVUhreUhObQkAzAgCAixFdjVweTVGZkJRWDljWnBZS25mUXJUQjQ5QnlmOFFtcFpXZURWUmltNHlWNwkAzAgCAixEVXV1TGpYdTk4bkJ3WmM3ZnF3Q1RqdEEzbm5Sd2dUYmtNU3I1U1UyTm1EUgkAzAgCAixEVXV1TGpYdTk4bkJ3WmM3ZnF3Q1RqdEEzbm5Sd2dUYmtNU3I1U1UyTm1EUgUDbmlsBQNTRVAEEHB1YktleUFkbWluc0xpc3QJALUJAgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ9jb250cm9sQ29udHJhY3QCDCVzX19tdWx0aXNpZwUTcHViS2V5QWRtaW5zTGlzdFN0cgUDU0VQBAVjb3VudAkAZAIJAGQCCQBkAgMJAPQDAwgFAnR4CWJvZHlCeXRlcwkAkQMCCAUCdHgGcHJvb2ZzAAAJANkEAQkAkQMCBRBwdWJLZXlBZG1pbnNMaXN0AAAAAQAAAwkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAQkA2QQBCQCRAwIFEHB1YktleUFkbWluc0xpc3QAAQABAAADCQD0AwMIBQJ0eAlib2R5Qnl0ZXMJAJEDAggFAnR4BnByb29mcwACCQDZBAEJAJEDAgUQcHViS2V5QWRtaW5zTGlzdAACAAEAAAMJAPQDAwgFAnR4CWJvZHlCeXRlcwkAkQMCCAUCdHgGcHJvb2ZzAAMJANkEAQkAkQMCBRBwdWJLZXlBZG1pbnNMaXN0AAMAAgAABAckbWF0Y2gwBQJ0eAMJAAECBQckbWF0Y2gwAhVTcG9uc29yRmVlVHJhbnNhY3Rpb24ECXNwb25zb3JUeAUHJG1hdGNoMAMJARtjaGVja0lzVmFsaWRNaW5TcG9uc29yZWRGZWUBBQlzcG9uc29yVHgJAGcCBQVjb3VudAADBwkAZwIFBWNvdW50AAMlKItO", "chainId": 84, "height": 2197101, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: T8qZPUstRzW3yfUS6qjcejZC78eSAJQxHoXTsHiFLY4 Next: 2YG32vXKqsqm5bGr318anrWctr9Uz2BQZiLuui7yxava Diff:
OldNewDifferences
4949 }
5050
5151
52+func asBytes (val) = match val {
53+ case valByte: ByteVector =>
54+ valByte
55+ case _ =>
56+ throw("fail to cast into ByteVector")
57+}
58+
59+
5260 func asPayment (v) = match v {
5361 case p: AttachedPayment =>
5462 p
5866
5967
6068 func asSwapParamsSTRUCT (v) = match v {
61- case struct: (Int, Int, Int, Int, Int) =>
69+ case struct: (Int, Int, Int, Int, Int, Int, Int) =>
6270 struct
6371 case _ =>
64- throw("fail to cast into Int")
72+ throw("fail to cast into Tuple5 ints")
6573 }
6674
6775
7482 let PRICELET = 1000000
7583
7684 let DEFAULTSWAPFEE = 20000
85+
86+let BRPROTECTED = 100000
7787
7888 let IdxNetAmount = 0
7989
222232 func swapsTimeframeKEY () = "swaps_timeframe"
223233
224234
235+func brProtectedKEY () = "min_BR_protection_level"
236+
237+
225238 func minSwapAmountREAD (swapType) = valueOrElse(getInteger(this, minSwapAmountKEY(swapType)), 0)
226239
227240
357370 }
358371
359372
360-func applyFees (amountGross,feePart) = {
361- let feeAmount = fraction(amountGross, feePart, PAULI)
362-[(amountGross - feeAmount), feeAmount, amountGross]
373+func applyFees (amountOutGross,inAmtToSURF,feePart) = {
374+ let feeAmount = fraction(amountOutGross, feePart, PAULI)
375+[(amountOutGross - feeAmount), feeAmount]
363376 }
364377
365378
423436
424437
425438 func commonSwap (swapType,pmtAmount,userAddressStr,txId58,swapParamsByUserSYSREADONLY) = {
426- let $t01722417304 = swapParamsByUserSYSREADONLY
427- let swapLimitMax = $t01722417304._1
428- let swapLimitSpent = $t01722417304._2
429- let blcks2LmtReset = $t01722417304._3
439+ let swapLimitSpent = swapParamsByUserSYSREADONLY._2
440+ let blcks2LmtReset = swapParamsByUserSYSREADONLY._3
441+ let wavesSwapLimitMax = swapParamsByUserSYSREADONLY._6
442+ let usdnSwapLimitMax = swapParamsByUserSYSREADONLY._7
430443 let minSwapAmount = minSwapAmountREAD(swapType)
431444 let totalLocked = totalLockedREAD(swapType)
432445 let totalLockedByUser = totalLockedByUserREAD(swapType, userAddressStr)
440453 let swapUsdnVolume = if ((swapType == "neutrino"))
441454 then pmtAmount
442455 else convertWavesToNeutrino(pmtAmount, priceByIndex)
456+ let swapLimitMax = if ((swapType == "neutrino"))
457+ then usdnSwapLimitMax
458+ else convertWavesToNeutrino(wavesSwapLimitMax, priceByIndex)
443459 if ((minSwapAmount > pmtAmount))
444460 then minSwapAmountFAIL(swapType, minSwapAmount)
445461 else if (if (!(isSwapByNode))
461477 }
462478
463479
480+let nMetricIdxPrice = 0
481+
482+let nMetricIdxUsdnLockedBalance = 1
483+
484+let nMetricIdxWavesLockedBalance = 2
485+
486+let nMetricIdxReserve = 3
487+
488+let nMetricIdxReserveInUsdn = 4
489+
490+let nMetricIdxUsdnSupply = 5
491+
492+let nMetricIdxSurplus = 6
493+
494+let nMetricIdxSurplusPercent = 7
495+
496+let nMetricIdxBR = 8
497+
498+let nMetricIdxNsbtSupply = 9
499+
500+let nMetricIdxMaxNsbtSupply = 10
501+
502+let nMetricIdxSurfSupply = 11
503+
504+let bFuncIdxSurf = 0
505+
506+let bFuncIdxWaves = 1
507+
508+let bFuncIdxUsdn = 2
509+
510+let bFuncIdxReserveStart = 3
511+
512+let bFuncIdxSupplyStart = 4
513+
514+let bFuncIdxBRStart = 5
515+
516+let bFuncIdxReserveEnd = 6
517+
518+let bFuncIdxSupplyEnd = 7
519+
520+let bFuncIdxBREnd = 8
521+
522+let bFuncIdxRest = 9
523+
524+let bFuncIdxWavesPrice = 10
525+
526+func calcWithdrawW2U (wavesIn,price) = {
527+ let outAmtGross = convertWavesToNeutrino(wavesIn, price)
528+ $Tuple9(outAmtGross, neutrinoAssetId, 0, unit, 0, wavesIn, 0, 0, 0)
529+ }
530+
531+
532+func calcWithdrawU2W (usdnIn,price,br,reservesInUsdn,usdnSupply) = {
533+ let brProtected = valueOrElse(getInteger(this, brProtectedKEY()), BRPROTECTED)
534+ let maxAllowedUsdnBeforeMinBr = if ((brProtected >= br))
535+ then 0
536+ else fraction((reservesInUsdn - fraction(brProtected, usdnSupply, PAULI)), PAULI, (PAULI - brProtected))
537+ let allowedUsdnBeforeMinBr = if ((usdnIn > maxAllowedUsdnBeforeMinBr))
538+ then maxAllowedUsdnBeforeMinBr
539+ else usdnIn
540+ let allowedUsdnAfterMinBr = if ((usdnIn > maxAllowedUsdnBeforeMinBr))
541+ then fraction((usdnIn - maxAllowedUsdnBeforeMinBr), br, PAULI)
542+ else 0
543+ let allowedUsdn = (allowedUsdnBeforeMinBr + allowedUsdnAfterMinBr)
544+ let usdn2SURF = (usdnIn - allowedUsdn)
545+ let outAmtGross = convertNeutrinoToWaves(allowedUsdn, price)
546+ $Tuple9(outAmtGross, unit, usdn2SURF, neutrinoAssetId, outAmtGross, allowedUsdn, maxAllowedUsdnBeforeMinBr, allowedUsdnBeforeMinBr, allowedUsdnAfterMinBr)
547+ }
548+
549+
550+func calcWithdraw (swapType,inAmount,price) = {
551+ let outFeePart = valueOrElse(getInteger(this, outFeePartKEY(swapType)), DEFAULTSWAPFEE)
552+ if (if ((0 > outFeePart))
553+ then true
554+ else (outFeePart >= PAULI))
555+ then throw(((("invalid outFeePart config for " + swapType) + " swap: outFeePart=") + toString(outFeePart)))
556+ else {
557+ let brProtected = valueOrElse(getInteger(this, brProtectedKEY()), BRPROTECTED)
558+ let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
559+ let BR = asInt(neutrinoMetrics[nMetricIdxBR])
560+ let reservesInUsdn = asInt(neutrinoMetrics[nMetricIdxReserveInUsdn])
561+ let usdnSupply = asInt(neutrinoMetrics[nMetricIdxUsdnSupply])
562+ let outDataTuple = if ((swapType == "waves"))
563+ then calcWithdrawW2U(inAmount, price)
564+ else if ((swapType == "neutrino"))
565+ then calcWithdrawU2W(inAmount, price, BR, reservesInUsdn, usdnSupply)
566+ else throw(("Unsupported swap type " + swapType))
567+ let outAmtGross = outDataTuple._1
568+ let outAssetId = outDataTuple._2
569+ let inAmtToSurfPart = outDataTuple._3
570+ let inAssetId = outDataTuple._4
571+ let unleaseAmt = outDataTuple._5
572+ let payoutsArray = applyFees(outAmtGross, inAmtToSurfPart, outFeePart)
573+ let outNetAmt = payoutsArray[IdxNetAmount]
574+ let outFeeAmt = payoutsArray[IdxFeeAmount]
575+ let outSurfAmt = if ((0 >= inAmtToSurfPart))
576+ then 0
577+ else {
578+ let surfResult = asAnyList(invoke(mathContract, "surfFunctionREADONLY", [inAmtToSurfPart, inAssetId], nil))
579+ asInt(surfResult[bFuncIdxSurf])
580+ }
581+ $Tuple7(outNetAmt, outAssetId, outSurfAmt, inAmtToSurfPart, unleaseAmt, outFeeAmt, outAmtGross)
582+ }
583+ }
584+
585+
464586 func commonWithdraw (account,index,swapTxId,withdrawTxId) = {
465587 let userAddress = addressFromStringValue(account)
466588 let dataArray = swapDataFailOrREAD(account, swapTxId)
476598 let indexHeight = getHeightPriceByIndex(index)
477599 let prevIndexHeight = getHeightPriceByIndex((index - 1))
478600 let priceByIndex = getPriceHistory(indexHeight)
479- let outAmountGrossTuple = if ((swapType == "waves"))
480- then $Tuple2(convertWavesToNeutrino(inAmount, priceByIndex), neutrinoAssetId)
481- else if ((swapType == "neutrino"))
482- then $Tuple2(convertNeutrinoToWaves(inAmount, priceByIndex), unit)
483- else throw(("Unsupported swap type " + swapType))
484- let payoutsArray = applyFees(outAmountGrossTuple._1, outFeePart)
485- let outNetAmount = payoutsArray[IdxNetAmount]
486- let outFeeAmount = payoutsArray[IdxFeeAmount]
487601 if (isBlocked)
488602 then emergencyShutdownFAIL()
489603 else if ((swapStatus != "PENDING"))
498612 then (prevIndexHeight >= unlockHeight)
499613 else false)
500614 then priceIndexFAIL(index, priceIndex, indexHeight, unlockHeight, prevIndexHeight)
501- else if ((0 >= payoutsArray[IdxGrossAmount]))
502- then throw("balance equals zero")
503- else if (if ((0 > outFeePart))
504- then true
505- else (outFeePart >= PAULI))
506- then throw(((("invalid outFeePart config for " + swapType) + " swap: outFeePart=") + toString(outFeePart)))
615+ else {
616+ let withdrawTuple = calcWithdraw(swapType, inAmount, priceByIndex)
617+ let outNetAmount = withdrawTuple._1
618+ let outAssetId = withdrawTuple._2
619+ let outSurfAmt = withdrawTuple._3
620+ let inAmtToSurfPart = withdrawTuple._4
621+ let unleaseAmt = withdrawTuple._5
622+ let outFeeAmount = withdrawTuple._6
623+ let outAmtGross = withdrawTuple._7
624+ if ((0 >= outAmtGross))
625+ then throw("balance equals zero")
507626 else {
508- let unleaseAmount = if (if ((swapType == "neutrino"))
509- then (outAmountGrossTuple._1 > 0)
510- else false)
511- then outAmountGrossTuple._1
627+ let state = [IntegerEntry(totalLockedByUserKEY(swapType, account), (totalLockedByUser - inAmount)), IntegerEntry(totalLockedKEY(swapType), (totalLocked - inAmount)), ScriptTransfer(userAddress, outNetAmount, outAssetId), StringEntry(swapKEY(account, swapTxId), finishSwapDATA(dataArray, priceByIndex, outNetAmount, outFeeAmount, unlockHeight, index, withdrawTxId))]
628+ let surfCondition = if ((outSurfAmt > 0))
629+ then {
630+ let issueResult = invoke(auctionContract, "issueSurf", [outSurfAmt, account], nil)
631+ if ((issueResult == issueResult))
632+ then 0
633+ else throw("Strict value is not equal to itself.")
634+ }
512635 else 0
513- let state = [IntegerEntry(totalLockedByUserKEY(swapType, account), (totalLockedByUser - inAmount)), IntegerEntry(totalLockedKEY(swapType), (totalLocked - inAmount)), ScriptTransfer(userAddress, outNetAmount, outAmountGrossTuple._2), StringEntry(swapKEY(account, swapTxId), finishSwapDATA(dataArray, priceByIndex, outNetAmount, outFeeAmount, unlockHeight, index, withdrawTxId))]
514- $Tuple3(state, AttachedPayment(outAmountGrossTuple._2, outFeeAmount), unleaseAmount)
636+ if ((surfCondition == surfCondition))
637+ then $Tuple3(state, AttachedPayment(outAssetId, outFeeAmount), unleaseAmt)
638+ else throw("Strict value is not equal to itself.")
515639 }
640+ }
516641 }
517642
518643
665790 if ((i.callerPublicKey != mngPub))
666791 then throw("approveLeasings not authorized")
667792 else {
668- let $t02838428446 = readNodeInfo(0)
669- let nAddr0 = $t02838428446._1
670- let lAmtKEY0 = $t02838428446._2
671- let lAmt0 = $t02838428446._3
672- let lIdKEY0 = $t02838428446._4
673- let lId0 = $t02838428446._5
674- let $t02844928511 = readNodeInfo(1)
675- let nAddr1 = $t02844928511._1
676- let lAmtKEY1 = $t02844928511._2
677- let lAmt1 = $t02844928511._3
678- let lIdKEY1 = $t02844928511._4
679- let lId1 = $t02844928511._5
793+ let $t03363933701 = readNodeInfo(0)
794+ let nAddr0 = $t03363933701._1
795+ let lAmtKEY0 = $t03363933701._2
796+ let lAmt0 = $t03363933701._3
797+ let lIdKEY0 = $t03363933701._4
798+ let lId0 = $t03363933701._5
799+ let $t03370433766 = readNodeInfo(1)
800+ let nAddr1 = $t03370433766._1
801+ let lAmtKEY1 = $t03370433766._2
802+ let lAmt1 = $t03370433766._3
803+ let lIdKEY1 = $t03370433766._4
804+ let lId1 = $t03370433766._5
680805 let newL0 = Lease(nAddr0, (lAmt0 - ((lAmt * expCount) / 2)))
681806 let newL1 = Lease(nAddr1, (lAmt1 - ((lAmt * expCount) / 2)))
682807 let validation = invoke(nodeRegAddr, "validateAndApproveLeasings", [nListS], nil)
711836
712837
713838 @Callable(i)
839+func rebalanceLeasings (amount,groupNum) = {
840+ let nIdxs = [0, 1, 2, 3, 4, 5, 6, 7]
841+ let mngPubS = valueOrElse(getString("%s%s__cfg__leasingManagerPub"), "7AUMX54ukYMYvPmma7yoFf5NjZhs4Bu5nz3Ez9EV8sur")
842+ let mngPub = fromBase58String(mngPubS)
843+ let lGroupNodeListKEY = getLeaseGroupNodeListKey(groupNum)
844+ let nListS = getStringOrFail(this, lGroupNodeListKEY)
845+ let nList = split(nListS, SEP)
846+ if ((i.callerPublicKey != mngPub))
847+ then throw("rebalanceLeasings not authorized")
848+ else {
849+ let unleaseAmt = ((amount / size(nList)) + 1)
850+ let $t03518335245 = readNodeInfo(0)
851+ let nAddr0 = $t03518335245._1
852+ let lAmtKEY0 = $t03518335245._2
853+ let lAmt0 = $t03518335245._3
854+ let lIdKEY0 = $t03518335245._4
855+ let lId0 = $t03518335245._5
856+ let newL0 = Lease(nAddr0, (lAmt0 + (unleaseAmt * size(nList))))
857+ func forEachNodeDoUnlease (a,i) = {
858+ let node = nList[i]
859+ let lIdKEY = getLeaseIdByAddressKey(node)
860+ let lId = getBinaryValue(this, lIdKEY)
861+ let lAmtKEY = getLeaseAmountByAddressKey(node)
862+ let lAmt = getIntegerValue(this, lAmtKEY)
863+ let ula = LeaseCancel(value(lId))
864+ let la = Lease(addressFromStringValue(node), (lAmt - unleaseAmt))
865+ (a ++ [LeaseCancel(value(lId)), la, BinaryEntry(lIdKEY, lcalc(la)), IntegerEntry(lAmtKEY, la.amount)])
866+ }
867+
868+ ({
869+ let $l = nIdxs
870+ let $s = size($l)
871+ let $acc0 = nil
872+ func $f0_1 ($a,$i) = if (($i >= $s))
873+ then $a
874+ else forEachNodeDoUnlease($a, $l[$i])
875+
876+ func $f0_2 ($a,$i) = if (($i >= $s))
877+ then $a
878+ else throw("List size exceeds 8")
879+
880+ $f0_2($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)
881+ } ++ [BinaryEntry(lIdKEY0, lcalc(newL0)), IntegerEntry(lAmtKEY0, newL0.amount), LeaseCancel(lId0), newL0])
882+ }
883+ }
884+
885+
886+
887+@Callable(i)
714888 func swapParamsByUserSYSREADONLY (userAddressStr,gnsbtDiff) = {
715889 let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", [userAddressStr, 0, 0], nil))
716890 let gnsbtAmt = (asInt(gnsbtData[0]) + gnsbtDiff)
717891 let gnsbtAmtTotal = (asInt(gnsbtData[1]) + gnsbtDiff)
718- let swapLimitMax = asInt(invoke(mathContract, "calcSwapLimitREADONLY", [gnsbtAmt], nil))
892+ let swapLimitData = asAnyList(invoke(mathContract, "calcSwapLimitREADONLY", [gnsbtAmt], nil))
893+ let wavesSwapLimitInUsdnMax = asInt(swapLimitData[0])
894+ let wavesSwapLimitMax = asInt(swapLimitData[1])
895+ let usdnSwapLimitMax = asInt(swapLimitData[2])
719896 let lastSwapHeight = valueOrElse(getInteger(this, keyUserLastSwapHeight(userAddressStr)), 0)
720897 let swapLimitTimelifeBlocks = swapsTimeframeREAD()
721898 let passedBlocksAfterLastSwap = (height - lastSwapHeight)
722899 let isSwapTimelifeNew = (passedBlocksAfterLastSwap >= swapLimitTimelifeBlocks)
723- let swapLimitSpent = if (isSwapTimelifeNew)
900+ let swapLimitSpentInUsdn = if (isSwapTimelifeNew)
724901 then 0
725902 else valueOrElse(getInteger(this, keySwapUserSpentInPeriod(userAddressStr)), 0)
726903 let blcks2LmtReset = if (isSwapTimelifeNew)
727904 then 0
728905 else (swapLimitTimelifeBlocks - passedBlocksAfterLastSwap)
729- $Tuple2(nil, $Tuple5(swapLimitMax, swapLimitSpent, blcks2LmtReset, gnsbtAmt, gnsbtAmtTotal))
906+ $Tuple2(nil, $Tuple7(wavesSwapLimitInUsdnMax, swapLimitSpentInUsdn, blcks2LmtReset, gnsbtAmt, gnsbtAmtTotal, wavesSwapLimitMax, usdnSwapLimitMax))
730907 }
908+
909+
910+
911+@Callable(i)
912+func calcWithdrawResultSYSREADONLY (swapType,inAmount,price) = $Tuple2(nil, calcWithdraw(swapType, inAmount, price))
731913
732914
733915
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], ""))
55
66
77 func lcalc (l) = calculateLeaseId(l)
88
99
1010 func getNumberByKey (key) = valueOrElse(getInteger(this, key), 0)
1111
1212
1313 func getStringByKey (key) = valueOrElse(getString(this, key), "")
1414
1515
1616 func getBoolByKey (key) = valueOrElse(getBoolean(this, key), false)
1717
1818
1919 func getNumberByAddressAndKey (address,key) = valueOrElse(getInteger(address, key), 0)
2020
2121
2222 func getStringByAddressAndKey (address,key) = valueOrElse(getString(addressFromStringValue(address), key), "")
2323
2424
2525 func getBoolByAddressAndKey (address,key) = valueOrElse(getBoolean(address, key), false)
2626
2727
2828 func asAnyList (v) = match v {
2929 case l: List[Any] =>
3030 l
3131 case _ =>
3232 throw("fail to cast into List[Any]")
3333 }
3434
3535
3636 func asString (v) = match v {
3737 case s: String =>
3838 s
3939 case _ =>
4040 throw("fail to cast into String")
4141 }
4242
4343
4444 func asInt (v) = match v {
4545 case i: Int =>
4646 i
4747 case _ =>
4848 throw("fail to cast into Int")
4949 }
5050
5151
52+func asBytes (val) = match val {
53+ case valByte: ByteVector =>
54+ valByte
55+ case _ =>
56+ throw("fail to cast into ByteVector")
57+}
58+
59+
5260 func asPayment (v) = match v {
5361 case p: AttachedPayment =>
5462 p
5563 case _ =>
5664 throw("fail to cast into AttachedPayment")
5765 }
5866
5967
6068 func asSwapParamsSTRUCT (v) = match v {
61- case struct: (Int, Int, Int, Int, Int) =>
69+ case struct: (Int, Int, Int, Int, Int, Int, Int) =>
6270 struct
6371 case _ =>
64- throw("fail to cast into Int")
72+ throw("fail to cast into Tuple5 ints")
6573 }
6674
6775
6876 let SEP = "__"
6977
7078 let WAVELET = 100000000
7179
7280 let PAULI = 1000000
7381
7482 let PRICELET = 1000000
7583
7684 let DEFAULTSWAPFEE = 20000
85+
86+let BRPROTECTED = 100000
7787
7888 let IdxNetAmount = 0
7989
8090 let IdxFeeAmount = 1
8191
8292 let IdxGrossAmount = 2
8393
8494 let IdxControlCfgNeutrinoDapp = 1
8595
8696 let IdxControlCfgAuctionDapp = 2
8797
8898 let IdxControlCfgRpdDapp = 3
8999
90100 let IdxControlCfgMathDapp = 4
91101
92102 let IdxControlCfgLiquidationDapp = 5
93103
94104 let IdxControlCfgRestDapp = 6
95105
96106 let IdxControlCfgNodeRegistryDapp = 7
97107
98108 let IdxControlCfgNsbtStakingDapp = 8
99109
100110 let IdxControlCfgMediatorDapp = 9
101111
102112 let IdxControlCfgSurfStakingDapp = 10
103113
104114 let IdxControlCfgGnsbtControllerDapp = 11
105115
106116 func keyControlAddress () = "%s%s__config__controlAddress"
107117
108118
109119 func keyControlCfg () = "%s__controlConfig"
110120
111121
112122 func readControlCfgOrFail (control) = split(getStringOrFail(control, keyControlCfg()), SEP)
113123
114124
115125 func getContractAddressOrFail (controlCfg,idx) = valueOrErrorMessage(addressFromString(controlCfg[idx]), ("Control cfg doesn't contain address at index " + toString(idx)))
116126
117127
118128 let controlContract = addressFromStringValue(valueOrElse(getString(this, keyControlAddress()), "3N4NS7d4Jo9a6F14LiFUKKYVdUkkf2eP4Zx"))
119129
120130 let controlCfg = readControlCfgOrFail(controlContract)
121131
122132 let mathContract = getContractAddressOrFail(controlCfg, IdxControlCfgMathDapp)
123133
124134 let nsbtStakingContract = getContractAddressOrFail(controlCfg, IdxControlCfgNsbtStakingDapp)
125135
126136 let surfStakingContract = getContractAddressOrFail(controlCfg, IdxControlCfgSurfStakingDapp)
127137
128138 let gnsbtControllerContract = getContractAddressOrFail(controlCfg, IdxControlCfgGnsbtControllerDapp)
129139
130140 let auctionContract = getContractAddressOrFail(controlCfg, IdxControlCfgAuctionDapp)
131141
132142 let NeutrinoAssetIdKey = "neutrino_asset_id"
133143
134144 let BondAssetIdKey = "bond_asset_id"
135145
136146 let AuctionContractKey = "auction_contract"
137147
138148 let NsbtStakingContractKey = "nsbtStakingContract"
139149
140150 let LiquidationContractKey = "liquidation_contract"
141151
142152 let RPDContractKey = "rpd_contract"
143153
144154 let ContolContractKey = "control_contract"
145155
146156 let MathContractKey = "math_contract"
147157
148158 let BalanceWavesLockIntervalKey = "balance_waves_lock_interval"
149159
150160 let BalanceNeutrinoLockIntervalKey = "balance_neutrino_lock_interval"
151161
152162 let MinWavesSwapAmountKey = "min_waves_swap_amount"
153163
154164 let MinNeutrinoSwapAmountKey = "min_neutrino_swap_amount"
155165
156166 let NodeOracleProviderPubKeyKey = "node_oracle_provider"
157167
158168 let NeutrinoOutFeePartKey = "neutrinoOut_swap_feePart"
159169
160170 let WavesOutFeePartKey = "wavesOut_swap_feePart"
161171
162172 func keyNodeRegistry (address) = ("%s__" + address)
163173
164174
165175 let PriceKey = "price"
166176
167177 let PriceIndexKey = "price_index"
168178
169179 let IsBlockedKey = "is_blocked"
170180
171181 func getPriceHistoryKey (block) = ((PriceKey + "_") + toString(block))
172182
173183
174184 func getHeightPriceByIndexKey (index) = ((PriceIndexKey + "_") + toString(index))
175185
176186
177187 func getStakingNodeByIndex (idx) = getStringByKey(makeString(["%s%d%s", "lease", toString(idx), "nodeAddress"], SEP))
178188
179189
180190 func getStakingNodeAddressByIndex (idx) = addressFromStringValue(getStakingNodeByIndex(idx))
181191
182192
183193 func getReservedAmountForSponsorship () = valueOrElse(getInteger(this, makeString(["%s%s", "lease", "sponsorshipWavesReserve"], SEP)), (1000 * WAVELET))
184194
185195
186196 func getBalanceUnlockBlockKey (owner) = ("balance_unlock_block_" + owner)
187197
188198
189199 func getLeaseIdKey (nodeIndex) = makeString(["%s%d%s", "lease", toString(nodeIndex), "id"], SEP)
190200
191201
192202 func getLeaseIdByAddressKey (nodeAddress) = makeString(["%s%s%s", "leaseByAddress", nodeAddress, "id"], SEP)
193203
194204
195205 func getLeaseAmountKey (nodeIndex) = makeString(["%s%d%s", "lease", toString(nodeIndex), "amount"], SEP)
196206
197207
198208 func getLeaseAmountByAddressKey (nodeAddress) = makeString(["%s%s%s", "leaseByAddress", nodeAddress, "amount"], SEP)
199209
200210
201211 func getLeaseGroupNodeListKey (groupNum) = makeString(["%s%d%s", "leaseGroup", toString(groupNum), "nodeList"], SEP)
202212
203213
204214 func minSwapAmountKEY (swapType) = (("min_" + swapType) + "_swap_amount")
205215
206216
207217 func totalLockedKEY (swapType) = ("balance_lock_" + swapType)
208218
209219
210220 func totalLockedByUserKEY (swapType,owner) = makeString(["balance_lock", swapType, owner], "_")
211221
212222
213223 func balanceLockIntervalKEY (swapType) = (("balance_" + swapType) + "_lock_interval")
214224
215225
216226 func nodeBalanceLockIntervalKEY () = "balance_node_lock_interval"
217227
218228
219229 func outFeePartKEY (swapType) = (swapType + "Out_swap_feePart")
220230
221231
222232 func swapsTimeframeKEY () = "swaps_timeframe"
223233
224234
235+func brProtectedKEY () = "min_BR_protection_level"
236+
237+
225238 func minSwapAmountREAD (swapType) = valueOrElse(getInteger(this, minSwapAmountKEY(swapType)), 0)
226239
227240
228241 func swapsTimeframeREAD () = valueOrElse(getInteger(this, swapsTimeframeKEY()), 1440)
229242
230243
231244 func totalLockedREAD (swapType) = valueOrElse(getInteger(this, totalLockedKEY(swapType)), 0)
232245
233246
234247 func totalLockedByUserREAD (swapType,owner) = valueOrElse(getInteger(this, totalLockedByUserKEY(swapType, owner)), 0)
235248
236249
237250 func balanceLockIntervalREAD (swapType) = valueOrElse(getInteger(this, balanceLockIntervalKEY(swapType)), 1440)
238251
239252
240253 func nodeBalanceLockIntervalREAD () = valueOrElse(getInteger(this, nodeBalanceLockIntervalKEY()), 1)
241254
242255
243256 func keySwapUserSpentInPeriod (userAddress) = makeString(["%s%s", "swapUserSpentInPeriod", userAddress], SEP)
244257
245258
246259 func keyUserLastSwapHeight (userAddress) = makeString(["%s%s", "userLastSwapHeight", userAddress], SEP)
247260
248261
249262 func convertNeutrinoToWaves (amount,price) = fraction(fraction(amount, PRICELET, price), WAVELET, PAULI)
250263
251264
252265 func convertWavesToNeutrino (amount,price) = fraction(fraction(amount, price, PRICELET), PAULI, WAVELET)
253266
254267
255268 func convertWavesToBond (amount,price) = convertWavesToNeutrino(amount, price)
256269
257270
258271 func convertJsonArrayToList (jsonArray) = split(jsonArray, ",")
259272
260273
261274 func minSwapAmountFAIL (swapType,minSwapAmount) = throw(((("The specified amount in " + swapType) + " swap is less than the required minimum of ") + toString(minSwapAmount)))
262275
263276
264277 func emergencyShutdownFAIL () = throw("contract is blocked by EMERGENCY SHUTDOWN actions untill reactivation by emergency oracles")
265278
266279
267280 func priceIndexFAIL (index,priceIndex,indexHeight,unlockHeight,prevIndexHeight) = throw(((((((((("invalid price history index: index=" + toString(index)) + " priceIndex=") + toString(priceIndex)) + " indexHeight=") + toString(indexHeight)) + " unlockHeight=") + toString(unlockHeight)) + " prevIndexHeight=") + toString(prevIndexHeight)))
268281
269282
270283 let neutrinoAssetId = fromBase58String(getStringByKey(NeutrinoAssetIdKey))
271284
272285 let priceIndex = getNumberByAddressAndKey(controlContract, PriceIndexKey)
273286
274287 let isBlocked = getBoolByAddressAndKey(controlContract, IsBlockedKey)
275288
276289 let nodeOracleProviderPubKey = fromBase58String(getStringByKey(NodeOracleProviderPubKeyKey))
277290
278291 let bondAssetId = fromBase58String("F3iaxzruFeKujfVfYSZEkejpjh67wmRfPCRHiNmWKp3Z")
279292
280293 let deprecatedBondAssetId = fromBase58String("975akZBfnMj513U7MZaHKzQrmsEx5aE3wdWKTrHBhbjF")
281294
282295 let neutrinoContract = this
283296
284297 let currentPrice = getNumberByAddressAndKey(controlContract, PriceKey)
285298
286299 func checkIsValidMinSponsoredFee (tx) = {
287300 let MINTRANSFERFEE = 100000
288301 let SponsoredFeeUpperBound = 1000
289302 let realNeutrinoFee = convertWavesToNeutrino(MINTRANSFERFEE, currentPrice)
290303 let minNeutrinoFee = (realNeutrinoFee * 2)
291304 let maxNeutrinoFee = fraction(realNeutrinoFee, SponsoredFeeUpperBound, 100)
292305 let inputFee = value(tx.minSponsoredAssetFee)
293306 if (if ((inputFee >= minNeutrinoFee))
294307 then (maxNeutrinoFee >= inputFee)
295308 else false)
296309 then (tx.assetId == neutrinoAssetId)
297310 else false
298311 }
299312
300313
301314 func getPriceHistory (block) = getNumberByAddressAndKey(controlContract, getPriceHistoryKey(block))
302315
303316
304317 func getHeightPriceByIndex (index) = getNumberByAddressAndKey(controlContract, getHeightPriceByIndexKey(index))
305318
306319
307320 func keyLockParamUserAmount (userAddress) = makeString(["%s%s%s", "paramByUser", userAddress, "amount"], SEP)
308321
309322
310323 let sIdxSwapType = 1
311324
312325 let sIdxStatus = 2
313326
314327 let sIdxInAmount = 3
315328
316329 let sIdxPrice = 4
317330
318331 let sIdxOutNetAmount = 5
319332
320333 let sIdxOutFeeAmount = 6
321334
322335 let sIdxStartHeight = 7
323336
324337 let sIdxStartTimestamp = 8
325338
326339 let sIdxEndHeight = 9
327340
328341 let sIdxEndTimestamp = 10
329342
330343 let sIdxSelfUnlockHeight = 11
331344
332345 let sIdxRandUnlockHeight = 12
333346
334347 let sIdxIndex = 13
335348
336349 let sIdxWithdrawTxId = 14
337350
338351 let sIdxMinRand = 15
339352
340353 let sIdxMaxRand = 16
341354
342355 func swapKEY (userAddress,txId) = makeString(["%s%s", userAddress, txId], SEP)
343356
344357
345358 func strSwapDATA (swapType,status,inAmount,price,outNetAmount,outFeeAmount,startHeight,startTimestamp,endHeight,endTimestamp,selfUnlockHeight,randUnlockHeight,index,withdrawTxId,randMin,randMax) = makeString(["%s%s%d%d%d%d%d%d%d%d%d%d%d%s", swapType, status, inAmount, price, outNetAmount, outFeeAmount, startHeight, startTimestamp, endHeight, endTimestamp, selfUnlockHeight, randUnlockHeight, index, withdrawTxId, randMin, randMax], SEP)
346359
347360
348361 func pendingSwapDATA (swapType,inAssetAmount,selfUnlockHeight) = strSwapDATA(swapType, "PENDING", toString(inAssetAmount), "0", "0", "0", toString(height), toString(lastBlock.timestamp), "0", "0", toString(selfUnlockHeight), "0", "0", "NULL", "0", "0")
349362
350363
351364 func finishSwapDATA (dataArray,price,outNetAmount,outFeeAmount,randUnlockHeight,index,withdrawTxId) = strSwapDATA(dataArray[sIdxSwapType], "FINISHED", dataArray[sIdxInAmount], toString(price), toString(outNetAmount), toString(outFeeAmount), dataArray[sIdxStartHeight], dataArray[sIdxStartTimestamp], toString(height), toString(lastBlock.timestamp), dataArray[sIdxSelfUnlockHeight], toString(randUnlockHeight), toString(index), withdrawTxId, dataArray[sIdxMinRand], dataArray[sIdxMaxRand])
352365
353366
354367 func swapDataFailOrREAD (userAddress,swapTxId) = {
355368 let swapKey = swapKEY(userAddress, swapTxId)
356369 split(valueOrErrorMessage(getString(this, swapKey), ("no swap data for " + swapKey)), SEP)
357370 }
358371
359372
360-func applyFees (amountGross,feePart) = {
361- let feeAmount = fraction(amountGross, feePart, PAULI)
362-[(amountGross - feeAmount), feeAmount, amountGross]
373+func applyFees (amountOutGross,inAmtToSURF,feePart) = {
374+ let feeAmount = fraction(amountOutGross, feePart, PAULI)
375+[(amountOutGross - feeAmount), feeAmount]
363376 }
364377
365378
366379 func abs (x) = if ((0 > x))
367380 then -(x)
368381 else x
369382
370383
371384 func selectNode (unleaseAmount) = {
372385 let amountToLease = ((wavesBalance(neutrinoContract).available - unleaseAmount) - getReservedAmountForSponsorship())
373386 let oldLeased0 = getNumberByKey(getLeaseAmountKey(0))
374387 let oldLeased1 = getNumberByKey(getLeaseAmountKey(1))
375388 let newLeased0 = (amountToLease + oldLeased0)
376389 let newLeased1 = (amountToLease + oldLeased1)
377390 if (if ((newLeased0 > 0))
378391 then true
379392 else (newLeased1 > 0))
380393 then {
381394 let delta0 = abs((newLeased0 - oldLeased1))
382395 let delta1 = abs((newLeased1 - oldLeased0))
383396 if ((delta1 >= delta0))
384397 then $Tuple2(0, newLeased0)
385398 else $Tuple2(1, newLeased1)
386399 }
387400 else $Tuple2(-1, 0)
388401 }
389402
390403
391404 func thisOnly (i) = if ((i.caller != this))
392405 then throw("Permission denied: this contract only allowed")
393406 else true
394407
395408
396409 func prepareUnleaseAndLease (unleaseAmount) = {
397410 let nodeTuple = selectNode(unleaseAmount)
398411 let nodeIndex = nodeTuple._1
399412 let newLeaseAmount = nodeTuple._2
400413 if ((newLeaseAmount > 0))
401414 then {
402415 let leaseIdKey = getLeaseIdKey(nodeIndex)
403416 let oldLease = getBinary(this, leaseIdKey)
404417 let unleaseOrEmpty = if (isDefined(oldLease))
405418 then [LeaseCancel(value(oldLease))]
406419 else nil
407420 let leaseAmountKey = getLeaseAmountKey(nodeIndex)
408421 let lease = Lease(getStakingNodeAddressByIndex(nodeIndex), newLeaseAmount)
409422 (unleaseOrEmpty ++ [lease, BinaryEntry(leaseIdKey, lcalc(lease)), IntegerEntry(getLeaseAmountKey(nodeIndex), newLeaseAmount)])
410423 }
411424 else nil
412425 }
413426
414427
415428 func readNodeInfo (nodeIdx) = {
416429 let nodeAddress = getStakingNodeAddressByIndex(nodeIdx)
417430 let leasedAmtKEY = getLeaseAmountKey(nodeIdx)
418431 let leasedAmt = getNumberByKey(leasedAmtKEY)
419432 let leaseIdKEY = getLeaseIdKey(nodeIdx)
420433 let leaseId = value(getBinary(this, leaseIdKEY))
421434 $Tuple5(nodeAddress, leasedAmtKEY, leasedAmt, leaseIdKEY, leaseId)
422435 }
423436
424437
425438 func commonSwap (swapType,pmtAmount,userAddressStr,txId58,swapParamsByUserSYSREADONLY) = {
426- let $t01722417304 = swapParamsByUserSYSREADONLY
427- let swapLimitMax = $t01722417304._1
428- let swapLimitSpent = $t01722417304._2
429- let blcks2LmtReset = $t01722417304._3
439+ let swapLimitSpent = swapParamsByUserSYSREADONLY._2
440+ let blcks2LmtReset = swapParamsByUserSYSREADONLY._3
441+ let wavesSwapLimitMax = swapParamsByUserSYSREADONLY._6
442+ let usdnSwapLimitMax = swapParamsByUserSYSREADONLY._7
430443 let minSwapAmount = minSwapAmountREAD(swapType)
431444 let totalLocked = totalLockedREAD(swapType)
432445 let totalLockedByUser = totalLockedByUserREAD(swapType, userAddressStr)
433446 let nodeAddress = getStakingNodeByIndex(0)
434447 let priceByIndex = getPriceHistory(getHeightPriceByIndex(priceIndex))
435448 let isSwapByNode = (nodeAddress == userAddressStr)
436449 let balanceLockMaxInterval = if (isSwapByNode)
437450 then nodeBalanceLockIntervalREAD()
438451 else balanceLockIntervalREAD(swapType)
439452 let selfUnlockHeight = (height + balanceLockMaxInterval)
440453 let swapUsdnVolume = if ((swapType == "neutrino"))
441454 then pmtAmount
442455 else convertWavesToNeutrino(pmtAmount, priceByIndex)
456+ let swapLimitMax = if ((swapType == "neutrino"))
457+ then usdnSwapLimitMax
458+ else convertWavesToNeutrino(wavesSwapLimitMax, priceByIndex)
443459 if ((minSwapAmount > pmtAmount))
444460 then minSwapAmountFAIL(swapType, minSwapAmount)
445461 else if (if (!(isSwapByNode))
446462 then (swapLimitSpent > 0)
447463 else false)
448464 then throw(("You have exceeded swap limit! Next allowed swap height is " + toString((height + blcks2LmtReset))))
449465 else if (if (!(isSwapByNode))
450466 then (swapUsdnVolume > swapLimitMax)
451467 else false)
452468 then throw(((("You have exceeded your swap limit! Requested: " + toString(swapUsdnVolume)) + ", available: ") + toString(swapLimitMax)))
453469 else if (isBlocked)
454470 then emergencyShutdownFAIL()
455471 else {
456472 let leasePart = if ((swapType == "waves"))
457473 then prepareUnleaseAndLease(0)
458474 else nil
459475 $Tuple2(([IntegerEntry(keySwapUserSpentInPeriod(userAddressStr), swapUsdnVolume), IntegerEntry(keyUserLastSwapHeight(userAddressStr), height), IntegerEntry(totalLockedByUserKEY(swapType, userAddressStr), (totalLockedByUser + pmtAmount)), IntegerEntry(getBalanceUnlockBlockKey(userAddressStr), selfUnlockHeight), IntegerEntry(totalLockedKEY(swapType), (totalLocked + pmtAmount)), StringEntry(swapKEY(userAddressStr, txId58), pendingSwapDATA(swapType, pmtAmount, selfUnlockHeight))] ++ leasePart), unit)
460476 }
461477 }
462478
463479
480+let nMetricIdxPrice = 0
481+
482+let nMetricIdxUsdnLockedBalance = 1
483+
484+let nMetricIdxWavesLockedBalance = 2
485+
486+let nMetricIdxReserve = 3
487+
488+let nMetricIdxReserveInUsdn = 4
489+
490+let nMetricIdxUsdnSupply = 5
491+
492+let nMetricIdxSurplus = 6
493+
494+let nMetricIdxSurplusPercent = 7
495+
496+let nMetricIdxBR = 8
497+
498+let nMetricIdxNsbtSupply = 9
499+
500+let nMetricIdxMaxNsbtSupply = 10
501+
502+let nMetricIdxSurfSupply = 11
503+
504+let bFuncIdxSurf = 0
505+
506+let bFuncIdxWaves = 1
507+
508+let bFuncIdxUsdn = 2
509+
510+let bFuncIdxReserveStart = 3
511+
512+let bFuncIdxSupplyStart = 4
513+
514+let bFuncIdxBRStart = 5
515+
516+let bFuncIdxReserveEnd = 6
517+
518+let bFuncIdxSupplyEnd = 7
519+
520+let bFuncIdxBREnd = 8
521+
522+let bFuncIdxRest = 9
523+
524+let bFuncIdxWavesPrice = 10
525+
526+func calcWithdrawW2U (wavesIn,price) = {
527+ let outAmtGross = convertWavesToNeutrino(wavesIn, price)
528+ $Tuple9(outAmtGross, neutrinoAssetId, 0, unit, 0, wavesIn, 0, 0, 0)
529+ }
530+
531+
532+func calcWithdrawU2W (usdnIn,price,br,reservesInUsdn,usdnSupply) = {
533+ let brProtected = valueOrElse(getInteger(this, brProtectedKEY()), BRPROTECTED)
534+ let maxAllowedUsdnBeforeMinBr = if ((brProtected >= br))
535+ then 0
536+ else fraction((reservesInUsdn - fraction(brProtected, usdnSupply, PAULI)), PAULI, (PAULI - brProtected))
537+ let allowedUsdnBeforeMinBr = if ((usdnIn > maxAllowedUsdnBeforeMinBr))
538+ then maxAllowedUsdnBeforeMinBr
539+ else usdnIn
540+ let allowedUsdnAfterMinBr = if ((usdnIn > maxAllowedUsdnBeforeMinBr))
541+ then fraction((usdnIn - maxAllowedUsdnBeforeMinBr), br, PAULI)
542+ else 0
543+ let allowedUsdn = (allowedUsdnBeforeMinBr + allowedUsdnAfterMinBr)
544+ let usdn2SURF = (usdnIn - allowedUsdn)
545+ let outAmtGross = convertNeutrinoToWaves(allowedUsdn, price)
546+ $Tuple9(outAmtGross, unit, usdn2SURF, neutrinoAssetId, outAmtGross, allowedUsdn, maxAllowedUsdnBeforeMinBr, allowedUsdnBeforeMinBr, allowedUsdnAfterMinBr)
547+ }
548+
549+
550+func calcWithdraw (swapType,inAmount,price) = {
551+ let outFeePart = valueOrElse(getInteger(this, outFeePartKEY(swapType)), DEFAULTSWAPFEE)
552+ if (if ((0 > outFeePart))
553+ then true
554+ else (outFeePart >= PAULI))
555+ then throw(((("invalid outFeePart config for " + swapType) + " swap: outFeePart=") + toString(outFeePart)))
556+ else {
557+ let brProtected = valueOrElse(getInteger(this, brProtectedKEY()), BRPROTECTED)
558+ let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
559+ let BR = asInt(neutrinoMetrics[nMetricIdxBR])
560+ let reservesInUsdn = asInt(neutrinoMetrics[nMetricIdxReserveInUsdn])
561+ let usdnSupply = asInt(neutrinoMetrics[nMetricIdxUsdnSupply])
562+ let outDataTuple = if ((swapType == "waves"))
563+ then calcWithdrawW2U(inAmount, price)
564+ else if ((swapType == "neutrino"))
565+ then calcWithdrawU2W(inAmount, price, BR, reservesInUsdn, usdnSupply)
566+ else throw(("Unsupported swap type " + swapType))
567+ let outAmtGross = outDataTuple._1
568+ let outAssetId = outDataTuple._2
569+ let inAmtToSurfPart = outDataTuple._3
570+ let inAssetId = outDataTuple._4
571+ let unleaseAmt = outDataTuple._5
572+ let payoutsArray = applyFees(outAmtGross, inAmtToSurfPart, outFeePart)
573+ let outNetAmt = payoutsArray[IdxNetAmount]
574+ let outFeeAmt = payoutsArray[IdxFeeAmount]
575+ let outSurfAmt = if ((0 >= inAmtToSurfPart))
576+ then 0
577+ else {
578+ let surfResult = asAnyList(invoke(mathContract, "surfFunctionREADONLY", [inAmtToSurfPart, inAssetId], nil))
579+ asInt(surfResult[bFuncIdxSurf])
580+ }
581+ $Tuple7(outNetAmt, outAssetId, outSurfAmt, inAmtToSurfPart, unleaseAmt, outFeeAmt, outAmtGross)
582+ }
583+ }
584+
585+
464586 func commonWithdraw (account,index,swapTxId,withdrawTxId) = {
465587 let userAddress = addressFromStringValue(account)
466588 let dataArray = swapDataFailOrREAD(account, swapTxId)
467589 let selfUnlockHeight = parseIntValue(dataArray[sIdxSelfUnlockHeight])
468590 let swapType = dataArray[sIdxSwapType]
469591 let inAmount = parseIntValue(dataArray[sIdxInAmount])
470592 let swapStatus = dataArray[sIdxStatus]
471593 let startHeight = parseIntValue(dataArray[sIdxStartHeight])
472594 let outFeePart = valueOrElse(getInteger(this, outFeePartKEY(swapType)), DEFAULTSWAPFEE)
473595 let totalLocked = totalLockedREAD(swapType)
474596 let totalLockedByUser = totalLockedByUserREAD(swapType, account)
475597 let unlockHeight = selfUnlockHeight
476598 let indexHeight = getHeightPriceByIndex(index)
477599 let prevIndexHeight = getHeightPriceByIndex((index - 1))
478600 let priceByIndex = getPriceHistory(indexHeight)
479- let outAmountGrossTuple = if ((swapType == "waves"))
480- then $Tuple2(convertWavesToNeutrino(inAmount, priceByIndex), neutrinoAssetId)
481- else if ((swapType == "neutrino"))
482- then $Tuple2(convertNeutrinoToWaves(inAmount, priceByIndex), unit)
483- else throw(("Unsupported swap type " + swapType))
484- let payoutsArray = applyFees(outAmountGrossTuple._1, outFeePart)
485- let outNetAmount = payoutsArray[IdxNetAmount]
486- let outFeeAmount = payoutsArray[IdxFeeAmount]
487601 if (isBlocked)
488602 then emergencyShutdownFAIL()
489603 else if ((swapStatus != "PENDING"))
490604 then throw("swap has been already processed")
491605 else if ((unlockHeight > height))
492606 then throw((("please wait for: " + toString(unlockHeight)) + " block height to withdraw funds"))
493607 else if (if (if ((index > priceIndex))
494608 then true
495609 else (unlockHeight > indexHeight))
496610 then true
497611 else if ((prevIndexHeight != 0))
498612 then (prevIndexHeight >= unlockHeight)
499613 else false)
500614 then priceIndexFAIL(index, priceIndex, indexHeight, unlockHeight, prevIndexHeight)
501- else if ((0 >= payoutsArray[IdxGrossAmount]))
502- then throw("balance equals zero")
503- else if (if ((0 > outFeePart))
504- then true
505- else (outFeePart >= PAULI))
506- then throw(((("invalid outFeePart config for " + swapType) + " swap: outFeePart=") + toString(outFeePart)))
615+ else {
616+ let withdrawTuple = calcWithdraw(swapType, inAmount, priceByIndex)
617+ let outNetAmount = withdrawTuple._1
618+ let outAssetId = withdrawTuple._2
619+ let outSurfAmt = withdrawTuple._3
620+ let inAmtToSurfPart = withdrawTuple._4
621+ let unleaseAmt = withdrawTuple._5
622+ let outFeeAmount = withdrawTuple._6
623+ let outAmtGross = withdrawTuple._7
624+ if ((0 >= outAmtGross))
625+ then throw("balance equals zero")
507626 else {
508- let unleaseAmount = if (if ((swapType == "neutrino"))
509- then (outAmountGrossTuple._1 > 0)
510- else false)
511- then outAmountGrossTuple._1
627+ let state = [IntegerEntry(totalLockedByUserKEY(swapType, account), (totalLockedByUser - inAmount)), IntegerEntry(totalLockedKEY(swapType), (totalLocked - inAmount)), ScriptTransfer(userAddress, outNetAmount, outAssetId), StringEntry(swapKEY(account, swapTxId), finishSwapDATA(dataArray, priceByIndex, outNetAmount, outFeeAmount, unlockHeight, index, withdrawTxId))]
628+ let surfCondition = if ((outSurfAmt > 0))
629+ then {
630+ let issueResult = invoke(auctionContract, "issueSurf", [outSurfAmt, account], nil)
631+ if ((issueResult == issueResult))
632+ then 0
633+ else throw("Strict value is not equal to itself.")
634+ }
512635 else 0
513- let state = [IntegerEntry(totalLockedByUserKEY(swapType, account), (totalLockedByUser - inAmount)), IntegerEntry(totalLockedKEY(swapType), (totalLocked - inAmount)), ScriptTransfer(userAddress, outNetAmount, outAmountGrossTuple._2), StringEntry(swapKEY(account, swapTxId), finishSwapDATA(dataArray, priceByIndex, outNetAmount, outFeeAmount, unlockHeight, index, withdrawTxId))]
514- $Tuple3(state, AttachedPayment(outAmountGrossTuple._2, outFeeAmount), unleaseAmount)
636+ if ((surfCondition == surfCondition))
637+ then $Tuple3(state, AttachedPayment(outAssetId, outFeeAmount), unleaseAmt)
638+ else throw("Strict value is not equal to itself.")
515639 }
640+ }
516641 }
517642
518643
519644 @Callable(i)
520645 func constructor (neutrinoAssetIdPrm,bondAssetIdPrm,auctionContractPrm,liquidationContractPrm,rpdContractPrm,nodeOracleProviderPubKeyPrm,balanceWavesLockIntervalPrm,balanceNeutrinoLockIntervalPrm,minWavesSwapAmountPrm,minNeutrinoSwapAmountPrm,neutrinoOutFeePartPrm,wavesOutFeePartPrm) = {
521646 let checkCaller = thisOnly(i)
522647 if ((checkCaller == checkCaller))
523648 then if ((size(i.payments) != 0))
524649 then throw("no payments allowed")
525650 else [StringEntry(NeutrinoAssetIdKey, neutrinoAssetIdPrm), StringEntry(BondAssetIdKey, bondAssetIdPrm), StringEntry(AuctionContractKey, auctionContractPrm), StringEntry(LiquidationContractKey, liquidationContractPrm), StringEntry(RPDContractKey, rpdContractPrm), StringEntry(NodeOracleProviderPubKeyKey, nodeOracleProviderPubKeyPrm), IntegerEntry(BalanceWavesLockIntervalKey, balanceWavesLockIntervalPrm), IntegerEntry(BalanceNeutrinoLockIntervalKey, balanceNeutrinoLockIntervalPrm), IntegerEntry(MinWavesSwapAmountKey, minWavesSwapAmountPrm), IntegerEntry(MinNeutrinoSwapAmountKey, minNeutrinoSwapAmountPrm), IntegerEntry(NeutrinoOutFeePartKey, neutrinoOutFeePartPrm), IntegerEntry(WavesOutFeePartKey, wavesOutFeePartPrm)]
526651 else throw("Strict value is not equal to itself.")
527652 }
528653
529654
530655
531656 @Callable(i)
532657 func constructorV2 (mathContract,nsbtStakingContract,swapsTimeframeBlocks) = {
533658 let checkCaller = thisOnly(i)
534659 if ((checkCaller == checkCaller))
535660 then if ((size(i.payments) != 0))
536661 then throw("no payments allowed")
537662 else [StringEntry(MathContractKey, mathContract), StringEntry(NsbtStakingContractKey, nsbtStakingContract), IntegerEntry(swapsTimeframeKEY(), swapsTimeframeBlocks)]
538663 else throw("Strict value is not equal to itself.")
539664 }
540665
541666
542667
543668 @Callable(i)
544669 func swapWavesToNeutrino () = if ((size(i.payments) != 1))
545670 then throw("swapWavesToNeutrino require only one payment")
546671 else {
547672 let pmt = value(i.payments[0])
548673 if (isDefined(pmt.assetId))
549674 then throw("Only Waves token is allowed for swapping.")
550675 else {
551676 let userAddress = toString(i.caller)
552677 let txId58 = toBase58String(i.transactionId)
553678 let swapParamsSTRUCT = asSwapParamsSTRUCT(invoke(this, "swapParamsByUserSYSREADONLY", [userAddress, 0], nil))
554679 let commonSwapResult = commonSwap("waves", pmt.amount, userAddress, txId58, swapParamsSTRUCT)
555680 commonSwapResult
556681 }
557682 }
558683
559684
560685
561686 @Callable(i)
562687 func swapNeutrinoToWaves () = if ((size(i.payments) != 1))
563688 then throw("swapNeutrinoToWaves require only one payment")
564689 else {
565690 let pmt = value(i.payments[0])
566691 if ((pmt.assetId != neutrinoAssetId))
567692 then throw("Only appropriate Neutrino tokens are allowed for swapping.")
568693 else {
569694 let userAddress = toString(i.caller)
570695 let txId58 = toBase58String(i.transactionId)
571696 let swapParamsSTRUCT = asSwapParamsSTRUCT(invoke(this, "swapParamsByUserSYSREADONLY", [userAddress, 0], nil))
572697 let commonSwapResult = commonSwap("neutrino", pmt.amount, userAddress, txId58, swapParamsSTRUCT)
573698 commonSwapResult
574699 }
575700 }
576701
577702
578703
579704 @Callable(i)
580705 func withdraw (account,index,swapTxId) = {
581706 let txId = toBase58String(i.transactionId)
582707 if ((size(i.payments) != 0))
583708 then throw("no payments allowed")
584709 else {
585710 let commonTuple = commonWithdraw(account, index, swapTxId, txId)
586711 let state = commonTuple._1
587712 let fee = commonTuple._2
588713 let unleaseAmt = commonTuple._3
589714 let unleaseInvOrEmpty = invoke(this, "internalUnleaseAndLease", [unleaseAmt], nil)
590715 if ((unleaseInvOrEmpty == unleaseInvOrEmpty))
591716 then {
592717 let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", ["", 0, 0], nil))
593718 let gnsbtAmtTotal = asInt(gnsbtData[1])
594719 let gnsbtAmtFromSurfTotal = asInt(asAnyList(gnsbtData[3])[3])
595720 let surfFeeAmt = if ((gnsbtAmtTotal != 0))
596721 then fraction(fee.amount, gnsbtAmtFromSurfTotal, gnsbtAmtTotal)
597722 else 0
598723 let nsbtFeeAmt = (fee.amount - surfFeeAmt)
599724 let surfDeposit = if ((surfFeeAmt > 0))
600725 then {
601726 let surfInv = invoke(surfStakingContract, "deposit", nil, [AttachedPayment(fee.assetId, surfFeeAmt)])
602727 if ((surfInv == surfInv))
603728 then nil
604729 else throw("Strict value is not equal to itself.")
605730 }
606731 else nil
607732 if ((surfDeposit == surfDeposit))
608733 then {
609734 let nsbtDeposit = if ((nsbtFeeAmt > 0))
610735 then {
611736 let nsbtInv = invoke(nsbtStakingContract, "deposit", nil, [AttachedPayment(fee.assetId, nsbtFeeAmt)])
612737 if ((nsbtInv == nsbtInv))
613738 then nil
614739 else throw("Strict value is not equal to itself.")
615740 }
616741 else nil
617742 if ((nsbtDeposit == nsbtDeposit))
618743 then state
619744 else throw("Strict value is not equal to itself.")
620745 }
621746 else throw("Strict value is not equal to itself.")
622747 }
623748 else throw("Strict value is not equal to itself.")
624749 }
625750 }
626751
627752
628753
629754 @Callable(i)
630755 func internalUnleaseAndLease (unleaseAmount) = if ((i.caller != this))
631756 then throw("internalUnleaseAndLease is not public method")
632757 else prepareUnleaseAndLease(unleaseAmount)
633758
634759
635760
636761 @Callable(i)
637762 func transferUsdnToUser (amount,addr) = if ((i.caller != auctionContract))
638763 then throw("Only auction contract is authorized")
639764 else [ScriptTransfer(addressFromStringValue(addr), amount, neutrinoAssetId)]
640765
641766
642767
643768 @Callable(i)
644769 func acceptWaves () = if ((i.caller != auctionContract))
645770 then throw("Currently only auction contract is allowed to call")
646771 else $Tuple2(prepareUnleaseAndLease(0), "success")
647772
648773
649774
650775 @Callable(i)
651776 func approveLeasings (nListS,groupNum) = {
652777 let lAmt = (50 * WAVELET)
653778 let nIdxs = [0, 1, 2, 3, 4, 5, 6, 7]
654779 let mngPubS = valueOrElse(getString("%s%s__cfg__leasingManagerPub"), "7AUMX54ukYMYvPmma7yoFf5NjZhs4Bu5nz3Ez9EV8sur")
655780 let mngPub = fromBase58String(mngPubS)
656781 let nodeRegAddrStr = valueOrElse(getString("%s%s__cfg__nodesRegistryAddress"), "3P9vKqQKjUdmpXAfiWau8krREYAY1Xr69pE")
657782 let nodeRegAddr = addressFromStringValue(nodeRegAddrStr)
658783 let lGroupNodeListKEY = getLeaseGroupNodeListKey(groupNum)
659784 let lGrNodeOpt = getString(this, lGroupNodeListKEY)
660785 if (isDefined(lGrNodeOpt))
661786 then throw((("group " + toString(groupNum)) + " already initialized"))
662787 else {
663788 let nList = split(nListS, SEP)
664789 let expCount = size(nIdxs)
665790 if ((i.callerPublicKey != mngPub))
666791 then throw("approveLeasings not authorized")
667792 else {
668- let $t02838428446 = readNodeInfo(0)
669- let nAddr0 = $t02838428446._1
670- let lAmtKEY0 = $t02838428446._2
671- let lAmt0 = $t02838428446._3
672- let lIdKEY0 = $t02838428446._4
673- let lId0 = $t02838428446._5
674- let $t02844928511 = readNodeInfo(1)
675- let nAddr1 = $t02844928511._1
676- let lAmtKEY1 = $t02844928511._2
677- let lAmt1 = $t02844928511._3
678- let lIdKEY1 = $t02844928511._4
679- let lId1 = $t02844928511._5
793+ let $t03363933701 = readNodeInfo(0)
794+ let nAddr0 = $t03363933701._1
795+ let lAmtKEY0 = $t03363933701._2
796+ let lAmt0 = $t03363933701._3
797+ let lIdKEY0 = $t03363933701._4
798+ let lId0 = $t03363933701._5
799+ let $t03370433766 = readNodeInfo(1)
800+ let nAddr1 = $t03370433766._1
801+ let lAmtKEY1 = $t03370433766._2
802+ let lAmt1 = $t03370433766._3
803+ let lIdKEY1 = $t03370433766._4
804+ let lId1 = $t03370433766._5
680805 let newL0 = Lease(nAddr0, (lAmt0 - ((lAmt * expCount) / 2)))
681806 let newL1 = Lease(nAddr1, (lAmt1 - ((lAmt * expCount) / 2)))
682807 let validation = invoke(nodeRegAddr, "validateAndApproveLeasings", [nListS], nil)
683808 if ((validation == validation))
684809 then {
685810 func forEachNodeValidateAndGenerateLease (a,i) = {
686811 let node = nList[i]
687812 let la = Lease(addressFromStringValue(node), lAmt)
688813 (a ++ [la, BinaryEntry(getLeaseIdByAddressKey(node), lcalc(la)), IntegerEntry(getLeaseAmountByAddressKey(node), lAmt)])
689814 }
690815
691816 ([StringEntry(lGroupNodeListKEY, nListS), BinaryEntry(lIdKEY0, lcalc(newL0)), BinaryEntry(lIdKEY1, lcalc(newL1)), IntegerEntry(lAmtKEY0, newL0.amount), IntegerEntry(lAmtKEY1, newL1.amount), LeaseCancel(lId0), LeaseCancel(lId1), newL0, newL1] ++ {
692817 let $l = nIdxs
693818 let $s = size($l)
694819 let $acc0 = nil
695820 func $f0_1 ($a,$i) = if (($i >= $s))
696821 then $a
697822 else forEachNodeValidateAndGenerateLease($a, $l[$i])
698823
699824 func $f0_2 ($a,$i) = if (($i >= $s))
700825 then $a
701826 else throw("List size exceeds 8")
702827
703828 $f0_2($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)
704829 })
705830 }
706831 else throw("Strict value is not equal to itself.")
707832 }
708833 }
709834 }
710835
711836
712837
713838 @Callable(i)
839+func rebalanceLeasings (amount,groupNum) = {
840+ let nIdxs = [0, 1, 2, 3, 4, 5, 6, 7]
841+ let mngPubS = valueOrElse(getString("%s%s__cfg__leasingManagerPub"), "7AUMX54ukYMYvPmma7yoFf5NjZhs4Bu5nz3Ez9EV8sur")
842+ let mngPub = fromBase58String(mngPubS)
843+ let lGroupNodeListKEY = getLeaseGroupNodeListKey(groupNum)
844+ let nListS = getStringOrFail(this, lGroupNodeListKEY)
845+ let nList = split(nListS, SEP)
846+ if ((i.callerPublicKey != mngPub))
847+ then throw("rebalanceLeasings not authorized")
848+ else {
849+ let unleaseAmt = ((amount / size(nList)) + 1)
850+ let $t03518335245 = readNodeInfo(0)
851+ let nAddr0 = $t03518335245._1
852+ let lAmtKEY0 = $t03518335245._2
853+ let lAmt0 = $t03518335245._3
854+ let lIdKEY0 = $t03518335245._4
855+ let lId0 = $t03518335245._5
856+ let newL0 = Lease(nAddr0, (lAmt0 + (unleaseAmt * size(nList))))
857+ func forEachNodeDoUnlease (a,i) = {
858+ let node = nList[i]
859+ let lIdKEY = getLeaseIdByAddressKey(node)
860+ let lId = getBinaryValue(this, lIdKEY)
861+ let lAmtKEY = getLeaseAmountByAddressKey(node)
862+ let lAmt = getIntegerValue(this, lAmtKEY)
863+ let ula = LeaseCancel(value(lId))
864+ let la = Lease(addressFromStringValue(node), (lAmt - unleaseAmt))
865+ (a ++ [LeaseCancel(value(lId)), la, BinaryEntry(lIdKEY, lcalc(la)), IntegerEntry(lAmtKEY, la.amount)])
866+ }
867+
868+ ({
869+ let $l = nIdxs
870+ let $s = size($l)
871+ let $acc0 = nil
872+ func $f0_1 ($a,$i) = if (($i >= $s))
873+ then $a
874+ else forEachNodeDoUnlease($a, $l[$i])
875+
876+ func $f0_2 ($a,$i) = if (($i >= $s))
877+ then $a
878+ else throw("List size exceeds 8")
879+
880+ $f0_2($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)
881+ } ++ [BinaryEntry(lIdKEY0, lcalc(newL0)), IntegerEntry(lAmtKEY0, newL0.amount), LeaseCancel(lId0), newL0])
882+ }
883+ }
884+
885+
886+
887+@Callable(i)
714888 func swapParamsByUserSYSREADONLY (userAddressStr,gnsbtDiff) = {
715889 let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", [userAddressStr, 0, 0], nil))
716890 let gnsbtAmt = (asInt(gnsbtData[0]) + gnsbtDiff)
717891 let gnsbtAmtTotal = (asInt(gnsbtData[1]) + gnsbtDiff)
718- let swapLimitMax = asInt(invoke(mathContract, "calcSwapLimitREADONLY", [gnsbtAmt], nil))
892+ let swapLimitData = asAnyList(invoke(mathContract, "calcSwapLimitREADONLY", [gnsbtAmt], nil))
893+ let wavesSwapLimitInUsdnMax = asInt(swapLimitData[0])
894+ let wavesSwapLimitMax = asInt(swapLimitData[1])
895+ let usdnSwapLimitMax = asInt(swapLimitData[2])
719896 let lastSwapHeight = valueOrElse(getInteger(this, keyUserLastSwapHeight(userAddressStr)), 0)
720897 let swapLimitTimelifeBlocks = swapsTimeframeREAD()
721898 let passedBlocksAfterLastSwap = (height - lastSwapHeight)
722899 let isSwapTimelifeNew = (passedBlocksAfterLastSwap >= swapLimitTimelifeBlocks)
723- let swapLimitSpent = if (isSwapTimelifeNew)
900+ let swapLimitSpentInUsdn = if (isSwapTimelifeNew)
724901 then 0
725902 else valueOrElse(getInteger(this, keySwapUserSpentInPeriod(userAddressStr)), 0)
726903 let blcks2LmtReset = if (isSwapTimelifeNew)
727904 then 0
728905 else (swapLimitTimelifeBlocks - passedBlocksAfterLastSwap)
729- $Tuple2(nil, $Tuple5(swapLimitMax, swapLimitSpent, blcks2LmtReset, gnsbtAmt, gnsbtAmtTotal))
906+ $Tuple2(nil, $Tuple7(wavesSwapLimitInUsdnMax, swapLimitSpentInUsdn, blcks2LmtReset, gnsbtAmt, gnsbtAmtTotal, wavesSwapLimitMax, usdnSwapLimitMax))
730907 }
908+
909+
910+
911+@Callable(i)
912+func calcWithdrawResultSYSREADONLY (swapType,inAmount,price) = $Tuple2(nil, calcWithdraw(swapType, inAmount, price))
731913
732914
733915
734916 @Callable(i)
735917 func updateReservesAndNeutrinoSupply () = {
736918 func getNumberByKeyInternal (key) = match getInteger(this, key) {
737919 case a: Int =>
738920 a
739921 case _ =>
740922 0
741923 }
742924
743925 let nMetrix = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
744926 let idx = getNumberByKeyInternal("updateReservesAndNeutrinoSupplyIdx")
745927 let newIdx = (idx + 1)
746928 [IntegerEntry("updateReservesAndNeutrinoSupplyIdx", newIdx), IntegerEntry("reserve", asInt(nMetrix[3])), IntegerEntry("neutrinoSupply", asInt(nMetrix[5])), IntegerEntry("reservesInUsdn", convertWavesToNeutrino(asInt(nMetrix[3]), asInt(nMetrix[0]))), IntegerEntry("surplus", asInt(nMetrix[6])), IntegerEntry("deficit", -(asInt(nMetrix[6])))]
747929 }
748930
749931
750932
751933 @Callable(i)
752934 func wavesBalancesVsPayment () = {
753935 let b = wavesBalance(this)
754936 [IntegerEntry("wavesBalance_available", b.available), IntegerEntry("wavesBalance_regular", b.regular), IntegerEntry("wavesBalance_generating", b.generating), IntegerEntry("wavesBalance_effective", b.effective), IntegerEntry("waves_payment", value(i.payments[0]).amount)]
755937 }
756938
757939
758940 @Verifier(tx)
759941 func verify () = {
760942 let id = toBase58String(tx.id)
761943 let pubKeyAdminsListStr = makeString(["ExtEEK19nmKj9mCpnWyvEEJFYATLMcVEMvohhUHkyHNm", "Ev5py5FfBQX9cZpYKnfQrTB49Byf8QmpZWeDVRim4yV7", "DUuuLjXu98nBwZc7fqwCTjtA3nnRwgTbkMSr5SU2NmDR", "DUuuLjXu98nBwZc7fqwCTjtA3nnRwgTbkMSr5SU2NmDR"], SEP)
762944 let pubKeyAdminsList = split(valueOrElse(getString(controlContract, "%s__multisig"), pubKeyAdminsListStr), SEP)
763945 let count = ((((if (sigVerify(tx.bodyBytes, tx.proofs[0], fromBase58String(pubKeyAdminsList[0])))
764946 then 1
765947 else 0) + (if (sigVerify(tx.bodyBytes, tx.proofs[1], fromBase58String(pubKeyAdminsList[1])))
766948 then 1
767949 else 0)) + (if (sigVerify(tx.bodyBytes, tx.proofs[2], fromBase58String(pubKeyAdminsList[2])))
768950 then 1
769951 else 0)) + (if (sigVerify(tx.bodyBytes, tx.proofs[3], fromBase58String(pubKeyAdminsList[3])))
770952 then 2
771953 else 0))
772954 match tx {
773955 case sponsorTx: SponsorFeeTransaction =>
774956 if (checkIsValidMinSponsoredFee(sponsorTx))
775957 then (count >= 3)
776958 else false
777959 case _ =>
778960 (count >= 3)
779961 }
780962 }
781963

github/deemru/w8io/3ef1775 
165.94 ms