tx · 4xKYLTW2puBWSmkjN2BfNKoWQSgA9qLvTiqbF69ipSpd

3N9be2mwrA52WJho6DiesZkk4351GvpnWuj:  -0.03700000 Waves

2023.01.12 15:30 [2401738] smart account 3N9be2mwrA52WJho6DiesZkk4351GvpnWuj > SELF 0.00000000 Waves

{ "type": 13, "id": "4xKYLTW2puBWSmkjN2BfNKoWQSgA9qLvTiqbF69ipSpd", "fee": 3700000, "feeAssetId": null, "timestamp": 1673526630483, "version": 2, "chainId": 84, "sender": "3N9be2mwrA52WJho6DiesZkk4351GvpnWuj", "senderPublicKey": "6mzmbCza9iqbzxMEELcEA4Xc9NeF4CYpbTtz1zMK3C7x", "proofs": [ "384RBxU6urwfkPtvEKSvsS1gP49ZDSg8um3aZe4x91dsANMrNJZ9TKjYEUu3Z4APbKFEyA4CHBNLoVmfei7xFycR", "3bTD7S8AgEMwjeB5ee2gvwRfqtCb5e6dGLSaSXed16XPAAaxstuGrmGBYnbV9M5dHnnkpzEDhohAetvMikKh9Wtk", "h79U8wioxTq2gCvUVBGNPyxUs8bMzPvQKuC8J8hu4KvFqeDurKADbevRqSPFbvFhLaWmHfZPouxaJdDRQKNnx7P" ], "script": "base64:BgJYCAISDwoNCAgICAgIAQEBAQEBARIFCgMICAESABIAEgUKAwgBCBIDCgEBEgQKAgEIEgASBQoDCAEBEgQKAgEBEgQKAggBEgUKAwgBARIGCgQICAEBEgASAKkBAQ9nZXRTdHJpbmdPckZhaWwCB2FkZHJlc3MDa2V5CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ0IAgUHYWRkcmVzcwUDa2V5CQC5CQIJAMwIAgIKbWFuZGF0b3J5IAkAzAgCCQClCAEFB2FkZHJlc3MJAMwIAgIBLgkAzAgCBQNrZXkJAMwIAgIPIGlzIG5vdCBkZWZpbmVkBQNuaWwCAAEFbGNhbGMBAWwJALkIAQUBbAEOZ2V0TnVtYmVyQnlLZXkBA2tleQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQNrZXkAAAEOZ2V0U3RyaW5nQnlLZXkBA2tleQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzBQNrZXkCAAEMZ2V0Qm9vbEJ5S2V5AQNrZXkJAQt2YWx1ZU9yRWxzZQIJAJsIAgUEdGhpcwUDa2V5BwEYZ2V0TnVtYmVyQnlBZGRyZXNzQW5kS2V5AgdhZGRyZXNzA2tleQkBC3ZhbHVlT3JFbHNlAgkAmggCBQdhZGRyZXNzBQNrZXkAAAEYZ2V0U3RyaW5nQnlBZGRyZXNzQW5kS2V5AgdhZGRyZXNzA2tleQkBC3ZhbHVlT3JFbHNlAgkAnQgCCQERQGV4dHJOYXRpdmUoMTA2MikBBQdhZGRyZXNzBQNrZXkCAAEWZ2V0Qm9vbEJ5QWRkcmVzc0FuZEtleQIHYWRkcmVzcwNrZXkJAQt2YWx1ZU9yRWxzZQIJAJsIAgUHYWRkcmVzcwUDa2V5BwEJYXNBbnlMaXN0AQF2BAckbWF0Y2gwBQF2AwkAAQIFByRtYXRjaDACCUxpc3RbQW55XQQBbAUHJG1hdGNoMAUBbAkAAgECG2ZhaWwgdG8gY2FzdCBpbnRvIExpc3RbQW55XQEIYXNTdHJpbmcBAXYEByRtYXRjaDAFAXYDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFzBQckbWF0Y2gwBQFzCQACAQIYZmFpbCB0byBjYXN0IGludG8gU3RyaW5nAQVhc0ludAEBdgQHJG1hdGNoMAUBdgMJAAECBQckbWF0Y2gwAgNJbnQEAWkFByRtYXRjaDAFAWkJAAIBAhVmYWlsIHRvIGNhc3QgaW50byBJbnQBB2FzQnl0ZXMBA3ZhbAQHJG1hdGNoMAUDdmFsAwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEB3ZhbEJ5dGUFByRtYXRjaDAFB3ZhbEJ5dGUJAAIBAhxmYWlsIHRvIGNhc3QgaW50byBCeXRlVmVjdG9yAQlhc1BheW1lbnQBAXYEByRtYXRjaDAFAXYDCQABAgUHJG1hdGNoMAIPQXR0YWNoZWRQYXltZW50BAFwBQckbWF0Y2gwBQFwCQACAQIhZmFpbCB0byBjYXN0IGludG8gQXR0YWNoZWRQYXltZW50ARJhc1N3YXBQYXJhbXNTVFJVQ1QBAXYEByRtYXRjaDAFAXYDCQABAgUHJG1hdGNoMAIjKEludCwgSW50LCBJbnQsIEludCwgSW50LCBJbnQsIEludCkEBnN0cnVjdAUHJG1hdGNoMAUGc3RydWN0CQACAQIdZmFpbCB0byBjYXN0IGludG8gVHVwbGU1IGludHMAA1NFUAICX18AB0xJU1RTRVACAToAB1dBVkVMRVQAgMLXLwAFUEFVTEkAwIQ9AAhQUklDRUxFVADAhD0ADkRFRkFVTFRTV0FQRkVFAKCcAQALQlJQUk9URUNURUQAoI0GAAxJZHhOZXRBbW91bnQAAAAMSWR4RmVlQW1vdW50AAEADklkeEdyb3NzQW1vdW50AAIAGUlkeENvbnRyb2xDZmdOZXV0cmlub0RhcHAAAQAYSWR4Q29udHJvbENmZ0F1Y3Rpb25EYXBwAAIAFElkeENvbnRyb2xDZmdScGREYXBwAAMAFUlkeENvbnRyb2xDZmdNYXRoRGFwcAAEABxJZHhDb250cm9sQ2ZnTGlxdWlkYXRpb25EYXBwAAUAFUlkeENvbnRyb2xDZmdSZXN0RGFwcAAGAB1JZHhDb250cm9sQ2ZnTm9kZVJlZ2lzdHJ5RGFwcAAHABxJZHhDb250cm9sQ2ZnTnNidFN0YWtpbmdEYXBwAAgAGUlkeENvbnRyb2xDZmdNZWRpYXRvckRhcHAACQAcSWR4Q29udHJvbENmZ1N1cmZTdGFraW5nRGFwcAAKACBJZHhDb250cm9sQ2ZnR25zYnRDb250cm9sbGVyRGFwcAALABdJZHhDb250cm9sQ2ZnUmVzdFYyRGFwcAAMABtJZHhDb250cm9sQ2ZnR292ZXJuYW5jZURhcHAADQERa2V5Q29udHJvbEFkZHJlc3MAAhwlcyVzX19jb25maWdfX2NvbnRyb2xBZGRyZXNzAQ1rZXlDb250cm9sQ2ZnAAIRJXNfX2NvbnRyb2xDb25maWcBFHJlYWRDb250cm9sQ2ZnT3JGYWlsAQdjb250cm9sCQC8CQIJAQ9nZXRTdHJpbmdPckZhaWwCBQdjb250cm9sCQENa2V5Q29udHJvbENmZwAFA1NFUAEYZ2V0Q29udHJhY3RBZGRyZXNzT3JGYWlsAgpjb250cm9sQ2ZnA2lkeAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJAJEDAgUKY29udHJvbENmZwUDaWR4CQCsAgICLUNvbnRyb2wgY2ZnIGRvZXNuJ3QgY29udGFpbiBhZGRyZXNzIGF0IGluZGV4IAkApAMBBQNpZHgAD2NvbnRyb2xDb250cmFjdAkBEUBleHRyTmF0aXZlKDEwNjIpAQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzCQERa2V5Q29udHJvbEFkZHJlc3MAAiMzTjROUzdkNEpvOWE2RjE0TGlGVUtLWVZkVWtrZjJlUDRaeAAKY29udHJvbENmZwkBFHJlYWRDb250cm9sQ2ZnT3JGYWlsAQUPY29udHJvbENvbnRyYWN0AAxtYXRoQ29udHJhY3QJARhnZXRDb250cmFjdEFkZHJlc3NPckZhaWwCBQpjb250cm9sQ2ZnBRVJZHhDb250cm9sQ2ZnTWF0aERhcHAAE25zYnRTdGFraW5nQ29udHJhY3QJARhnZXRDb250cmFjdEFkZHJlc3NPckZhaWwCBQpjb250cm9sQ2ZnBRxJZHhDb250cm9sQ2ZnTnNidFN0YWtpbmdEYXBwABNzdXJmU3Rha2luZ0NvbnRyYWN0CQEYZ2V0Q29udHJhY3RBZGRyZXNzT3JGYWlsAgUKY29udHJvbENmZwUcSWR4Q29udHJvbENmZ1N1cmZTdGFraW5nRGFwcAAXZ25zYnRDb250cm9sbGVyQ29udHJhY3QJARhnZXRDb250cmFjdEFkZHJlc3NPckZhaWwCBQpjb250cm9sQ2ZnBSBJZHhDb250cm9sQ2ZnR25zYnRDb250cm9sbGVyRGFwcAAPYXVjdGlvbkNvbnRyYWN0CQEYZ2V0Q29udHJhY3RBZGRyZXNzT3JGYWlsAgUKY29udHJvbENmZwUYSWR4Q29udHJvbENmZ0F1Y3Rpb25EYXBwABRub2RlUmVnaXN0cnlDb250cmFjdAkBGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAIFCmNvbnRyb2xDZmcFHUlkeENvbnRyb2xDZmdOb2RlUmVnaXN0cnlEYXBwAAtnb3ZDb250cmFjdAkBGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAIFCmNvbnRyb2xDZmcFG0lkeENvbnRyb2xDZmdHb3Zlcm5hbmNlRGFwcAASTmV1dHJpbm9Bc3NldElkS2V5AhFuZXV0cmlub19hc3NldF9pZAAOQm9uZEFzc2V0SWRLZXkCDWJvbmRfYXNzZXRfaWQAEkF1Y3Rpb25Db250cmFjdEtleQIQYXVjdGlvbl9jb250cmFjdAAWTnNidFN0YWtpbmdDb250cmFjdEtleQITbnNidFN0YWtpbmdDb250cmFjdAAWTGlxdWlkYXRpb25Db250cmFjdEtleQIUbGlxdWlkYXRpb25fY29udHJhY3QADlJQRENvbnRyYWN0S2V5AgxycGRfY29udHJhY3QAEUNvbnRvbENvbnRyYWN0S2V5AhBjb250cm9sX2NvbnRyYWN0AA9NYXRoQ29udHJhY3RLZXkCDW1hdGhfY29udHJhY3QAG0JhbGFuY2VXYXZlc0xvY2tJbnRlcnZhbEtleQIbYmFsYW5jZV93YXZlc19sb2NrX2ludGVydmFsAB5CYWxhbmNlTmV1dHJpbm9Mb2NrSW50ZXJ2YWxLZXkCHmJhbGFuY2VfbmV1dHJpbm9fbG9ja19pbnRlcnZhbAAVTWluV2F2ZXNTd2FwQW1vdW50S2V5AhVtaW5fd2F2ZXNfc3dhcF9hbW91bnQAGE1pbk5ldXRyaW5vU3dhcEFtb3VudEtleQIYbWluX25ldXRyaW5vX3N3YXBfYW1vdW50ABtOb2RlT3JhY2xlUHJvdmlkZXJQdWJLZXlLZXkCFG5vZGVfb3JhY2xlX3Byb3ZpZGVyABVOZXV0cmlub091dEZlZVBhcnRLZXkCGG5ldXRyaW5vT3V0X3N3YXBfZmVlUGFydAASV2F2ZXNPdXRGZWVQYXJ0S2V5AhV3YXZlc091dF9zd2FwX2ZlZVBhcnQAEk11bHRpT3V0RmVlUGFydEtleQIVbXVsdGlPdXRfc3dhcF9mZWVQYXJ0AQ9rZXlOb2RlUmVnaXN0cnkBB2FkZHJlc3MJAKwCAgIEJXNfXwUHYWRkcmVzcwAIUHJpY2VLZXkCBXByaWNlAA1QcmljZUluZGV4S2V5AgtwcmljZV9pbmRleAAMSXNCbG9ja2VkS2V5Agppc19ibG9ja2VkARJnZXRQcmljZUhpc3RvcnlLZXkBBWJsb2NrCQCsAgIJAKwCAgUIUHJpY2VLZXkCAV8JAKQDAQUFYmxvY2sBGGdldEhlaWdodFByaWNlQnlJbmRleEtleQEFaW5kZXgJAKwCAgkArAICBQ1QcmljZUluZGV4S2V5AgFfCQCkAwEFBWluZGV4ARVnZXRTdGFraW5nTm9kZUJ5SW5kZXgBA2lkeAkBDmdldFN0cmluZ0J5S2V5AQkAuQkCCQDMCAICBiVzJWQlcwkAzAgCAgVsZWFzZQkAzAgCCQCkAwEFA2lkeAkAzAgCAgtub2RlQWRkcmVzcwUDbmlsBQNTRVABHGdldFN0YWtpbmdOb2RlQWRkcmVzc0J5SW5kZXgBA2lkeAkBEUBleHRyTmF0aXZlKDEwNjIpAQkBFWdldFN0YWtpbmdOb2RlQnlJbmRleAEFA2lkeAEfZ2V0UmVzZXJ2ZWRBbW91bnRGb3JTcG9uc29yc2hpcAAJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkAuQkCCQDMCAICBCVzJXMJAMwIAgIFbGVhc2UJAMwIAgIXc3BvbnNvcnNoaXBXYXZlc1Jlc2VydmUFA25pbAUDU0VQCQBoAgDoBwUHV0FWRUxFVAEYZ2V0QmFsYW5jZVVubG9ja0Jsb2NrS2V5AQVvd25lcgkArAICAhViYWxhbmNlX3VubG9ja19ibG9ja18FBW93bmVyAQ1nZXRMZWFzZUlkS2V5AQlub2RlSW5kZXgJALkJAgkAzAgCAgYlcyVkJXMJAMwIAgIFbGVhc2UJAMwIAgkApAMBBQlub2RlSW5kZXgJAMwIAgICaWQFA25pbAUDU0VQARZnZXRMZWFzZUlkQnlBZGRyZXNzS2V5AQtub2RlQWRkcmVzcwkAuQkCCQDMCAICBiVzJXMlcwkAzAgCAg5sZWFzZUJ5QWRkcmVzcwkAzAgCBQtub2RlQWRkcmVzcwkAzAgCAgJpZAUDbmlsBQNTRVABEWdldExlYXNlQW1vdW50S2V5AQlub2RlSW5kZXgJALkJAgkAzAgCAgYlcyVkJXMJAMwIAgIFbGVhc2UJAMwIAgkApAMBBQlub2RlSW5kZXgJAMwIAgIGYW1vdW50BQNuaWwFA1NFUAEaZ2V0TGVhc2VBbW91bnRCeUFkZHJlc3NLZXkBC25vZGVBZGRyZXNzCQC5CQIJAMwIAgIGJXMlcyVzCQDMCAICDmxlYXNlQnlBZGRyZXNzCQDMCAIFC25vZGVBZGRyZXNzCQDMCAICBmFtb3VudAUDbmlsBQNTRVABGGdldExlYXNlR3JvdXBOb2RlTGlzdEtleQEIZ3JvdXBOdW0JALkJAgkAzAgCAgYlcyVkJXMJAMwIAgIKbGVhc2VHcm91cAkAzAgCCQCkAwEFCGdyb3VwTnVtCQDMCAICCG5vZGVMaXN0BQNuaWwFA1NFUAEQbWluU3dhcEFtb3VudEtFWQEIc3dhcFR5cGUJAKwCAgkArAICAgRtaW5fBQhzd2FwVHlwZQIMX3N3YXBfYW1vdW50AQ50b3RhbExvY2tlZEtFWQEIc3dhcFR5cGUJAKwCAgINYmFsYW5jZV9sb2NrXwUIc3dhcFR5cGUBFHRvdGFsTG9ja2VkQnlVc2VyS0VZAghzd2FwVHlwZQVvd25lcgkAuQkCCQDMCAICDGJhbGFuY2VfbG9jawkAzAgCBQhzd2FwVHlwZQkAzAgCBQVvd25lcgUDbmlsAgFfARZiYWxhbmNlTG9ja0ludGVydmFsS0VZAQhzd2FwVHlwZQkArAICCQCsAgICCGJhbGFuY2VfBQhzd2FwVHlwZQIOX2xvY2tfaW50ZXJ2YWwBGm5vZGVCYWxhbmNlTG9ja0ludGVydmFsS0VZAAIaYmFsYW5jZV9ub2RlX2xvY2tfaW50ZXJ2YWwBDW91dEZlZVBhcnRLRVkBCHN3YXBUeXBlCQCsAgIFCHN3YXBUeXBlAhBPdXRfc3dhcF9mZWVQYXJ0ARFzd2Fwc1RpbWVmcmFtZUtFWQACD3N3YXBzX3RpbWVmcmFtZQEOYnJQcm90ZWN0ZWRLRVkAAhdtaW5fQlJfcHJvdGVjdGlvbl9sZXZlbAERbWluU3dhcEFtb3VudFJFQUQBCHN3YXBUeXBlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJARBtaW5Td2FwQW1vdW50S0VZAQUIc3dhcFR5cGUAAAESc3dhcHNUaW1lZnJhbWVSRUFEAAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQERc3dhcHNUaW1lZnJhbWVLRVkAAKALAQ90b3RhbExvY2tlZFJFQUQBCHN3YXBUeXBlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQ50b3RhbExvY2tlZEtFWQEFCHN3YXBUeXBlAAABFXRvdGFsTG9ja2VkQnlVc2VyUkVBRAIIc3dhcFR5cGUFb3duZXIJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBFHRvdGFsTG9ja2VkQnlVc2VyS0VZAgUIc3dhcFR5cGUFBW93bmVyAAABF2JhbGFuY2VMb2NrSW50ZXJ2YWxSRUFEAQhzd2FwVHlwZQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEWYmFsYW5jZUxvY2tJbnRlcnZhbEtFWQEFCHN3YXBUeXBlAKALARtub2RlQmFsYW5jZUxvY2tJbnRlcnZhbFJFQUQACQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJARpub2RlQmFsYW5jZUxvY2tJbnRlcnZhbEtFWQAAAQEYa2V5U3dhcFVzZXJTcGVudEluUGVyaW9kAQt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBCVzJXMJAMwIAgIVc3dhcFVzZXJTcGVudEluUGVyaW9kCQDMCAIFC3VzZXJBZGRyZXNzBQNuaWwFA1NFUAEVa2V5VXNlckxhc3RTd2FwSGVpZ2h0AQt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBCVzJXMJAMwIAgISdXNlckxhc3RTd2FwSGVpZ2h0CQDMCAIFC3VzZXJBZGRyZXNzBQNuaWwFA1NFUAEWY29udmVydE5ldXRyaW5vVG9XYXZlcwIGYW1vdW50BXByaWNlCQBrAwkAawMFBmFtb3VudAUIUFJJQ0VMRVQFBXByaWNlBQdXQVZFTEVUBQVQQVVMSQEWY29udmVydFdhdmVzVG9OZXV0cmlubwIGYW1vdW50BXByaWNlCQBrAwkAawMFBmFtb3VudAUFcHJpY2UFCFBSSUNFTEVUBQVQQVVMSQUHV0FWRUxFVAESY29udmVydFdhdmVzVG9Cb25kAgZhbW91bnQFcHJpY2UJARZjb252ZXJ0V2F2ZXNUb05ldXRyaW5vAgUGYW1vdW50BQVwcmljZQEWY29udmVydEpzb25BcnJheVRvTGlzdAEJanNvbkFycmF5CQC1CQIFCWpzb25BcnJheQIBLAERbWluU3dhcEFtb3VudEZBSUwCCHN3YXBUeXBlDW1pblN3YXBBbW91bnQJAAIBCQCsAgIJAKwCAgkArAICAhhUaGUgc3BlY2lmaWVkIGFtb3VudCBpbiAFCHN3YXBUeXBlAisgc3dhcCBpcyBsZXNzIHRoYW4gdGhlIHJlcXVpcmVkIG1pbmltdW0gb2YgCQCkAwEFDW1pblN3YXBBbW91bnQBFWVtZXJnZW5jeVNodXRkb3duRkFJTAAJAAIBAlpjb250cmFjdCBpcyBibG9ja2VkIGJ5IEVNRVJHRU5DWSBTSFVURE9XTiBhY3Rpb25zIHVudGlsbCByZWFjdGl2YXRpb24gYnkgZW1lcmdlbmN5IG9yYWNsZXMBDnByaWNlSW5kZXhGQUlMBQVpbmRleApwcmljZUluZGV4C2luZGV4SGVpZ2h0DHVubG9ja0hlaWdodA9wcmV2SW5kZXhIZWlnaHQJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICAiNpbnZhbGlkIHByaWNlIGhpc3RvcnkgaW5kZXg6IGluZGV4PQkApAMBBQVpbmRleAIMIHByaWNlSW5kZXg9CQCkAwEFCnByaWNlSW5kZXgCDSBpbmRleEhlaWdodD0JAKQDAQULaW5kZXhIZWlnaHQCDiB1bmxvY2tIZWlnaHQ9CQCkAwEFDHVubG9ja0hlaWdodAIRIHByZXZJbmRleEhlaWdodD0JAKQDAQUPcHJldkluZGV4SGVpZ2h0AA9uZXV0cmlub0Fzc2V0SWQJANkEAQkBDmdldFN0cmluZ0J5S2V5AQUSTmV1dHJpbm9Bc3NldElkS2V5AApwcmljZUluZGV4CQEYZ2V0TnVtYmVyQnlBZGRyZXNzQW5kS2V5AgUPY29udHJvbENvbnRyYWN0BQ1QcmljZUluZGV4S2V5AAlpc0Jsb2NrZWQJARZnZXRCb29sQnlBZGRyZXNzQW5kS2V5AgUPY29udHJvbENvbnRyYWN0BQxJc0Jsb2NrZWRLZXkAGG5vZGVPcmFjbGVQcm92aWRlclB1YktleQkA2QQBCQEOZ2V0U3RyaW5nQnlLZXkBBRtOb2RlT3JhY2xlUHJvdmlkZXJQdWJLZXlLZXkAC2JvbmRBc3NldElkCQDZBAECLEYzaWF4enJ1RmVLdWpmVmZZU1pFa2VqcGpoNjd3bVJmUENSSGlObVdLcDNaABVkZXByZWNhdGVkQm9uZEFzc2V0SWQJANkEAQIsOTc1YWtaQmZuTWo1MTNVN01aYUhLelFybXNFeDVhRTN3ZFdLVHJIQmhiakYAEG5ldXRyaW5vQ29udHJhY3QFBHRoaXMADGN1cnJlbnRQcmljZQkBGGdldE51bWJlckJ5QWRkcmVzc0FuZEtleQIFD2NvbnRyb2xDb250cmFjdAUIUHJpY2VLZXkBG2NoZWNrSXNWYWxpZE1pblNwb25zb3JlZEZlZQECdHgEDk1JTlRSQU5TRkVSRkVFAKCNBgQWU3BvbnNvcmVkRmVlVXBwZXJCb3VuZADoBwQPcmVhbE5ldXRyaW5vRmVlCQEWY29udmVydFdhdmVzVG9OZXV0cmlubwIFDk1JTlRSQU5TRkVSRkVFBQxjdXJyZW50UHJpY2UEDm1pbk5ldXRyaW5vRmVlCQBoAgUPcmVhbE5ldXRyaW5vRmVlAAIEDm1heE5ldXRyaW5vRmVlCQBrAwUPcmVhbE5ldXRyaW5vRmVlBRZTcG9uc29yZWRGZWVVcHBlckJvdW5kAGQECGlucHV0RmVlCQEFdmFsdWUBCAUCdHgUbWluU3BvbnNvcmVkQXNzZXRGZWUDAwkAZwIFCGlucHV0RmVlBQ5taW5OZXV0cmlub0ZlZQkAZwIFDm1heE5ldXRyaW5vRmVlBQhpbnB1dEZlZQcJAAACCAUCdHgHYXNzZXRJZAUPbmV1dHJpbm9Bc3NldElkBwEPZ2V0UHJpY2VIaXN0b3J5AQVibG9jawkBGGdldE51bWJlckJ5QWRkcmVzc0FuZEtleQIFD2NvbnRyb2xDb250cmFjdAkBEmdldFByaWNlSGlzdG9yeUtleQEFBWJsb2NrARVnZXRIZWlnaHRQcmljZUJ5SW5kZXgBBWluZGV4CQEYZ2V0TnVtYmVyQnlBZGRyZXNzQW5kS2V5AgUPY29udHJvbENvbnRyYWN0CQEYZ2V0SGVpZ2h0UHJpY2VCeUluZGV4S2V5AQUFaW5kZXgBFmtleUxvY2tQYXJhbVVzZXJBbW91bnQBC3VzZXJBZGRyZXNzCQC5CQIJAMwIAgIGJXMlcyVzCQDMCAICC3BhcmFtQnlVc2VyCQDMCAIFC3VzZXJBZGRyZXNzCQDMCAICBmFtb3VudAUDbmlsBQNTRVAADHNJZHhTd2FwVHlwZQABAApzSWR4U3RhdHVzAAIADHNJZHhJbkFtb3VudAADAA9zSWR4U3RhcnRIZWlnaHQABwASc0lkeFN0YXJ0VGltZXN0YW1wAAgAFHNJZHhTZWxmVW5sb2NrSGVpZ2h0AAsAC3NJZHhNaW5SYW5kAA8AC3NJZHhNYXhSYW5kABABB3N3YXBLRVkCC3VzZXJBZGRyZXNzBHR4SWQJALkJAgkAzAgCAgQlcyVzCQDMCAIFC3VzZXJBZGRyZXNzCQDMCAIFBHR4SWQFA25pbAUDU0VQAQtzdHJTd2FwREFUQRMIc3dhcFR5cGUGc3RhdHVzCGluQW1vdW50BXByaWNlDG91dE5ldEFtb3VudAxvdXRGZWVBbW91bnQLc3RhcnRIZWlnaHQOc3RhcnRUaW1lc3RhbXAJZW5kSGVpZ2h0DGVuZFRpbWVzdGFtcBBzZWxmVW5sb2NrSGVpZ2h0EHJhbmRVbmxvY2tIZWlnaHQFaW5kZXgMd2l0aGRyYXdUeElkB3JhbmRNaW4HcmFuZE1heApvdXRTdXJmQW10AmJyCmJhc2tldERhdGEJALkJAgkAzAgCAiYlcyVzJWQlZCVkJWQlZCVkJWQlZCVkJWQlZCVzJWQlZCVkJWQlcwkAzAgCBQhzd2FwVHlwZQkAzAgCBQZzdGF0dXMJAMwIAgUIaW5BbW91bnQJAMwIAgUFcHJpY2UJAMwIAgUMb3V0TmV0QW1vdW50CQDMCAIFDG91dEZlZUFtb3VudAkAzAgCBQtzdGFydEhlaWdodAkAzAgCBQ5zdGFydFRpbWVzdGFtcAkAzAgCBQllbmRIZWlnaHQJAMwIAgUMZW5kVGltZXN0YW1wCQDMCAIFEHNlbGZVbmxvY2tIZWlnaHQJAMwIAgUQcmFuZFVubG9ja0hlaWdodAkAzAgCBQVpbmRleAkAzAgCBQx3aXRoZHJhd1R4SWQJAMwIAgUHcmFuZE1pbgkAzAgCBQdyYW5kTWF4CQDMCAIFCm91dFN1cmZBbXQJAMwIAgUCYnIJAMwIAgUKYmFza2V0RGF0YQUDbmlsBQNTRVABD3BlbmRpbmdTd2FwREFUQQMIc3dhcFR5cGUNaW5Bc3NldEFtb3VudBBzZWxmVW5sb2NrSGVpZ2h0CQELc3RyU3dhcERBVEETBQhzd2FwVHlwZQIHUEVORElORwkApAMBBQ1pbkFzc2V0QW1vdW50AgEwAgEwAgEwCQCkAwEFBmhlaWdodAkApAMBCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAIBMAIBMAkApAMBBRBzZWxmVW5sb2NrSGVpZ2h0AgEwAgEwAgROVUxMAgEwAgEwAgEwAgEwAgABDmZpbmlzaFN3YXBEQVRBCglkYXRhQXJyYXkFcHJpY2UMb3V0TmV0QW1vdW50DG91dEZlZUFtb3VudBByYW5kVW5sb2NrSGVpZ2h0BWluZGV4DHdpdGhkcmF3VHhJZApvdXRTdXJmQW10AmJyCmJhc2tldERhdGEJAQtzdHJTd2FwREFUQRMJAJEDAgUJZGF0YUFycmF5BQxzSWR4U3dhcFR5cGUCCEZJTklTSEVECQCRAwIFCWRhdGFBcnJheQUMc0lkeEluQW1vdW50CQCkAwEFBXByaWNlCQCkAwEFDG91dE5ldEFtb3VudAkApAMBBQxvdXRGZWVBbW91bnQJAJEDAgUJZGF0YUFycmF5BQ9zSWR4U3RhcnRIZWlnaHQJAJEDAgUJZGF0YUFycmF5BRJzSWR4U3RhcnRUaW1lc3RhbXAJAKQDAQUGaGVpZ2h0CQCkAwEIBQlsYXN0QmxvY2sJdGltZXN0YW1wCQCRAwIFCWRhdGFBcnJheQUUc0lkeFNlbGZVbmxvY2tIZWlnaHQJAKQDAQUQcmFuZFVubG9ja0hlaWdodAkApAMBBQVpbmRleAUMd2l0aGRyYXdUeElkCQCRAwIFCWRhdGFBcnJheQULc0lkeE1pblJhbmQJAJEDAgUJZGF0YUFycmF5BQtzSWR4TWF4UmFuZAkApAMBBQpvdXRTdXJmQW10CQCkAwEFAmJyBQpiYXNrZXREYXRhARJzd2FwRGF0YUZhaWxPclJFQUQCC3VzZXJBZGRyZXNzCHN3YXBUeElkBAdzd2FwS2V5CQEHc3dhcEtFWQIFC3VzZXJBZGRyZXNzBQhzd2FwVHhJZAkAtQkCCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ0IAgUEdGhpcwUHc3dhcEtleQkArAICAhFubyBzd2FwIGRhdGEgZm9yIAUHc3dhcEtleQUDU0VQAQlhcHBseUZlZXMDDmFtb3VudE91dEdyb3NzC2luQW10VG9TVVJGB2ZlZVBhcnQECWZlZUFtb3VudAkAawMFDmFtb3VudE91dEdyb3NzBQdmZWVQYXJ0BQVQQVVMSQkAzAgCCQBlAgUOYW1vdW50T3V0R3Jvc3MFCWZlZUFtb3VudAkAzAgCBQlmZWVBbW91bnQFA25pbAEDYWJzAQF4AwkAZgIAAAUBeAkBAS0BBQF4BQF4AQpzZWxlY3ROb2RlAQ11bmxlYXNlQW1vdW50BA1hbW91bnRUb0xlYXNlCQBlAgkAZQIICQDvBwEFEG5ldXRyaW5vQ29udHJhY3QJYXZhaWxhYmxlBQ11bmxlYXNlQW1vdW50CQEfZ2V0UmVzZXJ2ZWRBbW91bnRGb3JTcG9uc29yc2hpcAAECm9sZExlYXNlZDAJAQ5nZXROdW1iZXJCeUtleQEJARFnZXRMZWFzZUFtb3VudEtleQEAAAQKb2xkTGVhc2VkMQkBDmdldE51bWJlckJ5S2V5AQkBEWdldExlYXNlQW1vdW50S2V5AQABBApuZXdMZWFzZWQwCQBkAgUNYW1vdW50VG9MZWFzZQUKb2xkTGVhc2VkMAQKbmV3TGVhc2VkMQkAZAIFDWFtb3VudFRvTGVhc2UFCm9sZExlYXNlZDEDAwkAZgIFCm5ld0xlYXNlZDAAAAYJAGYCBQpuZXdMZWFzZWQxAAAEBmRlbHRhMAkBA2FicwEJAGUCBQpuZXdMZWFzZWQwBQpvbGRMZWFzZWQxBAZkZWx0YTEJAQNhYnMBCQBlAgUKbmV3TGVhc2VkMQUKb2xkTGVhc2VkMAMJAGcCBQZkZWx0YTEFBmRlbHRhMAkAlAoCAAAFCm5ld0xlYXNlZDAJAJQKAgABBQpuZXdMZWFzZWQxCQCUCgIA////////////AQAAAQh0aGlzT25seQEBaQMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECLVBlcm1pc3Npb24gZGVuaWVkOiB0aGlzIGNvbnRyYWN0IG9ubHkgYWxsb3dlZAYBFnByZXBhcmVVbmxlYXNlQW5kTGVhc2UBDXVubGVhc2VBbW91bnQECW5vZGVUdXBsZQkBCnNlbGVjdE5vZGUBBQ11bmxlYXNlQW1vdW50BAlub2RlSW5kZXgIBQlub2RlVHVwbGUCXzEEDm5ld0xlYXNlQW1vdW50CAUJbm9kZVR1cGxlAl8yAwkAZgIFDm5ld0xlYXNlQW1vdW50AAAECmxlYXNlSWRLZXkJAQ1nZXRMZWFzZUlkS2V5AQUJbm9kZUluZGV4BAhvbGRMZWFzZQkAnAgCBQR0aGlzBQpsZWFzZUlkS2V5BA51bmxlYXNlT3JFbXB0eQMJAQlpc0RlZmluZWQBBQhvbGRMZWFzZQkAzAgCCQELTGVhc2VDYW5jZWwBCQEFdmFsdWUBBQhvbGRMZWFzZQUDbmlsBQNuaWwEDmxlYXNlQW1vdW50S2V5CQERZ2V0TGVhc2VBbW91bnRLZXkBBQlub2RlSW5kZXgEBWxlYXNlCQDECAIJARxnZXRTdGFraW5nTm9kZUFkZHJlc3NCeUluZGV4AQUJbm9kZUluZGV4BQ5uZXdMZWFzZUFtb3VudAkAzggCBQ51bmxlYXNlT3JFbXB0eQkAzAgCBQVsZWFzZQkAzAgCCQELQmluYXJ5RW50cnkCBQpsZWFzZUlkS2V5CQEFbGNhbGMBBQVsZWFzZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBEWdldExlYXNlQW1vdW50S2V5AQUJbm9kZUluZGV4BQ5uZXdMZWFzZUFtb3VudAUDbmlsBQNuaWwBDHJlYWROb2RlSW5mbwEHbm9kZUlkeAQLbm9kZUFkZHJlc3MJARxnZXRTdGFraW5nTm9kZUFkZHJlc3NCeUluZGV4AQUHbm9kZUlkeAQMbGVhc2VkQW10S0VZCQERZ2V0TGVhc2VBbW91bnRLZXkBBQdub2RlSWR4BAlsZWFzZWRBbXQJAQ5nZXROdW1iZXJCeUtleQEFDGxlYXNlZEFtdEtFWQQKbGVhc2VJZEtFWQkBDWdldExlYXNlSWRLZXkBBQdub2RlSWR4BAdsZWFzZUlkCQEFdmFsdWUBCQCcCAIFBHRoaXMFCmxlYXNlSWRLRVkJAJcKBQULbm9kZUFkZHJlc3MFDGxlYXNlZEFtdEtFWQUJbGVhc2VkQW10BQpsZWFzZUlkS0VZBQdsZWFzZUlkAQpjb21tb25Td2FwBAhzd2FwVHlwZQlwbXRBbW91bnQOdXNlckFkZHJlc3NTdHIGdHhJZDU4BBBzd2FwUGFyYW1zU1RSVUNUCQESYXNTd2FwUGFyYW1zU1RSVUNUAQkA/AcEBQR0aGlzAhtzd2FwUGFyYW1zQnlVc2VyU1lTUkVBRE9OTFkJAMwIAgUOdXNlckFkZHJlc3NTdHIJAMwIAgAABQNuaWwFA25pbAQOc3dhcExpbWl0U3BlbnQIBRBzd2FwUGFyYW1zU1RSVUNUAl8yBA5ibGNrczJMbXRSZXNldAgFEHN3YXBQYXJhbXNTVFJVQ1QCXzMEEXdhdmVzU3dhcExpbWl0TWF4CAUQc3dhcFBhcmFtc1NUUlVDVAJfNgQQdXNkblN3YXBMaW1pdE1heAgFEHN3YXBQYXJhbXNTVFJVQ1QCXzcEDW1pblN3YXBBbW91bnQJARFtaW5Td2FwQW1vdW50UkVBRAEFCHN3YXBUeXBlBAt0b3RhbExvY2tlZAkBD3RvdGFsTG9ja2VkUkVBRAEFCHN3YXBUeXBlBBF0b3RhbExvY2tlZEJ5VXNlcgkBFXRvdGFsTG9ja2VkQnlVc2VyUkVBRAIFCHN3YXBUeXBlBQ51c2VyQWRkcmVzc1N0cgQLbm9kZUFkZHJlc3MJARVnZXRTdGFraW5nTm9kZUJ5SW5kZXgBAAAEDHByaWNlQnlJbmRleAkBD2dldFByaWNlSGlzdG9yeQEJARVnZXRIZWlnaHRQcmljZUJ5SW5kZXgBBQpwcmljZUluZGV4BAxpc1N3YXBCeU5vZGUJAAACBQtub2RlQWRkcmVzcwUOdXNlckFkZHJlc3NTdHIEFmJhbGFuY2VMb2NrTWF4SW50ZXJ2YWwDBQxpc1N3YXBCeU5vZGUJARtub2RlQmFsYW5jZUxvY2tJbnRlcnZhbFJFQUQACQEXYmFsYW5jZUxvY2tJbnRlcnZhbFJFQUQBBQhzd2FwVHlwZQQQc2VsZlVubG9ja0hlaWdodAkAZAIFBmhlaWdodAUWYmFsYW5jZUxvY2tNYXhJbnRlcnZhbAQOc3dhcFVzZG5Wb2x1bWUDCQAAAgUIc3dhcFR5cGUCBXdhdmVzCQEWY29udmVydFdhdmVzVG9OZXV0cmlubwIFCXBtdEFtb3VudAUMcHJpY2VCeUluZGV4BQlwbXRBbW91bnQEDHN3YXBMaW1pdE1heAMJAAACBQhzd2FwVHlwZQIFd2F2ZXMJARZjb252ZXJ0V2F2ZXNUb05ldXRyaW5vAgURd2F2ZXNTd2FwTGltaXRNYXgFDHByaWNlQnlJbmRleAUQdXNkblN3YXBMaW1pdE1heAMJAGYCBQ1taW5Td2FwQW1vdW50BQlwbXRBbW91bnQJARFtaW5Td2FwQW1vdW50RkFJTAIFCHN3YXBUeXBlBQ1taW5Td2FwQW1vdW50AwMJAQEhAQUMaXNTd2FwQnlOb2RlCQBmAgUOc3dhcExpbWl0U3BlbnQAAAcJAAIBCQCsAgICOllvdSBoYXZlIGV4Y2VlZGVkIHN3YXAgbGltaXQhIE5leHQgYWxsb3dlZCBzd2FwIGhlaWdodCBpcyAJAKQDAQkAZAIFBmhlaWdodAUOYmxja3MyTG10UmVzZXQDAwkBASEBBQxpc1N3YXBCeU5vZGUJAGYCBQ5zd2FwVXNkblZvbHVtZQUMc3dhcExpbWl0TWF4BwkAAgEJAKwCAgkArAICCQCsAgICLllvdSBoYXZlIGV4Y2VlZGVkIHlvdXIgc3dhcCBsaW1pdCEgUmVxdWVzdGVkOiAJAKQDAQUOc3dhcFVzZG5Wb2x1bWUCDSwgYXZhaWxhYmxlOiAJAKQDAQUMc3dhcExpbWl0TWF4AwUJaXNCbG9ja2VkCQEVZW1lcmdlbmN5U2h1dGRvd25GQUlMAAQJbGVhc2VQYXJ0AwkAAAIFCHN3YXBUeXBlAgV3YXZlcwkBFnByZXBhcmVVbmxlYXNlQW5kTGVhc2UBAAAFA25pbAkAlAoCCQDOCAIJAMwIAgkBDEludGVnZXJFbnRyeQIJARhrZXlTd2FwVXNlclNwZW50SW5QZXJpb2QBBQ51c2VyQWRkcmVzc1N0cgUOc3dhcFVzZG5Wb2x1bWUJAMwIAgkBDEludGVnZXJFbnRyeQIJARVrZXlVc2VyTGFzdFN3YXBIZWlnaHQBBQ51c2VyQWRkcmVzc1N0cgUGaGVpZ2h0CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEUdG90YWxMb2NrZWRCeVVzZXJLRVkCBQhzd2FwVHlwZQUOdXNlckFkZHJlc3NTdHIJAGQCBRF0b3RhbExvY2tlZEJ5VXNlcgUJcG10QW1vdW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEYZ2V0QmFsYW5jZVVubG9ja0Jsb2NrS2V5AQUOdXNlckFkZHJlc3NTdHIFEHNlbGZVbmxvY2tIZWlnaHQJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b3RhbExvY2tlZEtFWQEFCHN3YXBUeXBlCQBkAgULdG90YWxMb2NrZWQFCXBtdEFtb3VudAkAzAgCCQELU3RyaW5nRW50cnkCCQEHc3dhcEtFWQIFDnVzZXJBZGRyZXNzU3RyBQZ0eElkNTgJAQ9wZW5kaW5nU3dhcERBVEEDBQhzd2FwVHlwZQUJcG10QW1vdW50BRBzZWxmVW5sb2NrSGVpZ2h0BQNuaWwFCWxlYXNlUGFydAUEdW5pdAAPbk1ldHJpY0lkeFByaWNlAAAAG25NZXRyaWNJZHhVc2RuTG9ja2VkQmFsYW5jZQABABxuTWV0cmljSWR4V2F2ZXNMb2NrZWRCYWxhbmNlAAIAEW5NZXRyaWNJZHhSZXNlcnZlAAMAF25NZXRyaWNJZHhSZXNlcnZlSW5Vc2RuAAQAFG5NZXRyaWNJZHhVc2RuU3VwcGx5AAUAEW5NZXRyaWNJZHhTdXJwbHVzAAYAGG5NZXRyaWNJZHhTdXJwbHVzUGVyY2VudAAHAAxuTWV0cmljSWR4QlIACAAUbk1ldHJpY0lkeE5zYnRTdXBwbHkACQAXbk1ldHJpY0lkeE1heE5zYnRTdXBwbHkACgAUbk1ldHJpY0lkeFN1cmZTdXBwbHkACwASbk1ldHJpY1VzZG5Vc2R0UGVnAAwAFm5NZXRyaWNDdXJyZW50UHJpY2VBZGoADQAMYkZ1bmNJZHhTdXJmAAAADWJGdW5jSWR4V2F2ZXMAAQAMYkZ1bmNJZHhVc2RuAAIAFGJGdW5jSWR4UmVzZXJ2ZVN0YXJ0AAMAE2JGdW5jSWR4U3VwcGx5U3RhcnQABAAPYkZ1bmNJZHhCUlN0YXJ0AAUAEmJGdW5jSWR4UmVzZXJ2ZUVuZAAGABFiRnVuY0lkeFN1cHBseUVuZAAHAA1iRnVuY0lkeEJSRW5kAAgADGJGdW5jSWR4UmVzdAAJABJiRnVuY0lkeFdhdmVzUHJpY2UACgEPY2FsY1dpdGhkcmF3VzJVAgd3YXZlc0luBXByaWNlBAtvdXRBbXRHcm9zcwkBFmNvbnZlcnRXYXZlc1RvTmV1dHJpbm8CBQd3YXZlc0luBQVwcmljZQkAnAoKBQtvdXRBbXRHcm9zcwUPbmV1dHJpbm9Bc3NldElkAAAFBHVuaXQAAAUFcHJpY2UFB3dhdmVzSW4AAAAAAAABFGNhbGNXaXRoZHJhd1UyQmFza2V0BQZ1c2RuSW4FcHJpY2UCYnIOcmVzZXJ2ZXNJblVzZG4KdXNkblN1cHBseQQLYnJQcm90ZWN0ZWQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBDmJyUHJvdGVjdGVkS0VZAAULQlJQUk9URUNURUQEGW1heEFsbG93ZWRVc2RuQmVmb3JlTWluQnIDCQBnAgULYnJQcm90ZWN0ZWQFAmJyAAAJAGsDCQBlAgUOcmVzZXJ2ZXNJblVzZG4JAGsDBQticlByb3RlY3RlZAUKdXNkblN1cHBseQUFUEFVTEkFBVBBVUxJCQBlAgUFUEFVTEkFC2JyUHJvdGVjdGVkBBZhbGxvd2VkVXNkbkJlZm9yZU1pbkJyAwkAZgIFBnVzZG5JbgUZbWF4QWxsb3dlZFVzZG5CZWZvcmVNaW5CcgUZbWF4QWxsb3dlZFVzZG5CZWZvcmVNaW5CcgUGdXNkbkluBBVhbGxvd2VkVXNkbkFmdGVyTWluQnIDCQBmAgUGdXNkbkluBRltYXhBbGxvd2VkVXNkbkJlZm9yZU1pbkJyCQBrAwkAZQIFBnVzZG5JbgUZbWF4QWxsb3dlZFVzZG5CZWZvcmVNaW5CcgUCYnIFBVBBVUxJAAAEC2FsbG93ZWRVc2RuCQBkAgUWYWxsb3dlZFVzZG5CZWZvcmVNaW5CcgUVYWxsb3dlZFVzZG5BZnRlck1pbkJyBAl1c2RuMlNVUkYJAGUCBQZ1c2RuSW4FC2FsbG93ZWRVc2RuBAtvdXRBbXRHcm9zcwkBFmNvbnZlcnROZXV0cmlub1RvV2F2ZXMCBQthbGxvd2VkVXNkbgUFcHJpY2UJAJwKCgULb3V0QW10R3Jvc3MFBHVuaXQFCXVzZG4yU1VSRgUPbmV1dHJpbm9Bc3NldElkBQtvdXRBbXRHcm9zcwUFcHJpY2UFC2FsbG93ZWRVc2RuBRltYXhBbGxvd2VkVXNkbkJlZm9yZU1pbkJyBRZhbGxvd2VkVXNkbkJlZm9yZU1pbkJyBRVhbGxvd2VkVXNkbkFmdGVyTWluQnIBDGNhbGNXaXRoZHJhdwQIc3dhcFR5cGUIaW5BbW91bnQFcHJpY2UPbmV1dHJpbm9NZXRyaWNzBApvdXRGZWVQYXJ0CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQ1vdXRGZWVQYXJ0S0VZAQUIc3dhcFR5cGUFDkRFRkFVTFRTV0FQRkVFAwMJAGYCAAAFCm91dEZlZVBhcnQGCQBnAgUKb3V0RmVlUGFydAUFUEFVTEkJAAIBCQCsAgIJAKwCAgkArAICAh5pbnZhbGlkIG91dEZlZVBhcnQgY29uZmlnIGZvciAFCHN3YXBUeXBlAhIgc3dhcDogb3V0RmVlUGFydD0JAKQDAQUKb3V0RmVlUGFydAQLYnJQcm90ZWN0ZWQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBDmJyUHJvdGVjdGVkS0VZAAULQlJQUk9URUNURUQEAkJSCQEFYXNJbnQBCQCRAwIFD25ldXRyaW5vTWV0cmljcwUMbk1ldHJpY0lkeEJSBA5yZXNlcnZlc0luVXNkbgkBBWFzSW50AQkAkQMCBQ9uZXV0cmlub01ldHJpY3MFF25NZXRyaWNJZHhSZXNlcnZlSW5Vc2RuBAp1c2RuU3VwcGx5CQEFYXNJbnQBCQCRAwIFD25ldXRyaW5vTWV0cmljcwUUbk1ldHJpY0lkeFVzZG5TdXBwbHkECHByaWNlQWRqCQEFYXNJbnQBCQCRAwIFD25ldXRyaW5vTWV0cmljcwUWbk1ldHJpY0N1cnJlbnRQcmljZUFkagQMb3V0RGF0YVR1cGxlAwkAAAIFCHN3YXBUeXBlAgV3YXZlcwkBD2NhbGNXaXRoZHJhd1cyVQIFCGluQW1vdW50BQVwcmljZQMJAAACBQhzd2FwVHlwZQIIb3V0TXVsdGkJARRjYWxjV2l0aGRyYXdVMkJhc2tldAUFCGluQW1vdW50BQhwcmljZUFkagUCQlIFDnJlc2VydmVzSW5Vc2RuBQp1c2RuU3VwcGx5CQACAQkArAICAhZVbnN1cHBvcnRlZCBzd2FwIHR5cGUgBQhzd2FwVHlwZQQLb3V0QW10R3Jvc3MIBQxvdXREYXRhVHVwbGUCXzEECm91dEFzc2V0SWQIBQxvdXREYXRhVHVwbGUCXzIED2luQW10VG9TdXJmUGFydAgFDG91dERhdGFUdXBsZQJfMwQJaW5Bc3NldElkCAUMb3V0RGF0YVR1cGxlAl80BAp1bmxlYXNlQW10CAUMb3V0RGF0YVR1cGxlAl81BA13aXRoZHJhd1ByaWNlCAUMb3V0RGF0YVR1cGxlAl82BAxwYXlvdXRzQXJyYXkJAQlhcHBseUZlZXMDBQtvdXRBbXRHcm9zcwUPaW5BbXRUb1N1cmZQYXJ0BQpvdXRGZWVQYXJ0BAlvdXROZXRBbXQJAJEDAgUMcGF5b3V0c0FycmF5BQxJZHhOZXRBbW91bnQECW91dEZlZUFtdAkAkQMCBQxwYXlvdXRzQXJyYXkFDElkeEZlZUFtb3VudAQKb3V0U3VyZkFtdAMJAGcCAAAFD2luQW10VG9TdXJmUGFydAAABApzdXJmUmVzdWx0CQEJYXNBbnlMaXN0AQkA/AcEBQxtYXRoQ29udHJhY3QCFHN1cmZGdW5jdGlvblJFQURPTkxZCQDMCAIFD2luQW10VG9TdXJmUGFydAkAzAgCBQlpbkFzc2V0SWQFA25pbAUDbmlsCQEFYXNJbnQBCQCRAwIFCnN1cmZSZXN1bHQFDGJGdW5jSWR4U3VyZgkAmgoIBQlvdXROZXRBbXQFCm91dEFzc2V0SWQFCm91dFN1cmZBbXQFD2luQW10VG9TdXJmUGFydAUKdW5sZWFzZUFtdAUJb3V0RmVlQW10BQtvdXRBbXRHcm9zcwUNd2l0aGRyYXdQcmljZQEOY29tbW9uV2l0aGRyYXcFB2FjY291bnQFaW5kZXgIc3dhcFR4SWQMd2l0aGRyYXdUeElkD25ldXRyaW5vTWV0cmljcwQLdXNlckFkZHJlc3MJARFAZXh0ck5hdGl2ZSgxMDYyKQEFB2FjY291bnQECWRhdGFBcnJheQkBEnN3YXBEYXRhRmFpbE9yUkVBRAIFB2FjY291bnQFCHN3YXBUeElkBBBzZWxmVW5sb2NrSGVpZ2h0CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUJZGF0YUFycmF5BRRzSWR4U2VsZlVubG9ja0hlaWdodAQIc3dhcFR5cGUJAJEDAgUJZGF0YUFycmF5BQxzSWR4U3dhcFR5cGUECGluQW1vdW50CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUJZGF0YUFycmF5BQxzSWR4SW5BbW91bnQECnN3YXBTdGF0dXMJAJEDAgUJZGF0YUFycmF5BQpzSWR4U3RhdHVzBAtzdGFydEhlaWdodAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCWRhdGFBcnJheQUPc0lkeFN0YXJ0SGVpZ2h0BApvdXRGZWVQYXJ0CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQ1vdXRGZWVQYXJ0S0VZAQUIc3dhcFR5cGUFDkRFRkFVTFRTV0FQRkVFBAt0b3RhbExvY2tlZAkBD3RvdGFsTG9ja2VkUkVBRAEFCHN3YXBUeXBlBBF0b3RhbExvY2tlZEJ5VXNlcgkBFXRvdGFsTG9ja2VkQnlVc2VyUkVBRAIFCHN3YXBUeXBlBQdhY2NvdW50BAx1bmxvY2tIZWlnaHQFEHNlbGZVbmxvY2tIZWlnaHQEC2luZGV4SGVpZ2h0CQEVZ2V0SGVpZ2h0UHJpY2VCeUluZGV4AQUFaW5kZXgED3ByZXZJbmRleEhlaWdodAkBFWdldEhlaWdodFByaWNlQnlJbmRleAEJAGUCBQVpbmRleAABBAxwcmljZUJ5SW5kZXgJAQ9nZXRQcmljZUhpc3RvcnkBBQtpbmRleEhlaWdodAMFCWlzQmxvY2tlZAkBFWVtZXJnZW5jeVNodXRkb3duRkFJTAADCQECIT0CBQpzd2FwU3RhdHVzAgdQRU5ESU5HCQACAQIfc3dhcCBoYXMgYmVlbiBhbHJlYWR5IHByb2Nlc3NlZAMJAGYCBQx1bmxvY2tIZWlnaHQFBmhlaWdodAkAAgEJAKwCAgkArAICAhFwbGVhc2Ugd2FpdCBmb3I6IAkApAMBBQx1bmxvY2tIZWlnaHQCHyBibG9jayBoZWlnaHQgdG8gd2l0aGRyYXcgZnVuZHMDAwMJAGYCBQVpbmRleAUKcHJpY2VJbmRleAYJAGYCBQx1bmxvY2tIZWlnaHQFC2luZGV4SGVpZ2h0BgMJAQIhPQIFD3ByZXZJbmRleEhlaWdodAAACQBnAgUPcHJldkluZGV4SGVpZ2h0BQx1bmxvY2tIZWlnaHQHCQEOcHJpY2VJbmRleEZBSUwFBQVpbmRleAUKcHJpY2VJbmRleAULaW5kZXhIZWlnaHQFDHVubG9ja0hlaWdodAUPcHJldkluZGV4SGVpZ2h0BA13aXRoZHJhd1R1cGxlCQEMY2FsY1dpdGhkcmF3BAUIc3dhcFR5cGUFCGluQW1vdW50BQxwcmljZUJ5SW5kZXgFD25ldXRyaW5vTWV0cmljcwQMb3V0TmV0QW1vdW50CAUNd2l0aGRyYXdUdXBsZQJfMQQKb3V0QXNzZXRJZAgFDXdpdGhkcmF3VHVwbGUCXzIECm91dFN1cmZBbXQIBQ13aXRoZHJhd1R1cGxlAl8zBAp1bmxlYXNlQW10CAUNd2l0aGRyYXdUdXBsZQJfNQQMb3V0RmVlQW1vdW50CAUNd2l0aGRyYXdUdXBsZQJfNgQLb3V0QW10R3Jvc3MIBQ13aXRoZHJhd1R1cGxlAl83BA13aXRoZHJhd1ByaWNlCAUNd2l0aGRyYXdUdXBsZQJfOAMJAGcCAAAFC291dEFtdEdyb3NzCQACAQITYmFsYW5jZSBlcXVhbHMgemVybwQCQlIJAQVhc0ludAEJAJEDAgUPbmV1dHJpbm9NZXRyaWNzBQxuTWV0cmljSWR4QlIEBXN0YXRlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEUdG90YWxMb2NrZWRCeVVzZXJLRVkCBQhzd2FwVHlwZQUHYWNjb3VudAkAZQIFEXRvdGFsTG9ja2VkQnlVc2VyBQhpbkFtb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvdGFsTG9ja2VkS0VZAQUIc3dhcFR5cGUJAGUCBQt0b3RhbExvY2tlZAUIaW5BbW91bnQJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwULdXNlckFkZHJlc3MFDG91dE5ldEFtb3VudAUKb3V0QXNzZXRJZAkAzAgCCQELU3RyaW5nRW50cnkCCQEHc3dhcEtFWQIFB2FjY291bnQFCHN3YXBUeElkCQEOZmluaXNoU3dhcERBVEEKBQlkYXRhQXJyYXkFDXdpdGhkcmF3UHJpY2UFDG91dE5ldEFtb3VudAUMb3V0RmVlQW1vdW50BQx1bmxvY2tIZWlnaHQFBWluZGV4BQx3aXRoZHJhd1R4SWQFCm91dFN1cmZBbXQFAkJSAgRUT0RPBQNuaWwEDXN1cmZDb25kaXRpb24DCQBmAgUKb3V0U3VyZkFtdAAABAtpc3N1ZVJlc3VsdAkA/AcEBQ9hdWN0aW9uQ29udHJhY3QCCWlzc3VlU3VyZgkAzAgCBQpvdXRTdXJmQW10CQDMCAIFB2FjY291bnQFA25pbAUDbmlsAwkAAAIFC2lzc3VlUmVzdWx0BQtpc3N1ZVJlc3VsdAAACQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAAADCQAAAgUNc3VyZkNvbmRpdGlvbgUNc3VyZkNvbmRpdGlvbgkAlQoDBQVzdGF0ZQkBD0F0dGFjaGVkUGF5bWVudAIFCm91dEFzc2V0SWQFDG91dEZlZUFtb3VudAUKdW5sZWFzZUFtdAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgESa2V5QXBwbHlJblByb2dyZXNzAAITJXNfX2FwcGx5SW5Qcm9ncmVzcwETa2V5UHJvcG9zYWxEYXRhQnlJZAEKcHJvcG9zYWxJZAkArAICAhQlcyVkX19wcm9wb3NhbERhdGFfXwkApAMBBQpwcm9wb3NhbElkAAtnb3ZJZHhUeElkcwAJAQ52YWxpZGF0ZVVwZGF0ZQECdHgEByRtYXRjaDAFAnR4AwkAAQIFByRtYXRjaDACBU9yZGVyBAFvBQckbWF0Y2gwCQACAQIVT3JkZXJzIGFyZW4ndCBhbGxvd2VkAwMJAAECBQckbWF0Y2gwAg9EYXRhVHJhbnNhY3Rpb24GAwkAAQIFByRtYXRjaDACFVNwb25zb3JGZWVUcmFuc2FjdGlvbgYDCQABAgUHJG1hdGNoMAIUU2V0U2NyaXB0VHJhbnNhY3Rpb24GAwkAAQIFByRtYXRjaDACFkNyZWF0ZUFsaWFzVHJhbnNhY3Rpb24GAwkAAQIFByRtYXRjaDACFkxlYXNlQ2FuY2VsVHJhbnNhY3Rpb24GAwkAAQIFByRtYXRjaDACEExlYXNlVHJhbnNhY3Rpb24GAwkAAQIFByRtYXRjaDACEElzc3VlVHJhbnNhY3Rpb24GAwkAAQIFByRtYXRjaDACG0ludm9rZUV4cHJlc3Npb25UcmFuc2FjdGlvbgYDCQABAgUHJG1hdGNoMAIaVXBkYXRlQXNzZXRJbmZvVHJhbnNhY3Rpb24GAwkAAQIFByRtYXRjaDACF0ludm9rZVNjcmlwdFRyYW5zYWN0aW9uBgMJAAECBQckbWF0Y2gwAhlTZXRBc3NldFNjcmlwdFRyYW5zYWN0aW9uBgMJAAECBQckbWF0Y2gwAhNUcmFuc2ZlclRyYW5zYWN0aW9uBgMJAAECBQckbWF0Y2gwAhNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAECBQckbWF0Y2gwAhdNYXNzVHJhbnNmZXJUcmFuc2FjdGlvbgYDCQABAgUHJG1hdGNoMAIPQnVyblRyYW5zYWN0aW9uBgkAAQIFByRtYXRjaDACElJlaXNzdWVUcmFuc2FjdGlvbgQBdAUHJG1hdGNoMAQEdHhJZAkA2AQBCAUBdAJpZAQKcHJvcG9zYWxJZAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFC2dvdkNvbnRyYWN0CQESa2V5QXBwbHlJblByb2dyZXNzAAIWQXBwbHkgaXMgbm90IGhhcHBlbmluZwQGdHhMaXN0CQC1CQIJAJEDAgkAtQkCCQEPZ2V0U3RyaW5nT3JGYWlsAgULZ292Q29udHJhY3QJARNrZXlQcm9wb3NhbERhdGFCeUlkAQUKcHJvcG9zYWxJZAUDU0VQBQtnb3ZJZHhUeElkcwUHTElTVFNFUAMJAQEhAQkBCWlzRGVmaW5lZAEJAM8IAgUGdHhMaXN0BQR0eElkCQACAQkArAICCQCsAgIJAKwCAgIOVW5rbm93biB0eElkOiAFBHR4SWQCECBmb3IgcHJvcG9zYWxJZD0JAKQDAQUKcHJvcG9zYWxJZAYJAAIBAgtNYXRjaCBlcnJvcg8BaQENY29uc3RydWN0b3JWMQ0SbmV1dHJpbm9Bc3NldElkUHJtDmJvbmRBc3NldElkUHJtEmF1Y3Rpb25Db250cmFjdFBybRZsaXF1aWRhdGlvbkNvbnRyYWN0UHJtDnJwZENvbnRyYWN0UHJtG25vZGVPcmFjbGVQcm92aWRlclB1YktleVBybRtiYWxhbmNlV2F2ZXNMb2NrSW50ZXJ2YWxQcm0eYmFsYW5jZU5ldXRyaW5vTG9ja0ludGVydmFsUHJtFW1pbldhdmVzU3dhcEFtb3VudFBybRhtaW5OZXV0cmlub1N3YXBBbW91bnRQcm0VbmV1dHJpbm9PdXRGZWVQYXJ0UHJtEndhdmVzT3V0RmVlUGFydFBybRJtdWx0aU91dEZlZVBhcnRQcm0EC2NoZWNrQ2FsbGVyCQEIdGhpc09ubHkBBQFpAwkAAAIFC2NoZWNrQ2FsbGVyBQtjaGVja0NhbGxlcgMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAAkAAgECE25vIHBheW1lbnRzIGFsbG93ZWQJAMwIAgkBC1N0cmluZ0VudHJ5AgUSTmV1dHJpbm9Bc3NldElkS2V5BRJuZXV0cmlub0Fzc2V0SWRQcm0JAMwIAgkBC1N0cmluZ0VudHJ5AgUOQm9uZEFzc2V0SWRLZXkFDmJvbmRBc3NldElkUHJtCQDMCAIJAQtTdHJpbmdFbnRyeQIFEkF1Y3Rpb25Db250cmFjdEtleQUSYXVjdGlvbkNvbnRyYWN0UHJtCQDMCAIJAQtTdHJpbmdFbnRyeQIFFkxpcXVpZGF0aW9uQ29udHJhY3RLZXkFFmxpcXVpZGF0aW9uQ29udHJhY3RQcm0JAMwIAgkBC1N0cmluZ0VudHJ5AgUOUlBEQ29udHJhY3RLZXkFDnJwZENvbnRyYWN0UHJtCQDMCAIJAQtTdHJpbmdFbnRyeQIFG05vZGVPcmFjbGVQcm92aWRlclB1YktleUtleQUbbm9kZU9yYWNsZVByb3ZpZGVyUHViS2V5UHJtCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRtCYWxhbmNlV2F2ZXNMb2NrSW50ZXJ2YWxLZXkFG2JhbGFuY2VXYXZlc0xvY2tJbnRlcnZhbFBybQkAzAgCCQEMSW50ZWdlckVudHJ5AgUeQmFsYW5jZU5ldXRyaW5vTG9ja0ludGVydmFsS2V5BR5iYWxhbmNlTmV1dHJpbm9Mb2NrSW50ZXJ2YWxQcm0JAMwIAgkBDEludGVnZXJFbnRyeQIFFU1pbldhdmVzU3dhcEFtb3VudEtleQUVbWluV2F2ZXNTd2FwQW1vdW50UHJtCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRhNaW5OZXV0cmlub1N3YXBBbW91bnRLZXkFGG1pbk5ldXRyaW5vU3dhcEFtb3VudFBybQkAzAgCCQEMSW50ZWdlckVudHJ5AgUVTmV1dHJpbm9PdXRGZWVQYXJ0S2V5BRVuZXV0cmlub091dEZlZVBhcnRQcm0JAMwIAgkBDEludGVnZXJFbnRyeQIFEldhdmVzT3V0RmVlUGFydEtleQUSd2F2ZXNPdXRGZWVQYXJ0UHJtCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRJNdWx0aU91dEZlZVBhcnRLZXkFEm11bHRpT3V0RmVlUGFydFBybQUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDWNvbnN0cnVjdG9yVjIDDG1hdGhDb250cmFjdBNuc2J0U3Rha2luZ0NvbnRyYWN0FHN3YXBzVGltZWZyYW1lQmxvY2tzBAtjaGVja0NhbGxlcgkBCHRoaXNPbmx5AQUBaQMJAAACBQtjaGVja0NhbGxlcgULY2hlY2tDYWxsZXIDCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAAJAAIBAhNubyBwYXltZW50cyBhbGxvd2VkCQDMCAIJAQtTdHJpbmdFbnRyeQIFD01hdGhDb250cmFjdEtleQUMbWF0aENvbnRyYWN0CQDMCAIJAQtTdHJpbmdFbnRyeQIFFk5zYnRTdGFraW5nQ29udHJhY3RLZXkFE25zYnRTdGFraW5nQ29udHJhY3QJAMwIAgkBDEludGVnZXJFbnRyeQIJARFzd2Fwc1RpbWVmcmFtZUtFWQAFFHN3YXBzVGltZWZyYW1lQmxvY2tzBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQETc3dhcFdhdmVzVG9OZXV0cmlubwADCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAEJAAIBAixzd2FwV2F2ZXNUb05ldXRyaW5vIHJlcXVpcmUgb25seSBvbmUgcGF5bWVudAQDcG10CQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAADCQEJaXNEZWZpbmVkAQgFA3BtdAdhc3NldElkCQACAQIpT25seSBXYXZlcyB0b2tlbiBpcyBhbGxvd2VkIGZvciBzd2FwcGluZy4EC3VzZXJBZGRyZXNzCQClCAEIBQFpBmNhbGxlcgQGdHhJZDU4CQDYBAEIBQFpDXRyYW5zYWN0aW9uSWQJAQpjb21tb25Td2FwBAIFd2F2ZXMIBQNwbXQGYW1vdW50BQt1c2VyQWRkcmVzcwUGdHhJZDU4AWkBFHN3YXBOZXV0cmlub1RvQmFza2V0AAMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAQkAAgECLXN3YXBOZXV0cmlub1RvQmFza2V0IHJlcXVpcmUgb25seSBvbmUgcGF5bWVudAQDcG10CQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAADCQECIT0CCAUDcG10B2Fzc2V0SWQFD25ldXRyaW5vQXNzZXRJZAkAAgECOk9ubHkgYXBwcm9wcmlhdGUgTmV1dHJpbm8gdG9rZW5zIGFyZSBhbGxvd2VkIGZvciBzd2FwcGluZy4EC3VzZXJBZGRyZXNzCQClCAEIBQFpBmNhbGxlcgQGdHhJZDU4CQDYBAEIBQFpDXRyYW5zYWN0aW9uSWQJAQpjb21tb25Td2FwBAIIb3V0TXVsdGkIBQNwbXQGYW1vdW50BQt1c2VyQWRkcmVzcwUGdHhJZDU4AWkBCHdpdGhkcmF3AwdhY2NvdW50BWluZGV4CHN3YXBUeElkBAR0eElkCQDYBAEIBQFpDXRyYW5zYWN0aW9uSWQDCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAAJAAIBAhNubyBwYXltZW50cyBhbGxvd2VkBA9uZXV0cmlub01ldHJpY3MJAQlhc0FueUxpc3QBCQD8BwQFDG1hdGhDb250cmFjdAIaY2FsY05ldXRpbm9NZXRyaWNzUkVBRE9OTFkFA25pbAUDbmlsBAJCUgkBBWFzSW50AQkAkQMCBQ9uZXV0cmlub01ldHJpY3MFDG5NZXRyaWNJZHhCUgQLY29tbW9uVHVwbGUJAQ5jb21tb25XaXRoZHJhdwUFB2FjY291bnQFBWluZGV4BQhzd2FwVHhJZAUEdHhJZAUPbmV1dHJpbm9NZXRyaWNzBAVzdGF0ZQgFC2NvbW1vblR1cGxlAl8xBANmZWUIBQtjb21tb25UdXBsZQJfMgQKdW5sZWFzZUFtdAgFC2NvbW1vblR1cGxlAl8zBBF1bmxlYXNlSW52T3JFbXB0eQkA/AcEBQR0aGlzAhdpbnRlcm5hbFVubGVhc2VBbmRMZWFzZQkAzAgCBQp1bmxlYXNlQW10BQNuaWwFA25pbAMJAAACBRF1bmxlYXNlSW52T3JFbXB0eQURdW5sZWFzZUludk9yRW1wdHkECWduc2J0RGF0YQkBCWFzQW55TGlzdAEJAPwHBAUXZ25zYnRDb250cm9sbGVyQ29udHJhY3QCFGduc2J0SW5mb1NZU1JFQURPTkxZCQDMCAICAAkAzAgCAAAJAMwIAgAABQNuaWwFA25pbAQNZ25zYnRBbXRUb3RhbAkBBWFzSW50AQkAkQMCBQlnbnNidERhdGEAAQQVZ25zYnRBbXRGcm9tU3VyZlRvdGFsCQEFYXNJbnQBCQCRAwIJAQlhc0FueUxpc3QBCQCRAwIFCWduc2J0RGF0YQADAAMEC3N1cmZGZWVBbXQxAwkBAiE9AgUNZ25zYnRBbXRUb3RhbAAACQBrAwgFA2ZlZQZhbW91bnQFFWduc2J0QW10RnJvbVN1cmZUb3RhbAUNZ25zYnRBbXRUb3RhbAAABAtzdXJmRmVlQW10MgMJAQIhPQIFDWduc2J0QW10VG90YWwAAAkAawMIBQNmZWUGYW1vdW50CQBlAgUFUEFVTEkFAkJSBQVQQVVMSQAABApzdXJmRmVlQW10CQCWAwEJAMwIAgULc3VyZkZlZUFtdDEJAMwIAgULc3VyZkZlZUFtdDIFA25pbAQKbnNidEZlZUFtdAkAZQIIBQNmZWUGYW1vdW50BQpzdXJmRmVlQW10BAtzdXJmRGVwb3NpdAMJAGYCBQpzdXJmRmVlQW10AAAEB3N1cmZJbnYJAPwHBAUTc3VyZlN0YWtpbmdDb250cmFjdAIHZGVwb3NpdAUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCAUDZmVlB2Fzc2V0SWQFCnN1cmZGZWVBbXQFA25pbAMJAAACBQdzdXJmSW52BQdzdXJmSW52BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBQtzdXJmRGVwb3NpdAULc3VyZkRlcG9zaXQEC25zYnREZXBvc2l0AwkAZgIFCm5zYnRGZWVBbXQAAAQHbnNidEludgkA/AcEBRNuc2J0U3Rha2luZ0NvbnRyYWN0AgdkZXBvc2l0BQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIIBQNmZWUHYXNzZXRJZAUKbnNidEZlZUFtdAUDbmlsAwkAAAIFB25zYnRJbnYFB25zYnRJbnYFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFC25zYnREZXBvc2l0BQtuc2J0RGVwb3NpdAUFc3RhdGUJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEXaW50ZXJuYWxVbmxlYXNlQW5kTGVhc2UBDXVubGVhc2VBbW91bnQDCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAAIBAixpbnRlcm5hbFVubGVhc2VBbmRMZWFzZSBpcyBub3QgcHVibGljIG1ldGhvZAkBFnByZXBhcmVVbmxlYXNlQW5kTGVhc2UBBQ11bmxlYXNlQW1vdW50AWkBEnRyYW5zZmVyVXNkblRvVXNlcgIGYW1vdW50BGFkZHIDCQECIT0CCAUBaQZjYWxsZXIFD2F1Y3Rpb25Db250cmFjdAkAAgECI09ubHkgYXVjdGlvbiBjb250cmFjdCBpcyBhdXRob3JpemVkCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMJARFAZXh0ck5hdGl2ZSgxMDYyKQEFBGFkZHIFBmFtb3VudAUPbmV1dHJpbm9Bc3NldElkBQNuaWwBaQELYWNjZXB0V2F2ZXMAAwMJAQIhPQIIBQFpBmNhbGxlcgUPYXVjdGlvbkNvbnRyYWN0CQECIT0CCAUBaQZjYWxsZXIFC2dvdkNvbnRyYWN0BwkAAgECQ0N1cnJlbnRseSBvbmx5IGF1Y3Rpb24gYW5kIGdvdmVybmFuY2UgY29udHJhY3RzIGFyZSBhbGxvd2VkIHRvIGNhbGwJAJQKAgkBFnByZXBhcmVVbmxlYXNlQW5kTGVhc2UBAAACB3N1Y2Nlc3MBaQEPYXBwcm92ZUxlYXNpbmdzAwZuTGlzdFMIZ3JvdXBOdW0EbEFtdAQFbklkeHMJAMwIAgAACQDMCAIAAQkAzAgCAAIJAMwIAgADCQDMCAIABAkAzAgCAAUJAMwIAgAGCQDMCAIABwUDbmlsBAdtbmdQdWJTCQELdmFsdWVPckVsc2UCCQCiCAECHCVzJXNfX2NmZ19fbGVhc2luZ01hbmFnZXJQdWICLDdBVU1YNTR1a1lNWXZQbW1hN3lvRmY1TmpaaHM0QnU1bnozRXo5RVY4c3VyBAZtbmdQdWIJANkEAQUHbW5nUHViUwQObm9kZVJlZ0FkZHJTdHIJAQt2YWx1ZU9yRWxzZQIJAKIIAQIfJXMlc19fY2ZnX19ub2Rlc1JlZ2lzdHJ5QWRkcmVzcwIjM1A5dktxUUtqVWRtcFhBZmlXYXU4a3JSRVlBWTFYcjY5cEUEC25vZGVSZWdBZGRyCQERQGV4dHJOYXRpdmUoMTA2MikBBQ5ub2RlUmVnQWRkclN0cgQRbEdyb3VwTm9kZUxpc3RLRVkJARhnZXRMZWFzZUdyb3VwTm9kZUxpc3RLZXkBBQhncm91cE51bQQKbEdyTm9kZU9wdAkAnQgCBQR0aGlzBRFsR3JvdXBOb2RlTGlzdEtFWQMJAQlpc0RlZmluZWQBBQpsR3JOb2RlT3B0CQACAQkArAICCQCsAgICBmdyb3VwIAkApAMBBQhncm91cE51bQIUIGFscmVhZHkgaW5pdGlhbGl6ZWQEBW5MaXN0CQC1CQIFBm5MaXN0UwUDU0VQBAhleHBDb3VudAkAkAMBBQVuSWR4cwMJAQIhPQIIBQFpD2NhbGxlclB1YmxpY0tleQUGbW5nUHViCQACAQIeYXBwcm92ZUxlYXNpbmdzIG5vdCBhdXRob3JpemVkBA0kdDAzNTc3MDM1ODMyCQEMcmVhZE5vZGVJbmZvAQAABAZuQWRkcjAIBQ0kdDAzNTc3MDM1ODMyAl8xBAhsQW10S0VZMAgFDSR0MDM1NzcwMzU4MzICXzIEBWxBbXQwCAUNJHQwMzU3NzAzNTgzMgJfMwQHbElkS0VZMAgFDSR0MDM1NzcwMzU4MzICXzQEBGxJZDAIBQ0kdDAzNTc3MDM1ODMyAl81BAVuZXdMMAkAxAgCBQZuQWRkcjAJAGUCBQVsQW10MAkAaAIFBGxBbXQFCGV4cENvdW50BAp2YWxpZGF0aW9uCQD8BwQFC25vZGVSZWdBZGRyAhp2YWxpZGF0ZUFuZEFwcHJvdmVMZWFzaW5ncwkAzAgCBQZuTGlzdFMFA25pbAUDbmlsAwkAAAIFCnZhbGlkYXRpb24FCnZhbGlkYXRpb24KASNmb3JFYWNoTm9kZVZhbGlkYXRlQW5kR2VuZXJhdGVMZWFzZQIBYQFpBARub2RlCQCRAwIFBW5MaXN0BQFpBAJsYQkAxAgCCQERQGV4dHJOYXRpdmUoMTA2MikBBQRub2RlBQRsQW10CQDOCAIFAWEJAMwIAgUCbGEJAMwIAgkBC0JpbmFyeUVudHJ5AgkBFmdldExlYXNlSWRCeUFkZHJlc3NLZXkBBQRub2RlCQEFbGNhbGMBBQJsYQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBGmdldExlYXNlQW1vdW50QnlBZGRyZXNzS2V5AQUEbm9kZQUEbEFtdAUDbmlsCQDOCAIJAMwIAgkBC1N0cmluZ0VudHJ5AgURbEdyb3VwTm9kZUxpc3RLRVkFBm5MaXN0UwkAzAgCCQELQmluYXJ5RW50cnkCBQdsSWRLRVkwCQEFbGNhbGMBBQVuZXdMMAkAzAgCCQEMSW50ZWdlckVudHJ5AgUIbEFtdEtFWTAIBQVuZXdMMAZhbW91bnQJAMwIAgkBC0xlYXNlQ2FuY2VsAQUEbElkMAkAzAgCBQVuZXdMMAUDbmlsCgACJGwFBW5JZHhzCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJASNmb3JFYWNoTm9kZVZhbGlkYXRlQW5kR2VuZXJhdGVMZWFzZQIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQITTGlzdCBzaXplIGV4Y2VlZHMgOAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQERcmViYWxhbmNlTGVhc2luZ3MCBmFtb3VudAhncm91cE51bQQFbklkeHMJAMwIAgAACQDMCAIAAQkAzAgCAAIJAMwIAgADCQDMCAIABAkAzAgCAAUJAMwIAgAGCQDMCAIABwUDbmlsBAdtbmdQdWJTCQELdmFsdWVPckVsc2UCCQCiCAECHCVzJXNfX2NmZ19fbGVhc2luZ01hbmFnZXJQdWICLDdBVU1YNTR1a1lNWXZQbW1hN3lvRmY1TmpaaHM0QnU1bnozRXo5RVY4c3VyBAZtbmdQdWIJANkEAQUHbW5nUHViUwQRbEdyb3VwTm9kZUxpc3RLRVkJARhnZXRMZWFzZUdyb3VwTm9kZUxpc3RLZXkBBQhncm91cE51bQQGbkxpc3RTCQEPZ2V0U3RyaW5nT3JGYWlsAgUEdGhpcwURbEdyb3VwTm9kZUxpc3RLRVkEBW5MaXN0CQC1CQIFBm5MaXN0UwUDU0VQAwkBAiE9AggFAWkPY2FsbGVyUHVibGljS2V5BQZtbmdQdWIJAAIBAiByZWJhbGFuY2VMZWFzaW5ncyBub3QgYXV0aG9yaXplZAQKdW5sZWFzZUFtdAkAZAIJAGkCBQZhbW91bnQJAJADAQUFbkxpc3QAAQQNJHQwMzcwNzIzNzEzNAkBDHJlYWROb2RlSW5mbwEAAAQGbkFkZHIwCAUNJHQwMzcwNzIzNzEzNAJfMQQIbEFtdEtFWTAIBQ0kdDAzNzA3MjM3MTM0Al8yBAVsQW10MAgFDSR0MDM3MDcyMzcxMzQCXzMEB2xJZEtFWTAIBQ0kdDAzNzA3MjM3MTM0Al80BARsSWQwCAUNJHQwMzcwNzIzNzEzNAJfNQQFbmV3TDAJAMQIAgUGbkFkZHIwCQBkAgUFbEFtdDAJAGgCBQp1bmxlYXNlQW10CQCQAwEFBW5MaXN0CgEUZm9yRWFjaE5vZGVEb1VubGVhc2UCAWEBaQQEbm9kZQkAkQMCBQVuTGlzdAUBaQQGbElkS0VZCQEWZ2V0TGVhc2VJZEJ5QWRkcmVzc0tleQEFBG5vZGUEA2xJZAkBEUBleHRyTmF0aXZlKDEwNTIpAgUEdGhpcwUGbElkS0VZBAdsQW10S0VZCQEaZ2V0TGVhc2VBbW91bnRCeUFkZHJlc3NLZXkBBQRub2RlBARsQW10CQERQGV4dHJOYXRpdmUoMTA1MCkCBQR0aGlzBQdsQW10S0VZBAN1bGEJAQtMZWFzZUNhbmNlbAEJAQV2YWx1ZQEFA2xJZAQCbGEJAMQIAgkBEUBleHRyTmF0aXZlKDEwNjIpAQUEbm9kZQkAZQIFBGxBbXQFCnVubGVhc2VBbXQJAM4IAgUBYQkAzAgCCQELTGVhc2VDYW5jZWwBCQEFdmFsdWUBBQNsSWQJAMwIAgUCbGEJAMwIAgkBC0JpbmFyeUVudHJ5AgUGbElkS0VZCQEFbGNhbGMBBQJsYQkAzAgCCQEMSW50ZWdlckVudHJ5AgUHbEFtdEtFWQgFAmxhBmFtb3VudAUDbmlsCQDOCAIKAAIkbAUFbklkeHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBFGZvckVhY2hOb2RlRG9VbmxlYXNlAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhNMaXN0IHNpemUgZXhjZWVkcyA4CQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAkAzAgCCQELQmluYXJ5RW50cnkCBQdsSWRLRVkwCQEFbGNhbGMBBQVuZXdMMAkAzAgCCQEMSW50ZWdlckVudHJ5AgUIbEFtdEtFWTAIBQVuZXdMMAZhbW91bnQJAMwIAgkBC0xlYXNlQ2FuY2VsAQUEbElkMAkAzAgCBQVuZXdMMAUDbmlsAWkBG3N3YXBQYXJhbXNCeVVzZXJTWVNSRUFET05MWQIOdXNlckFkZHJlc3NTdHIJZ25zYnREaWZmBAlnbnNidERhdGEJAQlhc0FueUxpc3QBCQD8BwQFF2duc2J0Q29udHJvbGxlckNvbnRyYWN0AhRnbnNidEluZm9TWVNSRUFET05MWQkAzAgCBQ51c2VyQWRkcmVzc1N0cgkAzAgCAAAJAMwIAgAABQNuaWwFA25pbAQIZ25zYnRBbXQJAGQCCQEFYXNJbnQBCQCRAwIFCWduc2J0RGF0YQAABQlnbnNidERpZmYEDWduc2J0QW10VG90YWwJAGQCCQEFYXNJbnQBCQCRAwIFCWduc2J0RGF0YQABBQlnbnNidERpZmYEDXN3YXBMaW1pdERhdGEJAQlhc0FueUxpc3QBCQD8BwQFDG1hdGhDb250cmFjdAIVY2FsY1N3YXBMaW1pdFJFQURPTkxZCQDMCAIFCGduc2J0QW10BQNuaWwFA25pbAQXd2F2ZXNTd2FwTGltaXRJblVzZG5NYXgJAQVhc0ludAEJAJEDAgUNc3dhcExpbWl0RGF0YQAABBF3YXZlc1N3YXBMaW1pdE1heAkBBWFzSW50AQkAkQMCBQ1zd2FwTGltaXREYXRhAAEEEHVzZG5Td2FwTGltaXRNYXgJAQVhc0ludAEJAJEDAgUNc3dhcExpbWl0RGF0YQACBA5sYXN0U3dhcEhlaWdodAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEVa2V5VXNlckxhc3RTd2FwSGVpZ2h0AQUOdXNlckFkZHJlc3NTdHIAAAQXc3dhcExpbWl0VGltZWxpZmVCbG9ja3MJARJzd2Fwc1RpbWVmcmFtZVJFQUQABBlwYXNzZWRCbG9ja3NBZnRlckxhc3RTd2FwCQBlAgUGaGVpZ2h0BQ5sYXN0U3dhcEhlaWdodAQRaXNTd2FwVGltZWxpZmVOZXcJAGcCBRlwYXNzZWRCbG9ja3NBZnRlckxhc3RTd2FwBRdzd2FwTGltaXRUaW1lbGlmZUJsb2NrcwQUc3dhcExpbWl0U3BlbnRJblVzZG4DBRFpc1N3YXBUaW1lbGlmZU5ldwAACQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJARhrZXlTd2FwVXNlclNwZW50SW5QZXJpb2QBBQ51c2VyQWRkcmVzc1N0cgAABA5ibGNrczJMbXRSZXNldAMFEWlzU3dhcFRpbWVsaWZlTmV3AAAJAGUCBRdzd2FwTGltaXRUaW1lbGlmZUJsb2NrcwUZcGFzc2VkQmxvY2tzQWZ0ZXJMYXN0U3dhcAkAlAoCBQNuaWwJAJkKBwUXd2F2ZXNTd2FwTGltaXRJblVzZG5NYXgFFHN3YXBMaW1pdFNwZW50SW5Vc2RuBQ5ibGNrczJMbXRSZXNldAUIZ25zYnRBbXQFDWduc2J0QW10VG90YWwFEXdhdmVzU3dhcExpbWl0TWF4BRB1c2RuU3dhcExpbWl0TWF4AWkBHWNhbGNXaXRoZHJhd1Jlc3VsdFNZU1JFQURPTkxZAwhzd2FwVHlwZQhpbkFtb3VudAVwcmljZQQPbmV1dHJpbm9NZXRyaWNzCQEJYXNBbnlMaXN0AQkA/AcEBQxtYXRoQ29udHJhY3QCGmNhbGNOZXV0aW5vTWV0cmljc1JFQURPTkxZBQNuaWwFA25pbAkAlAoCBQNuaWwJAQxjYWxjV2l0aGRyYXcEBQhzd2FwVHlwZQUIaW5BbW91bnQFBXByaWNlBQ9uZXV0cmlub01ldHJpY3MBaQEUcmVwbGFjZUNvbW11bml0eU5vZGUECm9sZEFkZHJTdHIKbmV3QWRkclN0cghncm91cE51bQ1wZW5hbHR5QW1vdW50BAdtbmdQdWJTCQELdmFsdWVPckVsc2UCCQCiCAECHCVzJXNfX2NmZ19fbGVhc2luZ01hbmFnZXJQdWICLDdBVU1YNTR1a1lNWXZQbW1hN3lvRmY1TmpaaHM0QnU1bnozRXo5RVY4c3VyBAZtbmdQdWIJANkEAQUHbW5nUHViUwMJAQIhPQIIBQFpD2NhbGxlclB1YmxpY0tleQUGbW5nUHViCQACAQIjcmVwbGFjZUNvbW11bml0eU5vZGUgbm90IGF1dGhvcml6ZWQECGdyb3VwS2V5CQEYZ2V0TGVhc2VHcm91cE5vZGVMaXN0S2V5AQUIZ3JvdXBOdW0EDmdyb3VwTm9kZUxpc3RTCQEPZ2V0U3RyaW5nT3JGYWlsAgUEdGhpcwUIZ3JvdXBLZXkDCQEBIQEJAQhjb250YWlucwIFDmdyb3VwTm9kZUxpc3RTBQpvbGRBZGRyU3RyCQACAQkArAICCQCsAgIJAKwCAgIGR3JvdXAgCQCkAwEFCGdyb3VwTnVtAhogZG9lcyBub3QgY29udGFpbiBhZGRyZXNzIAUKb2xkQWRkclN0cgQJZG9SZXBsYWNlCQD8BwQFFG5vZGVSZWdpc3RyeUNvbnRyYWN0AhNyZXBsYWNlQXBwcm92ZWROb2RlCQDMCAIFCm9sZEFkZHJTdHIJAMwIAgUKbmV3QWRkclN0cgkAzAgCBQhncm91cE51bQkAzAgCBQ1wZW5hbHR5QW1vdW50BQNuaWwFA25pbAMJAAACBQlkb1JlcGxhY2UFCWRvUmVwbGFjZQQNb2xkTGVhc2VJZEtleQkBFmdldExlYXNlSWRCeUFkZHJlc3NLZXkBBQpvbGRBZGRyU3RyBA5vbGRMZWFzZUFtdEtleQkBGmdldExlYXNlQW1vdW50QnlBZGRyZXNzS2V5AQUKb2xkQWRkclN0cgQIbGVhc2VBbXQJARFAZXh0ck5hdGl2ZSgxMDU1KQEFDm9sZExlYXNlQW10S2V5BA1uZXdMZWFzZUlkS2V5CQEWZ2V0TGVhc2VJZEJ5QWRkcmVzc0tleQEFCm9sZEFkZHJTdHIEDm5ld0xlYXNlQW10S2V5CQEaZ2V0TGVhc2VBbW91bnRCeUFkZHJlc3NLZXkBBQpvbGRBZGRyU3RyBAhuZXdMZWFzZQkAxAgCCQERQGV4dHJOYXRpdmUoMTA2MikBBQpuZXdBZGRyU3RyBQhsZWFzZUFtdAQVdXBkYXRlZEdyb3VwTm9kZUxpc3RTCQC5CQIJALUJAgUOZ3JvdXBOb2RlTGlzdFMFCm9sZEFkZHJTdHIFCm5ld0FkZHJTdHIJAJQKAgkAzAgCCQELTGVhc2VDYW5jZWwBCQERQGV4dHJOYXRpdmUoMTA1NykBBQ1vbGRMZWFzZUlkS2V5CQDMCAIJAQtEZWxldGVFbnRyeQEFDW9sZExlYXNlSWRLZXkJAMwIAgkBC0RlbGV0ZUVudHJ5AQUOb2xkTGVhc2VBbXRLZXkJAMwIAgkBC1N0cmluZ0VudHJ5AgUIZ3JvdXBLZXkFFXVwZGF0ZWRHcm91cE5vZGVMaXN0UwkAzAgCBQhuZXdMZWFzZQkAzAgCCQELQmluYXJ5RW50cnkCBQ1uZXdMZWFzZUlkS2V5CQEFbGNhbGMBBQhuZXdMZWFzZQkAzAgCCQEMSW50ZWdlckVudHJ5AgUObmV3TGVhc2VBbXRLZXkFCGxlYXNlQW10BQNuaWwFBHVuaXQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEfdXBkYXRlUmVzZXJ2ZXNBbmROZXV0cmlub1N1cHBseQAKARZnZXROdW1iZXJCeUtleUludGVybmFsAQNrZXkEByRtYXRjaDAJAJoIAgUEdGhpcwUDa2V5AwkAAQIFByRtYXRjaDACA0ludAQBYQUHJG1hdGNoMAUBYQAABAduTWV0cml4CQEJYXNBbnlMaXN0AQkA/AcEBQxtYXRoQ29udHJhY3QCGmNhbGNOZXV0aW5vTWV0cmljc1JFQURPTkxZBQNuaWwFA25pbAQDaWR4CQEWZ2V0TnVtYmVyQnlLZXlJbnRlcm5hbAECInVwZGF0ZVJlc2VydmVzQW5kTmV1dHJpbm9TdXBwbHlJZHgEBm5ld0lkeAkAZAIFA2lkeAABCQDMCAIJAQxJbnRlZ2VyRW50cnkCAiJ1cGRhdGVSZXNlcnZlc0FuZE5ldXRyaW5vU3VwcGx5SWR4BQZuZXdJZHgJAMwIAgkBDEludGVnZXJFbnRyeQICB3Jlc2VydmUJAQVhc0ludAEJAJEDAgUHbk1ldHJpeAADCQDMCAIJAQxJbnRlZ2VyRW50cnkCAg5uZXV0cmlub1N1cHBseQkBBWFzSW50AQkAkQMCBQduTWV0cml4AAUJAMwIAgkBDEludGVnZXJFbnRyeQICDnJlc2VydmVzSW5Vc2RuCQEWY29udmVydFdhdmVzVG9OZXV0cmlubwIJAQVhc0ludAEJAJEDAgUHbk1ldHJpeAADCQEFYXNJbnQBCQCRAwIFB25NZXRyaXgAAAkAzAgCCQEMSW50ZWdlckVudHJ5AgIHc3VycGx1cwkBBWFzSW50AQkAkQMCBQduTWV0cml4AAYJAMwIAgkBDEludGVnZXJFbnRyeQICB2RlZmljaXQJAQEtAQkBBWFzSW50AQkAkQMCBQduTWV0cml4AAYFA25pbAFpARZ3YXZlc0JhbGFuY2VzVnNQYXltZW50AAQBYgkA7wcBBQR0aGlzCQDMCAIJAQxJbnRlZ2VyRW50cnkCAhZ3YXZlc0JhbGFuY2VfYXZhaWxhYmxlCAUBYglhdmFpbGFibGUJAMwIAgkBDEludGVnZXJFbnRyeQICFHdhdmVzQmFsYW5jZV9yZWd1bGFyCAUBYgdyZWd1bGFyCQDMCAIJAQxJbnRlZ2VyRW50cnkCAhd3YXZlc0JhbGFuY2VfZ2VuZXJhdGluZwgFAWIKZ2VuZXJhdGluZwkAzAgCCQEMSW50ZWdlckVudHJ5AgIWd2F2ZXNCYWxhbmNlX2VmZmVjdGl2ZQgFAWIJZWZmZWN0aXZlCQDMCAIJAQxJbnRlZ2VyRW50cnkCAg13YXZlc19wYXltZW50CAkBBXZhbHVlAQkAkQMCCAUBaQhwYXltZW50cwAABmFtb3VudAUDbmlsAQJ0eAEGdmVyaWZ5AAQTcHViS2V5QWRtaW5zTGlzdFN0cgkAuQkCCQDMCAICLEV4dEVFSzE5bm1LajltQ3BuV3l2RUVKRllBVExNY1ZFTXZvaGhVSGt5SE5tCQDMCAICLEV2NXB5NUZmQlFYOWNacFlLbmZRclRCNDlCeWY4UW1wWldlRFZSaW00eVY3CQDMCAICLERVdXVMalh1OThuQndaYzdmcXdDVGp0QTNublJ3Z1Ria01TcjVTVTJObURSCQDMCAICLERVdXVMalh1OThuQndaYzdmcXdDVGp0QTNublJ3Z1Ria01TcjVTVTJObURSBQNuaWwFA1NFUAQQcHViS2V5QWRtaW5zTGlzdAkAtQkCCQELdmFsdWVPckVsc2UCCQCdCAIFD2NvbnRyb2xDb250cmFjdAIMJXNfX211bHRpc2lnBRNwdWJLZXlBZG1pbnNMaXN0U3RyBQNTRVAEBWNvdW50CQBkAgkAZAIJAGQCAwkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAAkA2QQBCQCRAwIFEHB1YktleUFkbWluc0xpc3QAAAABAAADCQD0AwMIBQJ0eAlib2R5Qnl0ZXMJAJEDAggFAnR4BnByb29mcwABCQDZBAEJAJEDAgUQcHViS2V5QWRtaW5zTGlzdAABAAEAAAMJAPQDAwgFAnR4CWJvZHlCeXRlcwkAkQMCCAUCdHgGcHJvb2ZzAAIJANkEAQkAkQMCBRBwdWJLZXlBZG1pbnNMaXN0AAIAAQAAAwkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAwkA2QQBCQCRAwIFEHB1YktleUFkbWluc0xpc3QAAwACAAADAwUJaXNCbG9ja2VkCQAAAgkBEUBleHRyTmF0aXZlKDEwNTMpAgUPY29udHJvbENvbnRyYWN0AhFpc19ibG9ja2VkX2NhbGxlcgkApQgBBQtnb3ZDb250cmFjdAcJAQ52YWxpZGF0ZVVwZGF0ZQEFAnR4BAckbWF0Y2gwBQJ0eAMJAAECBQckbWF0Y2gwAhVTcG9uc29yRmVlVHJhbnNhY3Rpb24ECXNwb25zb3JUeAUHJG1hdGNoMAMJARtjaGVja0lzVmFsaWRNaW5TcG9uc29yZWRGZWUBBQlzcG9uc29yVHgJAGcCBQVjb3VudAADBwkAZwIFBWNvdW50AAMRFPLY", "height": 2401738, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 91q5zjyaVMW4S2c2ySi2xtdyWa5rRq3NxtHjEU8SmG8a Next: B8jrxogYe93WYYCD8GcQxAkn5r7KZQpYrC7k2g3xeDTi Diff:
OldNewDifferences
179179
180180 let WavesOutFeePartKey = "wavesOut_swap_feePart"
181181
182+let MultiOutFeePartKey = "multiOut_swap_feePart"
183+
182184 func keyNodeRegistry (address) = ("%s__" + address)
183185
184186
349351 func swapKEY (userAddress,txId) = makeString(["%s%s", userAddress, txId], SEP)
350352
351353
352-func strSwapDATA (swapType,status,inAmount,price,outNetAmount,outFeeAmount,startHeight,startTimestamp,endHeight,endTimestamp,selfUnlockHeight,randUnlockHeight,index,withdrawTxId,randMin,randMax,outSurfAmt,br) = makeString(["%s%s%d%d%d%d%d%d%d%d%d%d%d%s%d%d%d%d", swapType, status, inAmount, price, outNetAmount, outFeeAmount, startHeight, startTimestamp, endHeight, endTimestamp, selfUnlockHeight, randUnlockHeight, index, withdrawTxId, randMin, randMax, outSurfAmt, br], SEP)
354+func strSwapDATA (swapType,status,inAmount,price,outNetAmount,outFeeAmount,startHeight,startTimestamp,endHeight,endTimestamp,selfUnlockHeight,randUnlockHeight,index,withdrawTxId,randMin,randMax,outSurfAmt,br,basketData) = makeString(["%s%s%d%d%d%d%d%d%d%d%d%d%d%s%d%d%d%d%s", swapType, status, inAmount, price, outNetAmount, outFeeAmount, startHeight, startTimestamp, endHeight, endTimestamp, selfUnlockHeight, randUnlockHeight, index, withdrawTxId, randMin, randMax, outSurfAmt, br, basketData], SEP)
353355
354356
355-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", "0", "0")
357+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", "0", "0", "")
356358
357359
358-func finishSwapDATA (dataArray,price,outNetAmount,outFeeAmount,randUnlockHeight,index,withdrawTxId,outSurfAmt,br) = 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], toString(outSurfAmt), toString(br))
360+func finishSwapDATA (dataArray,price,outNetAmount,outFeeAmount,randUnlockHeight,index,withdrawTxId,outSurfAmt,br,basketData) = 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], toString(outSurfAmt), toString(br), basketData)
359361
360362
361363 func swapDataFailOrREAD (userAddress,swapTxId) = {
429431 }
430432
431433
432-func commonSwap (swapType,pmtAmount,userAddressStr,txId58,swapParamsByUserSYSREADONLY) = {
433- let swapLimitSpent = swapParamsByUserSYSREADONLY._2
434- let blcks2LmtReset = swapParamsByUserSYSREADONLY._3
435- let wavesSwapLimitMax = swapParamsByUserSYSREADONLY._6
436- let usdnSwapLimitMax = swapParamsByUserSYSREADONLY._7
434+func commonSwap (swapType,pmtAmount,userAddressStr,txId58) = {
435+ let swapParamsSTRUCT = asSwapParamsSTRUCT(invoke(this, "swapParamsByUserSYSREADONLY", [userAddressStr, 0], nil))
436+ let swapLimitSpent = swapParamsSTRUCT._2
437+ let blcks2LmtReset = swapParamsSTRUCT._3
438+ let wavesSwapLimitMax = swapParamsSTRUCT._6
439+ let usdnSwapLimitMax = swapParamsSTRUCT._7
437440 let minSwapAmount = minSwapAmountREAD(swapType)
438441 let totalLocked = totalLockedREAD(swapType)
439442 let totalLockedByUser = totalLockedByUserREAD(swapType, userAddressStr)
444447 then nodeBalanceLockIntervalREAD()
445448 else balanceLockIntervalREAD(swapType)
446449 let selfUnlockHeight = (height + balanceLockMaxInterval)
447- let swapUsdnVolume = if ((swapType == "neutrino"))
448- then pmtAmount
449- else convertWavesToNeutrino(pmtAmount, priceByIndex)
450- let swapLimitMax = if ((swapType == "neutrino"))
451- then usdnSwapLimitMax
452- else convertWavesToNeutrino(wavesSwapLimitMax, priceByIndex)
450+ let swapUsdnVolume = if ((swapType == "waves"))
451+ then convertWavesToNeutrino(pmtAmount, priceByIndex)
452+ else pmtAmount
453+ let swapLimitMax = if ((swapType == "waves"))
454+ then convertWavesToNeutrino(wavesSwapLimitMax, priceByIndex)
455+ else usdnSwapLimitMax
453456 if ((minSwapAmount > pmtAmount))
454457 then minSwapAmountFAIL(swapType, minSwapAmount)
455458 else if (if (!(isSwapByNode))
527530 }
528531
529532
530-func calcWithdrawU2W (usdnIn,price,br,reservesInUsdn,usdnSupply) = {
533+func calcWithdrawU2Basket (usdnIn,price,br,reservesInUsdn,usdnSupply) = {
531534 let brProtected = valueOrElse(getInteger(this, brProtectedKEY()), BRPROTECTED)
532535 let maxAllowedUsdnBeforeMinBr = if ((brProtected >= br))
533536 then 0
559562 let priceAdj = asInt(neutrinoMetrics[nMetricCurrentPriceAdj])
560563 let outDataTuple = if ((swapType == "waves"))
561564 then calcWithdrawW2U(inAmount, price)
562- else if ((swapType == "neutrino"))
563- then calcWithdrawU2W(inAmount, priceAdj, BR, reservesInUsdn, usdnSupply)
565+ else if ((swapType == "outMulti"))
566+ then calcWithdrawU2Basket(inAmount, priceAdj, BR, reservesInUsdn, usdnSupply)
564567 else throw(("Unsupported swap type " + swapType))
565568 let outAmtGross = outDataTuple._1
566569 let outAssetId = outDataTuple._2
624627 then throw("balance equals zero")
625628 else {
626629 let BR = asInt(neutrinoMetrics[nMetricIdxBR])
627- let state = [IntegerEntry(totalLockedByUserKEY(swapType, account), (totalLockedByUser - inAmount)), IntegerEntry(totalLockedKEY(swapType), (totalLocked - inAmount)), ScriptTransfer(userAddress, outNetAmount, outAssetId), StringEntry(swapKEY(account, swapTxId), finishSwapDATA(dataArray, withdrawPrice, outNetAmount, outFeeAmount, unlockHeight, index, withdrawTxId, outSurfAmt, BR))]
630+ let state = [IntegerEntry(totalLockedByUserKEY(swapType, account), (totalLockedByUser - inAmount)), IntegerEntry(totalLockedKEY(swapType), (totalLocked - inAmount)), ScriptTransfer(userAddress, outNetAmount, outAssetId), StringEntry(swapKEY(account, swapTxId), finishSwapDATA(dataArray, withdrawPrice, outNetAmount, outFeeAmount, unlockHeight, index, withdrawTxId, outSurfAmt, BR, "TODO"))]
628631 let surfCondition = if ((outSurfAmt > 0))
629632 then {
630633 let issueResult = invoke(auctionContract, "issueSurf", [outSurfAmt, account], nil)
665668
666669
667670 @Callable(i)
668-func constructor (neutrinoAssetIdPrm,bondAssetIdPrm,auctionContractPrm,liquidationContractPrm,rpdContractPrm,nodeOracleProviderPubKeyPrm,balanceWavesLockIntervalPrm,balanceNeutrinoLockIntervalPrm,minWavesSwapAmountPrm,minNeutrinoSwapAmountPrm,neutrinoOutFeePartPrm,wavesOutFeePartPrm) = {
671+func constructorV1 (neutrinoAssetIdPrm,bondAssetIdPrm,auctionContractPrm,liquidationContractPrm,rpdContractPrm,nodeOracleProviderPubKeyPrm,balanceWavesLockIntervalPrm,balanceNeutrinoLockIntervalPrm,minWavesSwapAmountPrm,minNeutrinoSwapAmountPrm,neutrinoOutFeePartPrm,wavesOutFeePartPrm,multiOutFeePartPrm) = {
669672 let checkCaller = thisOnly(i)
670673 if ((checkCaller == checkCaller))
671674 then if ((size(i.payments) != 0))
672675 then throw("no payments allowed")
673- 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)]
676+ 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), IntegerEntry(MultiOutFeePartKey, multiOutFeePartPrm)]
674677 else throw("Strict value is not equal to itself.")
675678 }
676679
698701 else {
699702 let userAddress = toString(i.caller)
700703 let txId58 = toBase58String(i.transactionId)
701- let swapParamsSTRUCT = asSwapParamsSTRUCT(invoke(this, "swapParamsByUserSYSREADONLY", [userAddress, 0], nil))
702- let commonSwapResult = commonSwap("waves", pmt.amount, userAddress, txId58, swapParamsSTRUCT)
703- commonSwapResult
704+ commonSwap("waves", pmt.amount, userAddress, txId58)
704705 }
705706 }
706707
707708
708709
709710 @Callable(i)
710-func swapNeutrinoToWaves () = if ((size(i.payments) != 1))
711- then throw("swapNeutrinoToWaves require only one payment")
711+func swapNeutrinoToBasket () = if ((size(i.payments) != 1))
712+ then throw("swapNeutrinoToBasket require only one payment")
712713 else {
713714 let pmt = value(i.payments[0])
714715 if ((pmt.assetId != neutrinoAssetId))
716717 else {
717718 let userAddress = toString(i.caller)
718719 let txId58 = toBase58String(i.transactionId)
719- let swapParamsSTRUCT = asSwapParamsSTRUCT(invoke(this, "swapParamsByUserSYSREADONLY", [userAddress, 0], nil))
720- let commonSwapResult = commonSwap("neutrino", pmt.amount, userAddress, txId58, swapParamsSTRUCT)
721- commonSwapResult
720+ commonSwap("outMulti", pmt.amount, userAddress, txId58)
722721 }
723722 }
724723
820819 if ((i.callerPublicKey != mngPub))
821820 then throw("approveLeasings not authorized")
822821 else {
823- let $t03574835810 = readNodeInfo(0)
824- let nAddr0 = $t03574835810._1
825- let lAmtKEY0 = $t03574835810._2
826- let lAmt0 = $t03574835810._3
827- let lIdKEY0 = $t03574835810._4
828- let lId0 = $t03574835810._5
822+ let $t03577035832 = readNodeInfo(0)
823+ let nAddr0 = $t03577035832._1
824+ let lAmtKEY0 = $t03577035832._2
825+ let lAmt0 = $t03577035832._3
826+ let lIdKEY0 = $t03577035832._4
827+ let lId0 = $t03577035832._5
829828 let newL0 = Lease(nAddr0, (lAmt0 - (lAmt * expCount)))
830829 let validation = invoke(nodeRegAddr, "validateAndApproveLeasings", [nListS], nil)
831830 if ((validation == validation))
870869 then throw("rebalanceLeasings not authorized")
871870 else {
872871 let unleaseAmt = ((amount / size(nList)) + 1)
873- let $t03705037112 = readNodeInfo(0)
874- let nAddr0 = $t03705037112._1
875- let lAmtKEY0 = $t03705037112._2
876- let lAmt0 = $t03705037112._3
877- let lIdKEY0 = $t03705037112._4
878- let lId0 = $t03705037112._5
872+ let $t03707237134 = readNodeInfo(0)
873+ let nAddr0 = $t03707237134._1
874+ let lAmtKEY0 = $t03707237134._2
875+ let lAmt0 = $t03707237134._3
876+ let lIdKEY0 = $t03707237134._4
877+ let lId0 = $t03707237134._5
879878 let newL0 = Lease(nAddr0, (lAmt0 + (unleaseAmt * size(nList))))
880879 func forEachNodeDoUnlease (a,i) = {
881880 let node = nList[i]
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], ""))
55
66
77 func lcalc (l) = calculateLeaseId(l)
88
99
1010 func getNumberByKey (key) = valueOrElse(getInteger(this, key), 0)
1111
1212
1313 func getStringByKey (key) = valueOrElse(getString(this, key), "")
1414
1515
1616 func getBoolByKey (key) = valueOrElse(getBoolean(this, key), false)
1717
1818
1919 func getNumberByAddressAndKey (address,key) = valueOrElse(getInteger(address, key), 0)
2020
2121
2222 func getStringByAddressAndKey (address,key) = valueOrElse(getString(addressFromStringValue(address), key), "")
2323
2424
2525 func getBoolByAddressAndKey (address,key) = valueOrElse(getBoolean(address, key), false)
2626
2727
2828 func asAnyList (v) = match v {
2929 case l: List[Any] =>
3030 l
3131 case _ =>
3232 throw("fail to cast into List[Any]")
3333 }
3434
3535
3636 func asString (v) = match v {
3737 case s: String =>
3838 s
3939 case _ =>
4040 throw("fail to cast into String")
4141 }
4242
4343
4444 func asInt (v) = match v {
4545 case i: Int =>
4646 i
4747 case _ =>
4848 throw("fail to cast into Int")
4949 }
5050
5151
5252 func asBytes (val) = match val {
5353 case valByte: ByteVector =>
5454 valByte
5555 case _ =>
5656 throw("fail to cast into ByteVector")
5757 }
5858
5959
6060 func asPayment (v) = match v {
6161 case p: AttachedPayment =>
6262 p
6363 case _ =>
6464 throw("fail to cast into AttachedPayment")
6565 }
6666
6767
6868 func asSwapParamsSTRUCT (v) = match v {
6969 case struct: (Int, Int, Int, Int, Int, Int, Int) =>
7070 struct
7171 case _ =>
7272 throw("fail to cast into Tuple5 ints")
7373 }
7474
7575
7676 let SEP = "__"
7777
7878 let LISTSEP = ":"
7979
8080 let WAVELET = 100000000
8181
8282 let PAULI = 1000000
8383
8484 let PRICELET = 1000000
8585
8686 let DEFAULTSWAPFEE = 20000
8787
8888 let BRPROTECTED = 100000
8989
9090 let IdxNetAmount = 0
9191
9292 let IdxFeeAmount = 1
9393
9494 let IdxGrossAmount = 2
9595
9696 let IdxControlCfgNeutrinoDapp = 1
9797
9898 let IdxControlCfgAuctionDapp = 2
9999
100100 let IdxControlCfgRpdDapp = 3
101101
102102 let IdxControlCfgMathDapp = 4
103103
104104 let IdxControlCfgLiquidationDapp = 5
105105
106106 let IdxControlCfgRestDapp = 6
107107
108108 let IdxControlCfgNodeRegistryDapp = 7
109109
110110 let IdxControlCfgNsbtStakingDapp = 8
111111
112112 let IdxControlCfgMediatorDapp = 9
113113
114114 let IdxControlCfgSurfStakingDapp = 10
115115
116116 let IdxControlCfgGnsbtControllerDapp = 11
117117
118118 let IdxControlCfgRestV2Dapp = 12
119119
120120 let IdxControlCfgGovernanceDapp = 13
121121
122122 func keyControlAddress () = "%s%s__config__controlAddress"
123123
124124
125125 func keyControlCfg () = "%s__controlConfig"
126126
127127
128128 func readControlCfgOrFail (control) = split_4C(getStringOrFail(control, keyControlCfg()), SEP)
129129
130130
131131 func getContractAddressOrFail (controlCfg,idx) = valueOrErrorMessage(addressFromString(controlCfg[idx]), ("Control cfg doesn't contain address at index " + toString(idx)))
132132
133133
134134 let controlContract = addressFromStringValue(valueOrElse(getString(this, keyControlAddress()), "3N4NS7d4Jo9a6F14LiFUKKYVdUkkf2eP4Zx"))
135135
136136 let controlCfg = readControlCfgOrFail(controlContract)
137137
138138 let mathContract = getContractAddressOrFail(controlCfg, IdxControlCfgMathDapp)
139139
140140 let nsbtStakingContract = getContractAddressOrFail(controlCfg, IdxControlCfgNsbtStakingDapp)
141141
142142 let surfStakingContract = getContractAddressOrFail(controlCfg, IdxControlCfgSurfStakingDapp)
143143
144144 let gnsbtControllerContract = getContractAddressOrFail(controlCfg, IdxControlCfgGnsbtControllerDapp)
145145
146146 let auctionContract = getContractAddressOrFail(controlCfg, IdxControlCfgAuctionDapp)
147147
148148 let nodeRegistryContract = getContractAddressOrFail(controlCfg, IdxControlCfgNodeRegistryDapp)
149149
150150 let govContract = getContractAddressOrFail(controlCfg, IdxControlCfgGovernanceDapp)
151151
152152 let NeutrinoAssetIdKey = "neutrino_asset_id"
153153
154154 let BondAssetIdKey = "bond_asset_id"
155155
156156 let AuctionContractKey = "auction_contract"
157157
158158 let NsbtStakingContractKey = "nsbtStakingContract"
159159
160160 let LiquidationContractKey = "liquidation_contract"
161161
162162 let RPDContractKey = "rpd_contract"
163163
164164 let ContolContractKey = "control_contract"
165165
166166 let MathContractKey = "math_contract"
167167
168168 let BalanceWavesLockIntervalKey = "balance_waves_lock_interval"
169169
170170 let BalanceNeutrinoLockIntervalKey = "balance_neutrino_lock_interval"
171171
172172 let MinWavesSwapAmountKey = "min_waves_swap_amount"
173173
174174 let MinNeutrinoSwapAmountKey = "min_neutrino_swap_amount"
175175
176176 let NodeOracleProviderPubKeyKey = "node_oracle_provider"
177177
178178 let NeutrinoOutFeePartKey = "neutrinoOut_swap_feePart"
179179
180180 let WavesOutFeePartKey = "wavesOut_swap_feePart"
181181
182+let MultiOutFeePartKey = "multiOut_swap_feePart"
183+
182184 func keyNodeRegistry (address) = ("%s__" + address)
183185
184186
185187 let PriceKey = "price"
186188
187189 let PriceIndexKey = "price_index"
188190
189191 let IsBlockedKey = "is_blocked"
190192
191193 func getPriceHistoryKey (block) = ((PriceKey + "_") + toString(block))
192194
193195
194196 func getHeightPriceByIndexKey (index) = ((PriceIndexKey + "_") + toString(index))
195197
196198
197199 func getStakingNodeByIndex (idx) = getStringByKey(makeString(["%s%d%s", "lease", toString(idx), "nodeAddress"], SEP))
198200
199201
200202 func getStakingNodeAddressByIndex (idx) = addressFromStringValue(getStakingNodeByIndex(idx))
201203
202204
203205 func getReservedAmountForSponsorship () = valueOrElse(getInteger(this, makeString(["%s%s", "lease", "sponsorshipWavesReserve"], SEP)), (1000 * WAVELET))
204206
205207
206208 func getBalanceUnlockBlockKey (owner) = ("balance_unlock_block_" + owner)
207209
208210
209211 func getLeaseIdKey (nodeIndex) = makeString(["%s%d%s", "lease", toString(nodeIndex), "id"], SEP)
210212
211213
212214 func getLeaseIdByAddressKey (nodeAddress) = makeString(["%s%s%s", "leaseByAddress", nodeAddress, "id"], SEP)
213215
214216
215217 func getLeaseAmountKey (nodeIndex) = makeString(["%s%d%s", "lease", toString(nodeIndex), "amount"], SEP)
216218
217219
218220 func getLeaseAmountByAddressKey (nodeAddress) = makeString(["%s%s%s", "leaseByAddress", nodeAddress, "amount"], SEP)
219221
220222
221223 func getLeaseGroupNodeListKey (groupNum) = makeString(["%s%d%s", "leaseGroup", toString(groupNum), "nodeList"], SEP)
222224
223225
224226 func minSwapAmountKEY (swapType) = (("min_" + swapType) + "_swap_amount")
225227
226228
227229 func totalLockedKEY (swapType) = ("balance_lock_" + swapType)
228230
229231
230232 func totalLockedByUserKEY (swapType,owner) = makeString(["balance_lock", swapType, owner], "_")
231233
232234
233235 func balanceLockIntervalKEY (swapType) = (("balance_" + swapType) + "_lock_interval")
234236
235237
236238 func nodeBalanceLockIntervalKEY () = "balance_node_lock_interval"
237239
238240
239241 func outFeePartKEY (swapType) = (swapType + "Out_swap_feePart")
240242
241243
242244 func swapsTimeframeKEY () = "swaps_timeframe"
243245
244246
245247 func brProtectedKEY () = "min_BR_protection_level"
246248
247249
248250 func minSwapAmountREAD (swapType) = valueOrElse(getInteger(this, minSwapAmountKEY(swapType)), 0)
249251
250252
251253 func swapsTimeframeREAD () = valueOrElse(getInteger(this, swapsTimeframeKEY()), 1440)
252254
253255
254256 func totalLockedREAD (swapType) = valueOrElse(getInteger(this, totalLockedKEY(swapType)), 0)
255257
256258
257259 func totalLockedByUserREAD (swapType,owner) = valueOrElse(getInteger(this, totalLockedByUserKEY(swapType, owner)), 0)
258260
259261
260262 func balanceLockIntervalREAD (swapType) = valueOrElse(getInteger(this, balanceLockIntervalKEY(swapType)), 1440)
261263
262264
263265 func nodeBalanceLockIntervalREAD () = valueOrElse(getInteger(this, nodeBalanceLockIntervalKEY()), 1)
264266
265267
266268 func keySwapUserSpentInPeriod (userAddress) = makeString(["%s%s", "swapUserSpentInPeriod", userAddress], SEP)
267269
268270
269271 func keyUserLastSwapHeight (userAddress) = makeString(["%s%s", "userLastSwapHeight", userAddress], SEP)
270272
271273
272274 func convertNeutrinoToWaves (amount,price) = fraction(fraction(amount, PRICELET, price), WAVELET, PAULI)
273275
274276
275277 func convertWavesToNeutrino (amount,price) = fraction(fraction(amount, price, PRICELET), PAULI, WAVELET)
276278
277279
278280 func convertWavesToBond (amount,price) = convertWavesToNeutrino(amount, price)
279281
280282
281283 func convertJsonArrayToList (jsonArray) = split(jsonArray, ",")
282284
283285
284286 func minSwapAmountFAIL (swapType,minSwapAmount) = throw(((("The specified amount in " + swapType) + " swap is less than the required minimum of ") + toString(minSwapAmount)))
285287
286288
287289 func emergencyShutdownFAIL () = throw("contract is blocked by EMERGENCY SHUTDOWN actions untill reactivation by emergency oracles")
288290
289291
290292 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)))
291293
292294
293295 let neutrinoAssetId = fromBase58String(getStringByKey(NeutrinoAssetIdKey))
294296
295297 let priceIndex = getNumberByAddressAndKey(controlContract, PriceIndexKey)
296298
297299 let isBlocked = getBoolByAddressAndKey(controlContract, IsBlockedKey)
298300
299301 let nodeOracleProviderPubKey = fromBase58String(getStringByKey(NodeOracleProviderPubKeyKey))
300302
301303 let bondAssetId = fromBase58String("F3iaxzruFeKujfVfYSZEkejpjh67wmRfPCRHiNmWKp3Z")
302304
303305 let deprecatedBondAssetId = fromBase58String("975akZBfnMj513U7MZaHKzQrmsEx5aE3wdWKTrHBhbjF")
304306
305307 let neutrinoContract = this
306308
307309 let currentPrice = getNumberByAddressAndKey(controlContract, PriceKey)
308310
309311 func checkIsValidMinSponsoredFee (tx) = {
310312 let MINTRANSFERFEE = 100000
311313 let SponsoredFeeUpperBound = 1000
312314 let realNeutrinoFee = convertWavesToNeutrino(MINTRANSFERFEE, currentPrice)
313315 let minNeutrinoFee = (realNeutrinoFee * 2)
314316 let maxNeutrinoFee = fraction(realNeutrinoFee, SponsoredFeeUpperBound, 100)
315317 let inputFee = value(tx.minSponsoredAssetFee)
316318 if (if ((inputFee >= minNeutrinoFee))
317319 then (maxNeutrinoFee >= inputFee)
318320 else false)
319321 then (tx.assetId == neutrinoAssetId)
320322 else false
321323 }
322324
323325
324326 func getPriceHistory (block) = getNumberByAddressAndKey(controlContract, getPriceHistoryKey(block))
325327
326328
327329 func getHeightPriceByIndex (index) = getNumberByAddressAndKey(controlContract, getHeightPriceByIndexKey(index))
328330
329331
330332 func keyLockParamUserAmount (userAddress) = makeString(["%s%s%s", "paramByUser", userAddress, "amount"], SEP)
331333
332334
333335 let sIdxSwapType = 1
334336
335337 let sIdxStatus = 2
336338
337339 let sIdxInAmount = 3
338340
339341 let sIdxStartHeight = 7
340342
341343 let sIdxStartTimestamp = 8
342344
343345 let sIdxSelfUnlockHeight = 11
344346
345347 let sIdxMinRand = 15
346348
347349 let sIdxMaxRand = 16
348350
349351 func swapKEY (userAddress,txId) = makeString(["%s%s", userAddress, txId], SEP)
350352
351353
352-func strSwapDATA (swapType,status,inAmount,price,outNetAmount,outFeeAmount,startHeight,startTimestamp,endHeight,endTimestamp,selfUnlockHeight,randUnlockHeight,index,withdrawTxId,randMin,randMax,outSurfAmt,br) = makeString(["%s%s%d%d%d%d%d%d%d%d%d%d%d%s%d%d%d%d", swapType, status, inAmount, price, outNetAmount, outFeeAmount, startHeight, startTimestamp, endHeight, endTimestamp, selfUnlockHeight, randUnlockHeight, index, withdrawTxId, randMin, randMax, outSurfAmt, br], SEP)
354+func strSwapDATA (swapType,status,inAmount,price,outNetAmount,outFeeAmount,startHeight,startTimestamp,endHeight,endTimestamp,selfUnlockHeight,randUnlockHeight,index,withdrawTxId,randMin,randMax,outSurfAmt,br,basketData) = makeString(["%s%s%d%d%d%d%d%d%d%d%d%d%d%s%d%d%d%d%s", swapType, status, inAmount, price, outNetAmount, outFeeAmount, startHeight, startTimestamp, endHeight, endTimestamp, selfUnlockHeight, randUnlockHeight, index, withdrawTxId, randMin, randMax, outSurfAmt, br, basketData], SEP)
353355
354356
355-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", "0", "0")
357+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", "0", "0", "")
356358
357359
358-func finishSwapDATA (dataArray,price,outNetAmount,outFeeAmount,randUnlockHeight,index,withdrawTxId,outSurfAmt,br) = 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], toString(outSurfAmt), toString(br))
360+func finishSwapDATA (dataArray,price,outNetAmount,outFeeAmount,randUnlockHeight,index,withdrawTxId,outSurfAmt,br,basketData) = 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], toString(outSurfAmt), toString(br), basketData)
359361
360362
361363 func swapDataFailOrREAD (userAddress,swapTxId) = {
362364 let swapKey = swapKEY(userAddress, swapTxId)
363365 split(valueOrErrorMessage(getString(this, swapKey), ("no swap data for " + swapKey)), SEP)
364366 }
365367
366368
367369 func applyFees (amountOutGross,inAmtToSURF,feePart) = {
368370 let feeAmount = fraction(amountOutGross, feePart, PAULI)
369371 [(amountOutGross - feeAmount), feeAmount]
370372 }
371373
372374
373375 func abs (x) = if ((0 > x))
374376 then -(x)
375377 else x
376378
377379
378380 func selectNode (unleaseAmount) = {
379381 let amountToLease = ((wavesBalance(neutrinoContract).available - unleaseAmount) - getReservedAmountForSponsorship())
380382 let oldLeased0 = getNumberByKey(getLeaseAmountKey(0))
381383 let oldLeased1 = getNumberByKey(getLeaseAmountKey(1))
382384 let newLeased0 = (amountToLease + oldLeased0)
383385 let newLeased1 = (amountToLease + oldLeased1)
384386 if (if ((newLeased0 > 0))
385387 then true
386388 else (newLeased1 > 0))
387389 then {
388390 let delta0 = abs((newLeased0 - oldLeased1))
389391 let delta1 = abs((newLeased1 - oldLeased0))
390392 if ((delta1 >= delta0))
391393 then $Tuple2(0, newLeased0)
392394 else $Tuple2(1, newLeased1)
393395 }
394396 else $Tuple2(-1, 0)
395397 }
396398
397399
398400 func thisOnly (i) = if ((i.caller != this))
399401 then throw("Permission denied: this contract only allowed")
400402 else true
401403
402404
403405 func prepareUnleaseAndLease (unleaseAmount) = {
404406 let nodeTuple = selectNode(unleaseAmount)
405407 let nodeIndex = nodeTuple._1
406408 let newLeaseAmount = nodeTuple._2
407409 if ((newLeaseAmount > 0))
408410 then {
409411 let leaseIdKey = getLeaseIdKey(nodeIndex)
410412 let oldLease = getBinary(this, leaseIdKey)
411413 let unleaseOrEmpty = if (isDefined(oldLease))
412414 then [LeaseCancel(value(oldLease))]
413415 else nil
414416 let leaseAmountKey = getLeaseAmountKey(nodeIndex)
415417 let lease = Lease(getStakingNodeAddressByIndex(nodeIndex), newLeaseAmount)
416418 (unleaseOrEmpty ++ [lease, BinaryEntry(leaseIdKey, lcalc(lease)), IntegerEntry(getLeaseAmountKey(nodeIndex), newLeaseAmount)])
417419 }
418420 else nil
419421 }
420422
421423
422424 func readNodeInfo (nodeIdx) = {
423425 let nodeAddress = getStakingNodeAddressByIndex(nodeIdx)
424426 let leasedAmtKEY = getLeaseAmountKey(nodeIdx)
425427 let leasedAmt = getNumberByKey(leasedAmtKEY)
426428 let leaseIdKEY = getLeaseIdKey(nodeIdx)
427429 let leaseId = value(getBinary(this, leaseIdKEY))
428430 $Tuple5(nodeAddress, leasedAmtKEY, leasedAmt, leaseIdKEY, leaseId)
429431 }
430432
431433
432-func commonSwap (swapType,pmtAmount,userAddressStr,txId58,swapParamsByUserSYSREADONLY) = {
433- let swapLimitSpent = swapParamsByUserSYSREADONLY._2
434- let blcks2LmtReset = swapParamsByUserSYSREADONLY._3
435- let wavesSwapLimitMax = swapParamsByUserSYSREADONLY._6
436- let usdnSwapLimitMax = swapParamsByUserSYSREADONLY._7
434+func commonSwap (swapType,pmtAmount,userAddressStr,txId58) = {
435+ let swapParamsSTRUCT = asSwapParamsSTRUCT(invoke(this, "swapParamsByUserSYSREADONLY", [userAddressStr, 0], nil))
436+ let swapLimitSpent = swapParamsSTRUCT._2
437+ let blcks2LmtReset = swapParamsSTRUCT._3
438+ let wavesSwapLimitMax = swapParamsSTRUCT._6
439+ let usdnSwapLimitMax = swapParamsSTRUCT._7
437440 let minSwapAmount = minSwapAmountREAD(swapType)
438441 let totalLocked = totalLockedREAD(swapType)
439442 let totalLockedByUser = totalLockedByUserREAD(swapType, userAddressStr)
440443 let nodeAddress = getStakingNodeByIndex(0)
441444 let priceByIndex = getPriceHistory(getHeightPriceByIndex(priceIndex))
442445 let isSwapByNode = (nodeAddress == userAddressStr)
443446 let balanceLockMaxInterval = if (isSwapByNode)
444447 then nodeBalanceLockIntervalREAD()
445448 else balanceLockIntervalREAD(swapType)
446449 let selfUnlockHeight = (height + balanceLockMaxInterval)
447- let swapUsdnVolume = if ((swapType == "neutrino"))
448- then pmtAmount
449- else convertWavesToNeutrino(pmtAmount, priceByIndex)
450- let swapLimitMax = if ((swapType == "neutrino"))
451- then usdnSwapLimitMax
452- else convertWavesToNeutrino(wavesSwapLimitMax, priceByIndex)
450+ let swapUsdnVolume = if ((swapType == "waves"))
451+ then convertWavesToNeutrino(pmtAmount, priceByIndex)
452+ else pmtAmount
453+ let swapLimitMax = if ((swapType == "waves"))
454+ then convertWavesToNeutrino(wavesSwapLimitMax, priceByIndex)
455+ else usdnSwapLimitMax
453456 if ((minSwapAmount > pmtAmount))
454457 then minSwapAmountFAIL(swapType, minSwapAmount)
455458 else if (if (!(isSwapByNode))
456459 then (swapLimitSpent > 0)
457460 else false)
458461 then throw(("You have exceeded swap limit! Next allowed swap height is " + toString((height + blcks2LmtReset))))
459462 else if (if (!(isSwapByNode))
460463 then (swapUsdnVolume > swapLimitMax)
461464 else false)
462465 then throw(((("You have exceeded your swap limit! Requested: " + toString(swapUsdnVolume)) + ", available: ") + toString(swapLimitMax)))
463466 else if (isBlocked)
464467 then emergencyShutdownFAIL()
465468 else {
466469 let leasePart = if ((swapType == "waves"))
467470 then prepareUnleaseAndLease(0)
468471 else nil
469472 $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)
470473 }
471474 }
472475
473476
474477 let nMetricIdxPrice = 0
475478
476479 let nMetricIdxUsdnLockedBalance = 1
477480
478481 let nMetricIdxWavesLockedBalance = 2
479482
480483 let nMetricIdxReserve = 3
481484
482485 let nMetricIdxReserveInUsdn = 4
483486
484487 let nMetricIdxUsdnSupply = 5
485488
486489 let nMetricIdxSurplus = 6
487490
488491 let nMetricIdxSurplusPercent = 7
489492
490493 let nMetricIdxBR = 8
491494
492495 let nMetricIdxNsbtSupply = 9
493496
494497 let nMetricIdxMaxNsbtSupply = 10
495498
496499 let nMetricIdxSurfSupply = 11
497500
498501 let nMetricUsdnUsdtPeg = 12
499502
500503 let nMetricCurrentPriceAdj = 13
501504
502505 let bFuncIdxSurf = 0
503506
504507 let bFuncIdxWaves = 1
505508
506509 let bFuncIdxUsdn = 2
507510
508511 let bFuncIdxReserveStart = 3
509512
510513 let bFuncIdxSupplyStart = 4
511514
512515 let bFuncIdxBRStart = 5
513516
514517 let bFuncIdxReserveEnd = 6
515518
516519 let bFuncIdxSupplyEnd = 7
517520
518521 let bFuncIdxBREnd = 8
519522
520523 let bFuncIdxRest = 9
521524
522525 let bFuncIdxWavesPrice = 10
523526
524527 func calcWithdrawW2U (wavesIn,price) = {
525528 let outAmtGross = convertWavesToNeutrino(wavesIn, price)
526529 $Tuple10(outAmtGross, neutrinoAssetId, 0, unit, 0, price, wavesIn, 0, 0, 0)
527530 }
528531
529532
530-func calcWithdrawU2W (usdnIn,price,br,reservesInUsdn,usdnSupply) = {
533+func calcWithdrawU2Basket (usdnIn,price,br,reservesInUsdn,usdnSupply) = {
531534 let brProtected = valueOrElse(getInteger(this, brProtectedKEY()), BRPROTECTED)
532535 let maxAllowedUsdnBeforeMinBr = if ((brProtected >= br))
533536 then 0
534537 else fraction((reservesInUsdn - fraction(brProtected, usdnSupply, PAULI)), PAULI, (PAULI - brProtected))
535538 let allowedUsdnBeforeMinBr = if ((usdnIn > maxAllowedUsdnBeforeMinBr))
536539 then maxAllowedUsdnBeforeMinBr
537540 else usdnIn
538541 let allowedUsdnAfterMinBr = if ((usdnIn > maxAllowedUsdnBeforeMinBr))
539542 then fraction((usdnIn - maxAllowedUsdnBeforeMinBr), br, PAULI)
540543 else 0
541544 let allowedUsdn = (allowedUsdnBeforeMinBr + allowedUsdnAfterMinBr)
542545 let usdn2SURF = (usdnIn - allowedUsdn)
543546 let outAmtGross = convertNeutrinoToWaves(allowedUsdn, price)
544547 $Tuple10(outAmtGross, unit, usdn2SURF, neutrinoAssetId, outAmtGross, price, allowedUsdn, maxAllowedUsdnBeforeMinBr, allowedUsdnBeforeMinBr, allowedUsdnAfterMinBr)
545548 }
546549
547550
548551 func calcWithdraw (swapType,inAmount,price,neutrinoMetrics) = {
549552 let outFeePart = valueOrElse(getInteger(this, outFeePartKEY(swapType)), DEFAULTSWAPFEE)
550553 if (if ((0 > outFeePart))
551554 then true
552555 else (outFeePart >= PAULI))
553556 then throw(((("invalid outFeePart config for " + swapType) + " swap: outFeePart=") + toString(outFeePart)))
554557 else {
555558 let brProtected = valueOrElse(getInteger(this, brProtectedKEY()), BRPROTECTED)
556559 let BR = asInt(neutrinoMetrics[nMetricIdxBR])
557560 let reservesInUsdn = asInt(neutrinoMetrics[nMetricIdxReserveInUsdn])
558561 let usdnSupply = asInt(neutrinoMetrics[nMetricIdxUsdnSupply])
559562 let priceAdj = asInt(neutrinoMetrics[nMetricCurrentPriceAdj])
560563 let outDataTuple = if ((swapType == "waves"))
561564 then calcWithdrawW2U(inAmount, price)
562- else if ((swapType == "neutrino"))
563- then calcWithdrawU2W(inAmount, priceAdj, BR, reservesInUsdn, usdnSupply)
565+ else if ((swapType == "outMulti"))
566+ then calcWithdrawU2Basket(inAmount, priceAdj, BR, reservesInUsdn, usdnSupply)
564567 else throw(("Unsupported swap type " + swapType))
565568 let outAmtGross = outDataTuple._1
566569 let outAssetId = outDataTuple._2
567570 let inAmtToSurfPart = outDataTuple._3
568571 let inAssetId = outDataTuple._4
569572 let unleaseAmt = outDataTuple._5
570573 let withdrawPrice = outDataTuple._6
571574 let payoutsArray = applyFees(outAmtGross, inAmtToSurfPart, outFeePart)
572575 let outNetAmt = payoutsArray[IdxNetAmount]
573576 let outFeeAmt = payoutsArray[IdxFeeAmount]
574577 let outSurfAmt = if ((0 >= inAmtToSurfPart))
575578 then 0
576579 else {
577580 let surfResult = asAnyList(invoke(mathContract, "surfFunctionREADONLY", [inAmtToSurfPart, inAssetId], nil))
578581 asInt(surfResult[bFuncIdxSurf])
579582 }
580583 $Tuple8(outNetAmt, outAssetId, outSurfAmt, inAmtToSurfPart, unleaseAmt, outFeeAmt, outAmtGross, withdrawPrice)
581584 }
582585 }
583586
584587
585588 func commonWithdraw (account,index,swapTxId,withdrawTxId,neutrinoMetrics) = {
586589 let userAddress = addressFromStringValue(account)
587590 let dataArray = swapDataFailOrREAD(account, swapTxId)
588591 let selfUnlockHeight = parseIntValue(dataArray[sIdxSelfUnlockHeight])
589592 let swapType = dataArray[sIdxSwapType]
590593 let inAmount = parseIntValue(dataArray[sIdxInAmount])
591594 let swapStatus = dataArray[sIdxStatus]
592595 let startHeight = parseIntValue(dataArray[sIdxStartHeight])
593596 let outFeePart = valueOrElse(getInteger(this, outFeePartKEY(swapType)), DEFAULTSWAPFEE)
594597 let totalLocked = totalLockedREAD(swapType)
595598 let totalLockedByUser = totalLockedByUserREAD(swapType, account)
596599 let unlockHeight = selfUnlockHeight
597600 let indexHeight = getHeightPriceByIndex(index)
598601 let prevIndexHeight = getHeightPriceByIndex((index - 1))
599602 let priceByIndex = getPriceHistory(indexHeight)
600603 if (isBlocked)
601604 then emergencyShutdownFAIL()
602605 else if ((swapStatus != "PENDING"))
603606 then throw("swap has been already processed")
604607 else if ((unlockHeight > height))
605608 then throw((("please wait for: " + toString(unlockHeight)) + " block height to withdraw funds"))
606609 else if (if (if ((index > priceIndex))
607610 then true
608611 else (unlockHeight > indexHeight))
609612 then true
610613 else if ((prevIndexHeight != 0))
611614 then (prevIndexHeight >= unlockHeight)
612615 else false)
613616 then priceIndexFAIL(index, priceIndex, indexHeight, unlockHeight, prevIndexHeight)
614617 else {
615618 let withdrawTuple = calcWithdraw(swapType, inAmount, priceByIndex, neutrinoMetrics)
616619 let outNetAmount = withdrawTuple._1
617620 let outAssetId = withdrawTuple._2
618621 let outSurfAmt = withdrawTuple._3
619622 let unleaseAmt = withdrawTuple._5
620623 let outFeeAmount = withdrawTuple._6
621624 let outAmtGross = withdrawTuple._7
622625 let withdrawPrice = withdrawTuple._8
623626 if ((0 >= outAmtGross))
624627 then throw("balance equals zero")
625628 else {
626629 let BR = asInt(neutrinoMetrics[nMetricIdxBR])
627- let state = [IntegerEntry(totalLockedByUserKEY(swapType, account), (totalLockedByUser - inAmount)), IntegerEntry(totalLockedKEY(swapType), (totalLocked - inAmount)), ScriptTransfer(userAddress, outNetAmount, outAssetId), StringEntry(swapKEY(account, swapTxId), finishSwapDATA(dataArray, withdrawPrice, outNetAmount, outFeeAmount, unlockHeight, index, withdrawTxId, outSurfAmt, BR))]
630+ let state = [IntegerEntry(totalLockedByUserKEY(swapType, account), (totalLockedByUser - inAmount)), IntegerEntry(totalLockedKEY(swapType), (totalLocked - inAmount)), ScriptTransfer(userAddress, outNetAmount, outAssetId), StringEntry(swapKEY(account, swapTxId), finishSwapDATA(dataArray, withdrawPrice, outNetAmount, outFeeAmount, unlockHeight, index, withdrawTxId, outSurfAmt, BR, "TODO"))]
628631 let surfCondition = if ((outSurfAmt > 0))
629632 then {
630633 let issueResult = invoke(auctionContract, "issueSurf", [outSurfAmt, account], nil)
631634 if ((issueResult == issueResult))
632635 then 0
633636 else throw("Strict value is not equal to itself.")
634637 }
635638 else 0
636639 if ((surfCondition == surfCondition))
637640 then $Tuple3(state, AttachedPayment(outAssetId, outFeeAmount), unleaseAmt)
638641 else throw("Strict value is not equal to itself.")
639642 }
640643 }
641644 }
642645
643646
644647 func keyApplyInProgress () = "%s__applyInProgress"
645648
646649
647650 func keyProposalDataById (proposalId) = ("%s%d__proposalData__" + toString(proposalId))
648651
649652
650653 let govIdxTxIds = 9
651654
652655 func validateUpdate (tx) = match tx {
653656 case o: Order =>
654657 throw("Orders aren't allowed")
655658 case t: DataTransaction|SponsorFeeTransaction|SetScriptTransaction|CreateAliasTransaction|LeaseCancelTransaction|LeaseTransaction|IssueTransaction|InvokeExpressionTransaction|UpdateAssetInfoTransaction|InvokeScriptTransaction|SetAssetScriptTransaction|TransferTransaction|ExchangeTransaction|MassTransferTransaction|BurnTransaction|ReissueTransaction =>
656659 let txId = toBase58String(t.id)
657660 let proposalId = valueOrErrorMessage(getInteger(govContract, keyApplyInProgress()), "Apply is not happening")
658661 let txList = split(split(getStringOrFail(govContract, keyProposalDataById(proposalId)), SEP)[govIdxTxIds], LISTSEP)
659662 if (!(isDefined(indexOf(txList, txId))))
660663 then throw(((("Unknown txId: " + txId) + " for proposalId=") + toString(proposalId)))
661664 else true
662665 case _ =>
663666 throw("Match error")
664667 }
665668
666669
667670 @Callable(i)
668-func constructor (neutrinoAssetIdPrm,bondAssetIdPrm,auctionContractPrm,liquidationContractPrm,rpdContractPrm,nodeOracleProviderPubKeyPrm,balanceWavesLockIntervalPrm,balanceNeutrinoLockIntervalPrm,minWavesSwapAmountPrm,minNeutrinoSwapAmountPrm,neutrinoOutFeePartPrm,wavesOutFeePartPrm) = {
671+func constructorV1 (neutrinoAssetIdPrm,bondAssetIdPrm,auctionContractPrm,liquidationContractPrm,rpdContractPrm,nodeOracleProviderPubKeyPrm,balanceWavesLockIntervalPrm,balanceNeutrinoLockIntervalPrm,minWavesSwapAmountPrm,minNeutrinoSwapAmountPrm,neutrinoOutFeePartPrm,wavesOutFeePartPrm,multiOutFeePartPrm) = {
669672 let checkCaller = thisOnly(i)
670673 if ((checkCaller == checkCaller))
671674 then if ((size(i.payments) != 0))
672675 then throw("no payments allowed")
673- 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)]
676+ 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), IntegerEntry(MultiOutFeePartKey, multiOutFeePartPrm)]
674677 else throw("Strict value is not equal to itself.")
675678 }
676679
677680
678681
679682 @Callable(i)
680683 func constructorV2 (mathContract,nsbtStakingContract,swapsTimeframeBlocks) = {
681684 let checkCaller = thisOnly(i)
682685 if ((checkCaller == checkCaller))
683686 then if ((size(i.payments) != 0))
684687 then throw("no payments allowed")
685688 else [StringEntry(MathContractKey, mathContract), StringEntry(NsbtStakingContractKey, nsbtStakingContract), IntegerEntry(swapsTimeframeKEY(), swapsTimeframeBlocks)]
686689 else throw("Strict value is not equal to itself.")
687690 }
688691
689692
690693
691694 @Callable(i)
692695 func swapWavesToNeutrino () = if ((size(i.payments) != 1))
693696 then throw("swapWavesToNeutrino require only one payment")
694697 else {
695698 let pmt = value(i.payments[0])
696699 if (isDefined(pmt.assetId))
697700 then throw("Only Waves token is allowed for swapping.")
698701 else {
699702 let userAddress = toString(i.caller)
700703 let txId58 = toBase58String(i.transactionId)
701- let swapParamsSTRUCT = asSwapParamsSTRUCT(invoke(this, "swapParamsByUserSYSREADONLY", [userAddress, 0], nil))
702- let commonSwapResult = commonSwap("waves", pmt.amount, userAddress, txId58, swapParamsSTRUCT)
703- commonSwapResult
704+ commonSwap("waves", pmt.amount, userAddress, txId58)
704705 }
705706 }
706707
707708
708709
709710 @Callable(i)
710-func swapNeutrinoToWaves () = if ((size(i.payments) != 1))
711- then throw("swapNeutrinoToWaves require only one payment")
711+func swapNeutrinoToBasket () = if ((size(i.payments) != 1))
712+ then throw("swapNeutrinoToBasket require only one payment")
712713 else {
713714 let pmt = value(i.payments[0])
714715 if ((pmt.assetId != neutrinoAssetId))
715716 then throw("Only appropriate Neutrino tokens are allowed for swapping.")
716717 else {
717718 let userAddress = toString(i.caller)
718719 let txId58 = toBase58String(i.transactionId)
719- let swapParamsSTRUCT = asSwapParamsSTRUCT(invoke(this, "swapParamsByUserSYSREADONLY", [userAddress, 0], nil))
720- let commonSwapResult = commonSwap("neutrino", pmt.amount, userAddress, txId58, swapParamsSTRUCT)
721- commonSwapResult
720+ commonSwap("outMulti", pmt.amount, userAddress, txId58)
722721 }
723722 }
724723
725724
726725
727726 @Callable(i)
728727 func withdraw (account,index,swapTxId) = {
729728 let txId = toBase58String(i.transactionId)
730729 if ((size(i.payments) != 0))
731730 then throw("no payments allowed")
732731 else {
733732 let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
734733 let BR = asInt(neutrinoMetrics[nMetricIdxBR])
735734 let commonTuple = commonWithdraw(account, index, swapTxId, txId, neutrinoMetrics)
736735 let state = commonTuple._1
737736 let fee = commonTuple._2
738737 let unleaseAmt = commonTuple._3
739738 let unleaseInvOrEmpty = invoke(this, "internalUnleaseAndLease", [unleaseAmt], nil)
740739 if ((unleaseInvOrEmpty == unleaseInvOrEmpty))
741740 then {
742741 let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", ["", 0, 0], nil))
743742 let gnsbtAmtTotal = asInt(gnsbtData[1])
744743 let gnsbtAmtFromSurfTotal = asInt(asAnyList(gnsbtData[3])[3])
745744 let surfFeeAmt1 = if ((gnsbtAmtTotal != 0))
746745 then fraction(fee.amount, gnsbtAmtFromSurfTotal, gnsbtAmtTotal)
747746 else 0
748747 let surfFeeAmt2 = if ((gnsbtAmtTotal != 0))
749748 then fraction(fee.amount, (PAULI - BR), PAULI)
750749 else 0
751750 let surfFeeAmt = max([surfFeeAmt1, surfFeeAmt2])
752751 let nsbtFeeAmt = (fee.amount - surfFeeAmt)
753752 let surfDeposit = if ((surfFeeAmt > 0))
754753 then {
755754 let surfInv = invoke(surfStakingContract, "deposit", nil, [AttachedPayment(fee.assetId, surfFeeAmt)])
756755 if ((surfInv == surfInv))
757756 then nil
758757 else throw("Strict value is not equal to itself.")
759758 }
760759 else nil
761760 if ((surfDeposit == surfDeposit))
762761 then {
763762 let nsbtDeposit = if ((nsbtFeeAmt > 0))
764763 then {
765764 let nsbtInv = invoke(nsbtStakingContract, "deposit", nil, [AttachedPayment(fee.assetId, nsbtFeeAmt)])
766765 if ((nsbtInv == nsbtInv))
767766 then nil
768767 else throw("Strict value is not equal to itself.")
769768 }
770769 else nil
771770 if ((nsbtDeposit == nsbtDeposit))
772771 then state
773772 else throw("Strict value is not equal to itself.")
774773 }
775774 else throw("Strict value is not equal to itself.")
776775 }
777776 else throw("Strict value is not equal to itself.")
778777 }
779778 }
780779
781780
782781
783782 @Callable(i)
784783 func internalUnleaseAndLease (unleaseAmount) = if ((i.caller != this))
785784 then throw("internalUnleaseAndLease is not public method")
786785 else prepareUnleaseAndLease(unleaseAmount)
787786
788787
789788
790789 @Callable(i)
791790 func transferUsdnToUser (amount,addr) = if ((i.caller != auctionContract))
792791 then throw("Only auction contract is authorized")
793792 else [ScriptTransfer(addressFromStringValue(addr), amount, neutrinoAssetId)]
794793
795794
796795
797796 @Callable(i)
798797 func acceptWaves () = if (if ((i.caller != auctionContract))
799798 then (i.caller != govContract)
800799 else false)
801800 then throw("Currently only auction and governance contracts are allowed to call")
802801 else $Tuple2(prepareUnleaseAndLease(0), "success")
803802
804803
805804
806805 @Callable(i)
807806 func approveLeasings (nListS,groupNum,lAmt) = {
808807 let nIdxs = [0, 1, 2, 3, 4, 5, 6, 7]
809808 let mngPubS = valueOrElse(getString("%s%s__cfg__leasingManagerPub"), "7AUMX54ukYMYvPmma7yoFf5NjZhs4Bu5nz3Ez9EV8sur")
810809 let mngPub = fromBase58String(mngPubS)
811810 let nodeRegAddrStr = valueOrElse(getString("%s%s__cfg__nodesRegistryAddress"), "3P9vKqQKjUdmpXAfiWau8krREYAY1Xr69pE")
812811 let nodeRegAddr = addressFromStringValue(nodeRegAddrStr)
813812 let lGroupNodeListKEY = getLeaseGroupNodeListKey(groupNum)
814813 let lGrNodeOpt = getString(this, lGroupNodeListKEY)
815814 if (isDefined(lGrNodeOpt))
816815 then throw((("group " + toString(groupNum)) + " already initialized"))
817816 else {
818817 let nList = split(nListS, SEP)
819818 let expCount = size(nIdxs)
820819 if ((i.callerPublicKey != mngPub))
821820 then throw("approveLeasings not authorized")
822821 else {
823- let $t03574835810 = readNodeInfo(0)
824- let nAddr0 = $t03574835810._1
825- let lAmtKEY0 = $t03574835810._2
826- let lAmt0 = $t03574835810._3
827- let lIdKEY0 = $t03574835810._4
828- let lId0 = $t03574835810._5
822+ let $t03577035832 = readNodeInfo(0)
823+ let nAddr0 = $t03577035832._1
824+ let lAmtKEY0 = $t03577035832._2
825+ let lAmt0 = $t03577035832._3
826+ let lIdKEY0 = $t03577035832._4
827+ let lId0 = $t03577035832._5
829828 let newL0 = Lease(nAddr0, (lAmt0 - (lAmt * expCount)))
830829 let validation = invoke(nodeRegAddr, "validateAndApproveLeasings", [nListS], nil)
831830 if ((validation == validation))
832831 then {
833832 func forEachNodeValidateAndGenerateLease (a,i) = {
834833 let node = nList[i]
835834 let la = Lease(addressFromStringValue(node), lAmt)
836835 (a ++ [la, BinaryEntry(getLeaseIdByAddressKey(node), lcalc(la)), IntegerEntry(getLeaseAmountByAddressKey(node), lAmt)])
837836 }
838837
839838 ([StringEntry(lGroupNodeListKEY, nListS), BinaryEntry(lIdKEY0, lcalc(newL0)), IntegerEntry(lAmtKEY0, newL0.amount), LeaseCancel(lId0), newL0] ++ {
840839 let $l = nIdxs
841840 let $s = size($l)
842841 let $acc0 = nil
843842 func $f0_1 ($a,$i) = if (($i >= $s))
844843 then $a
845844 else forEachNodeValidateAndGenerateLease($a, $l[$i])
846845
847846 func $f0_2 ($a,$i) = if (($i >= $s))
848847 then $a
849848 else throw("List size exceeds 8")
850849
851850 $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)
852851 })
853852 }
854853 else throw("Strict value is not equal to itself.")
855854 }
856855 }
857856 }
858857
859858
860859
861860 @Callable(i)
862861 func rebalanceLeasings (amount,groupNum) = {
863862 let nIdxs = [0, 1, 2, 3, 4, 5, 6, 7]
864863 let mngPubS = valueOrElse(getString("%s%s__cfg__leasingManagerPub"), "7AUMX54ukYMYvPmma7yoFf5NjZhs4Bu5nz3Ez9EV8sur")
865864 let mngPub = fromBase58String(mngPubS)
866865 let lGroupNodeListKEY = getLeaseGroupNodeListKey(groupNum)
867866 let nListS = getStringOrFail(this, lGroupNodeListKEY)
868867 let nList = split(nListS, SEP)
869868 if ((i.callerPublicKey != mngPub))
870869 then throw("rebalanceLeasings not authorized")
871870 else {
872871 let unleaseAmt = ((amount / size(nList)) + 1)
873- let $t03705037112 = readNodeInfo(0)
874- let nAddr0 = $t03705037112._1
875- let lAmtKEY0 = $t03705037112._2
876- let lAmt0 = $t03705037112._3
877- let lIdKEY0 = $t03705037112._4
878- let lId0 = $t03705037112._5
872+ let $t03707237134 = readNodeInfo(0)
873+ let nAddr0 = $t03707237134._1
874+ let lAmtKEY0 = $t03707237134._2
875+ let lAmt0 = $t03707237134._3
876+ let lIdKEY0 = $t03707237134._4
877+ let lId0 = $t03707237134._5
879878 let newL0 = Lease(nAddr0, (lAmt0 + (unleaseAmt * size(nList))))
880879 func forEachNodeDoUnlease (a,i) = {
881880 let node = nList[i]
882881 let lIdKEY = getLeaseIdByAddressKey(node)
883882 let lId = getBinaryValue(this, lIdKEY)
884883 let lAmtKEY = getLeaseAmountByAddressKey(node)
885884 let lAmt = getIntegerValue(this, lAmtKEY)
886885 let ula = LeaseCancel(value(lId))
887886 let la = Lease(addressFromStringValue(node), (lAmt - unleaseAmt))
888887 (a ++ [LeaseCancel(value(lId)), la, BinaryEntry(lIdKEY, lcalc(la)), IntegerEntry(lAmtKEY, la.amount)])
889888 }
890889
891890 ({
892891 let $l = nIdxs
893892 let $s = size($l)
894893 let $acc0 = nil
895894 func $f0_1 ($a,$i) = if (($i >= $s))
896895 then $a
897896 else forEachNodeDoUnlease($a, $l[$i])
898897
899898 func $f0_2 ($a,$i) = if (($i >= $s))
900899 then $a
901900 else throw("List size exceeds 8")
902901
903902 $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)
904903 } ++ [BinaryEntry(lIdKEY0, lcalc(newL0)), IntegerEntry(lAmtKEY0, newL0.amount), LeaseCancel(lId0), newL0])
905904 }
906905 }
907906
908907
909908
910909 @Callable(i)
911910 func swapParamsByUserSYSREADONLY (userAddressStr,gnsbtDiff) = {
912911 let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", [userAddressStr, 0, 0], nil))
913912 let gnsbtAmt = (asInt(gnsbtData[0]) + gnsbtDiff)
914913 let gnsbtAmtTotal = (asInt(gnsbtData[1]) + gnsbtDiff)
915914 let swapLimitData = asAnyList(invoke(mathContract, "calcSwapLimitREADONLY", [gnsbtAmt], nil))
916915 let wavesSwapLimitInUsdnMax = asInt(swapLimitData[0])
917916 let wavesSwapLimitMax = asInt(swapLimitData[1])
918917 let usdnSwapLimitMax = asInt(swapLimitData[2])
919918 let lastSwapHeight = valueOrElse(getInteger(this, keyUserLastSwapHeight(userAddressStr)), 0)
920919 let swapLimitTimelifeBlocks = swapsTimeframeREAD()
921920 let passedBlocksAfterLastSwap = (height - lastSwapHeight)
922921 let isSwapTimelifeNew = (passedBlocksAfterLastSwap >= swapLimitTimelifeBlocks)
923922 let swapLimitSpentInUsdn = if (isSwapTimelifeNew)
924923 then 0
925924 else valueOrElse(getInteger(this, keySwapUserSpentInPeriod(userAddressStr)), 0)
926925 let blcks2LmtReset = if (isSwapTimelifeNew)
927926 then 0
928927 else (swapLimitTimelifeBlocks - passedBlocksAfterLastSwap)
929928 $Tuple2(nil, $Tuple7(wavesSwapLimitInUsdnMax, swapLimitSpentInUsdn, blcks2LmtReset, gnsbtAmt, gnsbtAmtTotal, wavesSwapLimitMax, usdnSwapLimitMax))
930929 }
931930
932931
933932
934933 @Callable(i)
935934 func calcWithdrawResultSYSREADONLY (swapType,inAmount,price) = {
936935 let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
937936 $Tuple2(nil, calcWithdraw(swapType, inAmount, price, neutrinoMetrics))
938937 }
939938
940939
941940
942941 @Callable(i)
943942 func replaceCommunityNode (oldAddrStr,newAddrStr,groupNum,penaltyAmount) = {
944943 let mngPubS = valueOrElse(getString("%s%s__cfg__leasingManagerPub"), "7AUMX54ukYMYvPmma7yoFf5NjZhs4Bu5nz3Ez9EV8sur")
945944 let mngPub = fromBase58String(mngPubS)
946945 if ((i.callerPublicKey != mngPub))
947946 then throw("replaceCommunityNode not authorized")
948947 else {
949948 let groupKey = getLeaseGroupNodeListKey(groupNum)
950949 let groupNodeListS = getStringOrFail(this, groupKey)
951950 if (!(contains(groupNodeListS, oldAddrStr)))
952951 then throw(((("Group " + toString(groupNum)) + " does not contain address ") + oldAddrStr))
953952 else {
954953 let doReplace = invoke(nodeRegistryContract, "replaceApprovedNode", [oldAddrStr, newAddrStr, groupNum, penaltyAmount], nil)
955954 if ((doReplace == doReplace))
956955 then {
957956 let oldLeaseIdKey = getLeaseIdByAddressKey(oldAddrStr)
958957 let oldLeaseAmtKey = getLeaseAmountByAddressKey(oldAddrStr)
959958 let leaseAmt = getIntegerValue(oldLeaseAmtKey)
960959 let newLeaseIdKey = getLeaseIdByAddressKey(oldAddrStr)
961960 let newLeaseAmtKey = getLeaseAmountByAddressKey(oldAddrStr)
962961 let newLease = Lease(addressFromStringValue(newAddrStr), leaseAmt)
963962 let updatedGroupNodeListS = makeString(split(groupNodeListS, oldAddrStr), newAddrStr)
964963 $Tuple2([LeaseCancel(getBinaryValue(oldLeaseIdKey)), DeleteEntry(oldLeaseIdKey), DeleteEntry(oldLeaseAmtKey), StringEntry(groupKey, updatedGroupNodeListS), newLease, BinaryEntry(newLeaseIdKey, lcalc(newLease)), IntegerEntry(newLeaseAmtKey, leaseAmt)], unit)
965964 }
966965 else throw("Strict value is not equal to itself.")
967966 }
968967 }
969968 }
970969
971970
972971
973972 @Callable(i)
974973 func updateReservesAndNeutrinoSupply () = {
975974 func getNumberByKeyInternal (key) = match getInteger(this, key) {
976975 case a: Int =>
977976 a
978977 case _ =>
979978 0
980979 }
981980
982981 let nMetrix = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
983982 let idx = getNumberByKeyInternal("updateReservesAndNeutrinoSupplyIdx")
984983 let newIdx = (idx + 1)
985984 [IntegerEntry("updateReservesAndNeutrinoSupplyIdx", newIdx), IntegerEntry("reserve", asInt(nMetrix[3])), IntegerEntry("neutrinoSupply", asInt(nMetrix[5])), IntegerEntry("reservesInUsdn", convertWavesToNeutrino(asInt(nMetrix[3]), asInt(nMetrix[0]))), IntegerEntry("surplus", asInt(nMetrix[6])), IntegerEntry("deficit", -(asInt(nMetrix[6])))]
986985 }
987986
988987
989988
990989 @Callable(i)
991990 func wavesBalancesVsPayment () = {
992991 let b = wavesBalance(this)
993992 [IntegerEntry("wavesBalance_available", b.available), IntegerEntry("wavesBalance_regular", b.regular), IntegerEntry("wavesBalance_generating", b.generating), IntegerEntry("wavesBalance_effective", b.effective), IntegerEntry("waves_payment", value(i.payments[0]).amount)]
994993 }
995994
996995
997996 @Verifier(tx)
998997 func verify () = {
999998 let pubKeyAdminsListStr = makeString(["ExtEEK19nmKj9mCpnWyvEEJFYATLMcVEMvohhUHkyHNm", "Ev5py5FfBQX9cZpYKnfQrTB49Byf8QmpZWeDVRim4yV7", "DUuuLjXu98nBwZc7fqwCTjtA3nnRwgTbkMSr5SU2NmDR", "DUuuLjXu98nBwZc7fqwCTjtA3nnRwgTbkMSr5SU2NmDR"], SEP)
1000999 let pubKeyAdminsList = split(valueOrElse(getString(controlContract, "%s__multisig"), pubKeyAdminsListStr), SEP)
10011000 let count = ((((if (sigVerify(tx.bodyBytes, tx.proofs[0], fromBase58String(pubKeyAdminsList[0])))
10021001 then 1
10031002 else 0) + (if (sigVerify(tx.bodyBytes, tx.proofs[1], fromBase58String(pubKeyAdminsList[1])))
10041003 then 1
10051004 else 0)) + (if (sigVerify(tx.bodyBytes, tx.proofs[2], fromBase58String(pubKeyAdminsList[2])))
10061005 then 1
10071006 else 0)) + (if (sigVerify(tx.bodyBytes, tx.proofs[3], fromBase58String(pubKeyAdminsList[3])))
10081007 then 2
10091008 else 0))
10101009 if (if (isBlocked)
10111010 then (getStringValue(controlContract, "is_blocked_caller") == toString(govContract))
10121011 else false)
10131012 then validateUpdate(tx)
10141013 else match tx {
10151014 case sponsorTx: SponsorFeeTransaction =>
10161015 if (checkIsValidMinSponsoredFee(sponsorTx))
10171016 then (count >= 3)
10181017 else false
10191018 case _ =>
10201019 (count >= 3)
10211020 }
10221021 }
10231022

github/deemru/w8io/3ef1775 
738.37 ms