2022.08.24 18:07 [3264198] smart account 3PC9BfRwJWWiw9AREE2B3eWzCks3CYtg4yo > SELF 0.00000000 Waves

{ "type": 13, "id": "HKae2yUvjujvb8u1PfpHnpHQMCLgVXrHbr5Kz6L1btYt", "fee": 3400000, "feeAssetId": null, "timestamp": 1661352903892, "version": 1, "sender": "3PC9BfRwJWWiw9AREE2B3eWzCks3CYtg4yo", "senderPublicKey": "BRnVwSVctnV8pge5vRpsJdWnkjWEJspFb6QvrmZvu3Ht", "proofs": [ "", "3N7QUbb15ZAjTfxXQuUmWH4ELXGSqbF1RBFY29fGm6CYVxdu1Tcx9NbqzczpUhWUJFGmEddz26iFuJkE9Byx9KdZ", "", "5pjKUJZSF6rcWayMrScnqUJtxNVeezDWUv6ou8MQ4XEX3394FUyCwsV6W8vadLy4R5AmJwgdtTBMQyt7wuDE1DM8" ], "script": "base64:BgJLCAISDgoMCAgICAgIAQEBAQEBEgUKAwgIARIAEgASBQoDCAEIEgMKAQESBAoCAQgSABIFCgMIAQESBAoCAQESBAoCCAESBQoDCAEBpgEAC3JldmlzaW9uTnVtAigwNDlmZTdiNzg4OTZhZWMwM2M3ZmExMDZiYTkyZTk3YjZjZTQxNDQ1AQ9nZXRTdHJpbmdPckZhaWwCB2FkZHJlc3MDa2V5CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ0IAgUHYWRkcmVzcwUDa2V5CQC5CQIJAMwIAgIKbWFuZGF0b3J5IAkAzAgCCQClCAEFB2FkZHJlc3MJAMwIAgIBLgkAzAgCBQNrZXkJAMwIAgIPIGlzIG5vdCBkZWZpbmVkBQNuaWwCAAEFbGNhbGMBAWwJALkIAQUBbAEOZ2V0TnVtYmVyQnlLZXkBA2tleQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQNrZXkAAAEOZ2V0U3RyaW5nQnlLZXkBA2tleQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzBQNrZXkCAAEMZ2V0Qm9vbEJ5S2V5AQNrZXkJAQt2YWx1ZU9yRWxzZQIJAJsIAgUEdGhpcwUDa2V5BwEYZ2V0TnVtYmVyQnlBZGRyZXNzQW5kS2V5AgdhZGRyZXNzA2tleQkBC3ZhbHVlT3JFbHNlAgkAmggCBQdhZGRyZXNzBQNrZXkAAAEYZ2V0U3RyaW5nQnlBZGRyZXNzQW5kS2V5AgdhZGRyZXNzA2tleQkBC3ZhbHVlT3JFbHNlAgkAnQgCCQERQGV4dHJOYXRpdmUoMTA2MikBBQdhZGRyZXNzBQNrZXkCAAEWZ2V0Qm9vbEJ5QWRkcmVzc0FuZEtleQIHYWRkcmVzcwNrZXkJAQt2YWx1ZU9yRWxzZQIJAJsIAgUHYWRkcmVzcwUDa2V5BwEJYXNBbnlMaXN0AQF2BAckbWF0Y2gwBQF2AwkAAQIFByRtYXRjaDACCUxpc3RbQW55XQQBbAUHJG1hdGNoMAUBbAkAAgECG2ZhaWwgdG8gY2FzdCBpbnRvIExpc3RbQW55XQEIYXNTdHJpbmcBAXYEByRtYXRjaDAFAXYDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFzBQckbWF0Y2gwBQFzCQACAQIYZmFpbCB0byBjYXN0IGludG8gU3RyaW5nAQVhc0ludAEBdgQHJG1hdGNoMAUBdgMJAAECBQckbWF0Y2gwAgNJbnQEAWkFByRtYXRjaDAFAWkJAAIBAhVmYWlsIHRvIGNhc3QgaW50byBJbnQBB2FzQnl0ZXMBA3ZhbAQHJG1hdGNoMAUDdmFsAwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEB3ZhbEJ5dGUFByRtYXRjaDAFB3ZhbEJ5dGUJAAIBAhxmYWlsIHRvIGNhc3QgaW50byBCeXRlVmVjdG9yAQlhc1BheW1lbnQBAXYEByRtYXRjaDAFAXYDCQABAgUHJG1hdGNoMAIPQXR0YWNoZWRQYXltZW50BAFwBQckbWF0Y2gwBQFwCQACAQIhZmFpbCB0byBjYXN0IGludG8gQXR0YWNoZWRQYXltZW50ARJhc1N3YXBQYXJhbXNTVFJVQ1QBAXYEByRtYXRjaDAFAXYDCQABAgUHJG1hdGNoMAIjKEludCwgSW50LCBJbnQsIEludCwgSW50LCBJbnQsIEludCkEBnN0cnVjdAUHJG1hdGNoMAUGc3RydWN0CQACAQIdZmFpbCB0byBjYXN0IGludG8gVHVwbGU1IGludHMAA1NFUAICX18AB1dBVkVMRVQAgMLXLwAFUEFVTEkAwIQ9AAhQUklDRUxFVADAhD0ADkRFRkFVTFRTV0FQRkVFAKCcAQALQlJQUk9URUNURUQAoI0GAAxJZHhOZXRBbW91bnQAAAAMSWR4RmVlQW1vdW50AAEADklkeEdyb3NzQW1vdW50AAIAGUlkeENvbnRyb2xDZmdOZXV0cmlub0RhcHAAAQAYSWR4Q29udHJvbENmZ0F1Y3Rpb25EYXBwAAIAFElkeENvbnRyb2xDZmdScGREYXBwAAMAFUlkeENvbnRyb2xDZmdNYXRoRGFwcAAEABxJZHhDb250cm9sQ2ZnTGlxdWlkYXRpb25EYXBwAAUAFUlkeENvbnRyb2xDZmdSZXN0RGFwcAAGAB1JZHhDb250cm9sQ2ZnTm9kZVJlZ2lzdHJ5RGFwcAAHABxJZHhDb250cm9sQ2ZnTnNidFN0YWtpbmdEYXBwAAgAGUlkeENvbnRyb2xDZmdNZWRpYXRvckRhcHAACQAcSWR4Q29udHJvbENmZ1N1cmZTdGFraW5nRGFwcAAKACBJZHhDb250cm9sQ2ZnR25zYnRDb250cm9sbGVyRGFwcAALARFrZXlDb250cm9sQWRkcmVzcwACHCVzJXNfX2NvbmZpZ19fY29udHJvbEFkZHJlc3MBDWtleUNvbnRyb2xDZmcAAhElc19fY29udHJvbENvbmZpZwEUcmVhZENvbnRyb2xDZmdPckZhaWwBB2NvbnRyb2wJALUJAgkBD2dldFN0cmluZ09yRmFpbAIFB2NvbnRyb2wJAQ1rZXlDb250cm9sQ2ZnAAUDU0VQARhnZXRDb250cmFjdEFkZHJlc3NPckZhaWwCCmNvbnRyb2xDZmcDaWR4CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkAkQMCBQpjb250cm9sQ2ZnBQNpZHgJAKwCAgItQ29udHJvbCBjZmcgZG9lc24ndCBjb250YWluIGFkZHJlc3MgYXQgaW5kZXggCQCkAwEFA2lkeAAPY29udHJvbENvbnRyYWN0CQERQGV4dHJOYXRpdmUoMTA2MikBCQELdmFsdWVPckVsc2UCCQCdCAIFBHRoaXMJARFrZXlDb250cm9sQWRkcmVzcwACIzNQNUJmZDU4UFBmTnZCTTJIeThRZmJjRHFNZU50emc3S2ZQAApjb250cm9sQ2ZnCQEUcmVhZENvbnRyb2xDZmdPckZhaWwBBQ9jb250cm9sQ29udHJhY3QADG1hdGhDb250cmFjdAkBGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAIFCmNvbnRyb2xDZmcFFUlkeENvbnRyb2xDZmdNYXRoRGFwcAATbnNidFN0YWtpbmdDb250cmFjdAkBGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAIFCmNvbnRyb2xDZmcFHElkeENvbnRyb2xDZmdOc2J0U3Rha2luZ0RhcHAAE3N1cmZTdGFraW5nQ29udHJhY3QJARhnZXRDb250cmFjdEFkZHJlc3NPckZhaWwCBQpjb250cm9sQ2ZnBRxJZHhDb250cm9sQ2ZnU3VyZlN0YWtpbmdEYXBwABdnbnNidENvbnRyb2xsZXJDb250cmFjdAkBGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAIFCmNvbnRyb2xDZmcFIElkeENvbnRyb2xDZmdHbnNidENvbnRyb2xsZXJEYXBwAA9hdWN0aW9uQ29udHJhY3QJARhnZXRDb250cmFjdEFkZHJlc3NPckZhaWwCBQpjb250cm9sQ2ZnBRhJZHhDb250cm9sQ2ZnQXVjdGlvbkRhcHAAEk5ldXRyaW5vQXNzZXRJZEtleQIRbmV1dHJpbm9fYXNzZXRfaWQADkJvbmRBc3NldElkS2V5Ag1ib25kX2Fzc2V0X2lkABJBdWN0aW9uQ29udHJhY3RLZXkCEGF1Y3Rpb25fY29udHJhY3QAFk5zYnRTdGFraW5nQ29udHJhY3RLZXkCE25zYnRTdGFraW5nQ29udHJhY3QAFkxpcXVpZGF0aW9uQ29udHJhY3RLZXkCFGxpcXVpZGF0aW9uX2NvbnRyYWN0AA5SUERDb250cmFjdEtleQIMcnBkX2NvbnRyYWN0ABFDb250b2xDb250cmFjdEtleQIQY29udHJvbF9jb250cmFjdAAPTWF0aENvbnRyYWN0S2V5Ag1tYXRoX2NvbnRyYWN0ABtCYWxhbmNlV2F2ZXNMb2NrSW50ZXJ2YWxLZXkCG2JhbGFuY2Vfd2F2ZXNfbG9ja19pbnRlcnZhbAAeQmFsYW5jZU5ldXRyaW5vTG9ja0ludGVydmFsS2V5Ah5iYWxhbmNlX25ldXRyaW5vX2xvY2tfaW50ZXJ2YWwAFU1pbldhdmVzU3dhcEFtb3VudEtleQIVbWluX3dhdmVzX3N3YXBfYW1vdW50ABhNaW5OZXV0cmlub1N3YXBBbW91bnRLZXkCGG1pbl9uZXV0cmlub19zd2FwX2Ftb3VudAAbTm9kZU9yYWNsZVByb3ZpZGVyUHViS2V5S2V5AhRub2RlX29yYWNsZV9wcm92aWRlcgAVTmV1dHJpbm9PdXRGZWVQYXJ0S2V5AhhuZXV0cmlub091dF9zd2FwX2ZlZVBhcnQAEldhdmVzT3V0RmVlUGFydEtleQIVd2F2ZXNPdXRfc3dhcF9mZWVQYXJ0AQ9rZXlOb2RlUmVnaXN0cnkBB2FkZHJlc3MJAKwCAgIEJXNfXwUHYWRkcmVzcwAIUHJpY2VLZXkCBXByaWNlAA1QcmljZUluZGV4S2V5AgtwcmljZV9pbmRleAAMSXNCbG9ja2VkS2V5Agppc19ibG9ja2VkARJnZXRQcmljZUhpc3RvcnlLZXkBBWJsb2NrCQCsAgIJAKwCAgUIUHJpY2VLZXkCAV8JAKQDAQUFYmxvY2sBGGdldEhlaWdodFByaWNlQnlJbmRleEtleQEFaW5kZXgJAKwCAgkArAICBQ1QcmljZUluZGV4S2V5AgFfCQCkAwEFBWluZGV4ARVnZXRTdGFraW5nTm9kZUJ5SW5kZXgBA2lkeAkBDmdldFN0cmluZ0J5S2V5AQkAuQkCCQDMCAICBiVzJWQlcwkAzAgCAgVsZWFzZQkAzAgCCQCkAwEFA2lkeAkAzAgCAgtub2RlQWRkcmVzcwUDbmlsBQNTRVABHGdldFN0YWtpbmdOb2RlQWRkcmVzc0J5SW5kZXgBA2lkeAkBEUBleHRyTmF0aXZlKDEwNjIpAQkBFWdldFN0YWtpbmdOb2RlQnlJbmRleAEFA2lkeAEfZ2V0UmVzZXJ2ZWRBbW91bnRGb3JTcG9uc29yc2hpcAAJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkAuQkCCQDMCAICBCVzJXMJAMwIAgIFbGVhc2UJAMwIAgIXc3BvbnNvcnNoaXBXYXZlc1Jlc2VydmUFA25pbAUDU0VQCQBoAgDoBwUHV0FWRUxFVAEYZ2V0QmFsYW5jZVVubG9ja0Jsb2NrS2V5AQVvd25lcgkArAICAhViYWxhbmNlX3VubG9ja19ibG9ja18FBW93bmVyAQ1nZXRMZWFzZUlkS2V5AQlub2RlSW5kZXgJALkJAgkAzAgCAgYlcyVkJXMJAMwIAgIFbGVhc2UJAMwIAgkApAMBBQlub2RlSW5kZXgJAMwIAgICaWQFA25pbAUDU0VQARZnZXRMZWFzZUlkQnlBZGRyZXNzS2V5AQtub2RlQWRkcmVzcwkAuQkCCQDMCAICBiVzJXMlcwkAzAgCAg5sZWFzZUJ5QWRkcmVzcwkAzAgCBQtub2RlQWRkcmVzcwkAzAgCAgJpZAUDbmlsBQNTRVABEWdldExlYXNlQW1vdW50S2V5AQlub2RlSW5kZXgJALkJAgkAzAgCAgYlcyVkJXMJAMwIAgIFbGVhc2UJAMwIAgkApAMBBQlub2RlSW5kZXgJAMwIAgIGYW1vdW50BQNuaWwFA1NFUAEaZ2V0TGVhc2VBbW91bnRCeUFkZHJlc3NLZXkBC25vZGVBZGRyZXNzCQC5CQIJAMwIAgIGJXMlcyVzCQDMCAICDmxlYXNlQnlBZGRyZXNzCQDMCAIFC25vZGVBZGRyZXNzCQDMCAICBmFtb3VudAUDbmlsBQNTRVABGGdldExlYXNlR3JvdXBOb2RlTGlzdEtleQEIZ3JvdXBOdW0JALkJAgkAzAgCAgYlcyVkJXMJAMwIAgIKbGVhc2VHcm91cAkAzAgCCQCkAwEFCGdyb3VwTnVtCQDMCAICCG5vZGVMaXN0BQNuaWwFA1NFUAEQbWluU3dhcEFtb3VudEtFWQEIc3dhcFR5cGUJAKwCAgkArAICAgRtaW5fBQhzd2FwVHlwZQIMX3N3YXBfYW1vdW50AQ50b3RhbExvY2tlZEtFWQEIc3dhcFR5cGUJAKwCAgINYmFsYW5jZV9sb2NrXwUIc3dhcFR5cGUBFHRvdGFsTG9ja2VkQnlVc2VyS0VZAghzd2FwVHlwZQVvd25lcgkAuQkCCQDMCAICDGJhbGFuY2VfbG9jawkAzAgCBQhzd2FwVHlwZQkAzAgCBQVvd25lcgUDbmlsAgFfARZiYWxhbmNlTG9ja0ludGVydmFsS0VZAQhzd2FwVHlwZQkArAICCQCsAgICCGJhbGFuY2VfBQhzd2FwVHlwZQIOX2xvY2tfaW50ZXJ2YWwBGm5vZGVCYWxhbmNlTG9ja0ludGVydmFsS0VZAAIaYmFsYW5jZV9ub2RlX2xvY2tfaW50ZXJ2YWwBDW91dEZlZVBhcnRLRVkBCHN3YXBUeXBlCQCsAgIFCHN3YXBUeXBlAhBPdXRfc3dhcF9mZWVQYXJ0ARFzd2Fwc1RpbWVmcmFtZUtFWQACD3N3YXBzX3RpbWVmcmFtZQEOYnJQcm90ZWN0ZWRLRVkAAhdtaW5fQlJfcHJvdGVjdGlvbl9sZXZlbAERbWluU3dhcEFtb3VudFJFQUQBCHN3YXBUeXBlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJARBtaW5Td2FwQW1vdW50S0VZAQUIc3dhcFR5cGUAAAESc3dhcHNUaW1lZnJhbWVSRUFEAAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQERc3dhcHNUaW1lZnJhbWVLRVkAAKALAQ90b3RhbExvY2tlZFJFQUQBCHN3YXBUeXBlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQ50b3RhbExvY2tlZEtFWQEFCHN3YXBUeXBlAAABFXRvdGFsTG9ja2VkQnlVc2VyUkVBRAIIc3dhcFR5cGUFb3duZXIJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBFHRvdGFsTG9ja2VkQnlVc2VyS0VZAgUIc3dhcFR5cGUFBW93bmVyAAABF2JhbGFuY2VMb2NrSW50ZXJ2YWxSRUFEAQhzd2FwVHlwZQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEWYmFsYW5jZUxvY2tJbnRlcnZhbEtFWQEFCHN3YXBUeXBlAKALARtub2RlQmFsYW5jZUxvY2tJbnRlcnZhbFJFQUQACQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJARpub2RlQmFsYW5jZUxvY2tJbnRlcnZhbEtFWQAAAQEYa2V5U3dhcFVzZXJTcGVudEluUGVyaW9kAQt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBCVzJXMJAMwIAgIVc3dhcFVzZXJTcGVudEluUGVyaW9kCQDMCAIFC3VzZXJBZGRyZXNzBQNuaWwFA1NFUAEVa2V5VXNlckxhc3RTd2FwSGVpZ2h0AQt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBCVzJXMJAMwIAgISdXNlckxhc3RTd2FwSGVpZ2h0CQDMCAIFC3VzZXJBZGRyZXNzBQNuaWwFA1NFUAEWY29udmVydE5ldXRyaW5vVG9XYXZlcwIGYW1vdW50BXByaWNlCQBrAwkAawMFBmFtb3VudAUIUFJJQ0VMRVQFBXByaWNlBQdXQVZFTEVUBQVQQVVMSQEWY29udmVydFdhdmVzVG9OZXV0cmlubwIGYW1vdW50BXByaWNlCQBrAwkAawMFBmFtb3VudAUFcHJpY2UFCFBSSUNFTEVUBQVQQVVMSQUHV0FWRUxFVAESY29udmVydFdhdmVzVG9Cb25kAgZhbW91bnQFcHJpY2UJARZjb252ZXJ0V2F2ZXNUb05ldXRyaW5vAgUGYW1vdW50BQVwcmljZQEWY29udmVydEpzb25BcnJheVRvTGlzdAEJanNvbkFycmF5CQC1CQIFCWpzb25BcnJheQIBLAERbWluU3dhcEFtb3VudEZBSUwCCHN3YXBUeXBlDW1pblN3YXBBbW91bnQJAAIBCQCsAgIJAKwCAgkArAICAhhUaGUgc3BlY2lmaWVkIGFtb3VudCBpbiAFCHN3YXBUeXBlAisgc3dhcCBpcyBsZXNzIHRoYW4gdGhlIHJlcXVpcmVkIG1pbmltdW0gb2YgCQCkAwEFDW1pblN3YXBBbW91bnQBFWVtZXJnZW5jeVNodXRkb3duRkFJTAAJAAIBAlpjb250cmFjdCBpcyBibG9ja2VkIGJ5IEVNRVJHRU5DWSBTSFVURE9XTiBhY3Rpb25zIHVudGlsbCByZWFjdGl2YXRpb24gYnkgZW1lcmdlbmN5IG9yYWNsZXMBDnByaWNlSW5kZXhGQUlMBQVpbmRleApwcmljZUluZGV4C2luZGV4SGVpZ2h0DHVubG9ja0hlaWdodA9wcmV2SW5kZXhIZWlnaHQJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICAiNpbnZhbGlkIHByaWNlIGhpc3RvcnkgaW5kZXg6IGluZGV4PQkApAMBBQVpbmRleAIMIHByaWNlSW5kZXg9CQCkAwEFCnByaWNlSW5kZXgCDSBpbmRleEhlaWdodD0JAKQDAQULaW5kZXhIZWlnaHQCDiB1bmxvY2tIZWlnaHQ9CQCkAwEFDHVubG9ja0hlaWdodAIRIHByZXZJbmRleEhlaWdodD0JAKQDAQUPcHJldkluZGV4SGVpZ2h0AA9uZXV0cmlub0Fzc2V0SWQJANkEAQkBDmdldFN0cmluZ0J5S2V5AQUSTmV1dHJpbm9Bc3NldElkS2V5AApwcmljZUluZGV4CQEYZ2V0TnVtYmVyQnlBZGRyZXNzQW5kS2V5AgUPY29udHJvbENvbnRyYWN0BQ1QcmljZUluZGV4S2V5AAlpc0Jsb2NrZWQJARZnZXRCb29sQnlBZGRyZXNzQW5kS2V5AgUPY29udHJvbENvbnRyYWN0BQxJc0Jsb2NrZWRLZXkAGG5vZGVPcmFjbGVQcm92aWRlclB1YktleQkA2QQBCQEOZ2V0U3RyaW5nQnlLZXkBBRtOb2RlT3JhY2xlUHJvdmlkZXJQdWJLZXlLZXkAC2JvbmRBc3NldElkCQDZBAECLDZuU3BWeU5IN3lNNjllZzQ0NndyUVI5NGlwYmJjbVpNVTFFTlB3YW5DOTdnABVkZXByZWNhdGVkQm9uZEFzc2V0SWQJANkEAQIsOTc1YWtaQmZuTWo1MTNVN01aYUhLelFybXNFeDVhRTN3ZFdLVHJIQmhiakYAEG5ldXRyaW5vQ29udHJhY3QFBHRoaXMADGN1cnJlbnRQcmljZQkBGGdldE51bWJlckJ5QWRkcmVzc0FuZEtleQIFD2NvbnRyb2xDb250cmFjdAUIUHJpY2VLZXkBG2NoZWNrSXNWYWxpZE1pblNwb25zb3JlZEZlZQECdHgEDk1JTlRSQU5TRkVSRkVFAKCNBgQWU3BvbnNvcmVkRmVlVXBwZXJCb3VuZADoBwQPcmVhbE5ldXRyaW5vRmVlCQEWY29udmVydFdhdmVzVG9OZXV0cmlubwIFDk1JTlRSQU5TRkVSRkVFBQxjdXJyZW50UHJpY2UEDm1pbk5ldXRyaW5vRmVlCQBoAgUPcmVhbE5ldXRyaW5vRmVlAAIEDm1heE5ldXRyaW5vRmVlCQBrAwUPcmVhbE5ldXRyaW5vRmVlBRZTcG9uc29yZWRGZWVVcHBlckJvdW5kAGQECGlucHV0RmVlCQEFdmFsdWUBCAUCdHgUbWluU3BvbnNvcmVkQXNzZXRGZWUDAwkAZwIFCGlucHV0RmVlBQ5taW5OZXV0cmlub0ZlZQkAZwIFDm1heE5ldXRyaW5vRmVlBQhpbnB1dEZlZQcJAAACCAUCdHgHYXNzZXRJZAUPbmV1dHJpbm9Bc3NldElkBwEPZ2V0UHJpY2VIaXN0b3J5AQVibG9jawkBGGdldE51bWJlckJ5QWRkcmVzc0FuZEtleQIFD2NvbnRyb2xDb250cmFjdAkBEmdldFByaWNlSGlzdG9yeUtleQEFBWJsb2NrARVnZXRIZWlnaHRQcmljZUJ5SW5kZXgBBWluZGV4CQEYZ2V0TnVtYmVyQnlBZGRyZXNzQW5kS2V5AgUPY29udHJvbENvbnRyYWN0CQEYZ2V0SGVpZ2h0UHJpY2VCeUluZGV4S2V5AQUFaW5kZXgBFmtleUxvY2tQYXJhbVVzZXJBbW91bnQBC3VzZXJBZGRyZXNzCQC5CQIJAMwIAgIGJXMlcyVzCQDMCAICC3BhcmFtQnlVc2VyCQDMCAIFC3VzZXJBZGRyZXNzCQDMCAICBmFtb3VudAUDbmlsBQNTRVAADHNJZHhTd2FwVHlwZQABAApzSWR4U3RhdHVzAAIADHNJZHhJbkFtb3VudAADAAlzSWR4UHJpY2UABAAQc0lkeE91dE5ldEFtb3VudAAFABBzSWR4T3V0RmVlQW1vdW50AAYAD3NJZHhTdGFydEhlaWdodAAHABJzSWR4U3RhcnRUaW1lc3RhbXAACAANc0lkeEVuZEhlaWdodAAJABBzSWR4RW5kVGltZXN0YW1wAAoAFHNJZHhTZWxmVW5sb2NrSGVpZ2h0AAsAFHNJZHhSYW5kVW5sb2NrSGVpZ2h0AAwACXNJZHhJbmRleAANABBzSWR4V2l0aGRyYXdUeElkAA4AC3NJZHhNaW5SYW5kAA8AC3NJZHhNYXhSYW5kABABB3N3YXBLRVkCC3VzZXJBZGRyZXNzBHR4SWQJALkJAgkAzAgCAgQlcyVzCQDMCAIFC3VzZXJBZGRyZXNzCQDMCAIFBHR4SWQFA25pbAUDU0VQAQtzdHJTd2FwREFUQRAIc3dhcFR5cGUGc3RhdHVzCGluQW1vdW50BXByaWNlDG91dE5ldEFtb3VudAxvdXRGZWVBbW91bnQLc3RhcnRIZWlnaHQOc3RhcnRUaW1lc3RhbXAJZW5kSGVpZ2h0DGVuZFRpbWVzdGFtcBBzZWxmVW5sb2NrSGVpZ2h0EHJhbmRVbmxvY2tIZWlnaHQFaW5kZXgMd2l0aGRyYXdUeElkB3JhbmRNaW4HcmFuZE1heAkAuQkCCQDMCAICHCVzJXMlZCVkJWQlZCVkJWQlZCVkJWQlZCVkJXMJAMwIAgUIc3dhcFR5cGUJAMwIAgUGc3RhdHVzCQDMCAIFCGluQW1vdW50CQDMCAIFBXByaWNlCQDMCAIFDG91dE5ldEFtb3VudAkAzAgCBQxvdXRGZWVBbW91bnQJAMwIAgULc3RhcnRIZWlnaHQJAMwIAgUOc3RhcnRUaW1lc3RhbXAJAMwIAgUJZW5kSGVpZ2h0CQDMCAIFDGVuZFRpbWVzdGFtcAkAzAgCBRBzZWxmVW5sb2NrSGVpZ2h0CQDMCAIFEHJhbmRVbmxvY2tIZWlnaHQJAMwIAgUFaW5kZXgJAMwIAgUMd2l0aGRyYXdUeElkCQDMCAIFB3JhbmRNaW4JAMwIAgUHcmFuZE1heAUDbmlsBQNTRVABD3BlbmRpbmdTd2FwREFUQQMIc3dhcFR5cGUNaW5Bc3NldEFtb3VudBBzZWxmVW5sb2NrSGVpZ2h0CQELc3RyU3dhcERBVEEQBQhzd2FwVHlwZQIHUEVORElORwkApAMBBQ1pbkFzc2V0QW1vdW50AgEwAgEwAgEwCQCkAwEFBmhlaWdodAkApAMBCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAIBMAIBMAkApAMBBRBzZWxmVW5sb2NrSGVpZ2h0AgEwAgEwAgROVUxMAgEwAgEwAQ5maW5pc2hTd2FwREFUQQcJZGF0YUFycmF5BXByaWNlDG91dE5ldEFtb3VudAxvdXRGZWVBbW91bnQQcmFuZFVubG9ja0hlaWdodAVpbmRleAx3aXRoZHJhd1R4SWQJAQtzdHJTd2FwREFUQRAJAJEDAgUJZGF0YUFycmF5BQxzSWR4U3dhcFR5cGUCCEZJTklTSEVECQCRAwIFCWRhdGFBcnJheQUMc0lkeEluQW1vdW50CQCkAwEFBXByaWNlCQCkAwEFDG91dE5ldEFtb3VudAkApAMBBQxvdXRGZWVBbW91bnQJAJEDAgUJZGF0YUFycmF5BQ9zSWR4U3RhcnRIZWlnaHQJAJEDAgUJZGF0YUFycmF5BRJzSWR4U3RhcnRUaW1lc3RhbXAJAKQDAQUGaGVpZ2h0CQCkAwEIBQlsYXN0QmxvY2sJdGltZXN0YW1wCQCRAwIFCWRhdGFBcnJheQUUc0lkeFNlbGZVbmxvY2tIZWlnaHQJAKQDAQUQcmFuZFVubG9ja0hlaWdodAkApAMBBQVpbmRleAUMd2l0aGRyYXdUeElkCQCRAwIFCWRhdGFBcnJheQULc0lkeE1pblJhbmQJAJEDAgUJZGF0YUFycmF5BQtzSWR4TWF4UmFuZAESc3dhcERhdGFGYWlsT3JSRUFEAgt1c2VyQWRkcmVzcwhzd2FwVHhJZAQHc3dhcEtleQkBB3N3YXBLRVkCBQt1c2VyQWRkcmVzcwUIc3dhcFR4SWQJALUJAgkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFBHRoaXMFB3N3YXBLZXkJAKwCAgIRbm8gc3dhcCBkYXRhIGZvciAFB3N3YXBLZXkFA1NFUAEJYXBwbHlGZWVzAw5hbW91bnRPdXRHcm9zcwtpbkFtdFRvU1VSRgdmZWVQYXJ0BAlmZWVBbW91bnQJAGsDBQ5hbW91bnRPdXRHcm9zcwUHZmVlUGFydAUFUEFVTEkJAMwIAgkAZQIFDmFtb3VudE91dEdyb3NzBQlmZWVBbW91bnQJAMwIAgUJZmVlQW1vdW50BQNuaWwBA2FicwEBeAMJAGYCAAAFAXgJAQEtAQUBeAUBeAEKc2VsZWN0Tm9kZQENdW5sZWFzZUFtb3VudAQNYW1vdW50VG9MZWFzZQkAZQIJAGUCCAkA7wcBBRBuZXV0cmlub0NvbnRyYWN0CWF2YWlsYWJsZQUNdW5sZWFzZUFtb3VudAkBH2dldFJlc2VydmVkQW1vdW50Rm9yU3BvbnNvcnNoaXAABApvbGRMZWFzZWQwCQEOZ2V0TnVtYmVyQnlLZXkBCQERZ2V0TGVhc2VBbW91bnRLZXkBAAAECm9sZExlYXNlZDEJAQ5nZXROdW1iZXJCeUtleQEJARFnZXRMZWFzZUFtb3VudEtleQEAAQQKbmV3TGVhc2VkMAkAZAIFDWFtb3VudFRvTGVhc2UFCm9sZExlYXNlZDAECm5ld0xlYXNlZDEJAGQCBQ1hbW91bnRUb0xlYXNlBQpvbGRMZWFzZWQxAwMJAGYCBQpuZXdMZWFzZWQwAAAGCQBmAgUKbmV3TGVhc2VkMQAABAZkZWx0YTAJAQNhYnMBCQBlAgUKbmV3TGVhc2VkMAUKb2xkTGVhc2VkMQQGZGVsdGExCQEDYWJzAQkAZQIFCm5ld0xlYXNlZDEFCm9sZExlYXNlZDADCQBnAgUGZGVsdGExBQZkZWx0YTAJAJQKAgAABQpuZXdMZWFzZWQwCQCUCgIAAQUKbmV3TGVhc2VkMQkAlAoCAP///////////wEAAAEIdGhpc09ubHkBAWkDCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAAIBAi1QZXJtaXNzaW9uIGRlbmllZDogdGhpcyBjb250cmFjdCBvbmx5IGFsbG93ZWQGARZwcmVwYXJlVW5sZWFzZUFuZExlYXNlAQ11bmxlYXNlQW1vdW50BAlub2RlVHVwbGUJAQpzZWxlY3ROb2RlAQUNdW5sZWFzZUFtb3VudAQJbm9kZUluZGV4CAUJbm9kZVR1cGxlAl8xBA5uZXdMZWFzZUFtb3VudAgFCW5vZGVUdXBsZQJfMgMJAGYCBQ5uZXdMZWFzZUFtb3VudAAABApsZWFzZUlkS2V5CQENZ2V0TGVhc2VJZEtleQEFCW5vZGVJbmRleAQIb2xkTGVhc2UJAJwIAgUEdGhpcwUKbGVhc2VJZEtleQQOdW5sZWFzZU9yRW1wdHkDCQEJaXNEZWZpbmVkAQUIb2xkTGVhc2UJAMwIAgkBC0xlYXNlQ2FuY2VsAQkBBXZhbHVlAQUIb2xkTGVhc2UFA25pbAUDbmlsBA5sZWFzZUFtb3VudEtleQkBEWdldExlYXNlQW1vdW50S2V5AQUJbm9kZUluZGV4BAVsZWFzZQkAxAgCCQEcZ2V0U3Rha2luZ05vZGVBZGRyZXNzQnlJbmRleAEFCW5vZGVJbmRleAUObmV3TGVhc2VBbW91bnQJAM4IAgUOdW5sZWFzZU9yRW1wdHkJAMwIAgUFbGVhc2UJAMwIAgkBC0JpbmFyeUVudHJ5AgUKbGVhc2VJZEtleQkBBWxjYWxjAQUFbGVhc2UJAMwIAgkBDEludGVnZXJFbnRyeQIJARFnZXRMZWFzZUFtb3VudEtleQEFCW5vZGVJbmRleAUObmV3TGVhc2VBbW91bnQFA25pbAUDbmlsAQxyZWFkTm9kZUluZm8BB25vZGVJZHgEC25vZGVBZGRyZXNzCQEcZ2V0U3Rha2luZ05vZGVBZGRyZXNzQnlJbmRleAEFB25vZGVJZHgEDGxlYXNlZEFtdEtFWQkBEWdldExlYXNlQW1vdW50S2V5AQUHbm9kZUlkeAQJbGVhc2VkQW10CQEOZ2V0TnVtYmVyQnlLZXkBBQxsZWFzZWRBbXRLRVkECmxlYXNlSWRLRVkJAQ1nZXRMZWFzZUlkS2V5AQUHbm9kZUlkeAQHbGVhc2VJZAkBBXZhbHVlAQkAnAgCBQR0aGlzBQpsZWFzZUlkS0VZCQCXCgUFC25vZGVBZGRyZXNzBQxsZWFzZWRBbXRLRVkFCWxlYXNlZEFtdAUKbGVhc2VJZEtFWQUHbGVhc2VJZAEKY29tbW9uU3dhcAUIc3dhcFR5cGUJcG10QW1vdW50DnVzZXJBZGRyZXNzU3RyBnR4SWQ1OBtzd2FwUGFyYW1zQnlVc2VyU1lTUkVBRE9OTFkEDnN3YXBMaW1pdFNwZW50CAUbc3dhcFBhcmFtc0J5VXNlclNZU1JFQURPTkxZAl8yBA5ibGNrczJMbXRSZXNldAgFG3N3YXBQYXJhbXNCeVVzZXJTWVNSRUFET05MWQJfMwQRd2F2ZXNTd2FwTGltaXRNYXgIBRtzd2FwUGFyYW1zQnlVc2VyU1lTUkVBRE9OTFkCXzYEEHVzZG5Td2FwTGltaXRNYXgIBRtzd2FwUGFyYW1zQnlVc2VyU1lTUkVBRE9OTFkCXzcEDW1pblN3YXBBbW91bnQJARFtaW5Td2FwQW1vdW50UkVBRAEFCHN3YXBUeXBlBAt0b3RhbExvY2tlZAkBD3RvdGFsTG9ja2VkUkVBRAEFCHN3YXBUeXBlBBF0b3RhbExvY2tlZEJ5VXNlcgkBFXRvdGFsTG9ja2VkQnlVc2VyUkVBRAIFCHN3YXBUeXBlBQ51c2VyQWRkcmVzc1N0cgQLbm9kZUFkZHJlc3MJARVnZXRTdGFraW5nTm9kZUJ5SW5kZXgBAAAEDHByaWNlQnlJbmRleAkBD2dldFByaWNlSGlzdG9yeQEJARVnZXRIZWlnaHRQcmljZUJ5SW5kZXgBBQpwcmljZUluZGV4BAxpc1N3YXBCeU5vZGUJAAACBQtub2RlQWRkcmVzcwUOdXNlckFkZHJlc3NTdHIEFmJhbGFuY2VMb2NrTWF4SW50ZXJ2YWwDBQxpc1N3YXBCeU5vZGUJARtub2RlQmFsYW5jZUxvY2tJbnRlcnZhbFJFQUQACQEXYmFsYW5jZUxvY2tJbnRlcnZhbFJFQUQBBQhzd2FwVHlwZQQQc2VsZlVubG9ja0hlaWdodAkAZAIFBmhlaWdodAUWYmFsYW5jZUxvY2tNYXhJbnRlcnZhbAQOc3dhcFVzZG5Wb2x1bWUDCQAAAgUIc3dhcFR5cGUCCG5ldXRyaW5vBQlwbXRBbW91bnQJARZjb252ZXJ0V2F2ZXNUb05ldXRyaW5vAgUJcG10QW1vdW50BQxwcmljZUJ5SW5kZXgEDHN3YXBMaW1pdE1heAMJAAACBQhzd2FwVHlwZQIIbmV1dHJpbm8FEHVzZG5Td2FwTGltaXRNYXgJARZjb252ZXJ0V2F2ZXNUb05ldXRyaW5vAgURd2F2ZXNTd2FwTGltaXRNYXgFDHByaWNlQnlJbmRleAMJAGYCBQ1taW5Td2FwQW1vdW50BQlwbXRBbW91bnQJARFtaW5Td2FwQW1vdW50RkFJTAIFCHN3YXBUeXBlBQ1taW5Td2FwQW1vdW50AwMJAQEhAQUMaXNTd2FwQnlOb2RlCQBmAgUOc3dhcExpbWl0U3BlbnQAAAcJAAIBCQCsAgICOllvdSBoYXZlIGV4Y2VlZGVkIHN3YXAgbGltaXQhIE5leHQgYWxsb3dlZCBzd2FwIGhlaWdodCBpcyAJAKQDAQkAZAIFBmhlaWdodAUOYmxja3MyTG10UmVzZXQDAwkBASEBBQxpc1N3YXBCeU5vZGUJAGYCBQ5zd2FwVXNkblZvbHVtZQUMc3dhcExpbWl0TWF4BwkAAgEJAKwCAgkArAICCQCsAgICLllvdSBoYXZlIGV4Y2VlZGVkIHlvdXIgc3dhcCBsaW1pdCEgUmVxdWVzdGVkOiAJAKQDAQUOc3dhcFVzZG5Wb2x1bWUCDSwgYXZhaWxhYmxlOiAJAKQDAQUMc3dhcExpbWl0TWF4AwUJaXNCbG9ja2VkCQEVZW1lcmdlbmN5U2h1dGRvd25GQUlMAAQJbGVhc2VQYXJ0AwkAAAIFCHN3YXBUeXBlAgV3YXZlcwkBFnByZXBhcmVVbmxlYXNlQW5kTGVhc2UBAAAFA25pbAkAlAoCCQDOCAIJAMwIAgkBDEludGVnZXJFbnRyeQIJARhrZXlTd2FwVXNlclNwZW50SW5QZXJpb2QBBQ51c2VyQWRkcmVzc1N0cgUOc3dhcFVzZG5Wb2x1bWUJAMwIAgkBDEludGVnZXJFbnRyeQIJARVrZXlVc2VyTGFzdFN3YXBIZWlnaHQBBQ51c2VyQWRkcmVzc1N0cgUGaGVpZ2h0CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEUdG90YWxMb2NrZWRCeVVzZXJLRVkCBQhzd2FwVHlwZQUOdXNlckFkZHJlc3NTdHIJAGQCBRF0b3RhbExvY2tlZEJ5VXNlcgUJcG10QW1vdW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEYZ2V0QmFsYW5jZVVubG9ja0Jsb2NrS2V5AQUOdXNlckFkZHJlc3NTdHIFEHNlbGZVbmxvY2tIZWlnaHQJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b3RhbExvY2tlZEtFWQEFCHN3YXBUeXBlCQBkAgULdG90YWxMb2NrZWQFCXBtdEFtb3VudAkAzAgCCQELU3RyaW5nRW50cnkCCQEHc3dhcEtFWQIFDnVzZXJBZGRyZXNzU3RyBQZ0eElkNTgJAQ9wZW5kaW5nU3dhcERBVEEDBQhzd2FwVHlwZQUJcG10QW1vdW50BRBzZWxmVW5sb2NrSGVpZ2h0BQNuaWwFCWxlYXNlUGFydAUEdW5pdAAPbk1ldHJpY0lkeFByaWNlAAAAG25NZXRyaWNJZHhVc2RuTG9ja2VkQmFsYW5jZQABABxuTWV0cmljSWR4V2F2ZXNMb2NrZWRCYWxhbmNlAAIAEW5NZXRyaWNJZHhSZXNlcnZlAAMAF25NZXRyaWNJZHhSZXNlcnZlSW5Vc2RuAAQAFG5NZXRyaWNJZHhVc2RuU3VwcGx5AAUAEW5NZXRyaWNJZHhTdXJwbHVzAAYAGG5NZXRyaWNJZHhTdXJwbHVzUGVyY2VudAAHAAxuTWV0cmljSWR4QlIACAAUbk1ldHJpY0lkeE5zYnRTdXBwbHkACQAXbk1ldHJpY0lkeE1heE5zYnRTdXBwbHkACgAUbk1ldHJpY0lkeFN1cmZTdXBwbHkACwAMYkZ1bmNJZHhTdXJmAAAADWJGdW5jSWR4V2F2ZXMAAQAMYkZ1bmNJZHhVc2RuAAIAFGJGdW5jSWR4UmVzZXJ2ZVN0YXJ0AAMAE2JGdW5jSWR4U3VwcGx5U3RhcnQABAAPYkZ1bmNJZHhCUlN0YXJ0AAUAEmJGdW5jSWR4UmVzZXJ2ZUVuZAAGABFiRnVuY0lkeFN1cHBseUVuZAAHAA1iRnVuY0lkeEJSRW5kAAgADGJGdW5jSWR4UmVzdAAJABJiRnVuY0lkeFdhdmVzUHJpY2UACgEPY2FsY1dpdGhkcmF3VzJVAgd3YXZlc0luBXByaWNlBAtvdXRBbXRHcm9zcwkBFmNvbnZlcnRXYXZlc1RvTmV1dHJpbm8CBQd3YXZlc0luBQVwcmljZQkAmwoJBQtvdXRBbXRHcm9zcwUPbmV1dHJpbm9Bc3NldElkAAAFBHVuaXQAAAUHd2F2ZXNJbgAAAAAAAAEPY2FsY1dpdGhkcmF3VTJXBQZ1c2RuSW4FcHJpY2UCYnIOcmVzZXJ2ZXNJblVzZG4KdXNkblN1cHBseQQLYnJQcm90ZWN0ZWQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBDmJyUHJvdGVjdGVkS0VZAAULQlJQUk9URUNURUQEGW1heEFsbG93ZWRVc2RuQmVmb3JlTWluQnIDCQBnAgULYnJQcm90ZWN0ZWQFAmJyAAAJAGsDCQBlAgUOcmVzZXJ2ZXNJblVzZG4JAGsDBQticlByb3RlY3RlZAUKdXNkblN1cHBseQUFUEFVTEkFBVBBVUxJCQBlAgUFUEFVTEkFC2JyUHJvdGVjdGVkBBZhbGxvd2VkVXNkbkJlZm9yZU1pbkJyAwkAZgIFBnVzZG5JbgUZbWF4QWxsb3dlZFVzZG5CZWZvcmVNaW5CcgUZbWF4QWxsb3dlZFVzZG5CZWZvcmVNaW5CcgUGdXNkbkluBBVhbGxvd2VkVXNkbkFmdGVyTWluQnIDCQBmAgUGdXNkbkluBRltYXhBbGxvd2VkVXNkbkJlZm9yZU1pbkJyCQBrAwkAZQIFBnVzZG5JbgUZbWF4QWxsb3dlZFVzZG5CZWZvcmVNaW5CcgUCYnIFBVBBVUxJAAAEC2FsbG93ZWRVc2RuCQBkAgUWYWxsb3dlZFVzZG5CZWZvcmVNaW5CcgUVYWxsb3dlZFVzZG5BZnRlck1pbkJyBAl1c2RuMlNVUkYJAGUCBQZ1c2RuSW4FC2FsbG93ZWRVc2RuBAtvdXRBbXRHcm9zcwkBFmNvbnZlcnROZXV0cmlub1RvV2F2ZXMCBQthbGxvd2VkVXNkbgUFcHJpY2UJAJsKCQULb3V0QW10R3Jvc3MFBHVuaXQFCXVzZG4yU1VSRgUPbmV1dHJpbm9Bc3NldElkBQtvdXRBbXRHcm9zcwULYWxsb3dlZFVzZG4FGW1heEFsbG93ZWRVc2RuQmVmb3JlTWluQnIFFmFsbG93ZWRVc2RuQmVmb3JlTWluQnIFFWFsbG93ZWRVc2RuQWZ0ZXJNaW5CcgEMY2FsY1dpdGhkcmF3BAhzd2FwVHlwZQhpbkFtb3VudAVwcmljZQ9uZXV0cmlub01ldHJpY3MECm91dEZlZVBhcnQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBDW91dEZlZVBhcnRLRVkBBQhzd2FwVHlwZQUOREVGQVVMVFNXQVBGRUUDAwkAZgIAAAUKb3V0RmVlUGFydAYJAGcCBQpvdXRGZWVQYXJ0BQVQQVVMSQkAAgEJAKwCAgkArAICCQCsAgICHmludmFsaWQgb3V0RmVlUGFydCBjb25maWcgZm9yIAUIc3dhcFR5cGUCEiBzd2FwOiBvdXRGZWVQYXJ0PQkApAMBBQpvdXRGZWVQYXJ0BAticlByb3RlY3RlZAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEOYnJQcm90ZWN0ZWRLRVkABQtCUlBST1RFQ1RFRAQCQlIJAQVhc0ludAEJAJEDAgUPbmV1dHJpbm9NZXRyaWNzBQxuTWV0cmljSWR4QlIEDnJlc2VydmVzSW5Vc2RuCQEFYXNJbnQBCQCRAwIFD25ldXRyaW5vTWV0cmljcwUXbk1ldHJpY0lkeFJlc2VydmVJblVzZG4ECnVzZG5TdXBwbHkJAQVhc0ludAEJAJEDAgUPbmV1dHJpbm9NZXRyaWNzBRRuTWV0cmljSWR4VXNkblN1cHBseQQMb3V0RGF0YVR1cGxlAwkAAAIFCHN3YXBUeXBlAgV3YXZlcwkBD2NhbGNXaXRoZHJhd1cyVQIFCGluQW1vdW50BQVwcmljZQMJAAACBQhzd2FwVHlwZQIIbmV1dHJpbm8JAQ9jYWxjV2l0aGRyYXdVMlcFBQhpbkFtb3VudAUFcHJpY2UFAkJSBQ5yZXNlcnZlc0luVXNkbgUKdXNkblN1cHBseQkAAgEJAKwCAgIWVW5zdXBwb3J0ZWQgc3dhcCB0eXBlIAUIc3dhcFR5cGUEC291dEFtdEdyb3NzCAUMb3V0RGF0YVR1cGxlAl8xBApvdXRBc3NldElkCAUMb3V0RGF0YVR1cGxlAl8yBA9pbkFtdFRvU3VyZlBhcnQIBQxvdXREYXRhVHVwbGUCXzMECWluQXNzZXRJZAgFDG91dERhdGFUdXBsZQJfNAQKdW5sZWFzZUFtdAgFDG91dERhdGFUdXBsZQJfNQQMcGF5b3V0c0FycmF5CQEJYXBwbHlGZWVzAwULb3V0QW10R3Jvc3MFD2luQW10VG9TdXJmUGFydAUKb3V0RmVlUGFydAQJb3V0TmV0QW10CQCRAwIFDHBheW91dHNBcnJheQUMSWR4TmV0QW1vdW50BAlvdXRGZWVBbXQJAJEDAgUMcGF5b3V0c0FycmF5BQxJZHhGZWVBbW91bnQECm91dFN1cmZBbXQDCQBnAgAABQ9pbkFtdFRvU3VyZlBhcnQAAAQKc3VyZlJlc3VsdAkBCWFzQW55TGlzdAEJAPwHBAUMbWF0aENvbnRyYWN0AhRzdXJmRnVuY3Rpb25SRUFET05MWQkAzAgCBQ9pbkFtdFRvU3VyZlBhcnQJAMwIAgUJaW5Bc3NldElkBQNuaWwFA25pbAkBBWFzSW50AQkAkQMCBQpzdXJmUmVzdWx0BQxiRnVuY0lkeFN1cmYJAJkKBwUJb3V0TmV0QW10BQpvdXRBc3NldElkBQpvdXRTdXJmQW10BQ9pbkFtdFRvU3VyZlBhcnQFCnVubGVhc2VBbXQFCW91dEZlZUFtdAULb3V0QW10R3Jvc3MBDmNvbW1vbldpdGhkcmF3BQdhY2NvdW50BWluZGV4CHN3YXBUeElkDHdpdGhkcmF3VHhJZA9uZXV0cmlub01ldHJpY3MEC3VzZXJBZGRyZXNzCQERQGV4dHJOYXRpdmUoMTA2MikBBQdhY2NvdW50BAlkYXRhQXJyYXkJARJzd2FwRGF0YUZhaWxPclJFQUQCBQdhY2NvdW50BQhzd2FwVHhJZAQQc2VsZlVubG9ja0hlaWdodAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCWRhdGFBcnJheQUUc0lkeFNlbGZVbmxvY2tIZWlnaHQECHN3YXBUeXBlCQCRAwIFCWRhdGFBcnJheQUMc0lkeFN3YXBUeXBlBAhpbkFtb3VudAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCWRhdGFBcnJheQUMc0lkeEluQW1vdW50BApzd2FwU3RhdHVzCQCRAwIFCWRhdGFBcnJheQUKc0lkeFN0YXR1cwQLc3RhcnRIZWlnaHQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQlkYXRhQXJyYXkFD3NJZHhTdGFydEhlaWdodAQKb3V0RmVlUGFydAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQENb3V0RmVlUGFydEtFWQEFCHN3YXBUeXBlBQ5ERUZBVUxUU1dBUEZFRQQLdG90YWxMb2NrZWQJAQ90b3RhbExvY2tlZFJFQUQBBQhzd2FwVHlwZQQRdG90YWxMb2NrZWRCeVVzZXIJARV0b3RhbExvY2tlZEJ5VXNlclJFQUQCBQhzd2FwVHlwZQUHYWNjb3VudAQMdW5sb2NrSGVpZ2h0BRBzZWxmVW5sb2NrSGVpZ2h0BAtpbmRleEhlaWdodAkBFWdldEhlaWdodFByaWNlQnlJbmRleAEFBWluZGV4BA9wcmV2SW5kZXhIZWlnaHQJARVnZXRIZWlnaHRQcmljZUJ5SW5kZXgBCQBlAgUFaW5kZXgAAQQMcHJpY2VCeUluZGV4CQEPZ2V0UHJpY2VIaXN0b3J5AQULaW5kZXhIZWlnaHQDBQlpc0Jsb2NrZWQJARVlbWVyZ2VuY3lTaHV0ZG93bkZBSUwAAwkBAiE9AgUKc3dhcFN0YXR1cwIHUEVORElORwkAAgECH3N3YXAgaGFzIGJlZW4gYWxyZWFkeSBwcm9jZXNzZWQDCQBmAgUMdW5sb2NrSGVpZ2h0BQZoZWlnaHQJAAIBCQCsAgIJAKwCAgIRcGxlYXNlIHdhaXQgZm9yOiAJAKQDAQUMdW5sb2NrSGVpZ2h0Ah8gYmxvY2sgaGVpZ2h0IHRvIHdpdGhkcmF3IGZ1bmRzAwMDCQBmAgUFaW5kZXgFCnByaWNlSW5kZXgGCQBmAgUMdW5sb2NrSGVpZ2h0BQtpbmRleEhlaWdodAYDCQECIT0CBQ9wcmV2SW5kZXhIZWlnaHQAAAkAZwIFD3ByZXZJbmRleEhlaWdodAUMdW5sb2NrSGVpZ2h0BwkBDnByaWNlSW5kZXhGQUlMBQUFaW5kZXgFCnByaWNlSW5kZXgFC2luZGV4SGVpZ2h0BQx1bmxvY2tIZWlnaHQFD3ByZXZJbmRleEhlaWdodAQNd2l0aGRyYXdUdXBsZQkBDGNhbGNXaXRoZHJhdwQFCHN3YXBUeXBlBQhpbkFtb3VudAUMcHJpY2VCeUluZGV4BQ9uZXV0cmlub01ldHJpY3MEDG91dE5ldEFtb3VudAgFDXdpdGhkcmF3VHVwbGUCXzEECm91dEFzc2V0SWQIBQ13aXRoZHJhd1R1cGxlAl8yBApvdXRTdXJmQW10CAUNd2l0aGRyYXdUdXBsZQJfMwQPaW5BbXRUb1N1cmZQYXJ0CAUNd2l0aGRyYXdUdXBsZQJfNAQKdW5sZWFzZUFtdAgFDXdpdGhkcmF3VHVwbGUCXzUEDG91dEZlZUFtb3VudAgFDXdpdGhkcmF3VHVwbGUCXzYEC291dEFtdEdyb3NzCAUNd2l0aGRyYXdUdXBsZQJfNwMJAGcCAAAFC291dEFtdEdyb3NzCQACAQITYmFsYW5jZSBlcXVhbHMgemVybwQFc3RhdGUJAMwIAgkBDEludGVnZXJFbnRyeQIJARR0b3RhbExvY2tlZEJ5VXNlcktFWQIFCHN3YXBUeXBlBQdhY2NvdW50CQBlAgURdG90YWxMb2NrZWRCeVVzZXIFCGluQW1vdW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG90YWxMb2NrZWRLRVkBBQhzd2FwVHlwZQkAZQIFC3RvdGFsTG9ja2VkBQhpbkFtb3VudAkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDBQt1c2VyQWRkcmVzcwUMb3V0TmV0QW1vdW50BQpvdXRBc3NldElkCQDMCAIJAQtTdHJpbmdFbnRyeQIJAQdzd2FwS0VZAgUHYWNjb3VudAUIc3dhcFR4SWQJAQ5maW5pc2hTd2FwREFUQQcFCWRhdGFBcnJheQUMcHJpY2VCeUluZGV4BQxvdXROZXRBbW91bnQFDG91dEZlZUFtb3VudAUMdW5sb2NrSGVpZ2h0BQVpbmRleAUMd2l0aGRyYXdUeElkBQNuaWwEDXN1cmZDb25kaXRpb24DCQBmAgUKb3V0U3VyZkFtdAAABAtpc3N1ZVJlc3VsdAkA/AcEBQ9hdWN0aW9uQ29udHJhY3QCCWlzc3VlU3VyZgkAzAgCBQpvdXRTdXJmQW10CQDMCAIFB2FjY291bnQFA25pbAUDbmlsAwkAAAIFC2lzc3VlUmVzdWx0BQtpc3N1ZVJlc3VsdAAACQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAAADCQAAAgUNc3VyZkNvbmRpdGlvbgUNc3VyZkNvbmRpdGlvbgkAlQoDBQVzdGF0ZQkBD0F0dGFjaGVkUGF5bWVudAIFCm91dEFzc2V0SWQFDG91dEZlZUFtb3VudAUKdW5sZWFzZUFtdAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgwBaQELY29uc3RydWN0b3IMEm5ldXRyaW5vQXNzZXRJZFBybQ5ib25kQXNzZXRJZFBybRJhdWN0aW9uQ29udHJhY3RQcm0WbGlxdWlkYXRpb25Db250cmFjdFBybQ5ycGRDb250cmFjdFBybRtub2RlT3JhY2xlUHJvdmlkZXJQdWJLZXlQcm0bYmFsYW5jZVdhdmVzTG9ja0ludGVydmFsUHJtHmJhbGFuY2VOZXV0cmlub0xvY2tJbnRlcnZhbFBybRVtaW5XYXZlc1N3YXBBbW91bnRQcm0YbWluTmV1dHJpbm9Td2FwQW1vdW50UHJtFW5ldXRyaW5vT3V0RmVlUGFydFBybRJ3YXZlc091dEZlZVBhcnRQcm0EC2NoZWNrQ2FsbGVyCQEIdGhpc09ubHkBBQFpAwkAAAIFC2NoZWNrQ2FsbGVyBQtjaGVja0NhbGxlcgMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAAkAAgECE25vIHBheW1lbnRzIGFsbG93ZWQJAMwIAgkBC1N0cmluZ0VudHJ5AgUSTmV1dHJpbm9Bc3NldElkS2V5BRJuZXV0cmlub0Fzc2V0SWRQcm0JAMwIAgkBC1N0cmluZ0VudHJ5AgUOQm9uZEFzc2V0SWRLZXkFDmJvbmRBc3NldElkUHJtCQDMCAIJAQtTdHJpbmdFbnRyeQIFEkF1Y3Rpb25Db250cmFjdEtleQUSYXVjdGlvbkNvbnRyYWN0UHJtCQDMCAIJAQtTdHJpbmdFbnRyeQIFFkxpcXVpZGF0aW9uQ29udHJhY3RLZXkFFmxpcXVpZGF0aW9uQ29udHJhY3RQcm0JAMwIAgkBC1N0cmluZ0VudHJ5AgUOUlBEQ29udHJhY3RLZXkFDnJwZENvbnRyYWN0UHJtCQDMCAIJAQtTdHJpbmdFbnRyeQIFG05vZGVPcmFjbGVQcm92aWRlclB1YktleUtleQUbbm9kZU9yYWNsZVByb3ZpZGVyUHViS2V5UHJtCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRtCYWxhbmNlV2F2ZXNMb2NrSW50ZXJ2YWxLZXkFG2JhbGFuY2VXYXZlc0xvY2tJbnRlcnZhbFBybQkAzAgCCQEMSW50ZWdlckVudHJ5AgUeQmFsYW5jZU5ldXRyaW5vTG9ja0ludGVydmFsS2V5BR5iYWxhbmNlTmV1dHJpbm9Mb2NrSW50ZXJ2YWxQcm0JAMwIAgkBDEludGVnZXJFbnRyeQIFFU1pbldhdmVzU3dhcEFtb3VudEtleQUVbWluV2F2ZXNTd2FwQW1vdW50UHJtCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRhNaW5OZXV0cmlub1N3YXBBbW91bnRLZXkFGG1pbk5ldXRyaW5vU3dhcEFtb3VudFBybQkAzAgCCQEMSW50ZWdlckVudHJ5AgUVTmV1dHJpbm9PdXRGZWVQYXJ0S2V5BRVuZXV0cmlub091dEZlZVBhcnRQcm0JAMwIAgkBDEludGVnZXJFbnRyeQIFEldhdmVzT3V0RmVlUGFydEtleQUSd2F2ZXNPdXRGZWVQYXJ0UHJtBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQENY29uc3RydWN0b3JWMgMMbWF0aENvbnRyYWN0E25zYnRTdGFraW5nQ29udHJhY3QUc3dhcHNUaW1lZnJhbWVCbG9ja3MEC2NoZWNrQ2FsbGVyCQEIdGhpc09ubHkBBQFpAwkAAAIFC2NoZWNrQ2FsbGVyBQtjaGVja0NhbGxlcgMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAAkAAgECE25vIHBheW1lbnRzIGFsbG93ZWQJAMwIAgkBC1N0cmluZ0VudHJ5AgUPTWF0aENvbnRyYWN0S2V5BQxtYXRoQ29udHJhY3QJAMwIAgkBC1N0cmluZ0VudHJ5AgUWTnNidFN0YWtpbmdDb250cmFjdEtleQUTbnNidFN0YWtpbmdDb250cmFjdAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBEXN3YXBzVGltZWZyYW1lS0VZAAUUc3dhcHNUaW1lZnJhbWVCbG9ja3MFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARNzd2FwV2F2ZXNUb05ldXRyaW5vAAMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAQkAAgECLHN3YXBXYXZlc1RvTmV1dHJpbm8gcmVxdWlyZSBvbmx5IG9uZSBwYXltZW50BANwbXQJAQV2YWx1ZQEJAJEDAggFAWkIcGF5bWVudHMAAAMJAQlpc0RlZmluZWQBCAUDcG10B2Fzc2V0SWQJAAIBAilPbmx5IFdhdmVzIHRva2VuIGlzIGFsbG93ZWQgZm9yIHN3YXBwaW5nLgQLdXNlckFkZHJlc3MJAKUIAQgFAWkGY2FsbGVyBAZ0eElkNTgJANgEAQgFAWkNdHJhbnNhY3Rpb25JZAQQc3dhcFBhcmFtc1NUUlVDVAkBEmFzU3dhcFBhcmFtc1NUUlVDVAEJAPwHBAUEdGhpcwIbc3dhcFBhcmFtc0J5VXNlclNZU1JFQURPTkxZCQDMCAIFC3VzZXJBZGRyZXNzCQDMCAIAAAUDbmlsBQNuaWwEEGNvbW1vblN3YXBSZXN1bHQJAQpjb21tb25Td2FwBQIFd2F2ZXMIBQNwbXQGYW1vdW50BQt1c2VyQWRkcmVzcwUGdHhJZDU4BRBzd2FwUGFyYW1zU1RSVUNUBRBjb21tb25Td2FwUmVzdWx0AWkBE3N3YXBOZXV0cmlub1RvV2F2ZXMAAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwABCQACAQIsc3dhcE5ldXRyaW5vVG9XYXZlcyByZXF1aXJlIG9ubHkgb25lIHBheW1lbnQEA3BtdAkBBXZhbHVlAQkAkQMCCAUBaQhwYXltZW50cwAAAwkBAiE9AggFA3BtdAdhc3NldElkBQ9uZXV0cmlub0Fzc2V0SWQJAAIBAjpPbmx5IGFwcHJvcHJpYXRlIE5ldXRyaW5vIHRva2VucyBhcmUgYWxsb3dlZCBmb3Igc3dhcHBpbmcuBAt1c2VyQWRkcmVzcwkApQgBCAUBaQZjYWxsZXIEBnR4SWQ1OAkA2AQBCAUBaQ10cmFuc2FjdGlvbklkBBBzd2FwUGFyYW1zU1RSVUNUCQESYXNTd2FwUGFyYW1zU1RSVUNUAQkA/AcEBQR0aGlzAhtzd2FwUGFyYW1zQnlVc2VyU1lTUkVBRE9OTFkJAMwIAgULdXNlckFkZHJlc3MJAMwIAgAABQNuaWwFA25pbAQQY29tbW9uU3dhcFJlc3VsdAkBCmNvbW1vblN3YXAFAghuZXV0cmlubwgFA3BtdAZhbW91bnQFC3VzZXJBZGRyZXNzBQZ0eElkNTgFEHN3YXBQYXJhbXNTVFJVQ1QFEGNvbW1vblN3YXBSZXN1bHQBaQEId2l0aGRyYXcDB2FjY291bnQFaW5kZXgIc3dhcFR4SWQEBHR4SWQJANgEAQgFAWkNdHJhbnNhY3Rpb25JZAMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAAkAAgECE25vIHBheW1lbnRzIGFsbG93ZWQED25ldXRyaW5vTWV0cmljcwkBCWFzQW55TGlzdAEJAPwHBAUMbWF0aENvbnRyYWN0AhpjYWxjTmV1dGlub01ldHJpY3NSRUFET05MWQUDbmlsBQNuaWwEAkJSCQEFYXNJbnQBCQCRAwIFD25ldXRyaW5vTWV0cmljcwUMbk1ldHJpY0lkeEJSBAtjb21tb25UdXBsZQkBDmNvbW1vbldpdGhkcmF3BQUHYWNjb3VudAUFaW5kZXgFCHN3YXBUeElkBQR0eElkBQ9uZXV0cmlub01ldHJpY3MEBXN0YXRlCAULY29tbW9uVHVwbGUCXzEEA2ZlZQgFC2NvbW1vblR1cGxlAl8yBAp1bmxlYXNlQW10CAULY29tbW9uVHVwbGUCXzMEEXVubGVhc2VJbnZPckVtcHR5CQD8BwQFBHRoaXMCF2ludGVybmFsVW5sZWFzZUFuZExlYXNlCQDMCAIFCnVubGVhc2VBbXQFA25pbAUDbmlsAwkAAAIFEXVubGVhc2VJbnZPckVtcHR5BRF1bmxlYXNlSW52T3JFbXB0eQQJZ25zYnREYXRhCQEJYXNBbnlMaXN0AQkA/AcEBRdnbnNidENvbnRyb2xsZXJDb250cmFjdAIUZ25zYnRJbmZvU1lTUkVBRE9OTFkJAMwIAgIACQDMCAIAAAkAzAgCAAAFA25pbAUDbmlsBA1nbnNidEFtdFRvdGFsCQEFYXNJbnQBCQCRAwIFCWduc2J0RGF0YQABBBVnbnNidEFtdEZyb21TdXJmVG90YWwJAQVhc0ludAEJAJEDAgkBCWFzQW55TGlzdAEJAJEDAgUJZ25zYnREYXRhAAMAAwQLc3VyZkZlZUFtdDEDCQECIT0CBQ1nbnNidEFtdFRvdGFsAAAJAGsDCAUDZmVlBmFtb3VudAUVZ25zYnRBbXRGcm9tU3VyZlRvdGFsBQ1nbnNidEFtdFRvdGFsAAAEC3N1cmZGZWVBbXQyAwkBAiE9AgUNZ25zYnRBbXRUb3RhbAAACQBrAwgFA2ZlZQZhbW91bnQJAGUCBQVQQVVMSQUCQlIFBVBBVUxJAAAECnN1cmZGZWVBbXQJAJYDAQkAzAgCBQtzdXJmRmVlQW10MQkAzAgCBQtzdXJmRmVlQW10MgUDbmlsBApuc2J0RmVlQW10CQBlAggFA2ZlZQZhbW91bnQFCnN1cmZGZWVBbXQEC3N1cmZEZXBvc2l0AwkAZgIFCnN1cmZGZWVBbXQAAAQHc3VyZkludgkA/AcEBRNzdXJmU3Rha2luZ0NvbnRyYWN0AgdkZXBvc2l0BQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIIBQNmZWUHYXNzZXRJZAUKc3VyZkZlZUFtdAUDbmlsAwkAAAIFB3N1cmZJbnYFB3N1cmZJbnYFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFC3N1cmZEZXBvc2l0BQtzdXJmRGVwb3NpdAQLbnNidERlcG9zaXQDCQBmAgUKbnNidEZlZUFtdAAABAduc2J0SW52CQD8BwQFE25zYnRTdGFraW5nQ29udHJhY3QCB2RlcG9zaXQFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AggFA2ZlZQdhc3NldElkBQpuc2J0RmVlQW10BQNuaWwDCQAAAgUHbnNidEludgUHbnNidEludgUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgULbnNidERlcG9zaXQFC25zYnREZXBvc2l0BQVzdGF0ZQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARdpbnRlcm5hbFVubGVhc2VBbmRMZWFzZQENdW5sZWFzZUFtb3VudAMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECLGludGVybmFsVW5sZWFzZUFuZExlYXNlIGlzIG5vdCBwdWJsaWMgbWV0aG9kCQEWcHJlcGFyZVVubGVhc2VBbmRMZWFzZQEFDXVubGVhc2VBbW91bnQBaQESdHJhbnNmZXJVc2RuVG9Vc2VyAgZhbW91bnQEYWRkcgMJAQIhPQIIBQFpBmNhbGxlcgUPYXVjdGlvbkNvbnRyYWN0CQACAQIjT25seSBhdWN0aW9uIGNvbnRyYWN0IGlzIGF1dGhvcml6ZWQJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwkBEUBleHRyTmF0aXZlKDEwNjIpAQUEYWRkcgUGYW1vdW50BQ9uZXV0cmlub0Fzc2V0SWQFA25pbAFpAQthY2NlcHRXYXZlcwADCQECIT0CCAUBaQZjYWxsZXIFD2F1Y3Rpb25Db250cmFjdAkAAgECMkN1cnJlbnRseSBvbmx5IGF1Y3Rpb24gY29udHJhY3QgaXMgYWxsb3dlZCB0byBjYWxsCQCUCgIJARZwcmVwYXJlVW5sZWFzZUFuZExlYXNlAQAAAgdzdWNjZXNzAWkBD2FwcHJvdmVMZWFzaW5ncwMGbkxpc3RTCGdyb3VwTnVtBGxBbXQEBW5JZHhzCQDMCAIAAAkAzAgCAAEJAMwIAgACCQDMCAIAAwkAzAgCAAQJAMwIAgAFCQDMCAIABgkAzAgCAAcFA25pbAQHbW5nUHViUwkBC3ZhbHVlT3JFbHNlAgkAoggBAhwlcyVzX19jZmdfX2xlYXNpbmdNYW5hZ2VyUHViAiw3QVVNWDU0dWtZTVl2UG1tYTd5b0ZmNU5qWmhzNEJ1NW56M0V6OUVWOHN1cgQGbW5nUHViCQDZBAEFB21uZ1B1YlMEDm5vZGVSZWdBZGRyU3RyCQELdmFsdWVPckVsc2UCCQCiCAECHyVzJXNfX2NmZ19fbm9kZXNSZWdpc3RyeUFkZHJlc3MCIzNQOXZLcVFLalVkbXBYQWZpV2F1OGtyUkVZQVkxWHI2OXBFBAtub2RlUmVnQWRkcgkBEUBleHRyTmF0aXZlKDEwNjIpAQUObm9kZVJlZ0FkZHJTdHIEEWxHcm91cE5vZGVMaXN0S0VZCQEYZ2V0TGVhc2VHcm91cE5vZGVMaXN0S2V5AQUIZ3JvdXBOdW0ECmxHck5vZGVPcHQJAJ0IAgUEdGhpcwURbEdyb3VwTm9kZUxpc3RLRVkDCQEJaXNEZWZpbmVkAQUKbEdyTm9kZU9wdAkAAgEJAKwCAgkArAICAgZncm91cCAJAKQDAQUIZ3JvdXBOdW0CFCBhbHJlYWR5IGluaXRpYWxpemVkBAVuTGlzdAkAtQkCBQZuTGlzdFMFA1NFUAQIZXhwQ291bnQJAJADAQUFbklkeHMDCQECIT0CCAUBaQ9jYWxsZXJQdWJsaWNLZXkFBm1uZ1B1YgkAAgECHmFwcHJvdmVMZWFzaW5ncyBub3QgYXV0aG9yaXplZAQNJHQwMzM4ODczMzk0OQkBDHJlYWROb2RlSW5mbwEAAAQGbkFkZHIwCAUNJHQwMzM4ODczMzk0OQJfMQQIbEFtdEtFWTAIBQ0kdDAzMzg4NzMzOTQ5Al8yBAVsQW10MAgFDSR0MDMzODg3MzM5NDkCXzMEB2xJZEtFWTAIBQ0kdDAzMzg4NzMzOTQ5Al80BARsSWQwCAUNJHQwMzM4ODczMzk0OQJfNQQFbmV3TDAJAMQIAgUGbkFkZHIwCQBlAgUFbEFtdDAJAGgCBQRsQW10BQhleHBDb3VudAQKdmFsaWRhdGlvbgkA/AcEBQtub2RlUmVnQWRkcgIadmFsaWRhdGVBbmRBcHByb3ZlTGVhc2luZ3MJAMwIAgUGbkxpc3RTBQNuaWwFA25pbAMJAAACBQp2YWxpZGF0aW9uBQp2YWxpZGF0aW9uCgEjZm9yRWFjaE5vZGVWYWxpZGF0ZUFuZEdlbmVyYXRlTGVhc2UCAWEBaQQEbm9kZQkAkQMCBQVuTGlzdAUBaQQCbGEJAMQIAgkBEUBleHRyTmF0aXZlKDEwNjIpAQUEbm9kZQUEbEFtdAkAzggCBQFhCQDMCAIFAmxhCQDMCAIJAQtCaW5hcnlFbnRyeQIJARZnZXRMZWFzZUlkQnlBZGRyZXNzS2V5AQUEbm9kZQkBBWxjYWxjAQUCbGEJAMwIAgkBDEludGVnZXJFbnRyeQIJARpnZXRMZWFzZUFtb3VudEJ5QWRkcmVzc0tleQEFBG5vZGUFBGxBbXQFA25pbAkAzggCCQDMCAIJAQtTdHJpbmdFbnRyeQIFEWxHcm91cE5vZGVMaXN0S0VZBQZuTGlzdFMJAMwIAgkBC0JpbmFyeUVudHJ5AgUHbElkS0VZMAkBBWxjYWxjAQUFbmV3TDAJAMwIAgkBDEludGVnZXJFbnRyeQIFCGxBbXRLRVkwCAUFbmV3TDAGYW1vdW50CQDMCAIJAQtMZWFzZUNhbmNlbAEFBGxJZDAJAMwIAgUFbmV3TDAFA25pbAoAAiRsBQVuSWR4cwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEjZm9yRWFjaE5vZGVWYWxpZGF0ZUFuZEdlbmVyYXRlTGVhc2UCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECE0xpc3Qgc2l6ZSBleGNlZWRzIDgJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAICQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBEXJlYmFsYW5jZUxlYXNpbmdzAgZhbW91bnQIZ3JvdXBOdW0EBW5JZHhzCQDMCAIAAAkAzAgCAAEJAMwIAgACCQDMCAIAAwkAzAgCAAQJAMwIAgAFCQDMCAIABgkAzAgCAAcFA25pbAQHbW5nUHViUwkBC3ZhbHVlT3JFbHNlAgkAoggBAhwlcyVzX19jZmdfX2xlYXNpbmdNYW5hZ2VyUHViAiw3QVVNWDU0dWtZTVl2UG1tYTd5b0ZmNU5qWmhzNEJ1NW56M0V6OUVWOHN1cgQGbW5nUHViCQDZBAEFB21uZ1B1YlMEEWxHcm91cE5vZGVMaXN0S0VZCQEYZ2V0TGVhc2VHcm91cE5vZGVMaXN0S2V5AQUIZ3JvdXBOdW0EBm5MaXN0UwkBD2dldFN0cmluZ09yRmFpbAIFBHRoaXMFEWxHcm91cE5vZGVMaXN0S0VZBAVuTGlzdAkAtQkCBQZuTGlzdFMFA1NFUAMJAQIhPQIIBQFpD2NhbGxlclB1YmxpY0tleQUGbW5nUHViCQACAQIgcmViYWxhbmNlTGVhc2luZ3Mgbm90IGF1dGhvcml6ZWQECnVubGVhc2VBbXQJAGQCCQBpAgUGYW1vdW50CQCQAwEFBW5MaXN0AAEEDSR0MDM1MTg5MzUyNTEJAQxyZWFkTm9kZUluZm8BAAAEBm5BZGRyMAgFDSR0MDM1MTg5MzUyNTECXzEECGxBbXRLRVkwCAUNJHQwMzUxODkzNTI1MQJfMgQFbEFtdDAIBQ0kdDAzNTE4OTM1MjUxAl8zBAdsSWRLRVkwCAUNJHQwMzUxODkzNTI1MQJfNAQEbElkMAgFDSR0MDM1MTg5MzUyNTECXzUEBW5ld0wwCQDECAIFBm5BZGRyMAkAZAIFBWxBbXQwCQBoAgUKdW5sZWFzZUFtdAkAkAMBBQVuTGlzdAoBFGZvckVhY2hOb2RlRG9VbmxlYXNlAgFhAWkEBG5vZGUJAJEDAgUFbkxpc3QFAWkEBmxJZEtFWQkBFmdldExlYXNlSWRCeUFkZHJlc3NLZXkBBQRub2RlBANsSWQJARFAZXh0ck5hdGl2ZSgxMDUyKQIFBHRoaXMFBmxJZEtFWQQHbEFtdEtFWQkBGmdldExlYXNlQW1vdW50QnlBZGRyZXNzS2V5AQUEbm9kZQQEbEFtdAkBEUBleHRyTmF0aXZlKDEwNTApAgUEdGhpcwUHbEFtdEtFWQQDdWxhCQELTGVhc2VDYW5jZWwBCQEFdmFsdWUBBQNsSWQEAmxhCQDECAIJARFAZXh0ck5hdGl2ZSgxMDYyKQEFBG5vZGUJAGUCBQRsQW10BQp1bmxlYXNlQW10CQDOCAIFAWEJAMwIAgkBC0xlYXNlQ2FuY2VsAQkBBXZhbHVlAQUDbElkCQDMCAIFAmxhCQDMCAIJAQtCaW5hcnlFbnRyeQIFBmxJZEtFWQkBBWxjYWxjAQUCbGEJAMwIAgkBDEludGVnZXJFbnRyeQIFB2xBbXRLRVkIBQJsYQZhbW91bnQFA25pbAkAzggCCgACJGwFBW5JZHhzCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARRmb3JFYWNoTm9kZURvVW5sZWFzZQIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQITTGlzdCBzaXplIGV4Y2VlZHMgOAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgJAMwIAgkBC0JpbmFyeUVudHJ5AgUHbElkS0VZMAkBBWxjYWxjAQUFbmV3TDAJAMwIAgkBDEludGVnZXJFbnRyeQIFCGxBbXRLRVkwCAUFbmV3TDAGYW1vdW50CQDMCAIJAQtMZWFzZUNhbmNlbAEFBGxJZDAJAMwIAgUFbmV3TDAFA25pbAFpARtzd2FwUGFyYW1zQnlVc2VyU1lTUkVBRE9OTFkCDnVzZXJBZGRyZXNzU3RyCWduc2J0RGlmZgQJZ25zYnREYXRhCQEJYXNBbnlMaXN0AQkA/AcEBRdnbnNidENvbnRyb2xsZXJDb250cmFjdAIUZ25zYnRJbmZvU1lTUkVBRE9OTFkJAMwIAgUOdXNlckFkZHJlc3NTdHIJAMwIAgAACQDMCAIAAAUDbmlsBQNuaWwECGduc2J0QW10CQBkAgkBBWFzSW50AQkAkQMCBQlnbnNidERhdGEAAAUJZ25zYnREaWZmBA1nbnNidEFtdFRvdGFsCQBkAgkBBWFzSW50AQkAkQMCBQlnbnNidERhdGEAAQUJZ25zYnREaWZmBA1zd2FwTGltaXREYXRhCQEJYXNBbnlMaXN0AQkA/AcEBQxtYXRoQ29udHJhY3QCFWNhbGNTd2FwTGltaXRSRUFET05MWQkAzAgCBQhnbnNidEFtdAUDbmlsBQNuaWwEF3dhdmVzU3dhcExpbWl0SW5Vc2RuTWF4CQEFYXNJbnQBCQCRAwIFDXN3YXBMaW1pdERhdGEAAAQRd2F2ZXNTd2FwTGltaXRNYXgJAQVhc0ludAEJAJEDAgUNc3dhcExpbWl0RGF0YQABBBB1c2RuU3dhcExpbWl0TWF4CQEFYXNJbnQBCQCRAwIFDXN3YXBMaW1pdERhdGEAAgQObGFzdFN3YXBIZWlnaHQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBFWtleVVzZXJMYXN0U3dhcEhlaWdodAEFDnVzZXJBZGRyZXNzU3RyAAAEF3N3YXBMaW1pdFRpbWVsaWZlQmxvY2tzCQESc3dhcHNUaW1lZnJhbWVSRUFEAAQZcGFzc2VkQmxvY2tzQWZ0ZXJMYXN0U3dhcAkAZQIFBmhlaWdodAUObGFzdFN3YXBIZWlnaHQEEWlzU3dhcFRpbWVsaWZlTmV3CQBnAgUZcGFzc2VkQmxvY2tzQWZ0ZXJMYXN0U3dhcAUXc3dhcExpbWl0VGltZWxpZmVCbG9ja3MEFHN3YXBMaW1pdFNwZW50SW5Vc2RuAwURaXNTd2FwVGltZWxpZmVOZXcAAAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEYa2V5U3dhcFVzZXJTcGVudEluUGVyaW9kAQUOdXNlckFkZHJlc3NTdHIAAAQOYmxja3MyTG10UmVzZXQDBRFpc1N3YXBUaW1lbGlmZU5ldwAACQBlAgUXc3dhcExpbWl0VGltZWxpZmVCbG9ja3MFGXBhc3NlZEJsb2Nrc0FmdGVyTGFzdFN3YXAJAJQKAgUDbmlsCQCZCgcFF3dhdmVzU3dhcExpbWl0SW5Vc2RuTWF4BRRzd2FwTGltaXRTcGVudEluVXNkbgUOYmxja3MyTG10UmVzZXQFCGduc2J0QW10BQ1nbnNidEFtdFRvdGFsBRF3YXZlc1N3YXBMaW1pdE1heAUQdXNkblN3YXBMaW1pdE1heAFpAR1jYWxjV2l0aGRyYXdSZXN1bHRTWVNSRUFET05MWQMIc3dhcFR5cGUIaW5BbW91bnQFcHJpY2UED25ldXRyaW5vTWV0cmljcwkBCWFzQW55TGlzdAEJAPwHBAUMbWF0aENvbnRyYWN0AhpjYWxjTmV1dGlub01ldHJpY3NSRUFET05MWQUDbmlsBQNuaWwJAJQKAgUDbmlsCQEMY2FsY1dpdGhkcmF3BAUIc3dhcFR5cGUFCGluQW1vdW50BQVwcmljZQUPbmV1dHJpbm9NZXRyaWNzAQJ0eAEGdmVyaWZ5AAQCaWQJANgEAQgFAnR4AmlkBBNwdWJLZXlBZG1pbnNMaXN0U3RyCQC5CQIJAMwIAgIsR0pkTFNhTGl2NUs3eHVlamFjOG1jUmNIb3lvM2RQckVTcnZrdEczYTZNQVIJAMwIAgIsRVl3Wm1VUmQ1S0thUVJCanNWYTZnOERQaXNGb1M2U292Ukp0RmlMNWdNSFUJAMwIAgIsRHRtQWZ1RGRDckhLOHNwZEFlQVl6cTZNc1plZ2VEOWduc3JwdVRSa0NiVkEJAMwIAgIsNVdSWEZTandjVGJOZktjSnM4WnFYbVNTV1lzU1ZKVXRNdk1xWmo1aEg0TmMFA25pbAUDU0VQBBBwdWJLZXlBZG1pbnNMaXN0CQC1CQIJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUPY29udHJvbENvbnRyYWN0Agwlc19fbXVsdGlzaWcFE3B1YktleUFkbWluc0xpc3RTdHIFA1NFUAQFY291bnQJAGQCCQBkAgkAZAIDCQD0AwMIBQJ0eAlib2R5Qnl0ZXMJAJEDAggFAnR4BnByb29mcwAACQDZBAEJAJEDAgUQcHViS2V5QWRtaW5zTGlzdAAAAAEAAAMJAPQDAwgFAnR4CWJvZHlCeXRlcwkAkQMCCAUCdHgGcHJvb2ZzAAEJANkEAQkAkQMCBRBwdWJLZXlBZG1pbnNMaXN0AAEAAQAAAwkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAgkA2QQBCQCRAwIFEHB1YktleUFkbWluc0xpc3QAAgABAAADCQD0AwMIBQJ0eAlib2R5Qnl0ZXMJAJEDAggFAnR4BnByb29mcwADCQDZBAEJAJEDAgUQcHViS2V5QWRtaW5zTGlzdAADAAIAAAQHJG1hdGNoMAUCdHgDCQABAgUHJG1hdGNoMAIVU3BvbnNvckZlZVRyYW5zYWN0aW9uBAlzcG9uc29yVHgFByRtYXRjaDADCQEbY2hlY2tJc1ZhbGlkTWluU3BvbnNvcmVkRmVlAQUJc3BvbnNvclR4CQBnAgUFY291bnQAAwcJAGcCBQVjb3VudAADS2i+Uw==", "chainId": 87, "height": 3264198, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: Du2VrsbvTsWEzdbHYUBMiLPntXjvoFtbZzbegENZmTrb Next: 8iBAMmSsCEHGWdNu6iMuDhcGdnQqQvVo1GzipEbn85eZ Diff:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let revisionNum = "cbd0bdc8bbba91db64066b16a84913a4c965e23e"
4+let revisionNum = "049fe7b78896aec03c7fa106ba92e97b6ce41445"
55
66 func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], ""))
77
5151 }
5252
5353
54+func asBytes (val) = match val {
55+ case valByte: ByteVector =>
56+ valByte
57+ case _ =>
58+ throw("fail to cast into ByteVector")
59+}
60+
61+
5462 func asPayment (v) = match v {
5563 case p: AttachedPayment =>
5664 p
6068
6169
6270 func asSwapParamsSTRUCT (v) = match v {
63- case struct: (Int, Int, Int, Int, Int) =>
71+ case struct: (Int, Int, Int, Int, Int, Int, Int) =>
6472 struct
6573 case _ =>
66- throw("fail to cast into Int")
74+ throw("fail to cast into Tuple5 ints")
6775 }
6876
6977
7684 let PRICELET = 1000000
7785
7886 let DEFAULTSWAPFEE = 20000
87+
88+let BRPROTECTED = 100000
7989
8090 let IdxNetAmount = 0
8191
224234 func swapsTimeframeKEY () = "swaps_timeframe"
225235
226236
237+func brProtectedKEY () = "min_BR_protection_level"
238+
239+
227240 func minSwapAmountREAD (swapType) = valueOrElse(getInteger(this, minSwapAmountKEY(swapType)), 0)
228241
229242
359372 }
360373
361374
362-func applyFees (amountGross,feePart) = {
363- let feeAmount = fraction(amountGross, feePart, PAULI)
364-[(amountGross - feeAmount), feeAmount, amountGross]
375+func applyFees (amountOutGross,inAmtToSURF,feePart) = {
376+ let feeAmount = fraction(amountOutGross, feePart, PAULI)
377+[(amountOutGross - feeAmount), feeAmount]
365378 }
366379
367380
425438
426439
427440 func commonSwap (swapType,pmtAmount,userAddressStr,txId58,swapParamsByUserSYSREADONLY) = {
428- let $t01726517345 = swapParamsByUserSYSREADONLY
429- let swapLimitMax = $t01726517345._1
430- let swapLimitSpent = $t01726517345._2
431- let blcks2LmtReset = $t01726517345._3
441+ let swapLimitSpent = swapParamsByUserSYSREADONLY._2
442+ let blcks2LmtReset = swapParamsByUserSYSREADONLY._3
443+ let wavesSwapLimitMax = swapParamsByUserSYSREADONLY._6
444+ let usdnSwapLimitMax = swapParamsByUserSYSREADONLY._7
432445 let minSwapAmount = minSwapAmountREAD(swapType)
433446 let totalLocked = totalLockedREAD(swapType)
434447 let totalLockedByUser = totalLockedByUserREAD(swapType, userAddressStr)
442455 let swapUsdnVolume = if ((swapType == "neutrino"))
443456 then pmtAmount
444457 else convertWavesToNeutrino(pmtAmount, priceByIndex)
458+ let swapLimitMax = if ((swapType == "neutrino"))
459+ then usdnSwapLimitMax
460+ else convertWavesToNeutrino(wavesSwapLimitMax, priceByIndex)
445461 if ((minSwapAmount > pmtAmount))
446462 then minSwapAmountFAIL(swapType, minSwapAmount)
447463 else if (if (!(isSwapByNode))
463479 }
464480
465481
466-func commonWithdraw (account,index,swapTxId,withdrawTxId) = {
482+let nMetricIdxPrice = 0
483+
484+let nMetricIdxUsdnLockedBalance = 1
485+
486+let nMetricIdxWavesLockedBalance = 2
487+
488+let nMetricIdxReserve = 3
489+
490+let nMetricIdxReserveInUsdn = 4
491+
492+let nMetricIdxUsdnSupply = 5
493+
494+let nMetricIdxSurplus = 6
495+
496+let nMetricIdxSurplusPercent = 7
497+
498+let nMetricIdxBR = 8
499+
500+let nMetricIdxNsbtSupply = 9
501+
502+let nMetricIdxMaxNsbtSupply = 10
503+
504+let nMetricIdxSurfSupply = 11
505+
506+let bFuncIdxSurf = 0
507+
508+let bFuncIdxWaves = 1
509+
510+let bFuncIdxUsdn = 2
511+
512+let bFuncIdxReserveStart = 3
513+
514+let bFuncIdxSupplyStart = 4
515+
516+let bFuncIdxBRStart = 5
517+
518+let bFuncIdxReserveEnd = 6
519+
520+let bFuncIdxSupplyEnd = 7
521+
522+let bFuncIdxBREnd = 8
523+
524+let bFuncIdxRest = 9
525+
526+let bFuncIdxWavesPrice = 10
527+
528+func calcWithdrawW2U (wavesIn,price) = {
529+ let outAmtGross = convertWavesToNeutrino(wavesIn, price)
530+ $Tuple9(outAmtGross, neutrinoAssetId, 0, unit, 0, wavesIn, 0, 0, 0)
531+ }
532+
533+
534+func calcWithdrawU2W (usdnIn,price,br,reservesInUsdn,usdnSupply) = {
535+ let brProtected = valueOrElse(getInteger(this, brProtectedKEY()), BRPROTECTED)
536+ let maxAllowedUsdnBeforeMinBr = if ((brProtected >= br))
537+ then 0
538+ else fraction((reservesInUsdn - fraction(brProtected, usdnSupply, PAULI)), PAULI, (PAULI - brProtected))
539+ let allowedUsdnBeforeMinBr = if ((usdnIn > maxAllowedUsdnBeforeMinBr))
540+ then maxAllowedUsdnBeforeMinBr
541+ else usdnIn
542+ let allowedUsdnAfterMinBr = if ((usdnIn > maxAllowedUsdnBeforeMinBr))
543+ then fraction((usdnIn - maxAllowedUsdnBeforeMinBr), br, PAULI)
544+ else 0
545+ let allowedUsdn = (allowedUsdnBeforeMinBr + allowedUsdnAfterMinBr)
546+ let usdn2SURF = (usdnIn - allowedUsdn)
547+ let outAmtGross = convertNeutrinoToWaves(allowedUsdn, price)
548+ $Tuple9(outAmtGross, unit, usdn2SURF, neutrinoAssetId, outAmtGross, allowedUsdn, maxAllowedUsdnBeforeMinBr, allowedUsdnBeforeMinBr, allowedUsdnAfterMinBr)
549+ }
550+
551+
552+func calcWithdraw (swapType,inAmount,price,neutrinoMetrics) = {
553+ let outFeePart = valueOrElse(getInteger(this, outFeePartKEY(swapType)), DEFAULTSWAPFEE)
554+ if (if ((0 > outFeePart))
555+ then true
556+ else (outFeePart >= PAULI))
557+ then throw(((("invalid outFeePart config for " + swapType) + " swap: outFeePart=") + toString(outFeePart)))
558+ else {
559+ let brProtected = valueOrElse(getInteger(this, brProtectedKEY()), BRPROTECTED)
560+ let BR = asInt(neutrinoMetrics[nMetricIdxBR])
561+ let reservesInUsdn = asInt(neutrinoMetrics[nMetricIdxReserveInUsdn])
562+ let usdnSupply = asInt(neutrinoMetrics[nMetricIdxUsdnSupply])
563+ let outDataTuple = if ((swapType == "waves"))
564+ then calcWithdrawW2U(inAmount, price)
565+ else if ((swapType == "neutrino"))
566+ then calcWithdrawU2W(inAmount, price, BR, reservesInUsdn, usdnSupply)
567+ else throw(("Unsupported swap type " + swapType))
568+ let outAmtGross = outDataTuple._1
569+ let outAssetId = outDataTuple._2
570+ let inAmtToSurfPart = outDataTuple._3
571+ let inAssetId = outDataTuple._4
572+ let unleaseAmt = outDataTuple._5
573+ let payoutsArray = applyFees(outAmtGross, inAmtToSurfPart, outFeePart)
574+ let outNetAmt = payoutsArray[IdxNetAmount]
575+ let outFeeAmt = payoutsArray[IdxFeeAmount]
576+ let outSurfAmt = if ((0 >= inAmtToSurfPart))
577+ then 0
578+ else {
579+ let surfResult = asAnyList(invoke(mathContract, "surfFunctionREADONLY", [inAmtToSurfPart, inAssetId], nil))
580+ asInt(surfResult[bFuncIdxSurf])
581+ }
582+ $Tuple7(outNetAmt, outAssetId, outSurfAmt, inAmtToSurfPart, unleaseAmt, outFeeAmt, outAmtGross)
583+ }
584+ }
585+
586+
587+func commonWithdraw (account,index,swapTxId,withdrawTxId,neutrinoMetrics) = {
467588 let userAddress = addressFromStringValue(account)
468589 let dataArray = swapDataFailOrREAD(account, swapTxId)
469590 let selfUnlockHeight = parseIntValue(dataArray[sIdxSelfUnlockHeight])
478599 let indexHeight = getHeightPriceByIndex(index)
479600 let prevIndexHeight = getHeightPriceByIndex((index - 1))
480601 let priceByIndex = getPriceHistory(indexHeight)
481- let outAmountGrossTuple = if ((swapType == "waves"))
482- then $Tuple2(convertWavesToNeutrino(inAmount, priceByIndex), neutrinoAssetId)
483- else if ((swapType == "neutrino"))
484- then $Tuple2(convertNeutrinoToWaves(inAmount, priceByIndex), unit)
485- else throw(("Unsupported swap type " + swapType))
486- let payoutsArray = applyFees(outAmountGrossTuple._1, outFeePart)
487- let outNetAmount = payoutsArray[IdxNetAmount]
488- let outFeeAmount = payoutsArray[IdxFeeAmount]
489602 if (isBlocked)
490603 then emergencyShutdownFAIL()
491604 else if ((swapStatus != "PENDING"))
500613 then (prevIndexHeight >= unlockHeight)
501614 else false)
502615 then priceIndexFAIL(index, priceIndex, indexHeight, unlockHeight, prevIndexHeight)
503- else if ((0 >= payoutsArray[IdxGrossAmount]))
504- then throw("balance equals zero")
505- else if (if ((0 > outFeePart))
506- then true
507- else (outFeePart >= PAULI))
508- then throw(((("invalid outFeePart config for " + swapType) + " swap: outFeePart=") + toString(outFeePart)))
616+ else {
617+ let withdrawTuple = calcWithdraw(swapType, inAmount, priceByIndex, neutrinoMetrics)
618+ let outNetAmount = withdrawTuple._1
619+ let outAssetId = withdrawTuple._2
620+ let outSurfAmt = withdrawTuple._3
621+ let inAmtToSurfPart = withdrawTuple._4
622+ let unleaseAmt = withdrawTuple._5
623+ let outFeeAmount = withdrawTuple._6
624+ let outAmtGross = withdrawTuple._7
625+ if ((0 >= outAmtGross))
626+ then throw("balance equals zero")
509627 else {
510- let unleaseAmount = if (if ((swapType == "neutrino"))
511- then (outAmountGrossTuple._1 > 0)
512- else false)
513- then outAmountGrossTuple._1
628+ 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))]
629+ let surfCondition = if ((outSurfAmt > 0))
630+ then {
631+ let issueResult = invoke(auctionContract, "issueSurf", [outSurfAmt, account], nil)
632+ if ((issueResult == issueResult))
633+ then 0
634+ else throw("Strict value is not equal to itself.")
635+ }
514636 else 0
515- 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))]
516- $Tuple3(state, AttachedPayment(outAmountGrossTuple._2, outFeeAmount), unleaseAmount)
637+ if ((surfCondition == surfCondition))
638+ then $Tuple3(state, AttachedPayment(outAssetId, outFeeAmount), unleaseAmt)
639+ else throw("Strict value is not equal to itself.")
517640 }
641+ }
518642 }
519643
520644
584708 if ((size(i.payments) != 0))
585709 then throw("no payments allowed")
586710 else {
587- let commonTuple = commonWithdraw(account, index, swapTxId, txId)
711+ let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
712+ let BR = asInt(neutrinoMetrics[nMetricIdxBR])
713+ let commonTuple = commonWithdraw(account, index, swapTxId, txId, neutrinoMetrics)
588714 let state = commonTuple._1
589715 let fee = commonTuple._2
590716 let unleaseAmt = commonTuple._3
594720 let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", ["", 0, 0], nil))
595721 let gnsbtAmtTotal = asInt(gnsbtData[1])
596722 let gnsbtAmtFromSurfTotal = asInt(asAnyList(gnsbtData[3])[3])
597- let surfFeeAmt = if ((gnsbtAmtTotal != 0))
723+ let surfFeeAmt1 = if ((gnsbtAmtTotal != 0))
598724 then fraction(fee.amount, gnsbtAmtFromSurfTotal, gnsbtAmtTotal)
599725 else 0
726+ let surfFeeAmt2 = if ((gnsbtAmtTotal != 0))
727+ then fraction(fee.amount, (PAULI - BR), PAULI)
728+ else 0
729+ let surfFeeAmt = max([surfFeeAmt1, surfFeeAmt2])
600730 let nsbtFeeAmt = (fee.amount - surfFeeAmt)
601731 let surfDeposit = if ((surfFeeAmt > 0))
602732 then {
666796 if ((i.callerPublicKey != mngPub))
667797 then throw("approveLeasings not authorized")
668798 else {
669- let $t02841028472 = readNodeInfo(0)
670- let nAddr0 = $t02841028472._1
671- let lAmtKEY0 = $t02841028472._2
672- let lAmt0 = $t02841028472._3
673- let lIdKEY0 = $t02841028472._4
674- let lId0 = $t02841028472._5
799+ let $t03388733949 = readNodeInfo(0)
800+ let nAddr0 = $t03388733949._1
801+ let lAmtKEY0 = $t03388733949._2
802+ let lAmt0 = $t03388733949._3
803+ let lIdKEY0 = $t03388733949._4
804+ let lId0 = $t03388733949._5
675805 let newL0 = Lease(nAddr0, (lAmt0 - (lAmt * expCount)))
676806 let validation = invoke(nodeRegAddr, "validateAndApproveLeasings", [nListS], nil)
677807 if ((validation == validation))
716846 then throw("rebalanceLeasings not authorized")
717847 else {
718848 let unleaseAmt = ((amount / size(nList)) + 1)
719- let $t02971229774 = readNodeInfo(0)
720- let nAddr0 = $t02971229774._1
721- let lAmtKEY0 = $t02971229774._2
722- let lAmt0 = $t02971229774._3
723- let lIdKEY0 = $t02971229774._4
724- let lId0 = $t02971229774._5
849+ let $t03518935251 = readNodeInfo(0)
850+ let nAddr0 = $t03518935251._1
851+ let lAmtKEY0 = $t03518935251._2
852+ let lAmt0 = $t03518935251._3
853+ let lIdKEY0 = $t03518935251._4
854+ let lId0 = $t03518935251._5
725855 let newL0 = Lease(nAddr0, (lAmt0 + (unleaseAmt * size(nList))))
726856 func forEachNodeDoUnlease (a,i) = {
727857 let node = nList[i]
758888 let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", [userAddressStr, 0, 0], nil))
759889 let gnsbtAmt = (asInt(gnsbtData[0]) + gnsbtDiff)
760890 let gnsbtAmtTotal = (asInt(gnsbtData[1]) + gnsbtDiff)
761- let swapLimitMax = asInt(invoke(mathContract, "calcSwapLimitREADONLY", [gnsbtAmt], nil))
891+ let swapLimitData = asAnyList(invoke(mathContract, "calcSwapLimitREADONLY", [gnsbtAmt], nil))
892+ let wavesSwapLimitInUsdnMax = asInt(swapLimitData[0])
893+ let wavesSwapLimitMax = asInt(swapLimitData[1])
894+ let usdnSwapLimitMax = asInt(swapLimitData[2])
762895 let lastSwapHeight = valueOrElse(getInteger(this, keyUserLastSwapHeight(userAddressStr)), 0)
763896 let swapLimitTimelifeBlocks = swapsTimeframeREAD()
764897 let passedBlocksAfterLastSwap = (height - lastSwapHeight)
765898 let isSwapTimelifeNew = (passedBlocksAfterLastSwap >= swapLimitTimelifeBlocks)
766- let swapLimitSpent = if (isSwapTimelifeNew)
899+ let swapLimitSpentInUsdn = if (isSwapTimelifeNew)
767900 then 0
768901 else valueOrElse(getInteger(this, keySwapUserSpentInPeriod(userAddressStr)), 0)
769902 let blcks2LmtReset = if (isSwapTimelifeNew)
770903 then 0
771904 else (swapLimitTimelifeBlocks - passedBlocksAfterLastSwap)
772- $Tuple2(nil, $Tuple5(swapLimitMax, swapLimitSpent, blcks2LmtReset, gnsbtAmt, gnsbtAmtTotal))
905+ $Tuple2(nil, $Tuple7(wavesSwapLimitInUsdnMax, swapLimitSpentInUsdn, blcks2LmtReset, gnsbtAmt, gnsbtAmtTotal, wavesSwapLimitMax, usdnSwapLimitMax))
906+ }
907+
908+
909+
910+@Callable(i)
911+func calcWithdrawResultSYSREADONLY (swapType,inAmount,price) = {
912+ let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
913+ $Tuple2(nil, calcWithdraw(swapType, inAmount, price, neutrinoMetrics))
773914 }
774915
775916
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let revisionNum = "cbd0bdc8bbba91db64066b16a84913a4c965e23e"
4+let revisionNum = "049fe7b78896aec03c7fa106ba92e97b6ce41445"
55
66 func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], ""))
77
88
99 func lcalc (l) = calculateLeaseId(l)
1010
1111
1212 func getNumberByKey (key) = valueOrElse(getInteger(this, key), 0)
1313
1414
1515 func getStringByKey (key) = valueOrElse(getString(this, key), "")
1616
1717
1818 func getBoolByKey (key) = valueOrElse(getBoolean(this, key), false)
1919
2020
2121 func getNumberByAddressAndKey (address,key) = valueOrElse(getInteger(address, key), 0)
2222
2323
2424 func getStringByAddressAndKey (address,key) = valueOrElse(getString(addressFromStringValue(address), key), "")
2525
2626
2727 func getBoolByAddressAndKey (address,key) = valueOrElse(getBoolean(address, key), false)
2828
2929
3030 func asAnyList (v) = match v {
3131 case l: List[Any] =>
3232 l
3333 case _ =>
3434 throw("fail to cast into List[Any]")
3535 }
3636
3737
3838 func asString (v) = match v {
3939 case s: String =>
4040 s
4141 case _ =>
4242 throw("fail to cast into String")
4343 }
4444
4545
4646 func asInt (v) = match v {
4747 case i: Int =>
4848 i
4949 case _ =>
5050 throw("fail to cast into Int")
5151 }
5252
5353
54+func asBytes (val) = match val {
55+ case valByte: ByteVector =>
56+ valByte
57+ case _ =>
58+ throw("fail to cast into ByteVector")
59+}
60+
61+
5462 func asPayment (v) = match v {
5563 case p: AttachedPayment =>
5664 p
5765 case _ =>
5866 throw("fail to cast into AttachedPayment")
5967 }
6068
6169
6270 func asSwapParamsSTRUCT (v) = match v {
63- case struct: (Int, Int, Int, Int, Int) =>
71+ case struct: (Int, Int, Int, Int, Int, Int, Int) =>
6472 struct
6573 case _ =>
66- throw("fail to cast into Int")
74+ throw("fail to cast into Tuple5 ints")
6775 }
6876
6977
7078 let SEP = "__"
7179
7280 let WAVELET = 100000000
7381
7482 let PAULI = 1000000
7583
7684 let PRICELET = 1000000
7785
7886 let DEFAULTSWAPFEE = 20000
87+
88+let BRPROTECTED = 100000
7989
8090 let IdxNetAmount = 0
8191
8292 let IdxFeeAmount = 1
8393
8494 let IdxGrossAmount = 2
8595
8696 let IdxControlCfgNeutrinoDapp = 1
8797
8898 let IdxControlCfgAuctionDapp = 2
8999
90100 let IdxControlCfgRpdDapp = 3
91101
92102 let IdxControlCfgMathDapp = 4
93103
94104 let IdxControlCfgLiquidationDapp = 5
95105
96106 let IdxControlCfgRestDapp = 6
97107
98108 let IdxControlCfgNodeRegistryDapp = 7
99109
100110 let IdxControlCfgNsbtStakingDapp = 8
101111
102112 let IdxControlCfgMediatorDapp = 9
103113
104114 let IdxControlCfgSurfStakingDapp = 10
105115
106116 let IdxControlCfgGnsbtControllerDapp = 11
107117
108118 func keyControlAddress () = "%s%s__config__controlAddress"
109119
110120
111121 func keyControlCfg () = "%s__controlConfig"
112122
113123
114124 func readControlCfgOrFail (control) = split(getStringOrFail(control, keyControlCfg()), SEP)
115125
116126
117127 func getContractAddressOrFail (controlCfg,idx) = valueOrErrorMessage(addressFromString(controlCfg[idx]), ("Control cfg doesn't contain address at index " + toString(idx)))
118128
119129
120130 let controlContract = addressFromStringValue(valueOrElse(getString(this, keyControlAddress()), "3P5Bfd58PPfNvBM2Hy8QfbcDqMeNtzg7KfP"))
121131
122132 let controlCfg = readControlCfgOrFail(controlContract)
123133
124134 let mathContract = getContractAddressOrFail(controlCfg, IdxControlCfgMathDapp)
125135
126136 let nsbtStakingContract = getContractAddressOrFail(controlCfg, IdxControlCfgNsbtStakingDapp)
127137
128138 let surfStakingContract = getContractAddressOrFail(controlCfg, IdxControlCfgSurfStakingDapp)
129139
130140 let gnsbtControllerContract = getContractAddressOrFail(controlCfg, IdxControlCfgGnsbtControllerDapp)
131141
132142 let auctionContract = getContractAddressOrFail(controlCfg, IdxControlCfgAuctionDapp)
133143
134144 let NeutrinoAssetIdKey = "neutrino_asset_id"
135145
136146 let BondAssetIdKey = "bond_asset_id"
137147
138148 let AuctionContractKey = "auction_contract"
139149
140150 let NsbtStakingContractKey = "nsbtStakingContract"
141151
142152 let LiquidationContractKey = "liquidation_contract"
143153
144154 let RPDContractKey = "rpd_contract"
145155
146156 let ContolContractKey = "control_contract"
147157
148158 let MathContractKey = "math_contract"
149159
150160 let BalanceWavesLockIntervalKey = "balance_waves_lock_interval"
151161
152162 let BalanceNeutrinoLockIntervalKey = "balance_neutrino_lock_interval"
153163
154164 let MinWavesSwapAmountKey = "min_waves_swap_amount"
155165
156166 let MinNeutrinoSwapAmountKey = "min_neutrino_swap_amount"
157167
158168 let NodeOracleProviderPubKeyKey = "node_oracle_provider"
159169
160170 let NeutrinoOutFeePartKey = "neutrinoOut_swap_feePart"
161171
162172 let WavesOutFeePartKey = "wavesOut_swap_feePart"
163173
164174 func keyNodeRegistry (address) = ("%s__" + address)
165175
166176
167177 let PriceKey = "price"
168178
169179 let PriceIndexKey = "price_index"
170180
171181 let IsBlockedKey = "is_blocked"
172182
173183 func getPriceHistoryKey (block) = ((PriceKey + "_") + toString(block))
174184
175185
176186 func getHeightPriceByIndexKey (index) = ((PriceIndexKey + "_") + toString(index))
177187
178188
179189 func getStakingNodeByIndex (idx) = getStringByKey(makeString(["%s%d%s", "lease", toString(idx), "nodeAddress"], SEP))
180190
181191
182192 func getStakingNodeAddressByIndex (idx) = addressFromStringValue(getStakingNodeByIndex(idx))
183193
184194
185195 func getReservedAmountForSponsorship () = valueOrElse(getInteger(this, makeString(["%s%s", "lease", "sponsorshipWavesReserve"], SEP)), (1000 * WAVELET))
186196
187197
188198 func getBalanceUnlockBlockKey (owner) = ("balance_unlock_block_" + owner)
189199
190200
191201 func getLeaseIdKey (nodeIndex) = makeString(["%s%d%s", "lease", toString(nodeIndex), "id"], SEP)
192202
193203
194204 func getLeaseIdByAddressKey (nodeAddress) = makeString(["%s%s%s", "leaseByAddress", nodeAddress, "id"], SEP)
195205
196206
197207 func getLeaseAmountKey (nodeIndex) = makeString(["%s%d%s", "lease", toString(nodeIndex), "amount"], SEP)
198208
199209
200210 func getLeaseAmountByAddressKey (nodeAddress) = makeString(["%s%s%s", "leaseByAddress", nodeAddress, "amount"], SEP)
201211
202212
203213 func getLeaseGroupNodeListKey (groupNum) = makeString(["%s%d%s", "leaseGroup", toString(groupNum), "nodeList"], SEP)
204214
205215
206216 func minSwapAmountKEY (swapType) = (("min_" + swapType) + "_swap_amount")
207217
208218
209219 func totalLockedKEY (swapType) = ("balance_lock_" + swapType)
210220
211221
212222 func totalLockedByUserKEY (swapType,owner) = makeString(["balance_lock", swapType, owner], "_")
213223
214224
215225 func balanceLockIntervalKEY (swapType) = (("balance_" + swapType) + "_lock_interval")
216226
217227
218228 func nodeBalanceLockIntervalKEY () = "balance_node_lock_interval"
219229
220230
221231 func outFeePartKEY (swapType) = (swapType + "Out_swap_feePart")
222232
223233
224234 func swapsTimeframeKEY () = "swaps_timeframe"
225235
226236
237+func brProtectedKEY () = "min_BR_protection_level"
238+
239+
227240 func minSwapAmountREAD (swapType) = valueOrElse(getInteger(this, minSwapAmountKEY(swapType)), 0)
228241
229242
230243 func swapsTimeframeREAD () = valueOrElse(getInteger(this, swapsTimeframeKEY()), 1440)
231244
232245
233246 func totalLockedREAD (swapType) = valueOrElse(getInteger(this, totalLockedKEY(swapType)), 0)
234247
235248
236249 func totalLockedByUserREAD (swapType,owner) = valueOrElse(getInteger(this, totalLockedByUserKEY(swapType, owner)), 0)
237250
238251
239252 func balanceLockIntervalREAD (swapType) = valueOrElse(getInteger(this, balanceLockIntervalKEY(swapType)), 1440)
240253
241254
242255 func nodeBalanceLockIntervalREAD () = valueOrElse(getInteger(this, nodeBalanceLockIntervalKEY()), 1)
243256
244257
245258 func keySwapUserSpentInPeriod (userAddress) = makeString(["%s%s", "swapUserSpentInPeriod", userAddress], SEP)
246259
247260
248261 func keyUserLastSwapHeight (userAddress) = makeString(["%s%s", "userLastSwapHeight", userAddress], SEP)
249262
250263
251264 func convertNeutrinoToWaves (amount,price) = fraction(fraction(amount, PRICELET, price), WAVELET, PAULI)
252265
253266
254267 func convertWavesToNeutrino (amount,price) = fraction(fraction(amount, price, PRICELET), PAULI, WAVELET)
255268
256269
257270 func convertWavesToBond (amount,price) = convertWavesToNeutrino(amount, price)
258271
259272
260273 func convertJsonArrayToList (jsonArray) = split(jsonArray, ",")
261274
262275
263276 func minSwapAmountFAIL (swapType,minSwapAmount) = throw(((("The specified amount in " + swapType) + " swap is less than the required minimum of ") + toString(minSwapAmount)))
264277
265278
266279 func emergencyShutdownFAIL () = throw("contract is blocked by EMERGENCY SHUTDOWN actions untill reactivation by emergency oracles")
267280
268281
269282 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)))
270283
271284
272285 let neutrinoAssetId = fromBase58String(getStringByKey(NeutrinoAssetIdKey))
273286
274287 let priceIndex = getNumberByAddressAndKey(controlContract, PriceIndexKey)
275288
276289 let isBlocked = getBoolByAddressAndKey(controlContract, IsBlockedKey)
277290
278291 let nodeOracleProviderPubKey = fromBase58String(getStringByKey(NodeOracleProviderPubKeyKey))
279292
280293 let bondAssetId = fromBase58String("6nSpVyNH7yM69eg446wrQR94ipbbcmZMU1ENPwanC97g")
281294
282295 let deprecatedBondAssetId = fromBase58String("975akZBfnMj513U7MZaHKzQrmsEx5aE3wdWKTrHBhbjF")
283296
284297 let neutrinoContract = this
285298
286299 let currentPrice = getNumberByAddressAndKey(controlContract, PriceKey)
287300
288301 func checkIsValidMinSponsoredFee (tx) = {
289302 let MINTRANSFERFEE = 100000
290303 let SponsoredFeeUpperBound = 1000
291304 let realNeutrinoFee = convertWavesToNeutrino(MINTRANSFERFEE, currentPrice)
292305 let minNeutrinoFee = (realNeutrinoFee * 2)
293306 let maxNeutrinoFee = fraction(realNeutrinoFee, SponsoredFeeUpperBound, 100)
294307 let inputFee = value(tx.minSponsoredAssetFee)
295308 if (if ((inputFee >= minNeutrinoFee))
296309 then (maxNeutrinoFee >= inputFee)
297310 else false)
298311 then (tx.assetId == neutrinoAssetId)
299312 else false
300313 }
301314
302315
303316 func getPriceHistory (block) = getNumberByAddressAndKey(controlContract, getPriceHistoryKey(block))
304317
305318
306319 func getHeightPriceByIndex (index) = getNumberByAddressAndKey(controlContract, getHeightPriceByIndexKey(index))
307320
308321
309322 func keyLockParamUserAmount (userAddress) = makeString(["%s%s%s", "paramByUser", userAddress, "amount"], SEP)
310323
311324
312325 let sIdxSwapType = 1
313326
314327 let sIdxStatus = 2
315328
316329 let sIdxInAmount = 3
317330
318331 let sIdxPrice = 4
319332
320333 let sIdxOutNetAmount = 5
321334
322335 let sIdxOutFeeAmount = 6
323336
324337 let sIdxStartHeight = 7
325338
326339 let sIdxStartTimestamp = 8
327340
328341 let sIdxEndHeight = 9
329342
330343 let sIdxEndTimestamp = 10
331344
332345 let sIdxSelfUnlockHeight = 11
333346
334347 let sIdxRandUnlockHeight = 12
335348
336349 let sIdxIndex = 13
337350
338351 let sIdxWithdrawTxId = 14
339352
340353 let sIdxMinRand = 15
341354
342355 let sIdxMaxRand = 16
343356
344357 func swapKEY (userAddress,txId) = makeString(["%s%s", userAddress, txId], SEP)
345358
346359
347360 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)
348361
349362
350363 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")
351364
352365
353366 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])
354367
355368
356369 func swapDataFailOrREAD (userAddress,swapTxId) = {
357370 let swapKey = swapKEY(userAddress, swapTxId)
358371 split(valueOrErrorMessage(getString(this, swapKey), ("no swap data for " + swapKey)), SEP)
359372 }
360373
361374
362-func applyFees (amountGross,feePart) = {
363- let feeAmount = fraction(amountGross, feePart, PAULI)
364-[(amountGross - feeAmount), feeAmount, amountGross]
375+func applyFees (amountOutGross,inAmtToSURF,feePart) = {
376+ let feeAmount = fraction(amountOutGross, feePart, PAULI)
377+[(amountOutGross - feeAmount), feeAmount]
365378 }
366379
367380
368381 func abs (x) = if ((0 > x))
369382 then -(x)
370383 else x
371384
372385
373386 func selectNode (unleaseAmount) = {
374387 let amountToLease = ((wavesBalance(neutrinoContract).available - unleaseAmount) - getReservedAmountForSponsorship())
375388 let oldLeased0 = getNumberByKey(getLeaseAmountKey(0))
376389 let oldLeased1 = getNumberByKey(getLeaseAmountKey(1))
377390 let newLeased0 = (amountToLease + oldLeased0)
378391 let newLeased1 = (amountToLease + oldLeased1)
379392 if (if ((newLeased0 > 0))
380393 then true
381394 else (newLeased1 > 0))
382395 then {
383396 let delta0 = abs((newLeased0 - oldLeased1))
384397 let delta1 = abs((newLeased1 - oldLeased0))
385398 if ((delta1 >= delta0))
386399 then $Tuple2(0, newLeased0)
387400 else $Tuple2(1, newLeased1)
388401 }
389402 else $Tuple2(-1, 0)
390403 }
391404
392405
393406 func thisOnly (i) = if ((i.caller != this))
394407 then throw("Permission denied: this contract only allowed")
395408 else true
396409
397410
398411 func prepareUnleaseAndLease (unleaseAmount) = {
399412 let nodeTuple = selectNode(unleaseAmount)
400413 let nodeIndex = nodeTuple._1
401414 let newLeaseAmount = nodeTuple._2
402415 if ((newLeaseAmount > 0))
403416 then {
404417 let leaseIdKey = getLeaseIdKey(nodeIndex)
405418 let oldLease = getBinary(this, leaseIdKey)
406419 let unleaseOrEmpty = if (isDefined(oldLease))
407420 then [LeaseCancel(value(oldLease))]
408421 else nil
409422 let leaseAmountKey = getLeaseAmountKey(nodeIndex)
410423 let lease = Lease(getStakingNodeAddressByIndex(nodeIndex), newLeaseAmount)
411424 (unleaseOrEmpty ++ [lease, BinaryEntry(leaseIdKey, lcalc(lease)), IntegerEntry(getLeaseAmountKey(nodeIndex), newLeaseAmount)])
412425 }
413426 else nil
414427 }
415428
416429
417430 func readNodeInfo (nodeIdx) = {
418431 let nodeAddress = getStakingNodeAddressByIndex(nodeIdx)
419432 let leasedAmtKEY = getLeaseAmountKey(nodeIdx)
420433 let leasedAmt = getNumberByKey(leasedAmtKEY)
421434 let leaseIdKEY = getLeaseIdKey(nodeIdx)
422435 let leaseId = value(getBinary(this, leaseIdKEY))
423436 $Tuple5(nodeAddress, leasedAmtKEY, leasedAmt, leaseIdKEY, leaseId)
424437 }
425438
426439
427440 func commonSwap (swapType,pmtAmount,userAddressStr,txId58,swapParamsByUserSYSREADONLY) = {
428- let $t01726517345 = swapParamsByUserSYSREADONLY
429- let swapLimitMax = $t01726517345._1
430- let swapLimitSpent = $t01726517345._2
431- let blcks2LmtReset = $t01726517345._3
441+ let swapLimitSpent = swapParamsByUserSYSREADONLY._2
442+ let blcks2LmtReset = swapParamsByUserSYSREADONLY._3
443+ let wavesSwapLimitMax = swapParamsByUserSYSREADONLY._6
444+ let usdnSwapLimitMax = swapParamsByUserSYSREADONLY._7
432445 let minSwapAmount = minSwapAmountREAD(swapType)
433446 let totalLocked = totalLockedREAD(swapType)
434447 let totalLockedByUser = totalLockedByUserREAD(swapType, userAddressStr)
435448 let nodeAddress = getStakingNodeByIndex(0)
436449 let priceByIndex = getPriceHistory(getHeightPriceByIndex(priceIndex))
437450 let isSwapByNode = (nodeAddress == userAddressStr)
438451 let balanceLockMaxInterval = if (isSwapByNode)
439452 then nodeBalanceLockIntervalREAD()
440453 else balanceLockIntervalREAD(swapType)
441454 let selfUnlockHeight = (height + balanceLockMaxInterval)
442455 let swapUsdnVolume = if ((swapType == "neutrino"))
443456 then pmtAmount
444457 else convertWavesToNeutrino(pmtAmount, priceByIndex)
458+ let swapLimitMax = if ((swapType == "neutrino"))
459+ then usdnSwapLimitMax
460+ else convertWavesToNeutrino(wavesSwapLimitMax, priceByIndex)
445461 if ((minSwapAmount > pmtAmount))
446462 then minSwapAmountFAIL(swapType, minSwapAmount)
447463 else if (if (!(isSwapByNode))
448464 then (swapLimitSpent > 0)
449465 else false)
450466 then throw(("You have exceeded swap limit! Next allowed swap height is " + toString((height + blcks2LmtReset))))
451467 else if (if (!(isSwapByNode))
452468 then (swapUsdnVolume > swapLimitMax)
453469 else false)
454470 then throw(((("You have exceeded your swap limit! Requested: " + toString(swapUsdnVolume)) + ", available: ") + toString(swapLimitMax)))
455471 else if (isBlocked)
456472 then emergencyShutdownFAIL()
457473 else {
458474 let leasePart = if ((swapType == "waves"))
459475 then prepareUnleaseAndLease(0)
460476 else nil
461477 $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)
462478 }
463479 }
464480
465481
466-func commonWithdraw (account,index,swapTxId,withdrawTxId) = {
482+let nMetricIdxPrice = 0
483+
484+let nMetricIdxUsdnLockedBalance = 1
485+
486+let nMetricIdxWavesLockedBalance = 2
487+
488+let nMetricIdxReserve = 3
489+
490+let nMetricIdxReserveInUsdn = 4
491+
492+let nMetricIdxUsdnSupply = 5
493+
494+let nMetricIdxSurplus = 6
495+
496+let nMetricIdxSurplusPercent = 7
497+
498+let nMetricIdxBR = 8
499+
500+let nMetricIdxNsbtSupply = 9
501+
502+let nMetricIdxMaxNsbtSupply = 10
503+
504+let nMetricIdxSurfSupply = 11
505+
506+let bFuncIdxSurf = 0
507+
508+let bFuncIdxWaves = 1
509+
510+let bFuncIdxUsdn = 2
511+
512+let bFuncIdxReserveStart = 3
513+
514+let bFuncIdxSupplyStart = 4
515+
516+let bFuncIdxBRStart = 5
517+
518+let bFuncIdxReserveEnd = 6
519+
520+let bFuncIdxSupplyEnd = 7
521+
522+let bFuncIdxBREnd = 8
523+
524+let bFuncIdxRest = 9
525+
526+let bFuncIdxWavesPrice = 10
527+
528+func calcWithdrawW2U (wavesIn,price) = {
529+ let outAmtGross = convertWavesToNeutrino(wavesIn, price)
530+ $Tuple9(outAmtGross, neutrinoAssetId, 0, unit, 0, wavesIn, 0, 0, 0)
531+ }
532+
533+
534+func calcWithdrawU2W (usdnIn,price,br,reservesInUsdn,usdnSupply) = {
535+ let brProtected = valueOrElse(getInteger(this, brProtectedKEY()), BRPROTECTED)
536+ let maxAllowedUsdnBeforeMinBr = if ((brProtected >= br))
537+ then 0
538+ else fraction((reservesInUsdn - fraction(brProtected, usdnSupply, PAULI)), PAULI, (PAULI - brProtected))
539+ let allowedUsdnBeforeMinBr = if ((usdnIn > maxAllowedUsdnBeforeMinBr))
540+ then maxAllowedUsdnBeforeMinBr
541+ else usdnIn
542+ let allowedUsdnAfterMinBr = if ((usdnIn > maxAllowedUsdnBeforeMinBr))
543+ then fraction((usdnIn - maxAllowedUsdnBeforeMinBr), br, PAULI)
544+ else 0
545+ let allowedUsdn = (allowedUsdnBeforeMinBr + allowedUsdnAfterMinBr)
546+ let usdn2SURF = (usdnIn - allowedUsdn)
547+ let outAmtGross = convertNeutrinoToWaves(allowedUsdn, price)
548+ $Tuple9(outAmtGross, unit, usdn2SURF, neutrinoAssetId, outAmtGross, allowedUsdn, maxAllowedUsdnBeforeMinBr, allowedUsdnBeforeMinBr, allowedUsdnAfterMinBr)
549+ }
550+
551+
552+func calcWithdraw (swapType,inAmount,price,neutrinoMetrics) = {
553+ let outFeePart = valueOrElse(getInteger(this, outFeePartKEY(swapType)), DEFAULTSWAPFEE)
554+ if (if ((0 > outFeePart))
555+ then true
556+ else (outFeePart >= PAULI))
557+ then throw(((("invalid outFeePart config for " + swapType) + " swap: outFeePart=") + toString(outFeePart)))
558+ else {
559+ let brProtected = valueOrElse(getInteger(this, brProtectedKEY()), BRPROTECTED)
560+ let BR = asInt(neutrinoMetrics[nMetricIdxBR])
561+ let reservesInUsdn = asInt(neutrinoMetrics[nMetricIdxReserveInUsdn])
562+ let usdnSupply = asInt(neutrinoMetrics[nMetricIdxUsdnSupply])
563+ let outDataTuple = if ((swapType == "waves"))
564+ then calcWithdrawW2U(inAmount, price)
565+ else if ((swapType == "neutrino"))
566+ then calcWithdrawU2W(inAmount, price, BR, reservesInUsdn, usdnSupply)
567+ else throw(("Unsupported swap type " + swapType))
568+ let outAmtGross = outDataTuple._1
569+ let outAssetId = outDataTuple._2
570+ let inAmtToSurfPart = outDataTuple._3
571+ let inAssetId = outDataTuple._4
572+ let unleaseAmt = outDataTuple._5
573+ let payoutsArray = applyFees(outAmtGross, inAmtToSurfPart, outFeePart)
574+ let outNetAmt = payoutsArray[IdxNetAmount]
575+ let outFeeAmt = payoutsArray[IdxFeeAmount]
576+ let outSurfAmt = if ((0 >= inAmtToSurfPart))
577+ then 0
578+ else {
579+ let surfResult = asAnyList(invoke(mathContract, "surfFunctionREADONLY", [inAmtToSurfPart, inAssetId], nil))
580+ asInt(surfResult[bFuncIdxSurf])
581+ }
582+ $Tuple7(outNetAmt, outAssetId, outSurfAmt, inAmtToSurfPart, unleaseAmt, outFeeAmt, outAmtGross)
583+ }
584+ }
585+
586+
587+func commonWithdraw (account,index,swapTxId,withdrawTxId,neutrinoMetrics) = {
467588 let userAddress = addressFromStringValue(account)
468589 let dataArray = swapDataFailOrREAD(account, swapTxId)
469590 let selfUnlockHeight = parseIntValue(dataArray[sIdxSelfUnlockHeight])
470591 let swapType = dataArray[sIdxSwapType]
471592 let inAmount = parseIntValue(dataArray[sIdxInAmount])
472593 let swapStatus = dataArray[sIdxStatus]
473594 let startHeight = parseIntValue(dataArray[sIdxStartHeight])
474595 let outFeePart = valueOrElse(getInteger(this, outFeePartKEY(swapType)), DEFAULTSWAPFEE)
475596 let totalLocked = totalLockedREAD(swapType)
476597 let totalLockedByUser = totalLockedByUserREAD(swapType, account)
477598 let unlockHeight = selfUnlockHeight
478599 let indexHeight = getHeightPriceByIndex(index)
479600 let prevIndexHeight = getHeightPriceByIndex((index - 1))
480601 let priceByIndex = getPriceHistory(indexHeight)
481- let outAmountGrossTuple = if ((swapType == "waves"))
482- then $Tuple2(convertWavesToNeutrino(inAmount, priceByIndex), neutrinoAssetId)
483- else if ((swapType == "neutrino"))
484- then $Tuple2(convertNeutrinoToWaves(inAmount, priceByIndex), unit)
485- else throw(("Unsupported swap type " + swapType))
486- let payoutsArray = applyFees(outAmountGrossTuple._1, outFeePart)
487- let outNetAmount = payoutsArray[IdxNetAmount]
488- let outFeeAmount = payoutsArray[IdxFeeAmount]
489602 if (isBlocked)
490603 then emergencyShutdownFAIL()
491604 else if ((swapStatus != "PENDING"))
492605 then throw("swap has been already processed")
493606 else if ((unlockHeight > height))
494607 then throw((("please wait for: " + toString(unlockHeight)) + " block height to withdraw funds"))
495608 else if (if (if ((index > priceIndex))
496609 then true
497610 else (unlockHeight > indexHeight))
498611 then true
499612 else if ((prevIndexHeight != 0))
500613 then (prevIndexHeight >= unlockHeight)
501614 else false)
502615 then priceIndexFAIL(index, priceIndex, indexHeight, unlockHeight, prevIndexHeight)
503- else if ((0 >= payoutsArray[IdxGrossAmount]))
504- then throw("balance equals zero")
505- else if (if ((0 > outFeePart))
506- then true
507- else (outFeePart >= PAULI))
508- then throw(((("invalid outFeePart config for " + swapType) + " swap: outFeePart=") + toString(outFeePart)))
616+ else {
617+ let withdrawTuple = calcWithdraw(swapType, inAmount, priceByIndex, neutrinoMetrics)
618+ let outNetAmount = withdrawTuple._1
619+ let outAssetId = withdrawTuple._2
620+ let outSurfAmt = withdrawTuple._3
621+ let inAmtToSurfPart = withdrawTuple._4
622+ let unleaseAmt = withdrawTuple._5
623+ let outFeeAmount = withdrawTuple._6
624+ let outAmtGross = withdrawTuple._7
625+ if ((0 >= outAmtGross))
626+ then throw("balance equals zero")
509627 else {
510- let unleaseAmount = if (if ((swapType == "neutrino"))
511- then (outAmountGrossTuple._1 > 0)
512- else false)
513- then outAmountGrossTuple._1
628+ 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))]
629+ let surfCondition = if ((outSurfAmt > 0))
630+ then {
631+ let issueResult = invoke(auctionContract, "issueSurf", [outSurfAmt, account], nil)
632+ if ((issueResult == issueResult))
633+ then 0
634+ else throw("Strict value is not equal to itself.")
635+ }
514636 else 0
515- 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))]
516- $Tuple3(state, AttachedPayment(outAmountGrossTuple._2, outFeeAmount), unleaseAmount)
637+ if ((surfCondition == surfCondition))
638+ then $Tuple3(state, AttachedPayment(outAssetId, outFeeAmount), unleaseAmt)
639+ else throw("Strict value is not equal to itself.")
517640 }
641+ }
518642 }
519643
520644
521645 @Callable(i)
522646 func constructor (neutrinoAssetIdPrm,bondAssetIdPrm,auctionContractPrm,liquidationContractPrm,rpdContractPrm,nodeOracleProviderPubKeyPrm,balanceWavesLockIntervalPrm,balanceNeutrinoLockIntervalPrm,minWavesSwapAmountPrm,minNeutrinoSwapAmountPrm,neutrinoOutFeePartPrm,wavesOutFeePartPrm) = {
523647 let checkCaller = thisOnly(i)
524648 if ((checkCaller == checkCaller))
525649 then if ((size(i.payments) != 0))
526650 then throw("no payments allowed")
527651 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)]
528652 else throw("Strict value is not equal to itself.")
529653 }
530654
531655
532656
533657 @Callable(i)
534658 func constructorV2 (mathContract,nsbtStakingContract,swapsTimeframeBlocks) = {
535659 let checkCaller = thisOnly(i)
536660 if ((checkCaller == checkCaller))
537661 then if ((size(i.payments) != 0))
538662 then throw("no payments allowed")
539663 else [StringEntry(MathContractKey, mathContract), StringEntry(NsbtStakingContractKey, nsbtStakingContract), IntegerEntry(swapsTimeframeKEY(), swapsTimeframeBlocks)]
540664 else throw("Strict value is not equal to itself.")
541665 }
542666
543667
544668
545669 @Callable(i)
546670 func swapWavesToNeutrino () = if ((size(i.payments) != 1))
547671 then throw("swapWavesToNeutrino require only one payment")
548672 else {
549673 let pmt = value(i.payments[0])
550674 if (isDefined(pmt.assetId))
551675 then throw("Only Waves token is allowed for swapping.")
552676 else {
553677 let userAddress = toString(i.caller)
554678 let txId58 = toBase58String(i.transactionId)
555679 let swapParamsSTRUCT = asSwapParamsSTRUCT(invoke(this, "swapParamsByUserSYSREADONLY", [userAddress, 0], nil))
556680 let commonSwapResult = commonSwap("waves", pmt.amount, userAddress, txId58, swapParamsSTRUCT)
557681 commonSwapResult
558682 }
559683 }
560684
561685
562686
563687 @Callable(i)
564688 func swapNeutrinoToWaves () = if ((size(i.payments) != 1))
565689 then throw("swapNeutrinoToWaves require only one payment")
566690 else {
567691 let pmt = value(i.payments[0])
568692 if ((pmt.assetId != neutrinoAssetId))
569693 then throw("Only appropriate Neutrino tokens are allowed for swapping.")
570694 else {
571695 let userAddress = toString(i.caller)
572696 let txId58 = toBase58String(i.transactionId)
573697 let swapParamsSTRUCT = asSwapParamsSTRUCT(invoke(this, "swapParamsByUserSYSREADONLY", [userAddress, 0], nil))
574698 let commonSwapResult = commonSwap("neutrino", pmt.amount, userAddress, txId58, swapParamsSTRUCT)
575699 commonSwapResult
576700 }
577701 }
578702
579703
580704
581705 @Callable(i)
582706 func withdraw (account,index,swapTxId) = {
583707 let txId = toBase58String(i.transactionId)
584708 if ((size(i.payments) != 0))
585709 then throw("no payments allowed")
586710 else {
587- let commonTuple = commonWithdraw(account, index, swapTxId, txId)
711+ let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
712+ let BR = asInt(neutrinoMetrics[nMetricIdxBR])
713+ let commonTuple = commonWithdraw(account, index, swapTxId, txId, neutrinoMetrics)
588714 let state = commonTuple._1
589715 let fee = commonTuple._2
590716 let unleaseAmt = commonTuple._3
591717 let unleaseInvOrEmpty = invoke(this, "internalUnleaseAndLease", [unleaseAmt], nil)
592718 if ((unleaseInvOrEmpty == unleaseInvOrEmpty))
593719 then {
594720 let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", ["", 0, 0], nil))
595721 let gnsbtAmtTotal = asInt(gnsbtData[1])
596722 let gnsbtAmtFromSurfTotal = asInt(asAnyList(gnsbtData[3])[3])
597- let surfFeeAmt = if ((gnsbtAmtTotal != 0))
723+ let surfFeeAmt1 = if ((gnsbtAmtTotal != 0))
598724 then fraction(fee.amount, gnsbtAmtFromSurfTotal, gnsbtAmtTotal)
599725 else 0
726+ let surfFeeAmt2 = if ((gnsbtAmtTotal != 0))
727+ then fraction(fee.amount, (PAULI - BR), PAULI)
728+ else 0
729+ let surfFeeAmt = max([surfFeeAmt1, surfFeeAmt2])
600730 let nsbtFeeAmt = (fee.amount - surfFeeAmt)
601731 let surfDeposit = if ((surfFeeAmt > 0))
602732 then {
603733 let surfInv = invoke(surfStakingContract, "deposit", nil, [AttachedPayment(fee.assetId, surfFeeAmt)])
604734 if ((surfInv == surfInv))
605735 then nil
606736 else throw("Strict value is not equal to itself.")
607737 }
608738 else nil
609739 if ((surfDeposit == surfDeposit))
610740 then {
611741 let nsbtDeposit = if ((nsbtFeeAmt > 0))
612742 then {
613743 let nsbtInv = invoke(nsbtStakingContract, "deposit", nil, [AttachedPayment(fee.assetId, nsbtFeeAmt)])
614744 if ((nsbtInv == nsbtInv))
615745 then nil
616746 else throw("Strict value is not equal to itself.")
617747 }
618748 else nil
619749 if ((nsbtDeposit == nsbtDeposit))
620750 then state
621751 else throw("Strict value is not equal to itself.")
622752 }
623753 else throw("Strict value is not equal to itself.")
624754 }
625755 else throw("Strict value is not equal to itself.")
626756 }
627757 }
628758
629759
630760
631761 @Callable(i)
632762 func internalUnleaseAndLease (unleaseAmount) = if ((i.caller != this))
633763 then throw("internalUnleaseAndLease is not public method")
634764 else prepareUnleaseAndLease(unleaseAmount)
635765
636766
637767
638768 @Callable(i)
639769 func transferUsdnToUser (amount,addr) = if ((i.caller != auctionContract))
640770 then throw("Only auction contract is authorized")
641771 else [ScriptTransfer(addressFromStringValue(addr), amount, neutrinoAssetId)]
642772
643773
644774
645775 @Callable(i)
646776 func acceptWaves () = if ((i.caller != auctionContract))
647777 then throw("Currently only auction contract is allowed to call")
648778 else $Tuple2(prepareUnleaseAndLease(0), "success")
649779
650780
651781
652782 @Callable(i)
653783 func approveLeasings (nListS,groupNum,lAmt) = {
654784 let nIdxs = [0, 1, 2, 3, 4, 5, 6, 7]
655785 let mngPubS = valueOrElse(getString("%s%s__cfg__leasingManagerPub"), "7AUMX54ukYMYvPmma7yoFf5NjZhs4Bu5nz3Ez9EV8sur")
656786 let mngPub = fromBase58String(mngPubS)
657787 let nodeRegAddrStr = valueOrElse(getString("%s%s__cfg__nodesRegistryAddress"), "3P9vKqQKjUdmpXAfiWau8krREYAY1Xr69pE")
658788 let nodeRegAddr = addressFromStringValue(nodeRegAddrStr)
659789 let lGroupNodeListKEY = getLeaseGroupNodeListKey(groupNum)
660790 let lGrNodeOpt = getString(this, lGroupNodeListKEY)
661791 if (isDefined(lGrNodeOpt))
662792 then throw((("group " + toString(groupNum)) + " already initialized"))
663793 else {
664794 let nList = split(nListS, SEP)
665795 let expCount = size(nIdxs)
666796 if ((i.callerPublicKey != mngPub))
667797 then throw("approveLeasings not authorized")
668798 else {
669- let $t02841028472 = readNodeInfo(0)
670- let nAddr0 = $t02841028472._1
671- let lAmtKEY0 = $t02841028472._2
672- let lAmt0 = $t02841028472._3
673- let lIdKEY0 = $t02841028472._4
674- let lId0 = $t02841028472._5
799+ let $t03388733949 = readNodeInfo(0)
800+ let nAddr0 = $t03388733949._1
801+ let lAmtKEY0 = $t03388733949._2
802+ let lAmt0 = $t03388733949._3
803+ let lIdKEY0 = $t03388733949._4
804+ let lId0 = $t03388733949._5
675805 let newL0 = Lease(nAddr0, (lAmt0 - (lAmt * expCount)))
676806 let validation = invoke(nodeRegAddr, "validateAndApproveLeasings", [nListS], nil)
677807 if ((validation == validation))
678808 then {
679809 func forEachNodeValidateAndGenerateLease (a,i) = {
680810 let node = nList[i]
681811 let la = Lease(addressFromStringValue(node), lAmt)
682812 (a ++ [la, BinaryEntry(getLeaseIdByAddressKey(node), lcalc(la)), IntegerEntry(getLeaseAmountByAddressKey(node), lAmt)])
683813 }
684814
685815 ([StringEntry(lGroupNodeListKEY, nListS), BinaryEntry(lIdKEY0, lcalc(newL0)), IntegerEntry(lAmtKEY0, newL0.amount), LeaseCancel(lId0), newL0] ++ {
686816 let $l = nIdxs
687817 let $s = size($l)
688818 let $acc0 = nil
689819 func $f0_1 ($a,$i) = if (($i >= $s))
690820 then $a
691821 else forEachNodeValidateAndGenerateLease($a, $l[$i])
692822
693823 func $f0_2 ($a,$i) = if (($i >= $s))
694824 then $a
695825 else throw("List size exceeds 8")
696826
697827 $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)
698828 })
699829 }
700830 else throw("Strict value is not equal to itself.")
701831 }
702832 }
703833 }
704834
705835
706836
707837 @Callable(i)
708838 func rebalanceLeasings (amount,groupNum) = {
709839 let nIdxs = [0, 1, 2, 3, 4, 5, 6, 7]
710840 let mngPubS = valueOrElse(getString("%s%s__cfg__leasingManagerPub"), "7AUMX54ukYMYvPmma7yoFf5NjZhs4Bu5nz3Ez9EV8sur")
711841 let mngPub = fromBase58String(mngPubS)
712842 let lGroupNodeListKEY = getLeaseGroupNodeListKey(groupNum)
713843 let nListS = getStringOrFail(this, lGroupNodeListKEY)
714844 let nList = split(nListS, SEP)
715845 if ((i.callerPublicKey != mngPub))
716846 then throw("rebalanceLeasings not authorized")
717847 else {
718848 let unleaseAmt = ((amount / size(nList)) + 1)
719- let $t02971229774 = readNodeInfo(0)
720- let nAddr0 = $t02971229774._1
721- let lAmtKEY0 = $t02971229774._2
722- let lAmt0 = $t02971229774._3
723- let lIdKEY0 = $t02971229774._4
724- let lId0 = $t02971229774._5
849+ let $t03518935251 = readNodeInfo(0)
850+ let nAddr0 = $t03518935251._1
851+ let lAmtKEY0 = $t03518935251._2
852+ let lAmt0 = $t03518935251._3
853+ let lIdKEY0 = $t03518935251._4
854+ let lId0 = $t03518935251._5
725855 let newL0 = Lease(nAddr0, (lAmt0 + (unleaseAmt * size(nList))))
726856 func forEachNodeDoUnlease (a,i) = {
727857 let node = nList[i]
728858 let lIdKEY = getLeaseIdByAddressKey(node)
729859 let lId = getBinaryValue(this, lIdKEY)
730860 let lAmtKEY = getLeaseAmountByAddressKey(node)
731861 let lAmt = getIntegerValue(this, lAmtKEY)
732862 let ula = LeaseCancel(value(lId))
733863 let la = Lease(addressFromStringValue(node), (lAmt - unleaseAmt))
734864 (a ++ [LeaseCancel(value(lId)), la, BinaryEntry(lIdKEY, lcalc(la)), IntegerEntry(lAmtKEY, la.amount)])
735865 }
736866
737867 ({
738868 let $l = nIdxs
739869 let $s = size($l)
740870 let $acc0 = nil
741871 func $f0_1 ($a,$i) = if (($i >= $s))
742872 then $a
743873 else forEachNodeDoUnlease($a, $l[$i])
744874
745875 func $f0_2 ($a,$i) = if (($i >= $s))
746876 then $a
747877 else throw("List size exceeds 8")
748878
749879 $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)
750880 } ++ [BinaryEntry(lIdKEY0, lcalc(newL0)), IntegerEntry(lAmtKEY0, newL0.amount), LeaseCancel(lId0), newL0])
751881 }
752882 }
753883
754884
755885
756886 @Callable(i)
757887 func swapParamsByUserSYSREADONLY (userAddressStr,gnsbtDiff) = {
758888 let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", [userAddressStr, 0, 0], nil))
759889 let gnsbtAmt = (asInt(gnsbtData[0]) + gnsbtDiff)
760890 let gnsbtAmtTotal = (asInt(gnsbtData[1]) + gnsbtDiff)
761- let swapLimitMax = asInt(invoke(mathContract, "calcSwapLimitREADONLY", [gnsbtAmt], nil))
891+ let swapLimitData = asAnyList(invoke(mathContract, "calcSwapLimitREADONLY", [gnsbtAmt], nil))
892+ let wavesSwapLimitInUsdnMax = asInt(swapLimitData[0])
893+ let wavesSwapLimitMax = asInt(swapLimitData[1])
894+ let usdnSwapLimitMax = asInt(swapLimitData[2])
762895 let lastSwapHeight = valueOrElse(getInteger(this, keyUserLastSwapHeight(userAddressStr)), 0)
763896 let swapLimitTimelifeBlocks = swapsTimeframeREAD()
764897 let passedBlocksAfterLastSwap = (height - lastSwapHeight)
765898 let isSwapTimelifeNew = (passedBlocksAfterLastSwap >= swapLimitTimelifeBlocks)
766- let swapLimitSpent = if (isSwapTimelifeNew)
899+ let swapLimitSpentInUsdn = if (isSwapTimelifeNew)
767900 then 0
768901 else valueOrElse(getInteger(this, keySwapUserSpentInPeriod(userAddressStr)), 0)
769902 let blcks2LmtReset = if (isSwapTimelifeNew)
770903 then 0
771904 else (swapLimitTimelifeBlocks - passedBlocksAfterLastSwap)
772- $Tuple2(nil, $Tuple5(swapLimitMax, swapLimitSpent, blcks2LmtReset, gnsbtAmt, gnsbtAmtTotal))
905+ $Tuple2(nil, $Tuple7(wavesSwapLimitInUsdnMax, swapLimitSpentInUsdn, blcks2LmtReset, gnsbtAmt, gnsbtAmtTotal, wavesSwapLimitMax, usdnSwapLimitMax))
906+ }
907+
908+
909+
910+@Callable(i)
911+func calcWithdrawResultSYSREADONLY (swapType,inAmount,price) = {
912+ let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
913+ $Tuple2(nil, calcWithdraw(swapType, inAmount, price, neutrinoMetrics))
773914 }
774915
775916
776917 @Verifier(tx)
777918 func verify () = {
778919 let id = toBase58String(tx.id)
779920 let pubKeyAdminsListStr = makeString(["GJdLSaLiv5K7xuejac8mcRcHoyo3dPrESrvktG3a6MAR", "EYwZmURd5KKaQRBjsVa6g8DPisFoS6SovRJtFiL5gMHU", "DtmAfuDdCrHK8spdAeAYzq6MsZegeD9gnsrpuTRkCbVA", "5WRXFSjwcTbNfKcJs8ZqXmSSWYsSVJUtMvMqZj5hH4Nc"], SEP)
780921 let pubKeyAdminsList = split(valueOrElse(getString(controlContract, "%s__multisig"), pubKeyAdminsListStr), SEP)
781922 let count = ((((if (sigVerify(tx.bodyBytes, tx.proofs[0], fromBase58String(pubKeyAdminsList[0])))
782923 then 1
783924 else 0) + (if (sigVerify(tx.bodyBytes, tx.proofs[1], fromBase58String(pubKeyAdminsList[1])))
784925 then 1
785926 else 0)) + (if (sigVerify(tx.bodyBytes, tx.proofs[2], fromBase58String(pubKeyAdminsList[2])))
786927 then 1
787928 else 0)) + (if (sigVerify(tx.bodyBytes, tx.proofs[3], fromBase58String(pubKeyAdminsList[3])))
788929 then 2
789930 else 0))
790931 match tx {
791932 case sponsorTx: SponsorFeeTransaction =>
792933 if (checkIsValidMinSponsoredFee(sponsorTx))
793934 then (count >= 3)
794935 else false
795936 case _ =>
796937 (count >= 3)
797938 }
798939 }
799940

github/deemru/w8io/786bc32 
93.54 ms