2023.03.02 15:39 [3537923] smart account 3PC9BfRwJWWiw9AREE2B3eWzCks3CYtg4yo > SELF 0.00000000 Waves

{ "type": 13, "id": "7eyTCTkdPfAj4tkR3y6cunoNJU9uvGKmijM4njjPCWKt", "fee": 4200000, "feeAssetId": null, "timestamp": 1677763583817, "version": 2, "chainId": 87, "sender": "3PC9BfRwJWWiw9AREE2B3eWzCks3CYtg4yo", "senderPublicKey": "BRnVwSVctnV8pge5vRpsJdWnkjWEJspFb6QvrmZvu3Ht", "proofs": [ "", "3JwVdcWU9DkTwhteDBZvr4Yg2CbpV8y987ha4G783dPXgroXDb8zdbbhez8x9Cf8F1hEkYRw65cZfsdKNC7iAh32", "", "2fiMT2u49HBvnGhQLrRcYJddVuuSRXZLP87FkZ2VpiRa5CB2VzjtS1kT3VxEF8TmvjgR4XzLq8CKfU9c6WWCvEDf" ], "script": "base64:BgJjCAISDgoMCAgICAgIAQEBAQEBEgUKAwgIARIHCgUYAQEBARIAEgASBAoCCAESBQoDCAEIEgMKAQESBAoCAQgSABIFCgMIAQESBAoCAQESBAoCCAESBgoECAEBCBIGCgQICAEBtAEAC3JldmlzaW9uTnVtAig0NmRkZjlhZDRmNGE2N2E3OWQ4NzJmN2M1NjcxYWEwMTI5NTNhMzRiAQ9nZXRTdHJpbmdPckZhaWwCB2FkZHJlc3MDa2V5CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ0IAgUHYWRkcmVzcwUDa2V5CQC5CQIJAMwIAgIKbWFuZGF0b3J5IAkAzAgCCQClCAEFB2FkZHJlc3MJAMwIAgIBLgkAzAgCBQNrZXkJAMwIAgIPIGlzIG5vdCBkZWZpbmVkBQNuaWwCAAEFbGNhbGMBAWwJALkIAQUBbAEOZ2V0TnVtYmVyQnlLZXkBA2tleQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQNrZXkAAAEOZ2V0U3RyaW5nQnlLZXkBA2tleQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzBQNrZXkCAAEMZ2V0Qm9vbEJ5S2V5AQNrZXkJAQt2YWx1ZU9yRWxzZQIJAJsIAgUEdGhpcwUDa2V5BwEYZ2V0TnVtYmVyQnlBZGRyZXNzQW5kS2V5AgdhZGRyZXNzA2tleQkBC3ZhbHVlT3JFbHNlAgkAmggCBQdhZGRyZXNzBQNrZXkAAAEYZ2V0U3RyaW5nQnlBZGRyZXNzQW5kS2V5AgdhZGRyZXNzA2tleQkBC3ZhbHVlT3JFbHNlAgkAnQgCCQERQGV4dHJOYXRpdmUoMTA2MikBBQdhZGRyZXNzBQNrZXkCAAEWZ2V0Qm9vbEJ5QWRkcmVzc0FuZEtleQIHYWRkcmVzcwNrZXkJAQt2YWx1ZU9yRWxzZQIJAJsIAgUHYWRkcmVzcwUDa2V5BwEJYXNBbnlMaXN0AQF2BAckbWF0Y2gwBQF2AwkAAQIFByRtYXRjaDACCUxpc3RbQW55XQQBbAUHJG1hdGNoMAUBbAkAAgECG2ZhaWwgdG8gY2FzdCBpbnRvIExpc3RbQW55XQEIYXNTdHJpbmcBAXYEByRtYXRjaDAFAXYDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFzBQckbWF0Y2gwBQFzCQACAQIYZmFpbCB0byBjYXN0IGludG8gU3RyaW5nAQVhc0ludAEBdgQHJG1hdGNoMAUBdgMJAAECBQckbWF0Y2gwAgNJbnQEAWkFByRtYXRjaDAFAWkJAAIBAhVmYWlsIHRvIGNhc3QgaW50byBJbnQBB2FzQnl0ZXMBA3ZhbAQHJG1hdGNoMAUDdmFsAwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEB3ZhbEJ5dGUFByRtYXRjaDAFB3ZhbEJ5dGUJAAIBAhxmYWlsIHRvIGNhc3QgaW50byBCeXRlVmVjdG9yAQlhc1BheW1lbnQBAXYEByRtYXRjaDAFAXYDCQABAgUHJG1hdGNoMAIPQXR0YWNoZWRQYXltZW50BAFwBQckbWF0Y2gwBQFwCQACAQIhZmFpbCB0byBjYXN0IGludG8gQXR0YWNoZWRQYXltZW50ARJhc1N3YXBQYXJhbXNTVFJVQ1QBAXYEByRtYXRjaDAFAXYDCQABAgUHJG1hdGNoMAIjKEludCwgSW50LCBJbnQsIEludCwgSW50LCBJbnQsIEludCkEBnN0cnVjdAUHJG1hdGNoMAUGc3RydWN0CQACAQIdZmFpbCB0byBjYXN0IGludG8gVHVwbGU1IGludHMAA1NFUAICX18AB0xJU1RTRVACAToABU1VTFQ4AIDC1y8ABU1VTFQ2AMCEPQAOREVGQVVMVFNXQVBGRUUAoJwBAAtCUlBST1RFQ1RFRACgjQYAB1dBVkVTSUQBBBOr2TMAD25NZXRyaWNJZHhQcmljZQAAABtuTWV0cmljSWR4VXNkbkxvY2tlZEJhbGFuY2UAAQAcbk1ldHJpY0lkeFdhdmVzTG9ja2VkQmFsYW5jZQACABFuTWV0cmljSWR4UmVzZXJ2ZQADABduTWV0cmljSWR4UmVzZXJ2ZUluVXNkbgAEABRuTWV0cmljSWR4VXNkblN1cHBseQAFABFuTWV0cmljSWR4U3VycGx1cwAGABhuTWV0cmljSWR4U3VycGx1c1BlcmNlbnQABwAMbk1ldHJpY0lkeEJSAAgAFG5NZXRyaWNJZHhOc2J0U3VwcGx5AAkAF25NZXRyaWNJZHhNYXhOc2J0U3VwcGx5AAoAFG5NZXRyaWNJZHhTdXJmU3VwcGx5AAsAEm5NZXRyaWNVc2RuVXNkdFBlZwAMABZuTWV0cmljQ3VycmVudFByaWNlQWRqAA0AEW5NZXRyaWNCYXNrZXRJbmZvAA4AFG5NZXRyaWNXZWlnaHRlZFByaWNlAA8AF25NZXRyaWNUb3RhbFJlc2VydmVzVXNkABAAGUlkeENvbnRyb2xDZmdOZXV0cmlub0RhcHAAAQAYSWR4Q29udHJvbENmZ0F1Y3Rpb25EYXBwAAIAFElkeENvbnRyb2xDZmdScGREYXBwAAMAFUlkeENvbnRyb2xDZmdNYXRoRGFwcAAEABxJZHhDb250cm9sQ2ZnTGlxdWlkYXRpb25EYXBwAAUAFUlkeENvbnRyb2xDZmdSZXN0RGFwcAAGAB1JZHhDb250cm9sQ2ZnTm9kZVJlZ2lzdHJ5RGFwcAAHABxJZHhDb250cm9sQ2ZnTnNidFN0YWtpbmdEYXBwAAgAGUlkeENvbnRyb2xDZmdNZWRpYXRvckRhcHAACQAcSWR4Q29udHJvbENmZ1N1cmZTdGFraW5nRGFwcAAKACBJZHhDb250cm9sQ2ZnR25zYnRDb250cm9sbGVyRGFwcAALABdJZHhDb250cm9sQ2ZnUmVzdFYyRGFwcAAMABtJZHhDb250cm9sQ2ZnR292ZXJuYW5jZURhcHAADQERa2V5Q29udHJvbEFkZHJlc3MAAhwlcyVzX19jb25maWdfX2NvbnRyb2xBZGRyZXNzAQ1rZXlDb250cm9sQ2ZnAAIRJXNfX2NvbnRyb2xDb25maWcBFHJlYWRDb250cm9sQ2ZnT3JGYWlsAQdjb250cm9sCQC8CQIJAQ9nZXRTdHJpbmdPckZhaWwCBQdjb250cm9sCQENa2V5Q29udHJvbENmZwAFA1NFUAEYZ2V0Q29udHJhY3RBZGRyZXNzT3JGYWlsAgpjb250cm9sQ2ZnA2lkeAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJAJEDAgUKY29udHJvbENmZwUDaWR4CQCsAgICLUNvbnRyb2wgY2ZnIGRvZXNuJ3QgY29udGFpbiBhZGRyZXNzIGF0IGluZGV4IAkApAMBBQNpZHgAD2NvbnRyb2xDb250cmFjdAkBEUBleHRyTmF0aXZlKDEwNjIpAQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzCQERa2V5Q29udHJvbEFkZHJlc3MAAiMzUDVCZmQ1OFBQZk52Qk0ySHk4UWZiY0RxTWVOdHpnN0tmUAAKY29udHJvbENmZwkBFHJlYWRDb250cm9sQ2ZnT3JGYWlsAQUPY29udHJvbENvbnRyYWN0AAxtYXRoQ29udHJhY3QJARhnZXRDb250cmFjdEFkZHJlc3NPckZhaWwCBQpjb250cm9sQ2ZnBRVJZHhDb250cm9sQ2ZnTWF0aERhcHAAE25zYnRTdGFraW5nQ29udHJhY3QJARhnZXRDb250cmFjdEFkZHJlc3NPckZhaWwCBQpjb250cm9sQ2ZnBRxJZHhDb250cm9sQ2ZnTnNidFN0YWtpbmdEYXBwABNzdXJmU3Rha2luZ0NvbnRyYWN0CQEYZ2V0Q29udHJhY3RBZGRyZXNzT3JGYWlsAgUKY29udHJvbENmZwUcSWR4Q29udHJvbENmZ1N1cmZTdGFraW5nRGFwcAAXZ25zYnRDb250cm9sbGVyQ29udHJhY3QJARhnZXRDb250cmFjdEFkZHJlc3NPckZhaWwCBQpjb250cm9sQ2ZnBSBJZHhDb250cm9sQ2ZnR25zYnRDb250cm9sbGVyRGFwcAAPYXVjdGlvbkNvbnRyYWN0CQEYZ2V0Q29udHJhY3RBZGRyZXNzT3JGYWlsAgUKY29udHJvbENmZwUYSWR4Q29udHJvbENmZ0F1Y3Rpb25EYXBwABRub2RlUmVnaXN0cnlDb250cmFjdAkBGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAIFCmNvbnRyb2xDZmcFHUlkeENvbnRyb2xDZmdOb2RlUmVnaXN0cnlEYXBwAAtnb3ZDb250cmFjdAkBGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAIFCmNvbnRyb2xDZmcFG0lkeENvbnRyb2xDZmdHb3Zlcm5hbmNlRGFwcAASTmV1dHJpbm9Bc3NldElkS2V5AhFuZXV0cmlub19hc3NldF9pZAAOQm9uZEFzc2V0SWRLZXkCDWJvbmRfYXNzZXRfaWQAEkF1Y3Rpb25Db250cmFjdEtleQIQYXVjdGlvbl9jb250cmFjdAAWTnNidFN0YWtpbmdDb250cmFjdEtleQITbnNidFN0YWtpbmdDb250cmFjdAAWTGlxdWlkYXRpb25Db250cmFjdEtleQIUbGlxdWlkYXRpb25fY29udHJhY3QADlJQRENvbnRyYWN0S2V5AgxycGRfY29udHJhY3QAEUNvbnRvbENvbnRyYWN0S2V5AhBjb250cm9sX2NvbnRyYWN0AA9NYXRoQ29udHJhY3RLZXkCDW1hdGhfY29udHJhY3QAG0JhbGFuY2VXYXZlc0xvY2tJbnRlcnZhbEtleQIbYmFsYW5jZV93YXZlc19sb2NrX2ludGVydmFsAB5CYWxhbmNlTmV1dHJpbm9Mb2NrSW50ZXJ2YWxLZXkCHmJhbGFuY2VfbmV1dHJpbm9fbG9ja19pbnRlcnZhbAEVTWluVG9rZW5Td2FwQW1vdW50S2V5AQdhc3NldElkCQCsAgICHG1pbl9vdXROZXV0cmlub19zd2FwX2Ftb3VudF8FB2Fzc2V0SWQAGE1pbk5ldXRyaW5vU3dhcEFtb3VudEtleQIYbWluX291dE11bHRpX3N3YXBfYW1vdW50AB5MZWdhY3lNaW5OZXV0cmlub1N3YXBBbW91bnRLZXkCGG1pbl9uZXV0cmlub19zd2FwX2Ftb3VudAAbTm9kZU9yYWNsZVByb3ZpZGVyUHViS2V5S2V5AhRub2RlX29yYWNsZV9wcm92aWRlcgAVTmV1dHJpbm9PdXRGZWVQYXJ0S2V5AhhuZXV0cmlub091dF9zd2FwX2ZlZVBhcnQAEldhdmVzT3V0RmVlUGFydEtleQIVd2F2ZXNPdXRfc3dhcF9mZWVQYXJ0AQ9rZXlOb2RlUmVnaXN0cnkBB2FkZHJlc3MJAKwCAgIEJXNfXwUHYWRkcmVzcwAIUHJpY2VLZXkCBXByaWNlAA1QcmljZUluZGV4S2V5AgtwcmljZV9pbmRleAAMSXNCbG9ja2VkS2V5Agppc19ibG9ja2VkARJnZXRQcmljZUhpc3RvcnlLZXkBBWJsb2NrCQCsAgIJAKwCAgUIUHJpY2VLZXkCAV8JAKQDAQUFYmxvY2sBGGdldEhlaWdodFByaWNlQnlJbmRleEtleQEFaW5kZXgJAKwCAgkArAICBQ1QcmljZUluZGV4S2V5AgFfCQCkAwEFBWluZGV4ARVnZXRTdGFraW5nTm9kZUJ5SW5kZXgBA2lkeAkBDmdldFN0cmluZ0J5S2V5AQkAuQkCCQDMCAICBiVzJWQlcwkAzAgCAgVsZWFzZQkAzAgCCQCkAwEFA2lkeAkAzAgCAgtub2RlQWRkcmVzcwUDbmlsBQNTRVABHGdldFN0YWtpbmdOb2RlQWRkcmVzc0J5SW5kZXgBA2lkeAkBEUBleHRyTmF0aXZlKDEwNjIpAQkBFWdldFN0YWtpbmdOb2RlQnlJbmRleAEFA2lkeAEfZ2V0UmVzZXJ2ZWRBbW91bnRGb3JTcG9uc29yc2hpcAAJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkAuQkCCQDMCAICBCVzJXMJAMwIAgIFbGVhc2UJAMwIAgIXc3BvbnNvcnNoaXBXYXZlc1Jlc2VydmUFA25pbAUDU0VQCQBoAgDoBwUFTVVMVDgBGGdldEJhbGFuY2VVbmxvY2tCbG9ja0tleQEFb3duZXIJAKwCAgIVYmFsYW5jZV91bmxvY2tfYmxvY2tfBQVvd25lcgENZ2V0TGVhc2VJZEtleQEJbm9kZUluZGV4CQC5CQIJAMwIAgIGJXMlZCVzCQDMCAICBWxlYXNlCQDMCAIJAKQDAQUJbm9kZUluZGV4CQDMCAICAmlkBQNuaWwFA1NFUAEWZ2V0TGVhc2VJZEJ5QWRkcmVzc0tleQELbm9kZUFkZHJlc3MJALkJAgkAzAgCAgYlcyVzJXMJAMwIAgIObGVhc2VCeUFkZHJlc3MJAMwIAgULbm9kZUFkZHJlc3MJAMwIAgICaWQFA25pbAUDU0VQARFnZXRMZWFzZUFtb3VudEtleQEJbm9kZUluZGV4CQC5CQIJAMwIAgIGJXMlZCVzCQDMCAICBWxlYXNlCQDMCAIJAKQDAQUJbm9kZUluZGV4CQDMCAICBmFtb3VudAUDbmlsBQNTRVABGmdldExlYXNlQW1vdW50QnlBZGRyZXNzS2V5AQtub2RlQWRkcmVzcwkAuQkCCQDMCAICBiVzJXMlcwkAzAgCAg5sZWFzZUJ5QWRkcmVzcwkAzAgCBQtub2RlQWRkcmVzcwkAzAgCAgZhbW91bnQFA25pbAUDU0VQARhnZXRMZWFzZUdyb3VwTm9kZUxpc3RLZXkBCGdyb3VwTnVtCQC5CQIJAMwIAgIGJXMlZCVzCQDMCAICCmxlYXNlR3JvdXAJAMwIAgkApAMBBQhncm91cE51bQkAzAgCAghub2RlTGlzdAUDbmlsBQNTRVABEG1pblN3YXBBbW91bnRLRVkBCHN3YXBUeXBlCQCsAgIJAKwCAgIEbWluXwUIc3dhcFR5cGUCDF9zd2FwX2Ftb3VudAEOdG90YWxMb2NrZWRLRVkCCHN3YXBUeXBlB2Fzc2V0SWQJALkJAgkAzAgCAgYlcyVzJXMJAMwIAgILYmFsYW5jZUxvY2sJAMwIAgUIc3dhcFR5cGUJAMwIAgUHYXNzZXRJZAUDbmlsBQNTRVABFHRvdGFsTG9ja2VkQnlVc2VyS0VZAwhzd2FwVHlwZQVvd25lcgdhc3NldElkCQC5CQIJAMwIAgIIJXMlcyVzJXMJAMwIAgILYmFsYW5jZUxvY2sJAMwIAgUIc3dhcFR5cGUJAMwIAgUFb3duZXIJAMwIAgUHYXNzZXRJZAUDbmlsAgFfARZiYWxhbmNlTG9ja0ludGVydmFsS0VZAQhzd2FwVHlwZQMJAAACBQhzd2FwVHlwZQIIb3V0TXVsdGkFHkJhbGFuY2VOZXV0cmlub0xvY2tJbnRlcnZhbEtleQUbQmFsYW5jZVdhdmVzTG9ja0ludGVydmFsS2V5ARpub2RlQmFsYW5jZUxvY2tJbnRlcnZhbEtFWQACGmJhbGFuY2Vfbm9kZV9sb2NrX2ludGVydmFsARFzd2Fwc1RpbWVmcmFtZUtFWQACD3N3YXBzX3RpbWVmcmFtZQEOYnJQcm90ZWN0ZWRLRVkAAhdtaW5fQlJfcHJvdGVjdGlvbl9sZXZlbAEPYmFza2V0QXNzZXRzS2V5AAIaJXMlc19fY29tbW9uX19iYXNrZXRBc3NldHMBCmJhc2tldERLZXkAAhUlcyVzX19jb21tb25fX2Jhc2tldEQBCmJhc2tldEtLZXkAAhUlcyVzX19jb21tb25fX2Jhc2tldEsBCmJhc2tldEJLZXkAAhUlcyVzX19jb21tb25fX2Jhc2tldEIBEmJhc2tldExvZ2JEZWx0YUtleQACHSVzJXNfX2NvbW1vbl9fYmFza2V0TG9nYkRlbHRhARZiYXNrZXRXZWlnaHRCeUFzc2V0S2V5AQdhc3NldElkCQCsAgICHyVzJXMlc19fY29tbW9uX193ZWlnaHRCeUFzc2V0X18FB2Fzc2V0SWQBD2tleVByaWNlQnlBc3NldAEHYXNzZXRJZAkArAICAh4lcyVzJXNfX2NvbW1vbl9fcHJpY2VCeUFzc2V0X18FB2Fzc2V0SWQBEW1pblN3YXBBbW91bnRSRUFEAghzd2FwVHlwZQdhc3NldElkAwkAAAIFCHN3YXBUeXBlAghvdXRNdWx0aQkBC3ZhbHVlT3JFbHNlAgkAnwgBBRhNaW5OZXV0cmlub1N3YXBBbW91bnRLZXkJAQ5nZXROdW1iZXJCeUtleQEFHkxlZ2FjeU1pbk5ldXRyaW5vU3dhcEFtb3VudEtleQkBDmdldE51bWJlckJ5S2V5AQkBFU1pblRva2VuU3dhcEFtb3VudEtleQEFB2Fzc2V0SWQBEnN3YXBzVGltZWZyYW1lUkVBRAAJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBEXN3YXBzVGltZWZyYW1lS0VZAACgCwEPdG90YWxMb2NrZWRSRUFEAghzd2FwVHlwZQdhc3NldElkCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQ50b3RhbExvY2tlZEtFWQIFCHN3YXBUeXBlBQdhc3NldElkAAABFXRvdGFsTG9ja2VkQnlVc2VyUkVBRAMIc3dhcFR5cGUFb3duZXIHYXNzZXRJZAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEUdG90YWxMb2NrZWRCeVVzZXJLRVkDBQhzd2FwVHlwZQUFb3duZXIFB2Fzc2V0SWQAAAEXYmFsYW5jZUxvY2tJbnRlcnZhbFJFQUQBCHN3YXBUeXBlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJARZiYWxhbmNlTG9ja0ludGVydmFsS0VZAQUIc3dhcFR5cGUAoAsBG25vZGVCYWxhbmNlTG9ja0ludGVydmFsUkVBRAAJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBGm5vZGVCYWxhbmNlTG9ja0ludGVydmFsS0VZAAABARhrZXlTd2FwVXNlclNwZW50SW5QZXJpb2QBC3VzZXJBZGRyZXNzCQC5CQIJAMwIAgIEJXMlcwkAzAgCAhVzd2FwVXNlclNwZW50SW5QZXJpb2QJAMwIAgULdXNlckFkZHJlc3MFA25pbAUDU0VQARVrZXlVc2VyTGFzdFN3YXBIZWlnaHQBC3VzZXJBZGRyZXNzCQC5CQIJAMwIAgIEJXMlcwkAzAgCAhJ1c2VyTGFzdFN3YXBIZWlnaHQJAMwIAgULdXNlckFkZHJlc3MFA25pbAUDU0VQARZjb252ZXJ0TmV1dHJpbm9Ub1dhdmVzAgZhbW91bnQFcHJpY2UJAGsDBQZhbW91bnQFBU1VTFQ4BQVwcmljZQERY29udmVydFRva2VuVG9Vc2QCBmFtb3VudAVwcmljZQkAawMFBmFtb3VudAUFcHJpY2UFBU1VTFQ4ARZjb252ZXJ0V2F2ZXNUb05ldXRyaW5vAgZhbW91bnQFcHJpY2UJAGsDBQZhbW91bnQFBXByaWNlBQVNVUxUOAESY29udmVydFdhdmVzVG9Cb25kAgZhbW91bnQFcHJpY2UJARFjb252ZXJ0VG9rZW5Ub1VzZAIFBmFtb3VudAUFcHJpY2UBFmNvbnZlcnRKc29uQXJyYXlUb0xpc3QBCWpzb25BcnJheQkAtQkCBQlqc29uQXJyYXkCASwBG2NvbnZlcnRCYXNrZXRJdGVtVG9OZXV0cmlubwQIaW5BbW91bnQHaW5Bc3NldA1iYXNrZXRJbmZvU3RyDW5ldXRyaW5vUHJpY2UECmJhc2tldEluZm8JALwJAgUNYmFza2V0SW5mb1N0cgIBXwoBCGZpbmRJdGVtAgNhY2MEaXRlbQQFYkl0ZW0JALUJAgUEaXRlbQUHTElTVFNFUAMJAAACCQCRAwIFBWJJdGVtAAAFB2luQXNzZXQFBWJJdGVtBQNhY2MEAml0CgACJGwFCmJhc2tldEluZm8KAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBCGZpbmRJdGVtAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKBAVkbG9nNgkBBXZhbHVlAQkAnwgBCQESYmFza2V0TG9nYkRlbHRhS2V5AAQCZDYJAQV2YWx1ZQEJAJ8IAQkBCmJhc2tldERLZXkABAJiNgkBBXZhbHVlAQkAnwgBCQEKYmFza2V0QktleQAEAnc2CQEFdmFsdWUBCQCfCAEJARZiYXNrZXRXZWlnaHRCeUFzc2V0S2V5AQUHaW5Bc3NldAQCcDYJAGQCCQBlAgUFZGxvZzYFAnc2CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUCaXQAAQQDcHA2CQBsBgUCYjYABgUCcDYABgAGBQZIQUxGVVAEDm91dEFtb3VudEdyb3NzCQBrAwUIaW5BbW91bnQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQJpdAACAwkAAAIFDW5ldXRyaW5vUHJpY2UAAAUFTVVMVDgJAGgCBQ1uZXV0cmlub1ByaWNlAGQECm11bHRpcGxpZXIJAGUCCQBkAgUFTVVMVDYFAmQ2BQNwcDYECW5ldEFtb3VudAkAawMFDm91dEFtb3VudEdyb3NzBQptdWx0aXBsaWVyBQVNVUxUNgQJZmVlQW1vdW50AwkAZwIFCW5ldEFtb3VudAUOb3V0QW1vdW50R3Jvc3MAAAkAZQIFDm91dEFtb3VudEdyb3NzBQluZXRBbW91bnQJAMwIAgUOb3V0QW1vdW50R3Jvc3MJAMwIAgUJbmV0QW1vdW50CQDMCAIFCWZlZUFtb3VudAUDbmlsARdjb252ZXJ0TmV1dHJpbm9Ub0Jhc2tldAMGYW1vdW50DWJhc2tldEluZm9TdHIObmV1dHJpbm9TdXBwbHkECmJhc2tldEluZm8JALwJAgUNYmFza2V0SW5mb1N0cgIBXwoBBGNvbnYCA2FjYwRpdGVtBAVwYXJ0cwkAtQkCBQRpdGVtBQdMSVNUU0VQBAdhc3NldElkCQCRAwIFBXBhcnRzAAAEBXNoYXJlCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUFcGFydHMAAQQFcHJpY2UJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQVwYXJ0cwACBAZyZXNlcnYJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQVwYXJ0cwADAwkAAAIFDm5ldXRyaW5vU3VwcGx5AAAJAAIBAidBdHRlbXB0IHRvIGJ1cm4gbmV1dHJpbm8gYXQgemVybyBzdXBwbHkECW91dEFtb3VudAkAawMFBmFtb3VudAUGcmVzZXJ2BQ5uZXV0cmlub1N1cHBseQQKd2F2ZXNUdXBsZQMJAAACBQdhc3NldElkAgVXQVZFUwkAlAoCBQlvdXRBbW91bnQFBXByaWNlCQCUCgIIBQNhY2MCXzIIBQNhY2MCXzMJAJUKAwkAzQgCCAUDYWNjAl8xCQCWCgQFB2Fzc2V0SWQFCW91dEFtb3VudAUFcHJpY2UFBXNoYXJlCAUKd2F2ZXNUdXBsZQJfMQgFCndhdmVzVHVwbGUCXzIKAAIkbAUKYmFza2V0SW5mbwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAJAJUKAwUDbmlsAAAAAAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEEY29udgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgERbWluU3dhcEFtb3VudEZBSUwCCHN3YXBUeXBlDW1pblN3YXBBbW91bnQJAAIBCQCsAgIJAKwCAgkArAICAhhUaGUgc3BlY2lmaWVkIGFtb3VudCBpbiAFCHN3YXBUeXBlAisgc3dhcCBpcyBsZXNzIHRoYW4gdGhlIHJlcXVpcmVkIG1pbmltdW0gb2YgCQCkAwEFDW1pblN3YXBBbW91bnQBFWVtZXJnZW5jeVNodXRkb3duRkFJTAAJAAIBAlpjb250cmFjdCBpcyBibG9ja2VkIGJ5IEVNRVJHRU5DWSBTSFVURE9XTiBhY3Rpb25zIHVudGlsbCByZWFjdGl2YXRpb24gYnkgZW1lcmdlbmN5IG9yYWNsZXMBDnByaWNlSW5kZXhGQUlMBQVpbmRleApwcmljZUluZGV4C2luZGV4SGVpZ2h0DHVubG9ja0hlaWdodA9wcmV2SW5kZXhIZWlnaHQJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICAiNpbnZhbGlkIHByaWNlIGhpc3RvcnkgaW5kZXg6IGluZGV4PQkApAMBBQVpbmRleAIMIHByaWNlSW5kZXg9CQCkAwEFCnByaWNlSW5kZXgCDSBpbmRleEhlaWdodD0JAKQDAQULaW5kZXhIZWlnaHQCDiB1bmxvY2tIZWlnaHQ9CQCkAwEFDHVubG9ja0hlaWdodAIRIHByZXZJbmRleEhlaWdodD0JAKQDAQUPcHJldkluZGV4SGVpZ2h0AA9uZXV0cmlub0Fzc2V0SWQJANkEAQkBDmdldFN0cmluZ0J5S2V5AQUSTmV1dHJpbm9Bc3NldElkS2V5AApwcmljZUluZGV4CQEYZ2V0TnVtYmVyQnlBZGRyZXNzQW5kS2V5AgUPY29udHJvbENvbnRyYWN0BQ1QcmljZUluZGV4S2V5AAlpc0Jsb2NrZWQJARZnZXRCb29sQnlBZGRyZXNzQW5kS2V5AgUPY29udHJvbENvbnRyYWN0BQxJc0Jsb2NrZWRLZXkAGG5vZGVPcmFjbGVQcm92aWRlclB1YktleQkA2QQBCQEOZ2V0U3RyaW5nQnlLZXkBBRtOb2RlT3JhY2xlUHJvdmlkZXJQdWJLZXlLZXkAC2JvbmRBc3NldElkCQDZBAECLDZuU3BWeU5IN3lNNjllZzQ0NndyUVI5NGlwYmJjbVpNVTFFTlB3YW5DOTdnABVkZXByZWNhdGVkQm9uZEFzc2V0SWQJANkEAQIsOTc1YWtaQmZuTWo1MTNVN01aYUhLelFybXNFeDVhRTN3ZFdLVHJIQmhiakYAEG5ldXRyaW5vQ29udHJhY3QFBHRoaXMADGN1cnJlbnRQcmljZQkBGGdldE51bWJlckJ5QWRkcmVzc0FuZEtleQIFD2NvbnRyb2xDb250cmFjdAUIUHJpY2VLZXkBG2NoZWNrSXNWYWxpZE1pblNwb25zb3JlZEZlZQECdHgEDk1JTlRSQU5TRkVSRkVFAKCNBgQWU3BvbnNvcmVkRmVlVXBwZXJCb3VuZADoBwQPcmVhbE5ldXRyaW5vRmVlCQERY29udmVydFRva2VuVG9Vc2QCBQ5NSU5UUkFOU0ZFUkZFRQUMY3VycmVudFByaWNlBA5taW5OZXV0cmlub0ZlZQkAaAIFD3JlYWxOZXV0cmlub0ZlZQACBA5tYXhOZXV0cmlub0ZlZQkAawMFD3JlYWxOZXV0cmlub0ZlZQUWU3BvbnNvcmVkRmVlVXBwZXJCb3VuZABkBAhpbnB1dEZlZQkBBXZhbHVlAQgFAnR4FG1pblNwb25zb3JlZEFzc2V0RmVlAwMJAGcCBQhpbnB1dEZlZQUObWluTmV1dHJpbm9GZWUJAGcCBQ5tYXhOZXV0cmlub0ZlZQUIaW5wdXRGZWUHCQAAAggFAnR4B2Fzc2V0SWQFD25ldXRyaW5vQXNzZXRJZAcBD2dldFByaWNlSGlzdG9yeQEFYmxvY2sJARhnZXROdW1iZXJCeUFkZHJlc3NBbmRLZXkCBQ9jb250cm9sQ29udHJhY3QJARJnZXRQcmljZUhpc3RvcnlLZXkBBQVibG9jawEVZ2V0SGVpZ2h0UHJpY2VCeUluZGV4AQVpbmRleAkBGGdldE51bWJlckJ5QWRkcmVzc0FuZEtleQIFD2NvbnRyb2xDb250cmFjdAkBGGdldEhlaWdodFByaWNlQnlJbmRleEtleQEFBWluZGV4ARZrZXlMb2NrUGFyYW1Vc2VyQW1vdW50AQt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBiVzJXMlcwkAzAgCAgtwYXJhbUJ5VXNlcgkAzAgCBQt1c2VyQWRkcmVzcwkAzAgCAgZhbW91bnQFA25pbAUDU0VQAAxzSWR4U3dhcFR5cGUAAQAKc0lkeFN0YXR1cwACAAxzSWR4SW5BbW91bnQAAwAPc0lkeFN0YXJ0SGVpZ2h0AAcAEnNJZHhTdGFydFRpbWVzdGFtcAAIABRzSWR4U2VsZlVubG9ja0hlaWdodAALAAtzSWR4TWluUmFuZAAPAAtzSWR4TWF4UmFuZAAQAAtzSWR4SW5Bc3NldAAUAQdzd2FwS0VZAgt1c2VyQWRkcmVzcwR0eElkCQC5CQIJAMwIAgIEJXMlcwkAzAgCBQt1c2VyQWRkcmVzcwkAzAgCBQR0eElkBQNuaWwFA1NFUAELc3RyU3dhcERBVEEUCHN3YXBUeXBlBnN0YXR1cwhpbkFtb3VudAVwcmljZQxvdXROZXRBbW91bnQMb3V0RmVlQW1vdW50C3N0YXJ0SGVpZ2h0DnN0YXJ0VGltZXN0YW1wCWVuZEhlaWdodAxlbmRUaW1lc3RhbXAQc2VsZlVubG9ja0hlaWdodBByYW5kVW5sb2NrSGVpZ2h0BWluZGV4DHdpdGhkcmF3VHhJZAdyYW5kTWluB3JhbmRNYXgKb3V0U3VyZkFtdAJicgpiYXNrZXREYXRhB2luQXNzZXQJALoJAgkAzAgCAiglcyVzJWQlZCVkJWQlZCVkJWQlZCVkJWQlZCVzJWQlZCVkJWQlcyVzCQDMCAIFCHN3YXBUeXBlCQDMCAIFBnN0YXR1cwkAzAgCBQhpbkFtb3VudAkAzAgCBQVwcmljZQkAzAgCBQxvdXROZXRBbW91bnQJAMwIAgUMb3V0RmVlQW1vdW50CQDMCAIFC3N0YXJ0SGVpZ2h0CQDMCAIFDnN0YXJ0VGltZXN0YW1wCQDMCAIFCWVuZEhlaWdodAkAzAgCBQxlbmRUaW1lc3RhbXAJAMwIAgUQc2VsZlVubG9ja0hlaWdodAkAzAgCBRByYW5kVW5sb2NrSGVpZ2h0CQDMCAIFBWluZGV4CQDMCAIFDHdpdGhkcmF3VHhJZAkAzAgCBQdyYW5kTWluCQDMCAIFB3JhbmRNYXgJAMwIAgUKb3V0U3VyZkFtdAkAzAgCBQJicgkAzAgCBQpiYXNrZXREYXRhCQDMCAIFB2luQXNzZXQFA25pbAUDU0VQAQ9wZW5kaW5nU3dhcERBVEEECHN3YXBUeXBlDWluQXNzZXRBbW91bnQQc2VsZlVubG9ja0hlaWdodAdpbkFzc2V0CQELc3RyU3dhcERBVEEUBQhzd2FwVHlwZQIHUEVORElORwkApAMBBQ1pbkFzc2V0QW1vdW50AgEwAgEwAgEwCQCkAwEFBmhlaWdodAkApAMBCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAIBMAIBMAkApAMBBRBzZWxmVW5sb2NrSGVpZ2h0AgEwAgEwAgROVUxMAgEwAgEwAgEwAgEwAgAFB2luQXNzZXQBDmZpbmlzaFN3YXBEQVRBCwlkYXRhQXJyYXkFcHJpY2UMb3V0TmV0QW1vdW50DG91dEZlZUFtb3VudBByYW5kVW5sb2NrSGVpZ2h0BWluZGV4DHdpdGhkcmF3VHhJZApvdXRTdXJmQW10AmJyCmJhc2tldERhdGEHaW5Bc3NldAkBC3N0clN3YXBEQVRBFAkAkQMCBQlkYXRhQXJyYXkFDHNJZHhTd2FwVHlwZQIIRklOSVNIRUQJAJEDAgUJZGF0YUFycmF5BQxzSWR4SW5BbW91bnQJAKQDAQUFcHJpY2UJAKQDAQUMb3V0TmV0QW1vdW50CQCkAwEFDG91dEZlZUFtb3VudAkAkQMCBQlkYXRhQXJyYXkFD3NJZHhTdGFydEhlaWdodAkAkQMCBQlkYXRhQXJyYXkFEnNJZHhTdGFydFRpbWVzdGFtcAkApAMBBQZoZWlnaHQJAKQDAQgFCWxhc3RCbG9jawl0aW1lc3RhbXAJAJEDAgUJZGF0YUFycmF5BRRzSWR4U2VsZlVubG9ja0hlaWdodAkApAMBBRByYW5kVW5sb2NrSGVpZ2h0CQCkAwEFBWluZGV4BQx3aXRoZHJhd1R4SWQJAJEDAgUJZGF0YUFycmF5BQtzSWR4TWluUmFuZAkAkQMCBQlkYXRhQXJyYXkFC3NJZHhNYXhSYW5kCQCkAwEFCm91dFN1cmZBbXQJAKQDAQUCYnIFCmJhc2tldERhdGEFB2luQXNzZXQBEnN3YXBEYXRhRmFpbE9yUkVBRAILdXNlckFkZHJlc3MIc3dhcFR4SWQEB3N3YXBLZXkJAQdzd2FwS0VZAgULdXNlckFkZHJlc3MFCHN3YXBUeElkCQC8CQIJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBBQdzd2FwS2V5CQCsAgICEW5vIHN3YXAgZGF0YSBmb3IgBQdzd2FwS2V5BQNTRVABCWFwcGx5RmVlcwMOYW1vdW50T3V0R3Jvc3MLaW5BbXRUb1NVUkYHZmVlUGFydAQJZmVlQW1vdW50CQBrAwUOYW1vdW50T3V0R3Jvc3MFB2ZlZVBhcnQFBU1VTFQ2CQDMCAIJAGUCBQ5hbW91bnRPdXRHcm9zcwUJZmVlQW1vdW50CQDMCAIFCWZlZUFtb3VudAUDbmlsAQ9hcHBseUZlZXNCYXNrZXQBCWJhc2tldE91dAQCazYJAQV2YWx1ZQEJAJ8IAQkBCmJhc2tldEtLZXkABAJkNgkBBXZhbHVlAQkAnwgBCQEKYmFza2V0REtleQAEB2ZlZVBhcnQJAGsDBQJrNgUCZDYFBU1VTFQ2CgEKZmVlQXBwbGllcgIDYWNjBGl0ZW0ECWZlZUFtb3VudAkAawMIBQRpdGVtAl8yBQdmZWVQYXJ0BQVNVUxUNgkAzQgCBQNhY2MJALkJAgkAzAgCCAUEaXRlbQJfMQkAzAgCCQCkAwEIBQRpdGVtAl8zCQDMCAIJAKQDAQkAZQIIBQRpdGVtAl8yBQlmZWVBbW91bnQJAMwIAgkApAMBBQlmZWVBbW91bnQJAMwIAgkApAMBCAUEaXRlbQJfNAUDbmlsBQdMSVNUU0VQBAFhCgACJGwFCWJhc2tldE91dAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEKZmVlQXBwbGllcgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgkAugkCBQFhAgFfAQNhYnMBAXgDCQBmAgAABQF4CQEBLQEFAXgFAXgBCnNlbGVjdE5vZGUBDXVubGVhc2VBbW91bnQEDWFtb3VudFRvTGVhc2UJAGUCCQBlAggJAO8HAQUQbmV1dHJpbm9Db250cmFjdAlhdmFpbGFibGUFDXVubGVhc2VBbW91bnQJAR9nZXRSZXNlcnZlZEFtb3VudEZvclNwb25zb3JzaGlwAAQKb2xkTGVhc2VkMAkBDmdldE51bWJlckJ5S2V5AQkBEWdldExlYXNlQW1vdW50S2V5AQAABApvbGRMZWFzZWQxCQEOZ2V0TnVtYmVyQnlLZXkBCQERZ2V0TGVhc2VBbW91bnRLZXkBAAEECm5ld0xlYXNlZDAJAGQCBQ1hbW91bnRUb0xlYXNlBQpvbGRMZWFzZWQwBApuZXdMZWFzZWQxCQBkAgUNYW1vdW50VG9MZWFzZQUKb2xkTGVhc2VkMQMDCQBmAgUKbmV3TGVhc2VkMAAABgkAZgIFCm5ld0xlYXNlZDEAAAQGZGVsdGEwCQEDYWJzAQkAZQIFCm5ld0xlYXNlZDAFCm9sZExlYXNlZDEEBmRlbHRhMQkBA2FicwEJAGUCBQpuZXdMZWFzZWQxBQpvbGRMZWFzZWQwAwkAZwIFBmRlbHRhMQUGZGVsdGEwCQCUCgIAAAUKbmV3TGVhc2VkMAkAlAoCAAEFCm5ld0xlYXNlZDEJAJQKAgD///////////8BAAABCHRoaXNPbmx5AQFpAwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQItUGVybWlzc2lvbiBkZW5pZWQ6IHRoaXMgY29udHJhY3Qgb25seSBhbGxvd2VkBgEWcHJlcGFyZVVubGVhc2VBbmRMZWFzZQENdW5sZWFzZUFtb3VudAQJbm9kZVR1cGxlCQEKc2VsZWN0Tm9kZQEFDXVubGVhc2VBbW91bnQECW5vZGVJbmRleAgFCW5vZGVUdXBsZQJfMQQObmV3TGVhc2VBbW91bnQIBQlub2RlVHVwbGUCXzIDCQBmAgUObmV3TGVhc2VBbW91bnQAAAQKbGVhc2VJZEtleQkBDWdldExlYXNlSWRLZXkBBQlub2RlSW5kZXgECG9sZExlYXNlCQCcCAIFBHRoaXMFCmxlYXNlSWRLZXkEDnVubGVhc2VPckVtcHR5AwkBCWlzRGVmaW5lZAEFCG9sZExlYXNlCQDMCAIJAQtMZWFzZUNhbmNlbAEJAQV2YWx1ZQEFCG9sZExlYXNlBQNuaWwFA25pbAQObGVhc2VBbW91bnRLZXkJARFnZXRMZWFzZUFtb3VudEtleQEFCW5vZGVJbmRleAQFbGVhc2UJAMQIAgkBHGdldFN0YWtpbmdOb2RlQWRkcmVzc0J5SW5kZXgBBQlub2RlSW5kZXgFDm5ld0xlYXNlQW1vdW50CQDOCAIFDnVubGVhc2VPckVtcHR5CQDMCAIFBWxlYXNlCQDMCAIJAQtCaW5hcnlFbnRyeQIFCmxlYXNlSWRLZXkJAQVsY2FsYwEFBWxlYXNlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQERZ2V0TGVhc2VBbW91bnRLZXkBBQlub2RlSW5kZXgFDm5ld0xlYXNlQW1vdW50BQNuaWwFA25pbAEMcmVhZE5vZGVJbmZvAQdub2RlSWR4BAtub2RlQWRkcmVzcwkBHGdldFN0YWtpbmdOb2RlQWRkcmVzc0J5SW5kZXgBBQdub2RlSWR4BAxsZWFzZWRBbXRLRVkJARFnZXRMZWFzZUFtb3VudEtleQEFB25vZGVJZHgECWxlYXNlZEFtdAkBDmdldE51bWJlckJ5S2V5AQUMbGVhc2VkQW10S0VZBApsZWFzZUlkS0VZCQENZ2V0TGVhc2VJZEtleQEFB25vZGVJZHgEB2xlYXNlSWQJAQV2YWx1ZQEJAJwIAgUEdGhpcwUKbGVhc2VJZEtFWQkAlwoFBQtub2RlQWRkcmVzcwUMbGVhc2VkQW10S0VZBQlsZWFzZWRBbXQFCmxlYXNlSWRLRVkFB2xlYXNlSWQBCmNvbW1vblN3YXAFCHN3YXBUeXBlCXBtdEFtb3VudAdpbkFzc2V0DnVzZXJBZGRyZXNzU3RyBnR4SWQ1OAQQc3dhcFBhcmFtc1NUUlVDVAkBEmFzU3dhcFBhcmFtc1NUUlVDVAEJAPwHBAUEdGhpcwIbc3dhcFBhcmFtc0J5VXNlclNZU1JFQURPTkxZCQDMCAIFDnVzZXJBZGRyZXNzU3RyCQDMCAIAAAUDbmlsBQNuaWwEEXRva2VuU3dhcExpbWl0VXNkCAUQc3dhcFBhcmFtc1NUUlVDVAJfMQQOc3dhcExpbWl0U3BlbnQIBRBzd2FwUGFyYW1zU1RSVUNUAl8yBA5ibGNrczJMbXRSZXNldAgFEHN3YXBQYXJhbXNTVFJVQ1QCXzMEEHVzZG5Td2FwTGltaXRNYXgIBRBzd2FwUGFyYW1zU1RSVUNUAl83BA1taW5Td2FwQW1vdW50CQERbWluU3dhcEFtb3VudFJFQUQCBQhzd2FwVHlwZQUHaW5Bc3NldAQRdG90YWxMb2NrZWRCeVVzZXIJARV0b3RhbExvY2tlZEJ5VXNlclJFQUQDBQhzd2FwVHlwZQUOdXNlckFkZHJlc3NTdHIFB2luQXNzZXQEC25vZGVBZGRyZXNzCQEVZ2V0U3Rha2luZ05vZGVCeUluZGV4AQAABAxpc1N3YXBCeU5vZGUJAAACBQtub2RlQWRkcmVzcwUOdXNlckFkZHJlc3NTdHIEFmJhbGFuY2VMb2NrTWF4SW50ZXJ2YWwDBQxpc1N3YXBCeU5vZGUJARtub2RlQmFsYW5jZUxvY2tJbnRlcnZhbFJFQUQACQEXYmFsYW5jZUxvY2tJbnRlcnZhbFJFQUQBBQhzd2FwVHlwZQQQc2VsZlVubG9ja0hlaWdodAkAZAIFBmhlaWdodAUWYmFsYW5jZUxvY2tNYXhJbnRlcnZhbAQCcHIJAQV2YWx1ZQEJAJoIAgUPY29udHJvbENvbnRyYWN0CQEPa2V5UHJpY2VCeUFzc2V0AQUHaW5Bc3NldAQOc3dhcFVzZG5Wb2x1bWUDCQAAAgUIc3dhcFR5cGUCC291dE5ldXRyaW5vCQERY29udmVydFRva2VuVG9Vc2QCBQlwbXRBbW91bnQFAnByBQlwbXRBbW91bnQEDHN3YXBMaW1pdE1heAMJAAACBQhzd2FwVHlwZQILb3V0TmV1dHJpbm8FEXRva2VuU3dhcExpbWl0VXNkBRB1c2RuU3dhcExpbWl0TWF4AwkAZgIFDW1pblN3YXBBbW91bnQFCXBtdEFtb3VudAkBEW1pblN3YXBBbW91bnRGQUlMAgUIc3dhcFR5cGUFDW1pblN3YXBBbW91bnQDAwkBASEBBQxpc1N3YXBCeU5vZGUJAGYCBQ5zd2FwTGltaXRTcGVudAAABwkAAgEJAKwCAgI6WW91IGhhdmUgZXhjZWVkZWQgc3dhcCBsaW1pdCEgTmV4dCBhbGxvd2VkIHN3YXAgaGVpZ2h0IGlzIAkApAMBCQBkAgUGaGVpZ2h0BQ5ibGNrczJMbXRSZXNldAMDCQEBIQEFDGlzU3dhcEJ5Tm9kZQkAZgIFDnN3YXBVc2RuVm9sdW1lBQxzd2FwTGltaXRNYXgHCQACAQkArAICCQCsAgIJAKwCAgIuWW91IGhhdmUgZXhjZWVkZWQgeW91ciBzd2FwIGxpbWl0ISBSZXF1ZXN0ZWQ6IAkApAMBBQ5zd2FwVXNkblZvbHVtZQINLCBhdmFpbGFibGU6IAkApAMBBQxzd2FwTGltaXRNYXgDBQlpc0Jsb2NrZWQJARVlbWVyZ2VuY3lTaHV0ZG93bkZBSUwABA9uZXV0cmlub01ldHJpY3MJAQlhc0FueUxpc3QBCQD8BwQFDG1hdGhDb250cmFjdAIaY2FsY05ldXRpbm9NZXRyaWNzUkVBRE9OTFkFA25pbAUDbmlsBApiYXNrZXRJbmZvCQEIYXNTdHJpbmcBCQCRAwIFD25ldXRyaW5vTWV0cmljcwURbk1ldHJpY0Jhc2tldEluZm8EDXdlaWdodGVkUHJpY2UJAQVhc0ludAEJAJEDAgUPbmV1dHJpbm9NZXRyaWNzBRRuTWV0cmljV2VpZ2h0ZWRQcmljZQQDb3V0CQEbY29udmVydEJhc2tldEl0ZW1Ub05ldXRyaW5vBAUJcG10QW1vdW50BQdpbkFzc2V0BQpiYXNrZXRJbmZvBQ13ZWlnaHRlZFByaWNlAwMJAAACBQhzd2FwVHlwZQILb3V0TmV1dHJpbm8JAGcCAAAJAJEDAgUDb3V0AAEHCQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgI+TmV0IGFtb3VudCBpcyBub24tcG9zaXRpdmUsIGNhbm5vdCBzd2FwLiAoZ3Jvc3MsIG5ldCwgZmVlKSA9ICgJAKQDAQkAkQMCBQNvdXQAAAICLCAJAKQDAQkAkQMCBQNvdXQAAQICLCAJAKQDAQkAkQMCBQNvdXQAAgIBKQQJbGVhc2VQYXJ0AwMJAAACBQhzd2FwVHlwZQILb3V0TmV1dHJpbm8JAAACBQdpbkFzc2V0AgVXQVZFUwcJARZwcmVwYXJlVW5sZWFzZUFuZExlYXNlAQAABQNuaWwJAJQKAgkAzggCCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEYa2V5U3dhcFVzZXJTcGVudEluUGVyaW9kAQUOdXNlckFkZHJlc3NTdHIFDnN3YXBVc2RuVm9sdW1lCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEVa2V5VXNlckxhc3RTd2FwSGVpZ2h0AQUOdXNlckFkZHJlc3NTdHIFBmhlaWdodAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBFHRvdGFsTG9ja2VkQnlVc2VyS0VZAwUIc3dhcFR5cGUFDnVzZXJBZGRyZXNzU3RyBQdpbkFzc2V0CQBkAgURdG90YWxMb2NrZWRCeVVzZXIFCXBtdEFtb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBGGdldEJhbGFuY2VVbmxvY2tCbG9ja0tleQEFDnVzZXJBZGRyZXNzU3RyBRBzZWxmVW5sb2NrSGVpZ2h0CQDMCAIJAQtTdHJpbmdFbnRyeQIJAQdzd2FwS0VZAgUOdXNlckFkZHJlc3NTdHIFBnR4SWQ1OAkBD3BlbmRpbmdTd2FwREFUQQQFCHN3YXBUeXBlBQlwbXRBbW91bnQFEHNlbGZVbmxvY2tIZWlnaHQFB2luQXNzZXQFA25pbAUJbGVhc2VQYXJ0BQR1bml0AAxiRnVuY0lkeFN1cmYAAAANYkZ1bmNJZHhXYXZlcwABAAxiRnVuY0lkeFVzZG4AAgAUYkZ1bmNJZHhSZXNlcnZlU3RhcnQAAwATYkZ1bmNJZHhTdXBwbHlTdGFydAAEAA9iRnVuY0lkeEJSU3RhcnQABQASYkZ1bmNJZHhSZXNlcnZlRW5kAAYAEWJGdW5jSWR4U3VwcGx5RW5kAAcADWJGdW5jSWR4QlJFbmQACAAMYkZ1bmNJZHhSZXN0AAkAEmJGdW5jSWR4V2F2ZXNQcmljZQAKAQ9jYWxjV2l0aGRyYXdUMlUECGluQW1vdW50B2luQXNzZXQKYmFza2V0SW5mbw13ZWlnaHRlZFByaWNlBAZvdXRBbXQJARtjb252ZXJ0QmFza2V0SXRlbVRvTmV1dHJpbm8EBQhpbkFtb3VudAUHaW5Bc3NldAUKYmFza2V0SW5mbwUNd2VpZ2h0ZWRQcmljZQkAngoMCQCRAwIFBm91dEFtdAAABQ9uZXV0cmlub0Fzc2V0SWQAAAUHaW5Bc3NldAAABQ13ZWlnaHRlZFByaWNlBQhpbkFtb3VudAAAAAAAAAUDbmlsCQDMCAIJAJEDAgUGb3V0QW10AAEJAMwIAgkAkQMCBQZvdXRBbXQAAgUDbmlsARRjYWxjV2l0aGRyYXdVMkJhc2tldAMGdXNkbkluCmJhc2tldEluZm8ObmV1dHJpbm9TdXBwbHkEC291dEFtdEdyb3NzCQEXY29udmVydE5ldXRyaW5vVG9CYXNrZXQDBQZ1c2RuSW4FCmJhc2tldEluZm8FDm5ldXRyaW5vU3VwcGx5CQCeCgwIBQtvdXRBbXRHcm9zcwJfMgUEdW5pdAAABQ9uZXV0cmlub0Fzc2V0SWQIBQtvdXRBbXRHcm9zcwJfMggFC291dEFtdEdyb3NzAl8zBQZ1c2RuSW4FDm5ldXRyaW5vU3VwcGx5BQZ1c2RuSW4AAAgFC291dEFtdEdyb3NzAl8xBQNuaWwBDGNhbGNXaXRoZHJhdwUIc3dhcFR5cGUIaW5BbW91bnQFcHJpY2UPbmV1dHJpbm9NZXRyaWNzB2luQXNzZXQEDm5ldXRyaW5vU3VwcGx5CQEFYXNJbnQBCQCRAwIFD25ldXRyaW5vTWV0cmljcwUUbk1ldHJpY0lkeFVzZG5TdXBwbHkECmJhc2tldEluZm8JAQhhc1N0cmluZwEJAJEDAgUPbmV1dHJpbm9NZXRyaWNzBRFuTWV0cmljQmFza2V0SW5mbwQNd2VpZ2h0ZWRQcmljZQkBBWFzSW50AQkAkQMCBQ9uZXV0cmlub01ldHJpY3MFFG5NZXRyaWNXZWlnaHRlZFByaWNlBAxvdXREYXRhVHVwbGUDCQAAAgUIc3dhcFR5cGUCC291dE5ldXRyaW5vCQEPY2FsY1dpdGhkcmF3VDJVBAUIaW5BbW91bnQFB2luQXNzZXQFCmJhc2tldEluZm8FDXdlaWdodGVkUHJpY2UDCQAAAgUIc3dhcFR5cGUCCG91dE11bHRpCQEUY2FsY1dpdGhkcmF3VTJCYXNrZXQDBQhpbkFtb3VudAUKYmFza2V0SW5mbwUObmV1dHJpbm9TdXBwbHkJAAIBCQCsAgICFlVuc3VwcG9ydGVkIHN3YXAgdHlwZSAFCHN3YXBUeXBlBAtvdXRBbXRHcm9zcwgFDG91dERhdGFUdXBsZQJfMQQKb3V0QXNzZXRJZAgFDG91dERhdGFUdXBsZQJfMgQPaW5BbXRUb1N1cmZQYXJ0CAUMb3V0RGF0YVR1cGxlAl8zBAlpbkFzc2V0SWQIBQxvdXREYXRhVHVwbGUCXzQECnVubGVhc2VBbXQIBQxvdXREYXRhVHVwbGUCXzUEDXdpdGhkcmF3UHJpY2UIBQxvdXREYXRhVHVwbGUCXzYECmJhc2tldERhdGEIBQxvdXREYXRhVHVwbGUDXzExBApuZXRGZWVEYXRhCAUMb3V0RGF0YVR1cGxlA18xMgQJb3V0TmV0QW10AwkAAAIFCHN3YXBUeXBlAgtvdXROZXV0cmlubwkAkQMCBQpuZXRGZWVEYXRhAAAAAAQJb3V0RmVlQW10AwkAAAIFCHN3YXBUeXBlAgtvdXROZXV0cmlubwkAkQMCBQpuZXRGZWVEYXRhAAEAAAQKb3V0U3VyZkFtdAMJAGcCAAAFD2luQW10VG9TdXJmUGFydAAACQEFYXNJbnQBCQCRAwIJAQlhc0FueUxpc3QBCQD8BwQFDG1hdGhDb250cmFjdAIUc3VyZkZ1bmN0aW9uUkVBRE9OTFkJAMwIAgUPaW5BbXRUb1N1cmZQYXJ0CQDMCAIFCWluQXNzZXRJZAUDbmlsBQNuaWwFDGJGdW5jSWR4U3VyZgQOd2l0aGRyYXdCYXNrZXQDCQAAAgUIc3dhcFR5cGUCCG91dE11bHRpCQEPYXBwbHlGZWVzQmFza2V0AQUKYmFza2V0RGF0YQIACQCbCgkFCW91dE5ldEFtdAUKb3V0QXNzZXRJZAUKb3V0U3VyZkFtdAUPaW5BbXRUb1N1cmZQYXJ0BQp1bmxlYXNlQW10BQlvdXRGZWVBbXQFC291dEFtdEdyb3NzBQ13aXRoZHJhd1ByaWNlBQ53aXRoZHJhd0Jhc2tldAESa2V5QXBwbHlJblByb2dyZXNzAAITJXNfX2FwcGx5SW5Qcm9ncmVzcwETa2V5UHJvcG9zYWxEYXRhQnlJZAEKcHJvcG9zYWxJZAkArAICAhQlcyVkX19wcm9wb3NhbERhdGFfXwkApAMBBQpwcm9wb3NhbElkAAtnb3ZJZHhUeElkcwAJAQ52YWxpZGF0ZVVwZGF0ZQECdHgEByRtYXRjaDAFAnR4AwkAAQIFByRtYXRjaDACBU9yZGVyBAFvBQckbWF0Y2gwCQACAQIVT3JkZXJzIGFyZW4ndCBhbGxvd2VkAwMJAAECBQckbWF0Y2gwAg9EYXRhVHJhbnNhY3Rpb24GAwkAAQIFByRtYXRjaDACFVNwb25zb3JGZWVUcmFuc2FjdGlvbgYDCQABAgUHJG1hdGNoMAIUU2V0U2NyaXB0VHJhbnNhY3Rpb24GAwkAAQIFByRtYXRjaDACFkNyZWF0ZUFsaWFzVHJhbnNhY3Rpb24GAwkAAQIFByRtYXRjaDACFkxlYXNlQ2FuY2VsVHJhbnNhY3Rpb24GAwkAAQIFByRtYXRjaDACEExlYXNlVHJhbnNhY3Rpb24GAwkAAQIFByRtYXRjaDACEElzc3VlVHJhbnNhY3Rpb24GAwkAAQIFByRtYXRjaDACG0ludm9rZUV4cHJlc3Npb25UcmFuc2FjdGlvbgYDCQABAgUHJG1hdGNoMAIaVXBkYXRlQXNzZXRJbmZvVHJhbnNhY3Rpb24GAwkAAQIFByRtYXRjaDACF0ludm9rZVNjcmlwdFRyYW5zYWN0aW9uBgMJAAECBQckbWF0Y2gwAhlTZXRBc3NldFNjcmlwdFRyYW5zYWN0aW9uBgMJAAECBQckbWF0Y2gwAhNUcmFuc2ZlclRyYW5zYWN0aW9uBgMJAAECBQckbWF0Y2gwAhNFeGNoYW5nZVRyYW5zYWN0aW9uBgMJAAECBQckbWF0Y2gwAhdNYXNzVHJhbnNmZXJUcmFuc2FjdGlvbgYDCQABAgUHJG1hdGNoMAIPQnVyblRyYW5zYWN0aW9uBgkAAQIFByRtYXRjaDACElJlaXNzdWVUcmFuc2FjdGlvbgQBdAUHJG1hdGNoMAQEdHhJZAkA2AQBCAUBdAJpZAQKcHJvcG9zYWxJZAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFC2dvdkNvbnRyYWN0CQESa2V5QXBwbHlJblByb2dyZXNzAAIWQXBwbHkgaXMgbm90IGhhcHBlbmluZwQGdHhMaXN0CQC1CQIJAJEDAgkAtQkCCQEPZ2V0U3RyaW5nT3JGYWlsAgULZ292Q29udHJhY3QJARNrZXlQcm9wb3NhbERhdGFCeUlkAQUKcHJvcG9zYWxJZAUDU0VQBQtnb3ZJZHhUeElkcwUHTElTVFNFUAMJAQEhAQkBCWlzRGVmaW5lZAEJAM8IAgUGdHhMaXN0BQR0eElkCQACAQkArAICCQCsAgIJAKwCAgIOVW5rbm93biB0eElkOiAFBHR4SWQCECBmb3IgcHJvcG9zYWxJZD0JAKQDAQUKcHJvcG9zYWxJZAYJAAIBAgtNYXRjaCBlcnJvcg8BaQENY29uc3RydWN0b3JWMQwSbmV1dHJpbm9Bc3NldElkUHJtDmJvbmRBc3NldElkUHJtEmF1Y3Rpb25Db250cmFjdFBybRZsaXF1aWRhdGlvbkNvbnRyYWN0UHJtDnJwZENvbnRyYWN0UHJtG25vZGVPcmFjbGVQcm92aWRlclB1YktleVBybRtiYWxhbmNlV2F2ZXNMb2NrSW50ZXJ2YWxQcm0eYmFsYW5jZU5ldXRyaW5vTG9ja0ludGVydmFsUHJtFW1pbldhdmVzU3dhcEFtb3VudFBybRhtaW5OZXV0cmlub1N3YXBBbW91bnRQcm0VbmV1dHJpbm9PdXRGZWVQYXJ0UHJtEndhdmVzT3V0RmVlUGFydFBybQQLY2hlY2tDYWxsZXIJAQh0aGlzT25seQEFAWkDCQAAAgULY2hlY2tDYWxsZXIFC2NoZWNrQ2FsbGVyAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwAACQACAQITbm8gcGF5bWVudHMgYWxsb3dlZAkAzAgCCQELU3RyaW5nRW50cnkCBRJOZXV0cmlub0Fzc2V0SWRLZXkFEm5ldXRyaW5vQXNzZXRJZFBybQkAzAgCCQELU3RyaW5nRW50cnkCBQ5Cb25kQXNzZXRJZEtleQUOYm9uZEFzc2V0SWRQcm0JAMwIAgkBC1N0cmluZ0VudHJ5AgUSQXVjdGlvbkNvbnRyYWN0S2V5BRJhdWN0aW9uQ29udHJhY3RQcm0JAMwIAgkBC1N0cmluZ0VudHJ5AgUWTGlxdWlkYXRpb25Db250cmFjdEtleQUWbGlxdWlkYXRpb25Db250cmFjdFBybQkAzAgCCQELU3RyaW5nRW50cnkCBQ5SUERDb250cmFjdEtleQUOcnBkQ29udHJhY3RQcm0JAMwIAgkBC1N0cmluZ0VudHJ5AgUbTm9kZU9yYWNsZVByb3ZpZGVyUHViS2V5S2V5BRtub2RlT3JhY2xlUHJvdmlkZXJQdWJLZXlQcm0JAMwIAgkBDEludGVnZXJFbnRyeQIFG0JhbGFuY2VXYXZlc0xvY2tJbnRlcnZhbEtleQUbYmFsYW5jZVdhdmVzTG9ja0ludGVydmFsUHJtCQDMCAIJAQxJbnRlZ2VyRW50cnkCBR5CYWxhbmNlTmV1dHJpbm9Mb2NrSW50ZXJ2YWxLZXkFHmJhbGFuY2VOZXV0cmlub0xvY2tJbnRlcnZhbFBybQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBFU1pblRva2VuU3dhcEFtb3VudEtleQECBVdBVkVTBRVtaW5XYXZlc1N3YXBBbW91bnRQcm0JAMwIAgkBDEludGVnZXJFbnRyeQIFGE1pbk5ldXRyaW5vU3dhcEFtb3VudEtleQUYbWluTmV1dHJpbm9Td2FwQW1vdW50UHJtCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRVOZXV0cmlub091dEZlZVBhcnRLZXkFFW5ldXRyaW5vT3V0RmVlUGFydFBybQkAzAgCCQEMSW50ZWdlckVudHJ5AgUSV2F2ZXNPdXRGZWVQYXJ0S2V5BRJ3YXZlc091dEZlZVBhcnRQcm0FA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ1jb25zdHJ1Y3RvclYyAwxtYXRoQ29udHJhY3QTbnNidFN0YWtpbmdDb250cmFjdBRzd2Fwc1RpbWVmcmFtZUJsb2NrcwQLY2hlY2tDYWxsZXIJAQh0aGlzT25seQEFAWkDCQAAAgULY2hlY2tDYWxsZXIFC2NoZWNrQ2FsbGVyAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwAACQACAQITbm8gcGF5bWVudHMgYWxsb3dlZAkAzAgCCQELU3RyaW5nRW50cnkCBQ9NYXRoQ29udHJhY3RLZXkFDG1hdGhDb250cmFjdAkAzAgCCQELU3RyaW5nRW50cnkCBRZOc2J0U3Rha2luZ0NvbnRyYWN0S2V5BRNuc2J0U3Rha2luZ0NvbnRyYWN0CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQERc3dhcHNUaW1lZnJhbWVLRVkABRRzd2Fwc1RpbWVmcmFtZUJsb2NrcwUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDWNvbnN0cnVjdG9yVjMFEWFzc2V0c1dlaWdodHNNaW5zBmRQYXJhbQZrUGFyYW0GYlBhcmFtCmRlbHRhUGFyYW0EC2NoZWNrQ2FsbGVyCQEIdGhpc09ubHkBBQFpAwkAAAIFC2NoZWNrQ2FsbGVyBQtjaGVja0NhbGxlcgMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAAkAAgECE25vIHBheW1lbnRzIGFsbG93ZWQKAQdwcmVwYXJlAgNhY2MEaXRlbQQFcGFydHMJALUJAgUEaXRlbQIBXwQHYXNzZXRJZAkAkQMCBQVwYXJ0cwAABAZ3ZWlnaHQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQVwYXJ0cwABBAZtaW5WYWwJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQVwYXJ0cwACCQCUCgIJAM0IAggFA2FjYwJfMQUHYXNzZXRJZAkAzQgCCQDNCAIIBQNhY2MCXzIJAQxJbnRlZ2VyRW50cnkCCQEWYmFza2V0V2VpZ2h0QnlBc3NldEtleQEFB2Fzc2V0SWQFBndlaWdodAkBDEludGVnZXJFbnRyeQIJARVNaW5Ub2tlblN3YXBBbW91bnRLZXkBBQdhc3NldElkBQZtaW5WYWwEAXIKAAIkbAURYXNzZXRzV2VpZ2h0c01pbnMKAAIkcwkAkAMBBQIkbAoABSRhY2MwCQCUCgIFA25pbAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQdwcmVwYXJlAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKCQDNCAIJAM0IAgkAzQgCCQDNCAIJAM0IAggFAXICXzIJAQxJbnRlZ2VyRW50cnkCCQEKYmFza2V0REtleQAFBmRQYXJhbQkBDEludGVnZXJFbnRyeQIJAQpiYXNrZXRLS2V5AAUGa1BhcmFtCQEMSW50ZWdlckVudHJ5AgkBCmJhc2tldEJLZXkABQZiUGFyYW0JAQxJbnRlZ2VyRW50cnkCCQESYmFza2V0TG9nYkRlbHRhS2V5AAkAbQYFCmRlbHRhUGFyYW0ABgUGYlBhcmFtAAYABgUGSEFMRlVQCQELU3RyaW5nRW50cnkCCQEPYmFza2V0QXNzZXRzS2V5AAkAuQkCCAUBcgJfMQUDU0VQCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBE3N3YXBUb2tlblRvTmV1dHJpbm8AAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwABCQACAQIsc3dhcFRva2VuVG9OZXV0cmlubyByZXF1aXJlIG9ubHkgb25lIHBheW1lbnQEA3BtdAkBBXZhbHVlAQkAkQMCCAUBaQhwYXltZW50cwAABAxiYXNrZXRBc3NldHMJAQV2YWx1ZQEJAKIIAQkBD2Jhc2tldEFzc2V0c0tleQAEDXBtdEFzc2V0SWRTdHIJANgEAQkBC3ZhbHVlT3JFbHNlAggFA3BtdAdhc3NldElkBQdXQVZFU0lEAwkBASEBCQEIY29udGFpbnMCBQxiYXNrZXRBc3NldHMFDXBtdEFzc2V0SWRTdHIJAAIBCQCsAgIJAKwCAgUNcG10QXNzZXRJZFN0cgIdIGlzIG5vdCBvbmUgb2YgYmFza2V0IHRva2VuczoFDGJhc2tldEFzc2V0cwQLdXNlckFkZHJlc3MJAKUIAQgFAWkGY2FsbGVyBAZ0eElkNTgJANgEAQgFAWkNdHJhbnNhY3Rpb25JZAQLdG90YWxMb2NrZWQJAQ90b3RhbExvY2tlZFJFQUQCAgtvdXROZXV0cmlubwUNcG10QXNzZXRJZFN0cgQJcG10QW1vdW50CAUDcG10BmFtb3VudAQPc2F2ZVRvdGFsTG9ja2VkCQD8BwQFBHRoaXMCE2ludGVybmFsU2F2ZUludGVnZXIJAMwIAgkBDnRvdGFsTG9ja2VkS0VZAgILb3V0TmV1dHJpbm8FDXBtdEFzc2V0SWRTdHIJAMwIAgkAZAIFC3RvdGFsTG9ja2VkBQlwbXRBbW91bnQFA25pbAUDbmlsAwkAAAIFD3NhdmVUb3RhbExvY2tlZAUPc2F2ZVRvdGFsTG9ja2VkCQEKY29tbW9uU3dhcAUCC291dE5ldXRyaW5vBQlwbXRBbW91bnQFDXBtdEFzc2V0SWRTdHIFC3VzZXJBZGRyZXNzBQZ0eElkNTgJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEUc3dhcE5ldXRyaW5vVG9CYXNrZXQAAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwABCQACAQItc3dhcE5ldXRyaW5vVG9CYXNrZXQgcmVxdWlyZSBvbmx5IG9uZSBwYXltZW50BANwbXQJAQV2YWx1ZQEJAJEDAggFAWkIcGF5bWVudHMAAAMJAQIhPQIIBQNwbXQHYXNzZXRJZAUPbmV1dHJpbm9Bc3NldElkCQACAQI6T25seSBhcHByb3ByaWF0ZSBOZXV0cmlubyB0b2tlbnMgYXJlIGFsbG93ZWQgZm9yIHN3YXBwaW5nLgQLdXNlckFkZHJlc3MJAKUIAQgFAWkGY2FsbGVyBAZ0eElkNTgJANgEAQgFAWkNdHJhbnNhY3Rpb25JZAQSbmV1dHJpbm9Bc3NldElkU3RyCQDYBAEFD25ldXRyaW5vQXNzZXRJZAQLdG90YWxMb2NrZWQJAQ90b3RhbExvY2tlZFJFQUQCAghvdXRNdWx0aQUSbmV1dHJpbm9Bc3NldElkU3RyBAlwbXRBbW91bnQIBQNwbXQGYW1vdW50BA9zYXZlVG90YWxMb2NrZWQJAPwHBAUEdGhpcwITaW50ZXJuYWxTYXZlSW50ZWdlcgkAzAgCCQEOdG90YWxMb2NrZWRLRVkCAghvdXRNdWx0aQUSbmV1dHJpbm9Bc3NldElkU3RyCQDMCAIJAGQCBQt0b3RhbExvY2tlZAUJcG10QW1vdW50BQNuaWwFA25pbAMJAAACBQ9zYXZlVG90YWxMb2NrZWQFD3NhdmVUb3RhbExvY2tlZAkBCmNvbW1vblN3YXAFAghvdXRNdWx0aQgFA3BtdAZhbW91bnQFEm5ldXRyaW5vQXNzZXRJZFN0cgULdXNlckFkZHJlc3MFBnR4SWQ1OAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARNpbnRlcm5hbFNhdmVJbnRlZ2VyAgNrZXkGYW1vdW50AwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIoaW50ZXJuYWxTYXZlSW50ZWdlciBpcyBub3QgcHVibGljIG1ldGhvZAkAzAgCCQEMSW50ZWdlckVudHJ5AgUDa2V5BQZhbW91bnQFA25pbAFpAQh3aXRoZHJhdwMHYWNjb3VudAVpbmRleAhzd2FwVHhJZAQEdHhJZAkA2AQBCAUBaQ10cmFuc2FjdGlvbklkAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwAACQACAQITbm8gcGF5bWVudHMgYWxsb3dlZAQPbmV1dHJpbm9NZXRyaWNzCQEJYXNBbnlMaXN0AQkA/AcEBQxtYXRoQ29udHJhY3QCGmNhbGNOZXV0aW5vTWV0cmljc1JFQURPTkxZBQNuaWwFA25pbAQCQlIJAQVhc0ludAEJAJEDAgUPbmV1dHJpbm9NZXRyaWNzBQxuTWV0cmljSWR4QlIEC3VzZXJBZGRyZXNzCQERQGV4dHJOYXRpdmUoMTA2MikBBQdhY2NvdW50BAlkYXRhQXJyYXkJARJzd2FwRGF0YUZhaWxPclJFQUQCBQdhY2NvdW50BQhzd2FwVHhJZAQQc2VsZlVubG9ja0hlaWdodAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCWRhdGFBcnJheQUUc0lkeFNlbGZVbmxvY2tIZWlnaHQECHN3YXBUeXBlCQCRAwIFCWRhdGFBcnJheQUMc0lkeFN3YXBUeXBlBAhpbkFtb3VudAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCWRhdGFBcnJheQUMc0lkeEluQW1vdW50BApzd2FwU3RhdHVzCQCRAwIFCWRhdGFBcnJheQUKc0lkeFN0YXR1cwQLc3RhcnRIZWlnaHQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQlkYXRhQXJyYXkFD3NJZHhTdGFydEhlaWdodAQHaW5Bc3NldAkAkQMCBQlkYXRhQXJyYXkFC3NJZHhJbkFzc2V0BAt0b3RhbExvY2tlZAkBD3RvdGFsTG9ja2VkUkVBRAIFCHN3YXBUeXBlBQdpbkFzc2V0BBF0b3RhbExvY2tlZEJ5VXNlcgkBFXRvdGFsTG9ja2VkQnlVc2VyUkVBRAMFCHN3YXBUeXBlBQdhY2NvdW50BQdpbkFzc2V0BAx1bmxvY2tIZWlnaHQFEHNlbGZVbmxvY2tIZWlnaHQEC2luZGV4SGVpZ2h0CQEVZ2V0SGVpZ2h0UHJpY2VCeUluZGV4AQUFaW5kZXgED3ByZXZJbmRleEhlaWdodAkBFWdldEhlaWdodFByaWNlQnlJbmRleAEJAGUCBQVpbmRleAABBAxwcmljZUJ5SW5kZXgJAQ9nZXRQcmljZUhpc3RvcnkBBQtpbmRleEhlaWdodAMFCWlzQmxvY2tlZAkBFWVtZXJnZW5jeVNodXRkb3duRkFJTAADCQECIT0CBQpzd2FwU3RhdHVzAgdQRU5ESU5HCQACAQIfc3dhcCBoYXMgYmVlbiBhbHJlYWR5IHByb2Nlc3NlZAMJAGYCBQx1bmxvY2tIZWlnaHQFBmhlaWdodAkAAgEJAKwCAgkArAICAhFwbGVhc2Ugd2FpdCBmb3I6IAkApAMBBQx1bmxvY2tIZWlnaHQCHyBibG9jayBoZWlnaHQgdG8gd2l0aGRyYXcgZnVuZHMDAwMJAGYCBQVpbmRleAUKcHJpY2VJbmRleAYJAGYCBQx1bmxvY2tIZWlnaHQFC2luZGV4SGVpZ2h0BgMJAQIhPQIFD3ByZXZJbmRleEhlaWdodAAACQBnAgUPcHJldkluZGV4SGVpZ2h0BQx1bmxvY2tIZWlnaHQHCQEOcHJpY2VJbmRleEZBSUwFBQVpbmRleAUKcHJpY2VJbmRleAULaW5kZXhIZWlnaHQFDHVubG9ja0hlaWdodAUPcHJldkluZGV4SGVpZ2h0BA13aXRoZHJhd1R1cGxlCQEMY2FsY1dpdGhkcmF3BQUIc3dhcFR5cGUFCGluQW1vdW50BQxwcmljZUJ5SW5kZXgFD25ldXRyaW5vTWV0cmljcwUHaW5Bc3NldAQMb3V0TmV0QW1vdW50CAUNd2l0aGRyYXdUdXBsZQJfMQQKb3V0QXNzZXRJZAgFDXdpdGhkcmF3VHVwbGUCXzIECm91dFN1cmZBbXQIBQ13aXRoZHJhd1R1cGxlAl8zBAp1bmxlYXNlQW10CAUNd2l0aGRyYXdUdXBsZQJfNQQMb3V0RmVlQW1vdW50CAUNd2l0aGRyYXdUdXBsZQJfNgQLb3V0QW10R3Jvc3MIBQ13aXRoZHJhd1R1cGxlAl83BA13aXRoZHJhd1ByaWNlCAUNd2l0aGRyYXdUdXBsZQJfOAQOd2l0aGRyYXdCYXNrZXQIBQ13aXRoZHJhd1R1cGxlAl85AwMJAAACBQhzd2FwVHlwZQILb3V0TmV1dHJpbm8JAGcCAAAFC291dEFtdEdyb3NzBwkAAgECE2JhbGFuY2UgZXF1YWxzIHplcm8EDXN1cmZDb25kaXRpb24DCQBmAgUKb3V0U3VyZkFtdAAABAtpc3N1ZVJlc3VsdAkA/AcEBQ9hdWN0aW9uQ29udHJhY3QCCWlzc3VlU3VyZgkAzAgCBQpvdXRTdXJmQW10CQDMCAIFB2FjY291bnQFA25pbAUDbmlsAwkAAAIFC2lzc3VlUmVzdWx0BQtpc3N1ZVJlc3VsdAAACQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAAADCQAAAgUNc3VyZkNvbmRpdGlvbgUNc3VyZkNvbmRpdGlvbgQRdW5sZWFzZUludk9yRW1wdHkJAPwHBAUEdGhpcwIXaW50ZXJuYWxVbmxlYXNlQW5kTGVhc2UJAMwIAgUKdW5sZWFzZUFtdAUDbmlsBQNuaWwDCQAAAgURdW5sZWFzZUludk9yRW1wdHkFEXVubGVhc2VJbnZPckVtcHR5BAlnbnNidERhdGEJAQlhc0FueUxpc3QBCQD8BwQFF2duc2J0Q29udHJvbGxlckNvbnRyYWN0AhRnbnNidEluZm9TWVNSRUFET05MWQkAzAgCAgAJAMwIAgAACQDMCAIAAAUDbmlsBQNuaWwEDWduc2J0QW10VG90YWwJAQVhc0ludAEJAJEDAgUJZ25zYnREYXRhAAEEFWduc2J0QW10RnJvbVN1cmZUb3RhbAkBBWFzSW50AQkAkQMCCQEJYXNBbnlMaXN0AQkAkQMCBQlnbnNidERhdGEAAwADBA1jb21tb25BY3Rpb25zCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEUdG90YWxMb2NrZWRCeVVzZXJLRVkDBQhzd2FwVHlwZQUHYWNjb3VudAUHaW5Bc3NldAkAZQIFEXRvdGFsTG9ja2VkQnlVc2VyBQhpbkFtb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvdGFsTG9ja2VkS0VZAgUIc3dhcFR5cGUFB2luQXNzZXQJAGUCBQt0b3RhbExvY2tlZAUIaW5BbW91bnQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBB3N3YXBLRVkCBQdhY2NvdW50BQhzd2FwVHhJZAkBDmZpbmlzaFN3YXBEQVRBCwUJZGF0YUFycmF5BQ13aXRoZHJhd1ByaWNlBQxvdXROZXRBbW91bnQFDG91dEZlZUFtb3VudAUMdW5sb2NrSGVpZ2h0BQVpbmRleAUEdHhJZAUKb3V0U3VyZkFtdAUCQlIFDndpdGhkcmF3QmFza2V0BQdpbkFzc2V0BQNuaWwKAQhkZXBvc2l0cwQIc3VyZkZlZXMIbnNidEZlZXMMc3VyZlBheW1lbnRzDG5zYnRQYXltZW50cwQLc3VyZkRlcG9zaXQDCQBmAgUIc3VyZkZlZXMAAAkBBWFzSW50AQkA/AcEBRNzdXJmU3Rha2luZ0NvbnRyYWN0AgdkZXBvc2l0BQNuaWwFDHN1cmZQYXltZW50cwAABAtuc2J0RGVwb3NpdAMJAGYCBQhuc2J0RmVlcwAACQEFYXNJbnQBCQD8BwQFE25zYnRTdGFraW5nQ29udHJhY3QCB2RlcG9zaXQFA25pbAUMbnNidFBheW1lbnRzAAAJAGQCBQtzdXJmRGVwb3NpdAULbnNidERlcG9zaXQKAQpkaXZpZGVGZWVzAQlmZWVBbW91bnQECHN1cmZBbXQxAwkBAiE9AgUNZ25zYnRBbXRUb3RhbAAACQBrAwUJZmVlQW1vdW50BRVnbnNidEFtdEZyb21TdXJmVG90YWwFDWduc2J0QW10VG90YWwAAAQIc3VyZkFtdDIDCQECIT0CBQ1nbnNidEFtdFRvdGFsAAAJAGsDBQlmZWVBbW91bnQJAGUCBQVNVUxUNgUCQlIFBU1VTFQ2AAAEB3N1cmZBbXQJAJYDAQkAzAgCBQhzdXJmQW10MQkAzAgCBQhzdXJmQW10MgUDbmlsBAduc2J0QW10CQBlAgUJZmVlQW1vdW50BQdzdXJmQW10CQDMCAIFB3N1cmZBbXQJAMwIAgUHbnNidEFtdAUDbmlsBAl0cmFuc2ZlcnMDCQAAAgUIc3dhcFR5cGUCCG91dE11bHRpBAZiYXNrZXQJALwJAgUOd2l0aGRyYXdCYXNrZXQCAV8KAQZsb29wZXICA2FjYwRpdGVtBAJpdAkAtQkCBQRpdGVtBQdMSVNUU0VQBAt0ZW1wQXNzZXRJZAkA2QQBCQCRAwIFAml0AAAEB2Fzc2V0SWQDCQAAAgULdGVtcEFzc2V0SWQFB1dBVkVTSUQFBHVuaXQFC3RlbXBBc3NldElkBAluZXRBbW91bnQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQJpdAACBAlmZWVBbW91bnQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQJpdAADBARmZWVzCQEKZGl2aWRlRmVlcwEFCWZlZUFtb3VudAkAlwoFCQDNCAIIBQNhY2MCXzEJAQ5TY3JpcHRUcmFuc2ZlcgMFC3VzZXJBZGRyZXNzBQluZXRBbW91bnQFB2Fzc2V0SWQJAM0IAggFA2FjYwJfMgkBD0F0dGFjaGVkUGF5bWVudAIFB2Fzc2V0SWQJAJEDAgUEZmVlcwAACQDNCAIIBQNhY2MCXzMJAQ9BdHRhY2hlZFBheW1lbnQCBQdhc3NldElkCQCRAwIFBGZlZXMAAQkAZAIIBQNhY2MCXzQJAJEDAgUEZmVlcwAACQBkAggFA2FjYwJfNQkAkQMCBQRmZWVzAAEEAXIKAAIkbAUGYmFza2V0CgACJHMJAJADAQUCJGwKAAUkYWNjMAkAlwoFBQNuaWwFA25pbAUDbmlsAAAAAAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEGbG9vcGVyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKBApkZXBvUmVzdWx0CQEIZGVwb3NpdHMECAUBcgJfNAgFAXICXzUIBQFyAl8yCAUBcgJfMwkAlAoCCAUBcgJfMQUKZGVwb1Jlc3VsdAQEZmVlcwkBCmRpdmlkZUZlZXMBBQxvdXRGZWVBbW91bnQECmRlcG9SZXN1bHQJAQhkZXBvc2l0cwQJAJEDAgUEZmVlcwAACQCRAwIFBGZlZXMAAQkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgUKb3V0QXNzZXRJZAkAkQMCBQRmZWVzAAAFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgUKb3V0QXNzZXRJZAkAkQMCBQRmZWVzAAEFA25pbAkAlAoCCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMFC3VzZXJBZGRyZXNzBQxvdXROZXRBbW91bnQFCm91dEFzc2V0SWQFA25pbAUKZGVwb1Jlc3VsdAkAlAoCCQDOCAIFDWNvbW1vbkFjdGlvbnMIBQl0cmFuc2ZlcnMCXzEIBQl0cmFuc2ZlcnMCXzIJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEXaW50ZXJuYWxVbmxlYXNlQW5kTGVhc2UBDXVubGVhc2VBbW91bnQDCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAAIBAixpbnRlcm5hbFVubGVhc2VBbmRMZWFzZSBpcyBub3QgcHVibGljIG1ldGhvZAkBFnByZXBhcmVVbmxlYXNlQW5kTGVhc2UBBQ11bmxlYXNlQW1vdW50AWkBEnRyYW5zZmVyVXNkblRvVXNlcgIGYW1vdW50BGFkZHIDCQECIT0CCAUBaQZjYWxsZXIFD2F1Y3Rpb25Db250cmFjdAkAAgECI09ubHkgYXVjdGlvbiBjb250cmFjdCBpcyBhdXRob3JpemVkCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMJARFAZXh0ck5hdGl2ZSgxMDYyKQEFBGFkZHIFBmFtb3VudAUPbmV1dHJpbm9Bc3NldElkBQNuaWwBaQELYWNjZXB0V2F2ZXMAAwMJAQIhPQIIBQFpBmNhbGxlcgUPYXVjdGlvbkNvbnRyYWN0CQECIT0CCAUBaQZjYWxsZXIFC2dvdkNvbnRyYWN0BwkAAgECQ0N1cnJlbnRseSBvbmx5IGF1Y3Rpb24gYW5kIGdvdmVybmFuY2UgY29udHJhY3RzIGFyZSBhbGxvd2VkIHRvIGNhbGwJAJQKAgkBFnByZXBhcmVVbmxlYXNlQW5kTGVhc2UBAAACB3N1Y2Nlc3MBaQEPYXBwcm92ZUxlYXNpbmdzAwZuTGlzdFMIZ3JvdXBOdW0EbEFtdAQFbklkeHMJAMwIAgAACQDMCAIAAQkAzAgCAAIJAMwIAgADCQDMCAIABAkAzAgCAAUJAMwIAgAGCQDMCAIABwUDbmlsBAdtbmdQdWJTCQELdmFsdWVPckVsc2UCCQCiCAECHCVzJXNfX2NmZ19fbGVhc2luZ01hbmFnZXJQdWICLDdBVU1YNTR1a1lNWXZQbW1hN3lvRmY1TmpaaHM0QnU1bnozRXo5RVY4c3VyBAZtbmdQdWIJANkEAQUHbW5nUHViUwQObm9kZVJlZ0FkZHJTdHIJAQt2YWx1ZU9yRWxzZQIJAKIIAQIfJXMlc19fY2ZnX19ub2Rlc1JlZ2lzdHJ5QWRkcmVzcwIjM1A5dktxUUtqVWRtcFhBZmlXYXU4a3JSRVlBWTFYcjY5cEUEC25vZGVSZWdBZGRyCQERQGV4dHJOYXRpdmUoMTA2MikBBQ5ub2RlUmVnQWRkclN0cgQRbEdyb3VwTm9kZUxpc3RLRVkJARhnZXRMZWFzZUdyb3VwTm9kZUxpc3RLZXkBBQhncm91cE51bQQKbEdyTm9kZU9wdAkAnQgCBQR0aGlzBRFsR3JvdXBOb2RlTGlzdEtFWQMJAQlpc0RlZmluZWQBBQpsR3JOb2RlT3B0CQACAQkArAICCQCsAgICBmdyb3VwIAkApAMBBQhncm91cE51bQIUIGFscmVhZHkgaW5pdGlhbGl6ZWQEBW5MaXN0CQC1CQIFBm5MaXN0UwUDU0VQBAhleHBDb3VudAkAkAMBBQVuSWR4cwMJAQIhPQIIBQFpD2NhbGxlclB1YmxpY0tleQUGbW5nUHViCQACAQIeYXBwcm92ZUxlYXNpbmdzIG5vdCBhdXRob3JpemVkBA0kdDA0NDQ2NjQ0NTI4CQEMcmVhZE5vZGVJbmZvAQAABAZuQWRkcjAIBQ0kdDA0NDQ2NjQ0NTI4Al8xBAhsQW10S0VZMAgFDSR0MDQ0NDY2NDQ1MjgCXzIEBWxBbXQwCAUNJHQwNDQ0NjY0NDUyOAJfMwQHbElkS0VZMAgFDSR0MDQ0NDY2NDQ1MjgCXzQEBGxJZDAIBQ0kdDA0NDQ2NjQ0NTI4Al81BAVuZXdMMAkAxAgCBQZuQWRkcjAJAGUCBQVsQW10MAkAaAIFBGxBbXQFCGV4cENvdW50BAp2YWxpZGF0aW9uCQD8BwQFC25vZGVSZWdBZGRyAhp2YWxpZGF0ZUFuZEFwcHJvdmVMZWFzaW5ncwkAzAgCBQZuTGlzdFMFA25pbAUDbmlsAwkAAAIFCnZhbGlkYXRpb24FCnZhbGlkYXRpb24KASNmb3JFYWNoTm9kZVZhbGlkYXRlQW5kR2VuZXJhdGVMZWFzZQIBYQFpBARub2RlCQCRAwIFBW5MaXN0BQFpBAJsYQkAxAgCCQERQGV4dHJOYXRpdmUoMTA2MikBBQRub2RlBQRsQW10CQDOCAIFAWEJAMwIAgUCbGEJAMwIAgkBC0JpbmFyeUVudHJ5AgkBFmdldExlYXNlSWRCeUFkZHJlc3NLZXkBBQRub2RlCQEFbGNhbGMBBQJsYQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBGmdldExlYXNlQW1vdW50QnlBZGRyZXNzS2V5AQUEbm9kZQUEbEFtdAUDbmlsCQDOCAIJAMwIAgkBC1N0cmluZ0VudHJ5AgURbEdyb3VwTm9kZUxpc3RLRVkFBm5MaXN0UwkAzAgCCQELQmluYXJ5RW50cnkCBQdsSWRLRVkwCQEFbGNhbGMBBQVuZXdMMAkAzAgCCQEMSW50ZWdlckVudHJ5AgUIbEFtdEtFWTAIBQVuZXdMMAZhbW91bnQJAMwIAgkBC0xlYXNlQ2FuY2VsAQUEbElkMAkAzAgCBQVuZXdMMAUDbmlsCgACJGwFBW5JZHhzCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJASNmb3JFYWNoTm9kZVZhbGlkYXRlQW5kR2VuZXJhdGVMZWFzZQIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQITTGlzdCBzaXplIGV4Y2VlZHMgOAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQERcmViYWxhbmNlTGVhc2luZ3MCBmFtb3VudAhncm91cE51bQQFbklkeHMJAMwIAgAACQDMCAIAAQkAzAgCAAIJAMwIAgADCQDMCAIABAkAzAgCAAUJAMwIAgAGCQDMCAIABwUDbmlsBAdtbmdQdWJTCQELdmFsdWVPckVsc2UCCQCiCAECHCVzJXNfX2NmZ19fbGVhc2luZ01hbmFnZXJQdWICLDdBVU1YNTR1a1lNWXZQbW1hN3lvRmY1TmpaaHM0QnU1bnozRXo5RVY4c3VyBAZtbmdQdWIJANkEAQUHbW5nUHViUwQRbEdyb3VwTm9kZUxpc3RLRVkJARhnZXRMZWFzZUdyb3VwTm9kZUxpc3RLZXkBBQhncm91cE51bQQGbkxpc3RTCQEPZ2V0U3RyaW5nT3JGYWlsAgUEdGhpcwURbEdyb3VwTm9kZUxpc3RLRVkEBW5MaXN0CQC1CQIFBm5MaXN0UwUDU0VQAwkBAiE9AggFAWkPY2FsbGVyUHVibGljS2V5BQZtbmdQdWIJAAIBAiByZWJhbGFuY2VMZWFzaW5ncyBub3QgYXV0aG9yaXplZAQKdW5sZWFzZUFtdAkAZAIJAGkCBQZhbW91bnQJAJADAQUFbkxpc3QAAQQNJHQwNDU3Njg0NTgzMAkBDHJlYWROb2RlSW5mbwEAAAQGbkFkZHIwCAUNJHQwNDU3Njg0NTgzMAJfMQQIbEFtdEtFWTAIBQ0kdDA0NTc2ODQ1ODMwAl8yBAVsQW10MAgFDSR0MDQ1NzY4NDU4MzACXzMEB2xJZEtFWTAIBQ0kdDA0NTc2ODQ1ODMwAl80BARsSWQwCAUNJHQwNDU3Njg0NTgzMAJfNQQFbmV3TDAJAMQIAgUGbkFkZHIwCQBkAgUFbEFtdDAJAGgCBQp1bmxlYXNlQW10CQCQAwEFBW5MaXN0CgEUZm9yRWFjaE5vZGVEb1VubGVhc2UCAWEBaQQEbm9kZQkAkQMCBQVuTGlzdAUBaQQGbElkS0VZCQEWZ2V0TGVhc2VJZEJ5QWRkcmVzc0tleQEFBG5vZGUEA2xJZAkBEUBleHRyTmF0aXZlKDEwNTIpAgUEdGhpcwUGbElkS0VZBAdsQW10S0VZCQEaZ2V0TGVhc2VBbW91bnRCeUFkZHJlc3NLZXkBBQRub2RlBARsQW10CQERQGV4dHJOYXRpdmUoMTA1MCkCBQR0aGlzBQdsQW10S0VZBAN1bGEJAQtMZWFzZUNhbmNlbAEJAQV2YWx1ZQEFA2xJZAQCbGEJAMQIAgkBEUBleHRyTmF0aXZlKDEwNjIpAQUEbm9kZQkAZQIFBGxBbXQFCnVubGVhc2VBbXQJAM4IAgUBYQkAzAgCCQELTGVhc2VDYW5jZWwBCQEFdmFsdWUBBQNsSWQJAMwIAgUCbGEJAMwIAgkBC0JpbmFyeUVudHJ5AgUGbElkS0VZCQEFbGNhbGMBBQJsYQkAzAgCCQEMSW50ZWdlckVudHJ5AgUHbEFtdEtFWQgFAmxhBmFtb3VudAUDbmlsCQDOCAIKAAIkbAUFbklkeHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBFGZvckVhY2hOb2RlRG9VbmxlYXNlAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhNMaXN0IHNpemUgZXhjZWVkcyA4CQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAkAzAgCCQELQmluYXJ5RW50cnkCBQdsSWRLRVkwCQEFbGNhbGMBBQVuZXdMMAkAzAgCCQEMSW50ZWdlckVudHJ5AgUIbEFtdEtFWTAIBQVuZXdMMAZhbW91bnQJAMwIAgkBC0xlYXNlQ2FuY2VsAQUEbElkMAkAzAgCBQVuZXdMMAUDbmlsAWkBG3N3YXBQYXJhbXNCeVVzZXJTWVNSRUFET05MWQIOdXNlckFkZHJlc3NTdHIJZ25zYnREaWZmBAlnbnNidERhdGEJAQlhc0FueUxpc3QBCQD8BwQFF2duc2J0Q29udHJvbGxlckNvbnRyYWN0AhRnbnNidEluZm9TWVNSRUFET05MWQkAzAgCBQ51c2VyQWRkcmVzc1N0cgkAzAgCAAAJAMwIAgAABQNuaWwFA25pbAQIZ25zYnRBbXQJAGQCCQEFYXNJbnQBCQCRAwIFCWduc2J0RGF0YQAABQlnbnNidERpZmYEDWduc2J0QW10VG90YWwJAGQCCQEFYXNJbnQBCQCRAwIFCWduc2J0RGF0YQABBQlnbnNidERpZmYEDXN3YXBMaW1pdERhdGEJAQlhc0FueUxpc3QBCQD8BwQFDG1hdGhDb250cmFjdAIVY2FsY1N3YXBMaW1pdFJFQURPTkxZCQDMCAIFCGduc2J0QW10BQNuaWwFA25pbAQWdG9rZW5Td2FwTGltaXRJblVzZE1heAkBBWFzSW50AQkAkQMCBQ1zd2FwTGltaXREYXRhAAAEEHVzZG5Td2FwTGltaXRNYXgJAQVhc0ludAEJAJEDAgUNc3dhcExpbWl0RGF0YQACBA5sYXN0U3dhcEhlaWdodAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEVa2V5VXNlckxhc3RTd2FwSGVpZ2h0AQUOdXNlckFkZHJlc3NTdHIAAAQXc3dhcExpbWl0VGltZWxpZmVCbG9ja3MJARJzd2Fwc1RpbWVmcmFtZVJFQUQABBlwYXNzZWRCbG9ja3NBZnRlckxhc3RTd2FwCQBlAgUGaGVpZ2h0BQ5sYXN0U3dhcEhlaWdodAQRaXNTd2FwVGltZWxpZmVOZXcJAGcCBRlwYXNzZWRCbG9ja3NBZnRlckxhc3RTd2FwBRdzd2FwTGltaXRUaW1lbGlmZUJsb2NrcwQUc3dhcExpbWl0U3BlbnRJblVzZG4DBRFpc1N3YXBUaW1lbGlmZU5ldwAACQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJARhrZXlTd2FwVXNlclNwZW50SW5QZXJpb2QBBQ51c2VyQWRkcmVzc1N0cgAABA5ibGNrczJMbXRSZXNldAMFEWlzU3dhcFRpbWVsaWZlTmV3AAAJAGUCBRdzd2FwTGltaXRUaW1lbGlmZUJsb2NrcwUZcGFzc2VkQmxvY2tzQWZ0ZXJMYXN0U3dhcAkAlAoCBQNuaWwJAJkKBwUWdG9rZW5Td2FwTGltaXRJblVzZE1heAUUc3dhcExpbWl0U3BlbnRJblVzZG4FDmJsY2tzMkxtdFJlc2V0BQhnbnNidEFtdAUNZ25zYnRBbXRUb3RhbAAABRB1c2RuU3dhcExpbWl0TWF4AWkBHWNhbGNXaXRoZHJhd1Jlc3VsdFNZU1JFQURPTkxZBAhzd2FwVHlwZQhpbkFtb3VudAVwcmljZQdpbkFzc2V0BA9uZXV0cmlub01ldHJpY3MJAQlhc0FueUxpc3QBCQD8BwQFDG1hdGhDb250cmFjdAIaY2FsY05ldXRpbm9NZXRyaWNzUkVBRE9OTFkFA25pbAUDbmlsCQCUCgIFA25pbAkBDGNhbGNXaXRoZHJhdwUFCHN3YXBUeXBlBQhpbkFtb3VudAUFcHJpY2UFD25ldXRyaW5vTWV0cmljcwUHaW5Bc3NldAFpARRyZXBsYWNlQ29tbXVuaXR5Tm9kZQQKb2xkQWRkclN0cgpuZXdBZGRyU3RyCGdyb3VwTnVtDXBlbmFsdHlBbW91bnQEB21uZ1B1YlMJAQt2YWx1ZU9yRWxzZQIJAKIIAQIcJXMlc19fY2ZnX19sZWFzaW5nTWFuYWdlclB1YgIsN0FVTVg1NHVrWU1ZdlBtbWE3eW9GZjVOalpoczRCdTVuejNFejlFVjhzdXIEBm1uZ1B1YgkA2QQBBQdtbmdQdWJTAwkBAiE9AggFAWkPY2FsbGVyUHVibGljS2V5BQZtbmdQdWIJAAIBAiNyZXBsYWNlQ29tbXVuaXR5Tm9kZSBub3QgYXV0aG9yaXplZAQIZ3JvdXBLZXkJARhnZXRMZWFzZUdyb3VwTm9kZUxpc3RLZXkBBQhncm91cE51bQQOZ3JvdXBOb2RlTGlzdFMJAQ9nZXRTdHJpbmdPckZhaWwCBQR0aGlzBQhncm91cEtleQMJAQEhAQkBCGNvbnRhaW5zAgUOZ3JvdXBOb2RlTGlzdFMFCm9sZEFkZHJTdHIJAAIBCQCsAgIJAKwCAgkArAICAgZHcm91cCAJAKQDAQUIZ3JvdXBOdW0CGiBkb2VzIG5vdCBjb250YWluIGFkZHJlc3MgBQpvbGRBZGRyU3RyBAlkb1JlcGxhY2UJAPwHBAUUbm9kZVJlZ2lzdHJ5Q29udHJhY3QCE3JlcGxhY2VBcHByb3ZlZE5vZGUJAMwIAgUKb2xkQWRkclN0cgkAzAgCBQpuZXdBZGRyU3RyCQDMCAIFCGdyb3VwTnVtCQDMCAIFDXBlbmFsdHlBbW91bnQFA25pbAUDbmlsAwkAAAIFCWRvUmVwbGFjZQUJZG9SZXBsYWNlBA1vbGRMZWFzZUlkS2V5CQEWZ2V0TGVhc2VJZEJ5QWRkcmVzc0tleQEFCm9sZEFkZHJTdHIEDm9sZExlYXNlQW10S2V5CQEaZ2V0TGVhc2VBbW91bnRCeUFkZHJlc3NLZXkBBQpvbGRBZGRyU3RyBAhsZWFzZUFtdAkBEUBleHRyTmF0aXZlKDEwNTUpAQUOb2xkTGVhc2VBbXRLZXkEDW5ld0xlYXNlSWRLZXkJARZnZXRMZWFzZUlkQnlBZGRyZXNzS2V5AQUKbmV3QWRkclN0cgQObmV3TGVhc2VBbXRLZXkJARpnZXRMZWFzZUFtb3VudEJ5QWRkcmVzc0tleQEFCm5ld0FkZHJTdHIECG5ld0xlYXNlCQDECAIJARFAZXh0ck5hdGl2ZSgxMDYyKQEFCm5ld0FkZHJTdHIFCGxlYXNlQW10BBV1cGRhdGVkR3JvdXBOb2RlTGlzdFMJALkJAgkAtQkCBQ5ncm91cE5vZGVMaXN0UwUKb2xkQWRkclN0cgUKbmV3QWRkclN0cgkAlAoCCQDMCAIJAQtMZWFzZUNhbmNlbAEJARFAZXh0ck5hdGl2ZSgxMDU3KQEFDW9sZExlYXNlSWRLZXkJAMwIAgkBC0RlbGV0ZUVudHJ5AQUNb2xkTGVhc2VJZEtleQkAzAgCCQELRGVsZXRlRW50cnkBBQ5vbGRMZWFzZUFtdEtleQkAzAgCCQELU3RyaW5nRW50cnkCBQhncm91cEtleQUVdXBkYXRlZEdyb3VwTm9kZUxpc3RTCQDMCAIFCG5ld0xlYXNlCQDMCAIJAQtCaW5hcnlFbnRyeQIFDW5ld0xlYXNlSWRLZXkJAQVsY2FsYwEFCG5ld0xlYXNlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ5uZXdMZWFzZUFtdEtleQUIbGVhc2VBbXQFA25pbAUEdW5pdAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgECdHgBBnZlcmlmeQAEE3B1YktleUFkbWluc0xpc3RTdHIJALkJAgkAzAgCAixHSmRMU2FMaXY1Szd4dWVqYWM4bWNSY0hveW8zZFByRVNydmt0RzNhNk1BUgkAzAgCAixFWXdabVVSZDVLS2FRUkJqc1ZhNmc4RFBpc0ZvUzZTb3ZSSnRGaUw1Z01IVQkAzAgCAixEdG1BZnVEZENySEs4c3BkQWVBWXpxNk1zWmVnZUQ5Z25zcnB1VFJrQ2JWQQkAzAgCAiw1V1JYRlNqd2NUYk5mS2NKczhacVhtU1NXWXNTVkpVdE12TXFaajVoSDROYwUDbmlsBQNTRVAEEHB1YktleUFkbWluc0xpc3QJALUJAgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ9jb250cm9sQ29udHJhY3QCDCVzX19tdWx0aXNpZwUTcHViS2V5QWRtaW5zTGlzdFN0cgUDU0VQBAVjb3VudAkAZAIJAGQCCQBkAgMJAPQDAwgFAnR4CWJvZHlCeXRlcwkAkQMCCAUCdHgGcHJvb2ZzAAAJANkEAQkAkQMCBRBwdWJLZXlBZG1pbnNMaXN0AAAAAQAAAwkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAQkA2QQBCQCRAwIFEHB1YktleUFkbWluc0xpc3QAAQABAAADCQD0AwMIBQJ0eAlib2R5Qnl0ZXMJAJEDAggFAnR4BnByb29mcwACCQDZBAEJAJEDAgUQcHViS2V5QWRtaW5zTGlzdAACAAEAAAMJAPQDAwgFAnR4CWJvZHlCeXRlcwkAkQMCCAUCdHgGcHJvb2ZzAAMJANkEAQkAkQMCBRBwdWJLZXlBZG1pbnNMaXN0AAMAAgAAAwMFCWlzQmxvY2tlZAkAAAIJARFAZXh0ck5hdGl2ZSgxMDUzKQIFD2NvbnRyb2xDb250cmFjdAIRaXNfYmxvY2tlZF9jYWxsZXIJAKUIAQULZ292Q29udHJhY3QHCQEOdmFsaWRhdGVVcGRhdGUBBQJ0eAQHJG1hdGNoMAUCdHgDCQABAgUHJG1hdGNoMAIVU3BvbnNvckZlZVRyYW5zYWN0aW9uBAlzcG9uc29yVHgFByRtYXRjaDADCQEbY2hlY2tJc1ZhbGlkTWluU3BvbnNvcmVkRmVlAQUJc3BvbnNvclR4CQBnAgUFY291bnQAAwcJAGcCBQVjb3VudAADcIvulA==", "height": 3537923, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: FaBNGm2ij3me65fjEZ5pGEKBhua7wthLkSqWoxBomdPa Next: 3mYjZsNnASsKz1FWYc7ce8D6LuVQL7sBDYeqxdoH5Hjx Diff:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let revisionNum = "09edb6fbe9e8b1c20448e26435cb7f292ddab948"
4+let revisionNum = "46ddf9ad4f4a67a79d872f7c5671aa012953a34b"
55
66 func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], ""))
77
7979
8080 let LISTSEP = ":"
8181
82-let WAVELET = 100000000
82+let MULT8 = 100000000
8383
84-let PAULI = 1000000
85-
86-let PRICELET = 1000000
84+let MULT6 = 1000000
8785
8886 let DEFAULTSWAPFEE = 20000
8987
9088 let BRPROTECTED = 100000
9189
92-let IdxNetAmount = 0
90+let WAVESID = base58'WAVES'
9391
94-let IdxFeeAmount = 1
92+let nMetricIdxPrice = 0
9593
96-let IdxGrossAmount = 2
94+let nMetricIdxUsdnLockedBalance = 1
95+
96+let nMetricIdxWavesLockedBalance = 2
97+
98+let nMetricIdxReserve = 3
99+
100+let nMetricIdxReserveInUsdn = 4
101+
102+let nMetricIdxUsdnSupply = 5
103+
104+let nMetricIdxSurplus = 6
105+
106+let nMetricIdxSurplusPercent = 7
107+
108+let nMetricIdxBR = 8
109+
110+let nMetricIdxNsbtSupply = 9
111+
112+let nMetricIdxMaxNsbtSupply = 10
113+
114+let nMetricIdxSurfSupply = 11
115+
116+let nMetricUsdnUsdtPeg = 12
117+
118+let nMetricCurrentPriceAdj = 13
119+
120+let nMetricBasketInfo = 14
121+
122+let nMetricWeightedPrice = 15
123+
124+let nMetricTotalReservesUsd = 16
97125
98126 let IdxControlCfgNeutrinoDapp = 1
99127
171199
172200 let BalanceNeutrinoLockIntervalKey = "balance_neutrino_lock_interval"
173201
174-let MinWavesSwapAmountKey = "min_waves_swap_amount"
202+func MinTokenSwapAmountKey (assetId) = ("min_outNeutrino_swap_amount_" + assetId)
175203
176-let MinNeutrinoSwapAmountKey = "min_neutrino_swap_amount"
204+
205+let MinNeutrinoSwapAmountKey = "min_outMulti_swap_amount"
206+
207+let LegacyMinNeutrinoSwapAmountKey = "min_neutrino_swap_amount"
177208
178209 let NodeOracleProviderPubKeyKey = "node_oracle_provider"
179210
202233 func getStakingNodeAddressByIndex (idx) = addressFromStringValue(getStakingNodeByIndex(idx))
203234
204235
205-func getReservedAmountForSponsorship () = valueOrElse(getInteger(this, makeString(["%s%s", "lease", "sponsorshipWavesReserve"], SEP)), (1000 * WAVELET))
236+func getReservedAmountForSponsorship () = valueOrElse(getInteger(this, makeString(["%s%s", "lease", "sponsorshipWavesReserve"], SEP)), (1000 * MULT8))
206237
207238
208239 func getBalanceUnlockBlockKey (owner) = ("balance_unlock_block_" + owner)
226257 func minSwapAmountKEY (swapType) = (("min_" + swapType) + "_swap_amount")
227258
228259
229-func totalLockedKEY (swapType) = ("balance_lock_" + swapType)
260+func totalLockedKEY (swapType,assetId) = makeString(["%s%s%s", "balanceLock", swapType, assetId], SEP)
230261
231262
232-func totalLockedByUserKEY (swapType,owner) = makeString(["balance_lock", swapType, owner], "_")
263+func totalLockedByUserKEY (swapType,owner,assetId) = makeString(["%s%s%s%s", "balanceLock", swapType, owner, assetId], "_")
233264
234265
235-func balanceLockIntervalKEY (swapType) = (("balance_" + swapType) + "_lock_interval")
266+func balanceLockIntervalKEY (swapType) = if ((swapType == "outMulti"))
267+ then BalanceNeutrinoLockIntervalKey
268+ else BalanceWavesLockIntervalKey
236269
237270
238271 func nodeBalanceLockIntervalKEY () = "balance_node_lock_interval"
239-
240-
241-func outFeePartKEY (swapType) = (swapType + "Out_swap_feePart")
242272
243273
244274 func swapsTimeframeKEY () = "swaps_timeframe"
247277 func brProtectedKEY () = "min_BR_protection_level"
248278
249279
250-func minSwapAmountREAD (swapType) = valueOrElse(getInteger(this, minSwapAmountKEY(swapType)), 0)
280+func basketAssetsKey () = "%s%s__common__basketAssets"
281+
282+
283+func basketDKey () = "%s%s__common__basketD"
284+
285+
286+func basketKKey () = "%s%s__common__basketK"
287+
288+
289+func basketBKey () = "%s%s__common__basketB"
290+
291+
292+func basketLogbDeltaKey () = "%s%s__common__basketLogbDelta"
293+
294+
295+func basketWeightByAssetKey (assetId) = ("%s%s%s__common__weightByAsset__" + assetId)
296+
297+
298+func keyPriceByAsset (assetId) = ("%s%s%s__common__priceByAsset__" + assetId)
299+
300+
301+func minSwapAmountREAD (swapType,assetId) = if ((swapType == "outMulti"))
302+ then valueOrElse(getInteger(MinNeutrinoSwapAmountKey), getNumberByKey(LegacyMinNeutrinoSwapAmountKey))
303+ else getNumberByKey(MinTokenSwapAmountKey(assetId))
251304
252305
253306 func swapsTimeframeREAD () = valueOrElse(getInteger(this, swapsTimeframeKEY()), 1440)
254307
255308
256-func totalLockedREAD (swapType) = valueOrElse(getInteger(this, totalLockedKEY(swapType)), 0)
309+func totalLockedREAD (swapType,assetId) = valueOrElse(getInteger(this, totalLockedKEY(swapType, assetId)), 0)
257310
258311
259-func totalLockedByUserREAD (swapType,owner) = valueOrElse(getInteger(this, totalLockedByUserKEY(swapType, owner)), 0)
312+func totalLockedByUserREAD (swapType,owner,assetId) = valueOrElse(getInteger(this, totalLockedByUserKEY(swapType, owner, assetId)), 0)
260313
261314
262315 func balanceLockIntervalREAD (swapType) = valueOrElse(getInteger(this, balanceLockIntervalKEY(swapType)), 1440)
271324 func keyUserLastSwapHeight (userAddress) = makeString(["%s%s", "userLastSwapHeight", userAddress], SEP)
272325
273326
274-func convertNeutrinoToWaves (amount,price) = fraction(fraction(amount, PRICELET, price), WAVELET, PAULI)
327+func convertNeutrinoToWaves (amount,price) = fraction(amount, MULT8, price)
275328
276329
277-func convertWavesToNeutrino (amount,price) = fraction(fraction(amount, price, PRICELET), PAULI, WAVELET)
330+func convertTokenToUsd (amount,price) = fraction(amount, price, MULT8)
278331
279332
280-func convertWavesToBond (amount,price) = convertWavesToNeutrino(amount, price)
333+func convertWavesToNeutrino (amount,price) = fraction(amount, price, MULT8)
334+
335+
336+func convertWavesToBond (amount,price) = convertTokenToUsd(amount, price)
281337
282338
283339 func convertJsonArrayToList (jsonArray) = split(jsonArray, ",")
340+
341+
342+func convertBasketItemToNeutrino (inAmount,inAsset,basketInfoStr,neutrinoPrice) = {
343+ let basketInfo = split_4C(basketInfoStr, "_")
344+ func findItem (acc,item) = {
345+ let bItem = split(item, LISTSEP)
346+ if ((bItem[0] == inAsset))
347+ then bItem
348+ else acc
349+ }
350+
351+ let it = {
352+ let $l = basketInfo
353+ let $s = size($l)
354+ let $acc0 = nil
355+ func $f0_1 ($a,$i) = if (($i >= $s))
356+ then $a
357+ else findItem($a, $l[$i])
358+
359+ func $f0_2 ($a,$i) = if (($i >= $s))
360+ then $a
361+ else throw("List size exceeds 10")
362+
363+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
364+ }
365+ let dlog6 = value(getInteger(basketLogbDeltaKey()))
366+ let d6 = value(getInteger(basketDKey()))
367+ let b6 = value(getInteger(basketBKey()))
368+ let w6 = value(getInteger(basketWeightByAssetKey(inAsset)))
369+ let p6 = ((dlog6 - w6) + parseIntValue(it[1]))
370+ let pp6 = pow(b6, 6, p6, 6, 6, HALFUP)
371+ let outAmountGross = fraction(inAmount, parseIntValue(it[2]), if ((neutrinoPrice == 0))
372+ then MULT8
373+ else (neutrinoPrice * 100))
374+ let multiplier = ((MULT6 + d6) - pp6)
375+ let netAmount = fraction(outAmountGross, multiplier, MULT6)
376+ let feeAmount = if ((netAmount >= outAmountGross))
377+ then 0
378+ else (outAmountGross - netAmount)
379+[outAmountGross, netAmount, feeAmount]
380+ }
381+
382+
383+func convertNeutrinoToBasket (amount,basketInfoStr,neutrinoSupply) = {
384+ let basketInfo = split_4C(basketInfoStr, "_")
385+ func conv (acc,item) = {
386+ let parts = split(item, LISTSEP)
387+ let assetId = parts[0]
388+ let share = parseIntValue(parts[1])
389+ let price = parseIntValue(parts[2])
390+ let reserv = parseIntValue(parts[3])
391+ if ((neutrinoSupply == 0))
392+ then throw("Attempt to burn neutrino at zero supply")
393+ else {
394+ let outAmount = fraction(amount, reserv, neutrinoSupply)
395+ let wavesTuple = if ((assetId == "WAVES"))
396+ then $Tuple2(outAmount, price)
397+ else $Tuple2(acc._2, acc._3)
398+ $Tuple3((acc._1 :+ $Tuple4(assetId, outAmount, price, share)), wavesTuple._1, wavesTuple._2)
399+ }
400+ }
401+
402+ let $l = basketInfo
403+ let $s = size($l)
404+ let $acc0 = $Tuple3(nil, 0, 0)
405+ func $f0_1 ($a,$i) = if (($i >= $s))
406+ then $a
407+ else conv($a, $l[$i])
408+
409+ func $f0_2 ($a,$i) = if (($i >= $s))
410+ then $a
411+ else throw("List size exceeds 10")
412+
413+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
414+ }
284415
285416
286417 func minSwapAmountFAIL (swapType,minSwapAmount) = throw(((("The specified amount in " + swapType) + " swap is less than the required minimum of ") + toString(minSwapAmount)))
311442 func checkIsValidMinSponsoredFee (tx) = {
312443 let MINTRANSFERFEE = 100000
313444 let SponsoredFeeUpperBound = 1000
314- let realNeutrinoFee = convertWavesToNeutrino(MINTRANSFERFEE, currentPrice)
445+ let realNeutrinoFee = convertTokenToUsd(MINTRANSFERFEE, currentPrice)
315446 let minNeutrinoFee = (realNeutrinoFee * 2)
316447 let maxNeutrinoFee = fraction(realNeutrinoFee, SponsoredFeeUpperBound, 100)
317448 let inputFee = value(tx.minSponsoredAssetFee)
348479
349480 let sIdxMaxRand = 16
350481
482+let sIdxInAsset = 20
483+
351484 func swapKEY (userAddress,txId) = makeString(["%s%s", userAddress, txId], SEP)
352485
353486
354-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)
487+func strSwapDATA (swapType,status,inAmount,price,outNetAmount,outFeeAmount,startHeight,startTimestamp,endHeight,endTimestamp,selfUnlockHeight,randUnlockHeight,index,withdrawTxId,randMin,randMax,outSurfAmt,br,basketData,inAsset) = makeString_2C(["%s%s%d%d%d%d%d%d%d%d%d%d%d%s%d%d%d%d%s%s", swapType, status, inAmount, price, outNetAmount, outFeeAmount, startHeight, startTimestamp, endHeight, endTimestamp, selfUnlockHeight, randUnlockHeight, index, withdrawTxId, randMin, randMax, outSurfAmt, br, basketData, inAsset], SEP)
355488
356489
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")
490+func pendingSwapDATA (swapType,inAssetAmount,selfUnlockHeight,inAsset) = strSwapDATA(swapType, "PENDING", toString(inAssetAmount), "0", "0", "0", toString(height), toString(lastBlock.timestamp), "0", "0", toString(selfUnlockHeight), "0", "0", "NULL", "0", "0", "0", "0", "", inAsset)
358491
359492
360-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))
493+func finishSwapDATA (dataArray,price,outNetAmount,outFeeAmount,randUnlockHeight,index,withdrawTxId,outSurfAmt,br,basketData,inAsset) = 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, inAsset)
361494
362495
363496 func swapDataFailOrREAD (userAddress,swapTxId) = {
364497 let swapKey = swapKEY(userAddress, swapTxId)
365- split(valueOrErrorMessage(getString(this, swapKey), ("no swap data for " + swapKey)), SEP)
498+ split_4C(valueOrErrorMessage(getString(swapKey), ("no swap data for " + swapKey)), SEP)
366499 }
367500
368501
369502 func applyFees (amountOutGross,inAmtToSURF,feePart) = {
370- let feeAmount = fraction(amountOutGross, feePart, PAULI)
503+ let feeAmount = fraction(amountOutGross, feePart, MULT6)
371504 [(amountOutGross - feeAmount), feeAmount]
505+ }
506+
507+
508+func applyFeesBasket (basketOut) = {
509+ let k6 = value(getInteger(basketKKey()))
510+ let d6 = value(getInteger(basketDKey()))
511+ let feePart = fraction(k6, d6, MULT6)
512+ func feeApplier (acc,item) = {
513+ let feeAmount = fraction(item._2, feePart, MULT6)
514+ (acc :+ makeString([item._1, toString(item._3), toString((item._2 - feeAmount)), toString(feeAmount), toString(item._4)], LISTSEP))
515+ }
516+
517+ let a = {
518+ let $l = basketOut
519+ let $s = size($l)
520+ let $acc0 = nil
521+ func $f0_1 ($a,$i) = if (($i >= $s))
522+ then $a
523+ else feeApplier($a, $l[$i])
524+
525+ func $f0_2 ($a,$i) = if (($i >= $s))
526+ then $a
527+ else throw("List size exceeds 10")
528+
529+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
530+ }
531+ makeString_2C(a, "_")
372532 }
373533
374534
431591 }
432592
433593
434-func commonSwap (swapType,pmtAmount,userAddressStr,txId58,swapParamsByUserSYSREADONLY) = {
435- let swapLimitSpent = swapParamsByUserSYSREADONLY._2
436- let blcks2LmtReset = swapParamsByUserSYSREADONLY._3
437- let wavesSwapLimitMax = swapParamsByUserSYSREADONLY._6
438- let usdnSwapLimitMax = swapParamsByUserSYSREADONLY._7
439- let minSwapAmount = minSwapAmountREAD(swapType)
440- let totalLocked = totalLockedREAD(swapType)
441- let totalLockedByUser = totalLockedByUserREAD(swapType, userAddressStr)
594+func commonSwap (swapType,pmtAmount,inAsset,userAddressStr,txId58) = {
595+ let swapParamsSTRUCT = asSwapParamsSTRUCT(invoke(this, "swapParamsByUserSYSREADONLY", [userAddressStr, 0], nil))
596+ let tokenSwapLimitUsd = swapParamsSTRUCT._1
597+ let swapLimitSpent = swapParamsSTRUCT._2
598+ let blcks2LmtReset = swapParamsSTRUCT._3
599+ let usdnSwapLimitMax = swapParamsSTRUCT._7
600+ let minSwapAmount = minSwapAmountREAD(swapType, inAsset)
601+ let totalLockedByUser = totalLockedByUserREAD(swapType, userAddressStr, inAsset)
442602 let nodeAddress = getStakingNodeByIndex(0)
443- let priceByIndex = getPriceHistory(getHeightPriceByIndex(priceIndex))
444603 let isSwapByNode = (nodeAddress == userAddressStr)
445604 let balanceLockMaxInterval = if (isSwapByNode)
446605 then nodeBalanceLockIntervalREAD()
447606 else balanceLockIntervalREAD(swapType)
448607 let selfUnlockHeight = (height + balanceLockMaxInterval)
449- let swapUsdnVolume = if ((swapType == "neutrino"))
450- then pmtAmount
451- else convertWavesToNeutrino(pmtAmount, priceByIndex)
452- let swapLimitMax = if ((swapType == "neutrino"))
453- then usdnSwapLimitMax
454- else convertWavesToNeutrino(wavesSwapLimitMax, priceByIndex)
608+ let pr = value(getInteger(controlContract, keyPriceByAsset(inAsset)))
609+ let swapUsdnVolume = if ((swapType == "outNeutrino"))
610+ then convertTokenToUsd(pmtAmount, pr)
611+ else pmtAmount
612+ let swapLimitMax = if ((swapType == "outNeutrino"))
613+ then tokenSwapLimitUsd
614+ else usdnSwapLimitMax
455615 if ((minSwapAmount > pmtAmount))
456616 then minSwapAmountFAIL(swapType, minSwapAmount)
457617 else if (if (!(isSwapByNode))
465625 else if (isBlocked)
466626 then emergencyShutdownFAIL()
467627 else {
468- let leasePart = if ((swapType == "waves"))
469- then prepareUnleaseAndLease(0)
470- else nil
471- $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)
628+ let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
629+ let basketInfo = asString(neutrinoMetrics[nMetricBasketInfo])
630+ let weightedPrice = asInt(neutrinoMetrics[nMetricWeightedPrice])
631+ let out = convertBasketItemToNeutrino(pmtAmount, inAsset, basketInfo, weightedPrice)
632+ if (if ((swapType == "outNeutrino"))
633+ then (0 >= out[1])
634+ else false)
635+ then throw((((((("Net amount is non-positive, cannot swap. (gross, net, fee) = (" + toString(out[0])) + ", ") + toString(out[1])) + ", ") + toString(out[2])) + ")"))
636+ else {
637+ let leasePart = if (if ((swapType == "outNeutrino"))
638+ then (inAsset == "WAVES")
639+ else false)
640+ then prepareUnleaseAndLease(0)
641+ else nil
642+ $Tuple2(([IntegerEntry(keySwapUserSpentInPeriod(userAddressStr), swapUsdnVolume), IntegerEntry(keyUserLastSwapHeight(userAddressStr), height), IntegerEntry(totalLockedByUserKEY(swapType, userAddressStr, inAsset), (totalLockedByUser + pmtAmount)), IntegerEntry(getBalanceUnlockBlockKey(userAddressStr), selfUnlockHeight), StringEntry(swapKEY(userAddressStr, txId58), pendingSwapDATA(swapType, pmtAmount, selfUnlockHeight, inAsset))] ++ leasePart), unit)
643+ }
472644 }
473645 }
474646
475-
476-let nMetricIdxPrice = 0
477-
478-let nMetricIdxUsdnLockedBalance = 1
479-
480-let nMetricIdxWavesLockedBalance = 2
481-
482-let nMetricIdxReserve = 3
483-
484-let nMetricIdxReserveInUsdn = 4
485-
486-let nMetricIdxUsdnSupply = 5
487-
488-let nMetricIdxSurplus = 6
489-
490-let nMetricIdxSurplusPercent = 7
491-
492-let nMetricIdxBR = 8
493-
494-let nMetricIdxNsbtSupply = 9
495-
496-let nMetricIdxMaxNsbtSupply = 10
497-
498-let nMetricIdxSurfSupply = 11
499-
500-let nMetricUsdnUsdtPeg = 12
501-
502-let nMetricCurrentPriceAdj = 13
503647
504648 let bFuncIdxSurf = 0
505649
523667
524668 let bFuncIdxWavesPrice = 10
525669
526-func calcWithdrawW2U (wavesIn,price) = {
527- let outAmtGross = convertWavesToNeutrino(wavesIn, price)
528- $Tuple10(outAmtGross, neutrinoAssetId, 0, unit, 0, price, wavesIn, 0, 0, 0)
670+func calcWithdrawT2U (inAmount,inAsset,basketInfo,weightedPrice) = {
671+ let outAmt = convertBasketItemToNeutrino(inAmount, inAsset, basketInfo, weightedPrice)
672+ $Tuple12(outAmt[0], neutrinoAssetId, 0, inAsset, 0, weightedPrice, inAmount, 0, 0, 0, nil, [outAmt[1], outAmt[2]])
529673 }
530674
531675
532-func calcWithdrawU2W (usdnIn,price,br,reservesInUsdn,usdnSupply) = {
533- let brProtected = valueOrElse(getInteger(this, brProtectedKEY()), BRPROTECTED)
534- let maxAllowedUsdnBeforeMinBr = if ((brProtected >= br))
535- then 0
536- else fraction((reservesInUsdn - fraction(brProtected, usdnSupply, PAULI)), PAULI, (PAULI - brProtected))
537- let allowedUsdnBeforeMinBr = if ((usdnIn > maxAllowedUsdnBeforeMinBr))
538- then maxAllowedUsdnBeforeMinBr
539- else usdnIn
540- let allowedUsdnAfterMinBr = if ((usdnIn > maxAllowedUsdnBeforeMinBr))
541- then fraction((usdnIn - maxAllowedUsdnBeforeMinBr), br, PAULI)
542- else 0
543- let allowedUsdn = (allowedUsdnBeforeMinBr + allowedUsdnAfterMinBr)
544- let usdn2SURF = (usdnIn - allowedUsdn)
545- let outAmtGross = convertNeutrinoToWaves(allowedUsdn, price)
546- $Tuple10(outAmtGross, unit, usdn2SURF, neutrinoAssetId, outAmtGross, price, allowedUsdn, maxAllowedUsdnBeforeMinBr, allowedUsdnBeforeMinBr, allowedUsdnAfterMinBr)
676+func calcWithdrawU2Basket (usdnIn,basketInfo,neutrinoSupply) = {
677+ let outAmtGross = convertNeutrinoToBasket(usdnIn, basketInfo, neutrinoSupply)
678+ $Tuple12(outAmtGross._2, unit, 0, neutrinoAssetId, outAmtGross._2, outAmtGross._3, usdnIn, neutrinoSupply, usdnIn, 0, outAmtGross._1, nil)
547679 }
548680
549681
550-func calcWithdraw (swapType,inAmount,price,neutrinoMetrics) = {
551- let outFeePart = valueOrElse(getInteger(this, outFeePartKEY(swapType)), DEFAULTSWAPFEE)
552- if (if ((0 > outFeePart))
553- then true
554- else (outFeePart >= PAULI))
555- then throw(((("invalid outFeePart config for " + swapType) + " swap: outFeePart=") + toString(outFeePart)))
556- else {
557- let brProtected = valueOrElse(getInteger(this, brProtectedKEY()), BRPROTECTED)
558- let BR = asInt(neutrinoMetrics[nMetricIdxBR])
559- let reservesInUsdn = asInt(neutrinoMetrics[nMetricIdxReserveInUsdn])
560- let usdnSupply = asInt(neutrinoMetrics[nMetricIdxUsdnSupply])
561- let priceAdj = asInt(neutrinoMetrics[nMetricCurrentPriceAdj])
562- let outDataTuple = if ((swapType == "waves"))
563- then calcWithdrawW2U(inAmount, price)
564- else if ((swapType == "neutrino"))
565- then calcWithdrawU2W(inAmount, priceAdj, BR, reservesInUsdn, usdnSupply)
566- else throw(("Unsupported swap type " + swapType))
567- let outAmtGross = outDataTuple._1
568- let outAssetId = outDataTuple._2
569- let inAmtToSurfPart = outDataTuple._3
570- let inAssetId = outDataTuple._4
571- let unleaseAmt = outDataTuple._5
572- let withdrawPrice = outDataTuple._6
573- let payoutsArray = applyFees(outAmtGross, inAmtToSurfPart, outFeePart)
574- let outNetAmt = payoutsArray[IdxNetAmount]
575- let outFeeAmt = payoutsArray[IdxFeeAmount]
576- let outSurfAmt = if ((0 >= inAmtToSurfPart))
577- then 0
578- else {
579- let surfResult = asAnyList(invoke(mathContract, "surfFunctionREADONLY", [inAmtToSurfPart, inAssetId], nil))
580- asInt(surfResult[bFuncIdxSurf])
581- }
582- $Tuple8(outNetAmt, outAssetId, outSurfAmt, inAmtToSurfPart, unleaseAmt, outFeeAmt, outAmtGross, withdrawPrice)
583- }
584- }
585-
586-
587-func commonWithdraw (account,index,swapTxId,withdrawTxId,neutrinoMetrics) = {
588- let userAddress = addressFromStringValue(account)
589- let dataArray = swapDataFailOrREAD(account, swapTxId)
590- let selfUnlockHeight = parseIntValue(dataArray[sIdxSelfUnlockHeight])
591- let swapType = dataArray[sIdxSwapType]
592- let inAmount = parseIntValue(dataArray[sIdxInAmount])
593- let swapStatus = dataArray[sIdxStatus]
594- let startHeight = parseIntValue(dataArray[sIdxStartHeight])
595- let outFeePart = valueOrElse(getInteger(this, outFeePartKEY(swapType)), DEFAULTSWAPFEE)
596- let totalLocked = totalLockedREAD(swapType)
597- let totalLockedByUser = totalLockedByUserREAD(swapType, account)
598- let unlockHeight = selfUnlockHeight
599- let indexHeight = getHeightPriceByIndex(index)
600- let prevIndexHeight = getHeightPriceByIndex((index - 1))
601- let priceByIndex = getPriceHistory(indexHeight)
602- if (isBlocked)
603- then emergencyShutdownFAIL()
604- else if ((swapStatus != "PENDING"))
605- then throw("swap has been already processed")
606- else if ((unlockHeight > height))
607- then throw((("please wait for: " + toString(unlockHeight)) + " block height to withdraw funds"))
608- else if (if (if ((index > priceIndex))
609- then true
610- else (unlockHeight > indexHeight))
611- then true
612- else if ((prevIndexHeight != 0))
613- then (prevIndexHeight >= unlockHeight)
614- else false)
615- then priceIndexFAIL(index, priceIndex, indexHeight, unlockHeight, prevIndexHeight)
616- else {
617- let withdrawTuple = calcWithdraw(swapType, inAmount, priceByIndex, neutrinoMetrics)
618- let outNetAmount = withdrawTuple._1
619- let outAssetId = withdrawTuple._2
620- let outSurfAmt = withdrawTuple._3
621- let unleaseAmt = withdrawTuple._5
622- let outFeeAmount = withdrawTuple._6
623- let outAmtGross = withdrawTuple._7
624- let withdrawPrice = withdrawTuple._8
625- if ((0 >= outAmtGross))
626- then throw("balance equals zero")
627- else {
628- let BR = asInt(neutrinoMetrics[nMetricIdxBR])
629- 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 surfCondition = if ((outSurfAmt > 0))
631- then {
632- let issueResult = invoke(auctionContract, "issueSurf", [outSurfAmt, account], nil)
633- if ((issueResult == issueResult))
634- then 0
635- else throw("Strict value is not equal to itself.")
636- }
637- else 0
638- if ((surfCondition == surfCondition))
639- then $Tuple3(state, AttachedPayment(outAssetId, outFeeAmount), unleaseAmt)
640- else throw("Strict value is not equal to itself.")
641- }
642- }
682+func calcWithdraw (swapType,inAmount,price,neutrinoMetrics,inAsset) = {
683+ let neutrinoSupply = asInt(neutrinoMetrics[nMetricIdxUsdnSupply])
684+ let basketInfo = asString(neutrinoMetrics[nMetricBasketInfo])
685+ let weightedPrice = asInt(neutrinoMetrics[nMetricWeightedPrice])
686+ let outDataTuple = if ((swapType == "outNeutrino"))
687+ then calcWithdrawT2U(inAmount, inAsset, basketInfo, weightedPrice)
688+ else if ((swapType == "outMulti"))
689+ then calcWithdrawU2Basket(inAmount, basketInfo, neutrinoSupply)
690+ else throw(("Unsupported swap type " + swapType))
691+ let outAmtGross = outDataTuple._1
692+ let outAssetId = outDataTuple._2
693+ let inAmtToSurfPart = outDataTuple._3
694+ let inAssetId = outDataTuple._4
695+ let unleaseAmt = outDataTuple._5
696+ let withdrawPrice = outDataTuple._6
697+ let basketData = outDataTuple._11
698+ let netFeeData = outDataTuple._12
699+ let outNetAmt = if ((swapType == "outNeutrino"))
700+ then netFeeData[0]
701+ else 0
702+ let outFeeAmt = if ((swapType == "outNeutrino"))
703+ then netFeeData[1]
704+ else 0
705+ let outSurfAmt = if ((0 >= inAmtToSurfPart))
706+ then 0
707+ else asInt(asAnyList(invoke(mathContract, "surfFunctionREADONLY", [inAmtToSurfPart, inAssetId], nil))[bFuncIdxSurf])
708+ let withdrawBasket = if ((swapType == "outMulti"))
709+ then applyFeesBasket(basketData)
710+ else ""
711+ $Tuple9(outNetAmt, outAssetId, outSurfAmt, inAmtToSurfPart, unleaseAmt, outFeeAmt, outAmtGross, withdrawPrice, withdrawBasket)
643712 }
644713
645714
667736
668737
669738 @Callable(i)
670-func constructor (neutrinoAssetIdPrm,bondAssetIdPrm,auctionContractPrm,liquidationContractPrm,rpdContractPrm,nodeOracleProviderPubKeyPrm,balanceWavesLockIntervalPrm,balanceNeutrinoLockIntervalPrm,minWavesSwapAmountPrm,minNeutrinoSwapAmountPrm,neutrinoOutFeePartPrm,wavesOutFeePartPrm) = {
739+func constructorV1 (neutrinoAssetIdPrm,bondAssetIdPrm,auctionContractPrm,liquidationContractPrm,rpdContractPrm,nodeOracleProviderPubKeyPrm,balanceWavesLockIntervalPrm,balanceNeutrinoLockIntervalPrm,minWavesSwapAmountPrm,minNeutrinoSwapAmountPrm,neutrinoOutFeePartPrm,wavesOutFeePartPrm) = {
671740 let checkCaller = thisOnly(i)
672741 if ((checkCaller == checkCaller))
673742 then if ((size(i.payments) != 0))
674743 then throw("no payments allowed")
675- 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)]
744+ 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(MinTokenSwapAmountKey("WAVES"), minWavesSwapAmountPrm), IntegerEntry(MinNeutrinoSwapAmountKey, minNeutrinoSwapAmountPrm), IntegerEntry(NeutrinoOutFeePartKey, neutrinoOutFeePartPrm), IntegerEntry(WavesOutFeePartKey, wavesOutFeePartPrm)]
676745 else throw("Strict value is not equal to itself.")
677746 }
678747
691760
692761
693762 @Callable(i)
694-func swapWavesToNeutrino () = if ((size(i.payments) != 1))
695- then throw("swapWavesToNeutrino require only one payment")
763+func constructorV3 (assetsWeightsMins,dParam,kParam,bParam,deltaParam) = {
764+ let checkCaller = thisOnly(i)
765+ if ((checkCaller == checkCaller))
766+ then if ((size(i.payments) != 0))
767+ then throw("no payments allowed")
768+ else {
769+ func prepare (acc,item) = {
770+ let parts = split(item, "_")
771+ let assetId = parts[0]
772+ let weight = parseIntValue(parts[1])
773+ let minVal = parseIntValue(parts[2])
774+ $Tuple2((acc._1 :+ assetId), ((acc._2 :+ IntegerEntry(basketWeightByAssetKey(assetId), weight)) :+ IntegerEntry(MinTokenSwapAmountKey(assetId), minVal)))
775+ }
776+
777+ let r = {
778+ let $l = assetsWeightsMins
779+ let $s = size($l)
780+ let $acc0 = $Tuple2(nil, nil)
781+ func $f0_1 ($a,$i) = if (($i >= $s))
782+ then $a
783+ else prepare($a, $l[$i])
784+
785+ func $f0_2 ($a,$i) = if (($i >= $s))
786+ then $a
787+ else throw("List size exceeds 10")
788+
789+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
790+ }
791+ (((((r._2 :+ IntegerEntry(basketDKey(), dParam)) :+ IntegerEntry(basketKKey(), kParam)) :+ IntegerEntry(basketBKey(), bParam)) :+ IntegerEntry(basketLogbDeltaKey(), log(deltaParam, 6, bParam, 6, 6, HALFUP))) :+ StringEntry(basketAssetsKey(), makeString(r._1, SEP)))
792+ }
793+ else throw("Strict value is not equal to itself.")
794+ }
795+
796+
797+
798+@Callable(i)
799+func swapTokenToNeutrino () = if ((size(i.payments) != 1))
800+ then throw("swapTokenToNeutrino require only one payment")
696801 else {
697802 let pmt = value(i.payments[0])
698- if (isDefined(pmt.assetId))
699- then throw("Only Waves token is allowed for swapping.")
803+ let basketAssets = value(getString(basketAssetsKey()))
804+ let pmtAssetIdStr = toBase58String(valueOrElse(pmt.assetId, WAVESID))
805+ if (!(contains(basketAssets, pmtAssetIdStr)))
806+ then throw(((pmtAssetIdStr + " is not one of basket tokens:") + basketAssets))
700807 else {
701808 let userAddress = toString(i.caller)
702809 let txId58 = toBase58String(i.transactionId)
703- let swapParamsSTRUCT = asSwapParamsSTRUCT(invoke(this, "swapParamsByUserSYSREADONLY", [userAddress, 0], nil))
704- let commonSwapResult = commonSwap("waves", pmt.amount, userAddress, txId58, swapParamsSTRUCT)
705- commonSwapResult
810+ let totalLocked = totalLockedREAD("outNeutrino", pmtAssetIdStr)
811+ let pmtAmount = pmt.amount
812+ let saveTotalLocked = invoke(this, "internalSaveInteger", [totalLockedKEY("outNeutrino", pmtAssetIdStr), (totalLocked + pmtAmount)], nil)
813+ if ((saveTotalLocked == saveTotalLocked))
814+ then commonSwap("outNeutrino", pmtAmount, pmtAssetIdStr, userAddress, txId58)
815+ else throw("Strict value is not equal to itself.")
706816 }
707817 }
708818
709819
710820
711821 @Callable(i)
712-func swapNeutrinoToWaves () = if ((size(i.payments) != 1))
713- then throw("swapNeutrinoToWaves require only one payment")
822+func swapNeutrinoToBasket () = if ((size(i.payments) != 1))
823+ then throw("swapNeutrinoToBasket require only one payment")
714824 else {
715825 let pmt = value(i.payments[0])
716826 if ((pmt.assetId != neutrinoAssetId))
718828 else {
719829 let userAddress = toString(i.caller)
720830 let txId58 = toBase58String(i.transactionId)
721- let swapParamsSTRUCT = asSwapParamsSTRUCT(invoke(this, "swapParamsByUserSYSREADONLY", [userAddress, 0], nil))
722- let commonSwapResult = commonSwap("neutrino", pmt.amount, userAddress, txId58, swapParamsSTRUCT)
723- commonSwapResult
831+ let neutrinoAssetIdStr = toBase58String(neutrinoAssetId)
832+ let totalLocked = totalLockedREAD("outMulti", neutrinoAssetIdStr)
833+ let pmtAmount = pmt.amount
834+ let saveTotalLocked = invoke(this, "internalSaveInteger", [totalLockedKEY("outMulti", neutrinoAssetIdStr), (totalLocked + pmtAmount)], nil)
835+ if ((saveTotalLocked == saveTotalLocked))
836+ then commonSwap("outMulti", pmt.amount, neutrinoAssetIdStr, userAddress, txId58)
837+ else throw("Strict value is not equal to itself.")
724838 }
725839 }
840+
841+
842+
843+@Callable(i)
844+func internalSaveInteger (key,amount) = if ((i.caller != this))
845+ then throw("internalSaveInteger is not public method")
846+ else [IntegerEntry(key, amount)]
726847
727848
728849
734855 else {
735856 let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
736857 let BR = asInt(neutrinoMetrics[nMetricIdxBR])
737- let commonTuple = commonWithdraw(account, index, swapTxId, txId, neutrinoMetrics)
738- let state = commonTuple._1
739- let fee = commonTuple._2
740- let unleaseAmt = commonTuple._3
741- let unleaseInvOrEmpty = invoke(this, "internalUnleaseAndLease", [unleaseAmt], nil)
742- if ((unleaseInvOrEmpty == unleaseInvOrEmpty))
743- then {
744- let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", ["", 0, 0], nil))
745- let gnsbtAmtTotal = asInt(gnsbtData[1])
746- let gnsbtAmtFromSurfTotal = asInt(asAnyList(gnsbtData[3])[3])
747- let surfFeeAmt1 = if ((gnsbtAmtTotal != 0))
748- then fraction(fee.amount, gnsbtAmtFromSurfTotal, gnsbtAmtTotal)
749- else 0
750- let surfFeeAmt2 = if ((gnsbtAmtTotal != 0))
751- then fraction(fee.amount, (PAULI - BR), PAULI)
752- else 0
753- let surfFeeAmt = max([surfFeeAmt1, surfFeeAmt2])
754- let nsbtFeeAmt = (fee.amount - surfFeeAmt)
755- let surfDeposit = if ((surfFeeAmt > 0))
756- then {
757- let surfInv = invoke(surfStakingContract, "deposit", nil, [AttachedPayment(fee.assetId, surfFeeAmt)])
758- if ((surfInv == surfInv))
759- then nil
760- else throw("Strict value is not equal to itself.")
761- }
762- else nil
763- if ((surfDeposit == surfDeposit))
764- then {
765- let nsbtDeposit = if ((nsbtFeeAmt > 0))
766- then {
767- let nsbtInv = invoke(nsbtStakingContract, "deposit", nil, [AttachedPayment(fee.assetId, nsbtFeeAmt)])
768- if ((nsbtInv == nsbtInv))
769- then nil
770- else throw("Strict value is not equal to itself.")
771- }
772- else nil
773- if ((nsbtDeposit == nsbtDeposit))
774- then state
775- else throw("Strict value is not equal to itself.")
776- }
777- else throw("Strict value is not equal to itself.")
778- }
779- else throw("Strict value is not equal to itself.")
858+ let userAddress = addressFromStringValue(account)
859+ let dataArray = swapDataFailOrREAD(account, swapTxId)
860+ let selfUnlockHeight = parseIntValue(dataArray[sIdxSelfUnlockHeight])
861+ let swapType = dataArray[sIdxSwapType]
862+ let inAmount = parseIntValue(dataArray[sIdxInAmount])
863+ let swapStatus = dataArray[sIdxStatus]
864+ let startHeight = parseIntValue(dataArray[sIdxStartHeight])
865+ let inAsset = dataArray[sIdxInAsset]
866+ let totalLocked = totalLockedREAD(swapType, inAsset)
867+ let totalLockedByUser = totalLockedByUserREAD(swapType, account, inAsset)
868+ let unlockHeight = selfUnlockHeight
869+ let indexHeight = getHeightPriceByIndex(index)
870+ let prevIndexHeight = getHeightPriceByIndex((index - 1))
871+ let priceByIndex = getPriceHistory(indexHeight)
872+ if (isBlocked)
873+ then emergencyShutdownFAIL()
874+ else if ((swapStatus != "PENDING"))
875+ then throw("swap has been already processed")
876+ else if ((unlockHeight > height))
877+ then throw((("please wait for: " + toString(unlockHeight)) + " block height to withdraw funds"))
878+ else if (if (if ((index > priceIndex))
879+ then true
880+ else (unlockHeight > indexHeight))
881+ then true
882+ else if ((prevIndexHeight != 0))
883+ then (prevIndexHeight >= unlockHeight)
884+ else false)
885+ then priceIndexFAIL(index, priceIndex, indexHeight, unlockHeight, prevIndexHeight)
886+ else {
887+ let withdrawTuple = calcWithdraw(swapType, inAmount, priceByIndex, neutrinoMetrics, inAsset)
888+ let outNetAmount = withdrawTuple._1
889+ let outAssetId = withdrawTuple._2
890+ let outSurfAmt = withdrawTuple._3
891+ let unleaseAmt = withdrawTuple._5
892+ let outFeeAmount = withdrawTuple._6
893+ let outAmtGross = withdrawTuple._7
894+ let withdrawPrice = withdrawTuple._8
895+ let withdrawBasket = withdrawTuple._9
896+ if (if ((swapType == "outNeutrino"))
897+ then (0 >= outAmtGross)
898+ else false)
899+ then throw("balance equals zero")
900+ else {
901+ let surfCondition = if ((outSurfAmt > 0))
902+ then {
903+ let issueResult = invoke(auctionContract, "issueSurf", [outSurfAmt, account], nil)
904+ if ((issueResult == issueResult))
905+ then 0
906+ else throw("Strict value is not equal to itself.")
907+ }
908+ else 0
909+ if ((surfCondition == surfCondition))
910+ then {
911+ let unleaseInvOrEmpty = invoke(this, "internalUnleaseAndLease", [unleaseAmt], nil)
912+ if ((unleaseInvOrEmpty == unleaseInvOrEmpty))
913+ then {
914+ let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", ["", 0, 0], nil))
915+ let gnsbtAmtTotal = asInt(gnsbtData[1])
916+ let gnsbtAmtFromSurfTotal = asInt(asAnyList(gnsbtData[3])[3])
917+ let commonActions = [IntegerEntry(totalLockedByUserKEY(swapType, account, inAsset), (totalLockedByUser - inAmount)), IntegerEntry(totalLockedKEY(swapType, inAsset), (totalLocked - inAmount)), StringEntry(swapKEY(account, swapTxId), finishSwapDATA(dataArray, withdrawPrice, outNetAmount, outFeeAmount, unlockHeight, index, txId, outSurfAmt, BR, withdrawBasket, inAsset))]
918+ func deposits (surfFees,nsbtFees,surfPayments,nsbtPayments) = {
919+ let surfDeposit = if ((surfFees > 0))
920+ then asInt(invoke(surfStakingContract, "deposit", nil, surfPayments))
921+ else 0
922+ let nsbtDeposit = if ((nsbtFees > 0))
923+ then asInt(invoke(nsbtStakingContract, "deposit", nil, nsbtPayments))
924+ else 0
925+ (surfDeposit + nsbtDeposit)
926+ }
927+
928+ func divideFees (feeAmount) = {
929+ let surfAmt1 = if ((gnsbtAmtTotal != 0))
930+ then fraction(feeAmount, gnsbtAmtFromSurfTotal, gnsbtAmtTotal)
931+ else 0
932+ let surfAmt2 = if ((gnsbtAmtTotal != 0))
933+ then fraction(feeAmount, (MULT6 - BR), MULT6)
934+ else 0
935+ let surfAmt = max([surfAmt1, surfAmt2])
936+ let nsbtAmt = (feeAmount - surfAmt)
937+[surfAmt, nsbtAmt]
938+ }
939+
940+ let transfers = if ((swapType == "outMulti"))
941+ then {
942+ let basket = split_4C(withdrawBasket, "_")
943+ func looper (acc,item) = {
944+ let it = split(item, LISTSEP)
945+ let tempAssetId = fromBase58String(it[0])
946+ let assetId = if ((tempAssetId == WAVESID))
947+ then unit
948+ else tempAssetId
949+ let netAmount = parseIntValue(it[2])
950+ let feeAmount = parseIntValue(it[3])
951+ let fees = divideFees(feeAmount)
952+ $Tuple5((acc._1 :+ ScriptTransfer(userAddress, netAmount, assetId)), (acc._2 :+ AttachedPayment(assetId, fees[0])), (acc._3 :+ AttachedPayment(assetId, fees[1])), (acc._4 + fees[0]), (acc._5 + fees[1]))
953+ }
954+
955+ let r = {
956+ let $l = basket
957+ let $s = size($l)
958+ let $acc0 = $Tuple5(nil, nil, nil, 0, 0)
959+ func $f0_1 ($a,$i) = if (($i >= $s))
960+ then $a
961+ else looper($a, $l[$i])
962+
963+ func $f0_2 ($a,$i) = if (($i >= $s))
964+ then $a
965+ else throw("List size exceeds 10")
966+
967+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
968+ }
969+ let depoResult = deposits(r._4, r._5, r._2, r._3)
970+ $Tuple2(r._1, depoResult)
971+ }
972+ else {
973+ let fees = divideFees(outFeeAmount)
974+ let depoResult = deposits(fees[0], fees[1], [AttachedPayment(outAssetId, fees[0])], [AttachedPayment(outAssetId, fees[1])])
975+ $Tuple2([ScriptTransfer(userAddress, outNetAmount, outAssetId)], depoResult)
976+ }
977+ $Tuple2((commonActions ++ transfers._1), transfers._2)
978+ }
979+ else throw("Strict value is not equal to itself.")
980+ }
981+ else throw("Strict value is not equal to itself.")
982+ }
983+ }
780984 }
781985 }
782986
8221026 if ((i.callerPublicKey != mngPub))
8231027 then throw("approveLeasings not authorized")
8241028 else {
825- let $t03578935851 = readNodeInfo(0)
826- let nAddr0 = $t03578935851._1
827- let lAmtKEY0 = $t03578935851._2
828- let lAmt0 = $t03578935851._3
829- let lIdKEY0 = $t03578935851._4
830- let lId0 = $t03578935851._5
1029+ let $t04446644528 = readNodeInfo(0)
1030+ let nAddr0 = $t04446644528._1
1031+ let lAmtKEY0 = $t04446644528._2
1032+ let lAmt0 = $t04446644528._3
1033+ let lIdKEY0 = $t04446644528._4
1034+ let lId0 = $t04446644528._5
8311035 let newL0 = Lease(nAddr0, (lAmt0 - (lAmt * expCount)))
8321036 let validation = invoke(nodeRegAddr, "validateAndApproveLeasings", [nListS], nil)
8331037 if ((validation == validation))
8721076 then throw("rebalanceLeasings not authorized")
8731077 else {
8741078 let unleaseAmt = ((amount / size(nList)) + 1)
875- let $t03709137153 = readNodeInfo(0)
876- let nAddr0 = $t03709137153._1
877- let lAmtKEY0 = $t03709137153._2
878- let lAmt0 = $t03709137153._3
879- let lIdKEY0 = $t03709137153._4
880- let lId0 = $t03709137153._5
1079+ let $t04576845830 = readNodeInfo(0)
1080+ let nAddr0 = $t04576845830._1
1081+ let lAmtKEY0 = $t04576845830._2
1082+ let lAmt0 = $t04576845830._3
1083+ let lIdKEY0 = $t04576845830._4
1084+ let lId0 = $t04576845830._5
8811085 let newL0 = Lease(nAddr0, (lAmt0 + (unleaseAmt * size(nList))))
8821086 func forEachNodeDoUnlease (a,i) = {
8831087 let node = nList[i]
9151119 let gnsbtAmt = (asInt(gnsbtData[0]) + gnsbtDiff)
9161120 let gnsbtAmtTotal = (asInt(gnsbtData[1]) + gnsbtDiff)
9171121 let swapLimitData = asAnyList(invoke(mathContract, "calcSwapLimitREADONLY", [gnsbtAmt], nil))
918- let wavesSwapLimitInUsdnMax = asInt(swapLimitData[0])
919- let wavesSwapLimitMax = asInt(swapLimitData[1])
1122+ let tokenSwapLimitInUsdMax = asInt(swapLimitData[0])
9201123 let usdnSwapLimitMax = asInt(swapLimitData[2])
9211124 let lastSwapHeight = valueOrElse(getInteger(this, keyUserLastSwapHeight(userAddressStr)), 0)
9221125 let swapLimitTimelifeBlocks = swapsTimeframeREAD()
9281131 let blcks2LmtReset = if (isSwapTimelifeNew)
9291132 then 0
9301133 else (swapLimitTimelifeBlocks - passedBlocksAfterLastSwap)
931- $Tuple2(nil, $Tuple7(wavesSwapLimitInUsdnMax, swapLimitSpentInUsdn, blcks2LmtReset, gnsbtAmt, gnsbtAmtTotal, wavesSwapLimitMax, usdnSwapLimitMax))
1134+ $Tuple2(nil, $Tuple7(tokenSwapLimitInUsdMax, swapLimitSpentInUsdn, blcks2LmtReset, gnsbtAmt, gnsbtAmtTotal, 0, usdnSwapLimitMax))
9321135 }
9331136
9341137
9351138
9361139 @Callable(i)
937-func calcWithdrawResultSYSREADONLY (swapType,inAmount,price) = {
1140+func calcWithdrawResultSYSREADONLY (swapType,inAmount,price,inAsset) = {
9381141 let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
939- $Tuple2(nil, calcWithdraw(swapType, inAmount, price, neutrinoMetrics))
1142+ $Tuple2(nil, calcWithdraw(swapType, inAmount, price, neutrinoMetrics, inAsset))
9401143 }
9411144
9421145
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let revisionNum = "09edb6fbe9e8b1c20448e26435cb7f292ddab948"
4+let revisionNum = "46ddf9ad4f4a67a79d872f7c5671aa012953a34b"
55
66 func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], ""))
77
88
99 func lcalc (l) = calculateLeaseId(l)
1010
1111
1212 func getNumberByKey (key) = valueOrElse(getInteger(this, key), 0)
1313
1414
1515 func getStringByKey (key) = valueOrElse(getString(this, key), "")
1616
1717
1818 func getBoolByKey (key) = valueOrElse(getBoolean(this, key), false)
1919
2020
2121 func getNumberByAddressAndKey (address,key) = valueOrElse(getInteger(address, key), 0)
2222
2323
2424 func getStringByAddressAndKey (address,key) = valueOrElse(getString(addressFromStringValue(address), key), "")
2525
2626
2727 func getBoolByAddressAndKey (address,key) = valueOrElse(getBoolean(address, key), false)
2828
2929
3030 func asAnyList (v) = match v {
3131 case l: List[Any] =>
3232 l
3333 case _ =>
3434 throw("fail to cast into List[Any]")
3535 }
3636
3737
3838 func asString (v) = match v {
3939 case s: String =>
4040 s
4141 case _ =>
4242 throw("fail to cast into String")
4343 }
4444
4545
4646 func asInt (v) = match v {
4747 case i: Int =>
4848 i
4949 case _ =>
5050 throw("fail to cast into Int")
5151 }
5252
5353
5454 func asBytes (val) = match val {
5555 case valByte: ByteVector =>
5656 valByte
5757 case _ =>
5858 throw("fail to cast into ByteVector")
5959 }
6060
6161
6262 func asPayment (v) = match v {
6363 case p: AttachedPayment =>
6464 p
6565 case _ =>
6666 throw("fail to cast into AttachedPayment")
6767 }
6868
6969
7070 func asSwapParamsSTRUCT (v) = match v {
7171 case struct: (Int, Int, Int, Int, Int, Int, Int) =>
7272 struct
7373 case _ =>
7474 throw("fail to cast into Tuple5 ints")
7575 }
7676
7777
7878 let SEP = "__"
7979
8080 let LISTSEP = ":"
8181
82-let WAVELET = 100000000
82+let MULT8 = 100000000
8383
84-let PAULI = 1000000
85-
86-let PRICELET = 1000000
84+let MULT6 = 1000000
8785
8886 let DEFAULTSWAPFEE = 20000
8987
9088 let BRPROTECTED = 100000
9189
92-let IdxNetAmount = 0
90+let WAVESID = base58'WAVES'
9391
94-let IdxFeeAmount = 1
92+let nMetricIdxPrice = 0
9593
96-let IdxGrossAmount = 2
94+let nMetricIdxUsdnLockedBalance = 1
95+
96+let nMetricIdxWavesLockedBalance = 2
97+
98+let nMetricIdxReserve = 3
99+
100+let nMetricIdxReserveInUsdn = 4
101+
102+let nMetricIdxUsdnSupply = 5
103+
104+let nMetricIdxSurplus = 6
105+
106+let nMetricIdxSurplusPercent = 7
107+
108+let nMetricIdxBR = 8
109+
110+let nMetricIdxNsbtSupply = 9
111+
112+let nMetricIdxMaxNsbtSupply = 10
113+
114+let nMetricIdxSurfSupply = 11
115+
116+let nMetricUsdnUsdtPeg = 12
117+
118+let nMetricCurrentPriceAdj = 13
119+
120+let nMetricBasketInfo = 14
121+
122+let nMetricWeightedPrice = 15
123+
124+let nMetricTotalReservesUsd = 16
97125
98126 let IdxControlCfgNeutrinoDapp = 1
99127
100128 let IdxControlCfgAuctionDapp = 2
101129
102130 let IdxControlCfgRpdDapp = 3
103131
104132 let IdxControlCfgMathDapp = 4
105133
106134 let IdxControlCfgLiquidationDapp = 5
107135
108136 let IdxControlCfgRestDapp = 6
109137
110138 let IdxControlCfgNodeRegistryDapp = 7
111139
112140 let IdxControlCfgNsbtStakingDapp = 8
113141
114142 let IdxControlCfgMediatorDapp = 9
115143
116144 let IdxControlCfgSurfStakingDapp = 10
117145
118146 let IdxControlCfgGnsbtControllerDapp = 11
119147
120148 let IdxControlCfgRestV2Dapp = 12
121149
122150 let IdxControlCfgGovernanceDapp = 13
123151
124152 func keyControlAddress () = "%s%s__config__controlAddress"
125153
126154
127155 func keyControlCfg () = "%s__controlConfig"
128156
129157
130158 func readControlCfgOrFail (control) = split_4C(getStringOrFail(control, keyControlCfg()), SEP)
131159
132160
133161 func getContractAddressOrFail (controlCfg,idx) = valueOrErrorMessage(addressFromString(controlCfg[idx]), ("Control cfg doesn't contain address at index " + toString(idx)))
134162
135163
136164 let controlContract = addressFromStringValue(valueOrElse(getString(this, keyControlAddress()), "3P5Bfd58PPfNvBM2Hy8QfbcDqMeNtzg7KfP"))
137165
138166 let controlCfg = readControlCfgOrFail(controlContract)
139167
140168 let mathContract = getContractAddressOrFail(controlCfg, IdxControlCfgMathDapp)
141169
142170 let nsbtStakingContract = getContractAddressOrFail(controlCfg, IdxControlCfgNsbtStakingDapp)
143171
144172 let surfStakingContract = getContractAddressOrFail(controlCfg, IdxControlCfgSurfStakingDapp)
145173
146174 let gnsbtControllerContract = getContractAddressOrFail(controlCfg, IdxControlCfgGnsbtControllerDapp)
147175
148176 let auctionContract = getContractAddressOrFail(controlCfg, IdxControlCfgAuctionDapp)
149177
150178 let nodeRegistryContract = getContractAddressOrFail(controlCfg, IdxControlCfgNodeRegistryDapp)
151179
152180 let govContract = getContractAddressOrFail(controlCfg, IdxControlCfgGovernanceDapp)
153181
154182 let NeutrinoAssetIdKey = "neutrino_asset_id"
155183
156184 let BondAssetIdKey = "bond_asset_id"
157185
158186 let AuctionContractKey = "auction_contract"
159187
160188 let NsbtStakingContractKey = "nsbtStakingContract"
161189
162190 let LiquidationContractKey = "liquidation_contract"
163191
164192 let RPDContractKey = "rpd_contract"
165193
166194 let ContolContractKey = "control_contract"
167195
168196 let MathContractKey = "math_contract"
169197
170198 let BalanceWavesLockIntervalKey = "balance_waves_lock_interval"
171199
172200 let BalanceNeutrinoLockIntervalKey = "balance_neutrino_lock_interval"
173201
174-let MinWavesSwapAmountKey = "min_waves_swap_amount"
202+func MinTokenSwapAmountKey (assetId) = ("min_outNeutrino_swap_amount_" + assetId)
175203
176-let MinNeutrinoSwapAmountKey = "min_neutrino_swap_amount"
204+
205+let MinNeutrinoSwapAmountKey = "min_outMulti_swap_amount"
206+
207+let LegacyMinNeutrinoSwapAmountKey = "min_neutrino_swap_amount"
177208
178209 let NodeOracleProviderPubKeyKey = "node_oracle_provider"
179210
180211 let NeutrinoOutFeePartKey = "neutrinoOut_swap_feePart"
181212
182213 let WavesOutFeePartKey = "wavesOut_swap_feePart"
183214
184215 func keyNodeRegistry (address) = ("%s__" + address)
185216
186217
187218 let PriceKey = "price"
188219
189220 let PriceIndexKey = "price_index"
190221
191222 let IsBlockedKey = "is_blocked"
192223
193224 func getPriceHistoryKey (block) = ((PriceKey + "_") + toString(block))
194225
195226
196227 func getHeightPriceByIndexKey (index) = ((PriceIndexKey + "_") + toString(index))
197228
198229
199230 func getStakingNodeByIndex (idx) = getStringByKey(makeString(["%s%d%s", "lease", toString(idx), "nodeAddress"], SEP))
200231
201232
202233 func getStakingNodeAddressByIndex (idx) = addressFromStringValue(getStakingNodeByIndex(idx))
203234
204235
205-func getReservedAmountForSponsorship () = valueOrElse(getInteger(this, makeString(["%s%s", "lease", "sponsorshipWavesReserve"], SEP)), (1000 * WAVELET))
236+func getReservedAmountForSponsorship () = valueOrElse(getInteger(this, makeString(["%s%s", "lease", "sponsorshipWavesReserve"], SEP)), (1000 * MULT8))
206237
207238
208239 func getBalanceUnlockBlockKey (owner) = ("balance_unlock_block_" + owner)
209240
210241
211242 func getLeaseIdKey (nodeIndex) = makeString(["%s%d%s", "lease", toString(nodeIndex), "id"], SEP)
212243
213244
214245 func getLeaseIdByAddressKey (nodeAddress) = makeString(["%s%s%s", "leaseByAddress", nodeAddress, "id"], SEP)
215246
216247
217248 func getLeaseAmountKey (nodeIndex) = makeString(["%s%d%s", "lease", toString(nodeIndex), "amount"], SEP)
218249
219250
220251 func getLeaseAmountByAddressKey (nodeAddress) = makeString(["%s%s%s", "leaseByAddress", nodeAddress, "amount"], SEP)
221252
222253
223254 func getLeaseGroupNodeListKey (groupNum) = makeString(["%s%d%s", "leaseGroup", toString(groupNum), "nodeList"], SEP)
224255
225256
226257 func minSwapAmountKEY (swapType) = (("min_" + swapType) + "_swap_amount")
227258
228259
229-func totalLockedKEY (swapType) = ("balance_lock_" + swapType)
260+func totalLockedKEY (swapType,assetId) = makeString(["%s%s%s", "balanceLock", swapType, assetId], SEP)
230261
231262
232-func totalLockedByUserKEY (swapType,owner) = makeString(["balance_lock", swapType, owner], "_")
263+func totalLockedByUserKEY (swapType,owner,assetId) = makeString(["%s%s%s%s", "balanceLock", swapType, owner, assetId], "_")
233264
234265
235-func balanceLockIntervalKEY (swapType) = (("balance_" + swapType) + "_lock_interval")
266+func balanceLockIntervalKEY (swapType) = if ((swapType == "outMulti"))
267+ then BalanceNeutrinoLockIntervalKey
268+ else BalanceWavesLockIntervalKey
236269
237270
238271 func nodeBalanceLockIntervalKEY () = "balance_node_lock_interval"
239-
240-
241-func outFeePartKEY (swapType) = (swapType + "Out_swap_feePart")
242272
243273
244274 func swapsTimeframeKEY () = "swaps_timeframe"
245275
246276
247277 func brProtectedKEY () = "min_BR_protection_level"
248278
249279
250-func minSwapAmountREAD (swapType) = valueOrElse(getInteger(this, minSwapAmountKEY(swapType)), 0)
280+func basketAssetsKey () = "%s%s__common__basketAssets"
281+
282+
283+func basketDKey () = "%s%s__common__basketD"
284+
285+
286+func basketKKey () = "%s%s__common__basketK"
287+
288+
289+func basketBKey () = "%s%s__common__basketB"
290+
291+
292+func basketLogbDeltaKey () = "%s%s__common__basketLogbDelta"
293+
294+
295+func basketWeightByAssetKey (assetId) = ("%s%s%s__common__weightByAsset__" + assetId)
296+
297+
298+func keyPriceByAsset (assetId) = ("%s%s%s__common__priceByAsset__" + assetId)
299+
300+
301+func minSwapAmountREAD (swapType,assetId) = if ((swapType == "outMulti"))
302+ then valueOrElse(getInteger(MinNeutrinoSwapAmountKey), getNumberByKey(LegacyMinNeutrinoSwapAmountKey))
303+ else getNumberByKey(MinTokenSwapAmountKey(assetId))
251304
252305
253306 func swapsTimeframeREAD () = valueOrElse(getInteger(this, swapsTimeframeKEY()), 1440)
254307
255308
256-func totalLockedREAD (swapType) = valueOrElse(getInteger(this, totalLockedKEY(swapType)), 0)
309+func totalLockedREAD (swapType,assetId) = valueOrElse(getInteger(this, totalLockedKEY(swapType, assetId)), 0)
257310
258311
259-func totalLockedByUserREAD (swapType,owner) = valueOrElse(getInteger(this, totalLockedByUserKEY(swapType, owner)), 0)
312+func totalLockedByUserREAD (swapType,owner,assetId) = valueOrElse(getInteger(this, totalLockedByUserKEY(swapType, owner, assetId)), 0)
260313
261314
262315 func balanceLockIntervalREAD (swapType) = valueOrElse(getInteger(this, balanceLockIntervalKEY(swapType)), 1440)
263316
264317
265318 func nodeBalanceLockIntervalREAD () = valueOrElse(getInteger(this, nodeBalanceLockIntervalKEY()), 1)
266319
267320
268321 func keySwapUserSpentInPeriod (userAddress) = makeString(["%s%s", "swapUserSpentInPeriod", userAddress], SEP)
269322
270323
271324 func keyUserLastSwapHeight (userAddress) = makeString(["%s%s", "userLastSwapHeight", userAddress], SEP)
272325
273326
274-func convertNeutrinoToWaves (amount,price) = fraction(fraction(amount, PRICELET, price), WAVELET, PAULI)
327+func convertNeutrinoToWaves (amount,price) = fraction(amount, MULT8, price)
275328
276329
277-func convertWavesToNeutrino (amount,price) = fraction(fraction(amount, price, PRICELET), PAULI, WAVELET)
330+func convertTokenToUsd (amount,price) = fraction(amount, price, MULT8)
278331
279332
280-func convertWavesToBond (amount,price) = convertWavesToNeutrino(amount, price)
333+func convertWavesToNeutrino (amount,price) = fraction(amount, price, MULT8)
334+
335+
336+func convertWavesToBond (amount,price) = convertTokenToUsd(amount, price)
281337
282338
283339 func convertJsonArrayToList (jsonArray) = split(jsonArray, ",")
340+
341+
342+func convertBasketItemToNeutrino (inAmount,inAsset,basketInfoStr,neutrinoPrice) = {
343+ let basketInfo = split_4C(basketInfoStr, "_")
344+ func findItem (acc,item) = {
345+ let bItem = split(item, LISTSEP)
346+ if ((bItem[0] == inAsset))
347+ then bItem
348+ else acc
349+ }
350+
351+ let it = {
352+ let $l = basketInfo
353+ let $s = size($l)
354+ let $acc0 = nil
355+ func $f0_1 ($a,$i) = if (($i >= $s))
356+ then $a
357+ else findItem($a, $l[$i])
358+
359+ func $f0_2 ($a,$i) = if (($i >= $s))
360+ then $a
361+ else throw("List size exceeds 10")
362+
363+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
364+ }
365+ let dlog6 = value(getInteger(basketLogbDeltaKey()))
366+ let d6 = value(getInteger(basketDKey()))
367+ let b6 = value(getInteger(basketBKey()))
368+ let w6 = value(getInteger(basketWeightByAssetKey(inAsset)))
369+ let p6 = ((dlog6 - w6) + parseIntValue(it[1]))
370+ let pp6 = pow(b6, 6, p6, 6, 6, HALFUP)
371+ let outAmountGross = fraction(inAmount, parseIntValue(it[2]), if ((neutrinoPrice == 0))
372+ then MULT8
373+ else (neutrinoPrice * 100))
374+ let multiplier = ((MULT6 + d6) - pp6)
375+ let netAmount = fraction(outAmountGross, multiplier, MULT6)
376+ let feeAmount = if ((netAmount >= outAmountGross))
377+ then 0
378+ else (outAmountGross - netAmount)
379+[outAmountGross, netAmount, feeAmount]
380+ }
381+
382+
383+func convertNeutrinoToBasket (amount,basketInfoStr,neutrinoSupply) = {
384+ let basketInfo = split_4C(basketInfoStr, "_")
385+ func conv (acc,item) = {
386+ let parts = split(item, LISTSEP)
387+ let assetId = parts[0]
388+ let share = parseIntValue(parts[1])
389+ let price = parseIntValue(parts[2])
390+ let reserv = parseIntValue(parts[3])
391+ if ((neutrinoSupply == 0))
392+ then throw("Attempt to burn neutrino at zero supply")
393+ else {
394+ let outAmount = fraction(amount, reserv, neutrinoSupply)
395+ let wavesTuple = if ((assetId == "WAVES"))
396+ then $Tuple2(outAmount, price)
397+ else $Tuple2(acc._2, acc._3)
398+ $Tuple3((acc._1 :+ $Tuple4(assetId, outAmount, price, share)), wavesTuple._1, wavesTuple._2)
399+ }
400+ }
401+
402+ let $l = basketInfo
403+ let $s = size($l)
404+ let $acc0 = $Tuple3(nil, 0, 0)
405+ func $f0_1 ($a,$i) = if (($i >= $s))
406+ then $a
407+ else conv($a, $l[$i])
408+
409+ func $f0_2 ($a,$i) = if (($i >= $s))
410+ then $a
411+ else throw("List size exceeds 10")
412+
413+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
414+ }
284415
285416
286417 func minSwapAmountFAIL (swapType,minSwapAmount) = throw(((("The specified amount in " + swapType) + " swap is less than the required minimum of ") + toString(minSwapAmount)))
287418
288419
289420 func emergencyShutdownFAIL () = throw("contract is blocked by EMERGENCY SHUTDOWN actions untill reactivation by emergency oracles")
290421
291422
292423 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)))
293424
294425
295426 let neutrinoAssetId = fromBase58String(getStringByKey(NeutrinoAssetIdKey))
296427
297428 let priceIndex = getNumberByAddressAndKey(controlContract, PriceIndexKey)
298429
299430 let isBlocked = getBoolByAddressAndKey(controlContract, IsBlockedKey)
300431
301432 let nodeOracleProviderPubKey = fromBase58String(getStringByKey(NodeOracleProviderPubKeyKey))
302433
303434 let bondAssetId = fromBase58String("6nSpVyNH7yM69eg446wrQR94ipbbcmZMU1ENPwanC97g")
304435
305436 let deprecatedBondAssetId = fromBase58String("975akZBfnMj513U7MZaHKzQrmsEx5aE3wdWKTrHBhbjF")
306437
307438 let neutrinoContract = this
308439
309440 let currentPrice = getNumberByAddressAndKey(controlContract, PriceKey)
310441
311442 func checkIsValidMinSponsoredFee (tx) = {
312443 let MINTRANSFERFEE = 100000
313444 let SponsoredFeeUpperBound = 1000
314- let realNeutrinoFee = convertWavesToNeutrino(MINTRANSFERFEE, currentPrice)
445+ let realNeutrinoFee = convertTokenToUsd(MINTRANSFERFEE, currentPrice)
315446 let minNeutrinoFee = (realNeutrinoFee * 2)
316447 let maxNeutrinoFee = fraction(realNeutrinoFee, SponsoredFeeUpperBound, 100)
317448 let inputFee = value(tx.minSponsoredAssetFee)
318449 if (if ((inputFee >= minNeutrinoFee))
319450 then (maxNeutrinoFee >= inputFee)
320451 else false)
321452 then (tx.assetId == neutrinoAssetId)
322453 else false
323454 }
324455
325456
326457 func getPriceHistory (block) = getNumberByAddressAndKey(controlContract, getPriceHistoryKey(block))
327458
328459
329460 func getHeightPriceByIndex (index) = getNumberByAddressAndKey(controlContract, getHeightPriceByIndexKey(index))
330461
331462
332463 func keyLockParamUserAmount (userAddress) = makeString(["%s%s%s", "paramByUser", userAddress, "amount"], SEP)
333464
334465
335466 let sIdxSwapType = 1
336467
337468 let sIdxStatus = 2
338469
339470 let sIdxInAmount = 3
340471
341472 let sIdxStartHeight = 7
342473
343474 let sIdxStartTimestamp = 8
344475
345476 let sIdxSelfUnlockHeight = 11
346477
347478 let sIdxMinRand = 15
348479
349480 let sIdxMaxRand = 16
350481
482+let sIdxInAsset = 20
483+
351484 func swapKEY (userAddress,txId) = makeString(["%s%s", userAddress, txId], SEP)
352485
353486
354-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)
487+func strSwapDATA (swapType,status,inAmount,price,outNetAmount,outFeeAmount,startHeight,startTimestamp,endHeight,endTimestamp,selfUnlockHeight,randUnlockHeight,index,withdrawTxId,randMin,randMax,outSurfAmt,br,basketData,inAsset) = makeString_2C(["%s%s%d%d%d%d%d%d%d%d%d%d%d%s%d%d%d%d%s%s", swapType, status, inAmount, price, outNetAmount, outFeeAmount, startHeight, startTimestamp, endHeight, endTimestamp, selfUnlockHeight, randUnlockHeight, index, withdrawTxId, randMin, randMax, outSurfAmt, br, basketData, inAsset], SEP)
355488
356489
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")
490+func pendingSwapDATA (swapType,inAssetAmount,selfUnlockHeight,inAsset) = strSwapDATA(swapType, "PENDING", toString(inAssetAmount), "0", "0", "0", toString(height), toString(lastBlock.timestamp), "0", "0", toString(selfUnlockHeight), "0", "0", "NULL", "0", "0", "0", "0", "", inAsset)
358491
359492
360-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))
493+func finishSwapDATA (dataArray,price,outNetAmount,outFeeAmount,randUnlockHeight,index,withdrawTxId,outSurfAmt,br,basketData,inAsset) = 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, inAsset)
361494
362495
363496 func swapDataFailOrREAD (userAddress,swapTxId) = {
364497 let swapKey = swapKEY(userAddress, swapTxId)
365- split(valueOrErrorMessage(getString(this, swapKey), ("no swap data for " + swapKey)), SEP)
498+ split_4C(valueOrErrorMessage(getString(swapKey), ("no swap data for " + swapKey)), SEP)
366499 }
367500
368501
369502 func applyFees (amountOutGross,inAmtToSURF,feePart) = {
370- let feeAmount = fraction(amountOutGross, feePart, PAULI)
503+ let feeAmount = fraction(amountOutGross, feePart, MULT6)
371504 [(amountOutGross - feeAmount), feeAmount]
505+ }
506+
507+
508+func applyFeesBasket (basketOut) = {
509+ let k6 = value(getInteger(basketKKey()))
510+ let d6 = value(getInteger(basketDKey()))
511+ let feePart = fraction(k6, d6, MULT6)
512+ func feeApplier (acc,item) = {
513+ let feeAmount = fraction(item._2, feePart, MULT6)
514+ (acc :+ makeString([item._1, toString(item._3), toString((item._2 - feeAmount)), toString(feeAmount), toString(item._4)], LISTSEP))
515+ }
516+
517+ let a = {
518+ let $l = basketOut
519+ let $s = size($l)
520+ let $acc0 = nil
521+ func $f0_1 ($a,$i) = if (($i >= $s))
522+ then $a
523+ else feeApplier($a, $l[$i])
524+
525+ func $f0_2 ($a,$i) = if (($i >= $s))
526+ then $a
527+ else throw("List size exceeds 10")
528+
529+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
530+ }
531+ makeString_2C(a, "_")
372532 }
373533
374534
375535 func abs (x) = if ((0 > x))
376536 then -(x)
377537 else x
378538
379539
380540 func selectNode (unleaseAmount) = {
381541 let amountToLease = ((wavesBalance(neutrinoContract).available - unleaseAmount) - getReservedAmountForSponsorship())
382542 let oldLeased0 = getNumberByKey(getLeaseAmountKey(0))
383543 let oldLeased1 = getNumberByKey(getLeaseAmountKey(1))
384544 let newLeased0 = (amountToLease + oldLeased0)
385545 let newLeased1 = (amountToLease + oldLeased1)
386546 if (if ((newLeased0 > 0))
387547 then true
388548 else (newLeased1 > 0))
389549 then {
390550 let delta0 = abs((newLeased0 - oldLeased1))
391551 let delta1 = abs((newLeased1 - oldLeased0))
392552 if ((delta1 >= delta0))
393553 then $Tuple2(0, newLeased0)
394554 else $Tuple2(1, newLeased1)
395555 }
396556 else $Tuple2(-1, 0)
397557 }
398558
399559
400560 func thisOnly (i) = if ((i.caller != this))
401561 then throw("Permission denied: this contract only allowed")
402562 else true
403563
404564
405565 func prepareUnleaseAndLease (unleaseAmount) = {
406566 let nodeTuple = selectNode(unleaseAmount)
407567 let nodeIndex = nodeTuple._1
408568 let newLeaseAmount = nodeTuple._2
409569 if ((newLeaseAmount > 0))
410570 then {
411571 let leaseIdKey = getLeaseIdKey(nodeIndex)
412572 let oldLease = getBinary(this, leaseIdKey)
413573 let unleaseOrEmpty = if (isDefined(oldLease))
414574 then [LeaseCancel(value(oldLease))]
415575 else nil
416576 let leaseAmountKey = getLeaseAmountKey(nodeIndex)
417577 let lease = Lease(getStakingNodeAddressByIndex(nodeIndex), newLeaseAmount)
418578 (unleaseOrEmpty ++ [lease, BinaryEntry(leaseIdKey, lcalc(lease)), IntegerEntry(getLeaseAmountKey(nodeIndex), newLeaseAmount)])
419579 }
420580 else nil
421581 }
422582
423583
424584 func readNodeInfo (nodeIdx) = {
425585 let nodeAddress = getStakingNodeAddressByIndex(nodeIdx)
426586 let leasedAmtKEY = getLeaseAmountKey(nodeIdx)
427587 let leasedAmt = getNumberByKey(leasedAmtKEY)
428588 let leaseIdKEY = getLeaseIdKey(nodeIdx)
429589 let leaseId = value(getBinary(this, leaseIdKEY))
430590 $Tuple5(nodeAddress, leasedAmtKEY, leasedAmt, leaseIdKEY, leaseId)
431591 }
432592
433593
434-func commonSwap (swapType,pmtAmount,userAddressStr,txId58,swapParamsByUserSYSREADONLY) = {
435- let swapLimitSpent = swapParamsByUserSYSREADONLY._2
436- let blcks2LmtReset = swapParamsByUserSYSREADONLY._3
437- let wavesSwapLimitMax = swapParamsByUserSYSREADONLY._6
438- let usdnSwapLimitMax = swapParamsByUserSYSREADONLY._7
439- let minSwapAmount = minSwapAmountREAD(swapType)
440- let totalLocked = totalLockedREAD(swapType)
441- let totalLockedByUser = totalLockedByUserREAD(swapType, userAddressStr)
594+func commonSwap (swapType,pmtAmount,inAsset,userAddressStr,txId58) = {
595+ let swapParamsSTRUCT = asSwapParamsSTRUCT(invoke(this, "swapParamsByUserSYSREADONLY", [userAddressStr, 0], nil))
596+ let tokenSwapLimitUsd = swapParamsSTRUCT._1
597+ let swapLimitSpent = swapParamsSTRUCT._2
598+ let blcks2LmtReset = swapParamsSTRUCT._3
599+ let usdnSwapLimitMax = swapParamsSTRUCT._7
600+ let minSwapAmount = minSwapAmountREAD(swapType, inAsset)
601+ let totalLockedByUser = totalLockedByUserREAD(swapType, userAddressStr, inAsset)
442602 let nodeAddress = getStakingNodeByIndex(0)
443- let priceByIndex = getPriceHistory(getHeightPriceByIndex(priceIndex))
444603 let isSwapByNode = (nodeAddress == userAddressStr)
445604 let balanceLockMaxInterval = if (isSwapByNode)
446605 then nodeBalanceLockIntervalREAD()
447606 else balanceLockIntervalREAD(swapType)
448607 let selfUnlockHeight = (height + balanceLockMaxInterval)
449- let swapUsdnVolume = if ((swapType == "neutrino"))
450- then pmtAmount
451- else convertWavesToNeutrino(pmtAmount, priceByIndex)
452- let swapLimitMax = if ((swapType == "neutrino"))
453- then usdnSwapLimitMax
454- else convertWavesToNeutrino(wavesSwapLimitMax, priceByIndex)
608+ let pr = value(getInteger(controlContract, keyPriceByAsset(inAsset)))
609+ let swapUsdnVolume = if ((swapType == "outNeutrino"))
610+ then convertTokenToUsd(pmtAmount, pr)
611+ else pmtAmount
612+ let swapLimitMax = if ((swapType == "outNeutrino"))
613+ then tokenSwapLimitUsd
614+ else usdnSwapLimitMax
455615 if ((minSwapAmount > pmtAmount))
456616 then minSwapAmountFAIL(swapType, minSwapAmount)
457617 else if (if (!(isSwapByNode))
458618 then (swapLimitSpent > 0)
459619 else false)
460620 then throw(("You have exceeded swap limit! Next allowed swap height is " + toString((height + blcks2LmtReset))))
461621 else if (if (!(isSwapByNode))
462622 then (swapUsdnVolume > swapLimitMax)
463623 else false)
464624 then throw(((("You have exceeded your swap limit! Requested: " + toString(swapUsdnVolume)) + ", available: ") + toString(swapLimitMax)))
465625 else if (isBlocked)
466626 then emergencyShutdownFAIL()
467627 else {
468- let leasePart = if ((swapType == "waves"))
469- then prepareUnleaseAndLease(0)
470- else nil
471- $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)
628+ let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
629+ let basketInfo = asString(neutrinoMetrics[nMetricBasketInfo])
630+ let weightedPrice = asInt(neutrinoMetrics[nMetricWeightedPrice])
631+ let out = convertBasketItemToNeutrino(pmtAmount, inAsset, basketInfo, weightedPrice)
632+ if (if ((swapType == "outNeutrino"))
633+ then (0 >= out[1])
634+ else false)
635+ then throw((((((("Net amount is non-positive, cannot swap. (gross, net, fee) = (" + toString(out[0])) + ", ") + toString(out[1])) + ", ") + toString(out[2])) + ")"))
636+ else {
637+ let leasePart = if (if ((swapType == "outNeutrino"))
638+ then (inAsset == "WAVES")
639+ else false)
640+ then prepareUnleaseAndLease(0)
641+ else nil
642+ $Tuple2(([IntegerEntry(keySwapUserSpentInPeriod(userAddressStr), swapUsdnVolume), IntegerEntry(keyUserLastSwapHeight(userAddressStr), height), IntegerEntry(totalLockedByUserKEY(swapType, userAddressStr, inAsset), (totalLockedByUser + pmtAmount)), IntegerEntry(getBalanceUnlockBlockKey(userAddressStr), selfUnlockHeight), StringEntry(swapKEY(userAddressStr, txId58), pendingSwapDATA(swapType, pmtAmount, selfUnlockHeight, inAsset))] ++ leasePart), unit)
643+ }
472644 }
473645 }
474646
475-
476-let nMetricIdxPrice = 0
477-
478-let nMetricIdxUsdnLockedBalance = 1
479-
480-let nMetricIdxWavesLockedBalance = 2
481-
482-let nMetricIdxReserve = 3
483-
484-let nMetricIdxReserveInUsdn = 4
485-
486-let nMetricIdxUsdnSupply = 5
487-
488-let nMetricIdxSurplus = 6
489-
490-let nMetricIdxSurplusPercent = 7
491-
492-let nMetricIdxBR = 8
493-
494-let nMetricIdxNsbtSupply = 9
495-
496-let nMetricIdxMaxNsbtSupply = 10
497-
498-let nMetricIdxSurfSupply = 11
499-
500-let nMetricUsdnUsdtPeg = 12
501-
502-let nMetricCurrentPriceAdj = 13
503647
504648 let bFuncIdxSurf = 0
505649
506650 let bFuncIdxWaves = 1
507651
508652 let bFuncIdxUsdn = 2
509653
510654 let bFuncIdxReserveStart = 3
511655
512656 let bFuncIdxSupplyStart = 4
513657
514658 let bFuncIdxBRStart = 5
515659
516660 let bFuncIdxReserveEnd = 6
517661
518662 let bFuncIdxSupplyEnd = 7
519663
520664 let bFuncIdxBREnd = 8
521665
522666 let bFuncIdxRest = 9
523667
524668 let bFuncIdxWavesPrice = 10
525669
526-func calcWithdrawW2U (wavesIn,price) = {
527- let outAmtGross = convertWavesToNeutrino(wavesIn, price)
528- $Tuple10(outAmtGross, neutrinoAssetId, 0, unit, 0, price, wavesIn, 0, 0, 0)
670+func calcWithdrawT2U (inAmount,inAsset,basketInfo,weightedPrice) = {
671+ let outAmt = convertBasketItemToNeutrino(inAmount, inAsset, basketInfo, weightedPrice)
672+ $Tuple12(outAmt[0], neutrinoAssetId, 0, inAsset, 0, weightedPrice, inAmount, 0, 0, 0, nil, [outAmt[1], outAmt[2]])
529673 }
530674
531675
532-func calcWithdrawU2W (usdnIn,price,br,reservesInUsdn,usdnSupply) = {
533- let brProtected = valueOrElse(getInteger(this, brProtectedKEY()), BRPROTECTED)
534- let maxAllowedUsdnBeforeMinBr = if ((brProtected >= br))
535- then 0
536- else fraction((reservesInUsdn - fraction(brProtected, usdnSupply, PAULI)), PAULI, (PAULI - brProtected))
537- let allowedUsdnBeforeMinBr = if ((usdnIn > maxAllowedUsdnBeforeMinBr))
538- then maxAllowedUsdnBeforeMinBr
539- else usdnIn
540- let allowedUsdnAfterMinBr = if ((usdnIn > maxAllowedUsdnBeforeMinBr))
541- then fraction((usdnIn - maxAllowedUsdnBeforeMinBr), br, PAULI)
542- else 0
543- let allowedUsdn = (allowedUsdnBeforeMinBr + allowedUsdnAfterMinBr)
544- let usdn2SURF = (usdnIn - allowedUsdn)
545- let outAmtGross = convertNeutrinoToWaves(allowedUsdn, price)
546- $Tuple10(outAmtGross, unit, usdn2SURF, neutrinoAssetId, outAmtGross, price, allowedUsdn, maxAllowedUsdnBeforeMinBr, allowedUsdnBeforeMinBr, allowedUsdnAfterMinBr)
676+func calcWithdrawU2Basket (usdnIn,basketInfo,neutrinoSupply) = {
677+ let outAmtGross = convertNeutrinoToBasket(usdnIn, basketInfo, neutrinoSupply)
678+ $Tuple12(outAmtGross._2, unit, 0, neutrinoAssetId, outAmtGross._2, outAmtGross._3, usdnIn, neutrinoSupply, usdnIn, 0, outAmtGross._1, nil)
547679 }
548680
549681
550-func calcWithdraw (swapType,inAmount,price,neutrinoMetrics) = {
551- let outFeePart = valueOrElse(getInteger(this, outFeePartKEY(swapType)), DEFAULTSWAPFEE)
552- if (if ((0 > outFeePart))
553- then true
554- else (outFeePart >= PAULI))
555- then throw(((("invalid outFeePart config for " + swapType) + " swap: outFeePart=") + toString(outFeePart)))
556- else {
557- let brProtected = valueOrElse(getInteger(this, brProtectedKEY()), BRPROTECTED)
558- let BR = asInt(neutrinoMetrics[nMetricIdxBR])
559- let reservesInUsdn = asInt(neutrinoMetrics[nMetricIdxReserveInUsdn])
560- let usdnSupply = asInt(neutrinoMetrics[nMetricIdxUsdnSupply])
561- let priceAdj = asInt(neutrinoMetrics[nMetricCurrentPriceAdj])
562- let outDataTuple = if ((swapType == "waves"))
563- then calcWithdrawW2U(inAmount, price)
564- else if ((swapType == "neutrino"))
565- then calcWithdrawU2W(inAmount, priceAdj, BR, reservesInUsdn, usdnSupply)
566- else throw(("Unsupported swap type " + swapType))
567- let outAmtGross = outDataTuple._1
568- let outAssetId = outDataTuple._2
569- let inAmtToSurfPart = outDataTuple._3
570- let inAssetId = outDataTuple._4
571- let unleaseAmt = outDataTuple._5
572- let withdrawPrice = outDataTuple._6
573- let payoutsArray = applyFees(outAmtGross, inAmtToSurfPart, outFeePart)
574- let outNetAmt = payoutsArray[IdxNetAmount]
575- let outFeeAmt = payoutsArray[IdxFeeAmount]
576- let outSurfAmt = if ((0 >= inAmtToSurfPart))
577- then 0
578- else {
579- let surfResult = asAnyList(invoke(mathContract, "surfFunctionREADONLY", [inAmtToSurfPart, inAssetId], nil))
580- asInt(surfResult[bFuncIdxSurf])
581- }
582- $Tuple8(outNetAmt, outAssetId, outSurfAmt, inAmtToSurfPart, unleaseAmt, outFeeAmt, outAmtGross, withdrawPrice)
583- }
584- }
585-
586-
587-func commonWithdraw (account,index,swapTxId,withdrawTxId,neutrinoMetrics) = {
588- let userAddress = addressFromStringValue(account)
589- let dataArray = swapDataFailOrREAD(account, swapTxId)
590- let selfUnlockHeight = parseIntValue(dataArray[sIdxSelfUnlockHeight])
591- let swapType = dataArray[sIdxSwapType]
592- let inAmount = parseIntValue(dataArray[sIdxInAmount])
593- let swapStatus = dataArray[sIdxStatus]
594- let startHeight = parseIntValue(dataArray[sIdxStartHeight])
595- let outFeePart = valueOrElse(getInteger(this, outFeePartKEY(swapType)), DEFAULTSWAPFEE)
596- let totalLocked = totalLockedREAD(swapType)
597- let totalLockedByUser = totalLockedByUserREAD(swapType, account)
598- let unlockHeight = selfUnlockHeight
599- let indexHeight = getHeightPriceByIndex(index)
600- let prevIndexHeight = getHeightPriceByIndex((index - 1))
601- let priceByIndex = getPriceHistory(indexHeight)
602- if (isBlocked)
603- then emergencyShutdownFAIL()
604- else if ((swapStatus != "PENDING"))
605- then throw("swap has been already processed")
606- else if ((unlockHeight > height))
607- then throw((("please wait for: " + toString(unlockHeight)) + " block height to withdraw funds"))
608- else if (if (if ((index > priceIndex))
609- then true
610- else (unlockHeight > indexHeight))
611- then true
612- else if ((prevIndexHeight != 0))
613- then (prevIndexHeight >= unlockHeight)
614- else false)
615- then priceIndexFAIL(index, priceIndex, indexHeight, unlockHeight, prevIndexHeight)
616- else {
617- let withdrawTuple = calcWithdraw(swapType, inAmount, priceByIndex, neutrinoMetrics)
618- let outNetAmount = withdrawTuple._1
619- let outAssetId = withdrawTuple._2
620- let outSurfAmt = withdrawTuple._3
621- let unleaseAmt = withdrawTuple._5
622- let outFeeAmount = withdrawTuple._6
623- let outAmtGross = withdrawTuple._7
624- let withdrawPrice = withdrawTuple._8
625- if ((0 >= outAmtGross))
626- then throw("balance equals zero")
627- else {
628- let BR = asInt(neutrinoMetrics[nMetricIdxBR])
629- 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 surfCondition = if ((outSurfAmt > 0))
631- then {
632- let issueResult = invoke(auctionContract, "issueSurf", [outSurfAmt, account], nil)
633- if ((issueResult == issueResult))
634- then 0
635- else throw("Strict value is not equal to itself.")
636- }
637- else 0
638- if ((surfCondition == surfCondition))
639- then $Tuple3(state, AttachedPayment(outAssetId, outFeeAmount), unleaseAmt)
640- else throw("Strict value is not equal to itself.")
641- }
642- }
682+func calcWithdraw (swapType,inAmount,price,neutrinoMetrics,inAsset) = {
683+ let neutrinoSupply = asInt(neutrinoMetrics[nMetricIdxUsdnSupply])
684+ let basketInfo = asString(neutrinoMetrics[nMetricBasketInfo])
685+ let weightedPrice = asInt(neutrinoMetrics[nMetricWeightedPrice])
686+ let outDataTuple = if ((swapType == "outNeutrino"))
687+ then calcWithdrawT2U(inAmount, inAsset, basketInfo, weightedPrice)
688+ else if ((swapType == "outMulti"))
689+ then calcWithdrawU2Basket(inAmount, basketInfo, neutrinoSupply)
690+ else throw(("Unsupported swap type " + swapType))
691+ let outAmtGross = outDataTuple._1
692+ let outAssetId = outDataTuple._2
693+ let inAmtToSurfPart = outDataTuple._3
694+ let inAssetId = outDataTuple._4
695+ let unleaseAmt = outDataTuple._5
696+ let withdrawPrice = outDataTuple._6
697+ let basketData = outDataTuple._11
698+ let netFeeData = outDataTuple._12
699+ let outNetAmt = if ((swapType == "outNeutrino"))
700+ then netFeeData[0]
701+ else 0
702+ let outFeeAmt = if ((swapType == "outNeutrino"))
703+ then netFeeData[1]
704+ else 0
705+ let outSurfAmt = if ((0 >= inAmtToSurfPart))
706+ then 0
707+ else asInt(asAnyList(invoke(mathContract, "surfFunctionREADONLY", [inAmtToSurfPart, inAssetId], nil))[bFuncIdxSurf])
708+ let withdrawBasket = if ((swapType == "outMulti"))
709+ then applyFeesBasket(basketData)
710+ else ""
711+ $Tuple9(outNetAmt, outAssetId, outSurfAmt, inAmtToSurfPart, unleaseAmt, outFeeAmt, outAmtGross, withdrawPrice, withdrawBasket)
643712 }
644713
645714
646715 func keyApplyInProgress () = "%s__applyInProgress"
647716
648717
649718 func keyProposalDataById (proposalId) = ("%s%d__proposalData__" + toString(proposalId))
650719
651720
652721 let govIdxTxIds = 9
653722
654723 func validateUpdate (tx) = match tx {
655724 case o: Order =>
656725 throw("Orders aren't allowed")
657726 case t: DataTransaction|SponsorFeeTransaction|SetScriptTransaction|CreateAliasTransaction|LeaseCancelTransaction|LeaseTransaction|IssueTransaction|InvokeExpressionTransaction|UpdateAssetInfoTransaction|InvokeScriptTransaction|SetAssetScriptTransaction|TransferTransaction|ExchangeTransaction|MassTransferTransaction|BurnTransaction|ReissueTransaction =>
658727 let txId = toBase58String(t.id)
659728 let proposalId = valueOrErrorMessage(getInteger(govContract, keyApplyInProgress()), "Apply is not happening")
660729 let txList = split(split(getStringOrFail(govContract, keyProposalDataById(proposalId)), SEP)[govIdxTxIds], LISTSEP)
661730 if (!(isDefined(indexOf(txList, txId))))
662731 then throw(((("Unknown txId: " + txId) + " for proposalId=") + toString(proposalId)))
663732 else true
664733 case _ =>
665734 throw("Match error")
666735 }
667736
668737
669738 @Callable(i)
670-func constructor (neutrinoAssetIdPrm,bondAssetIdPrm,auctionContractPrm,liquidationContractPrm,rpdContractPrm,nodeOracleProviderPubKeyPrm,balanceWavesLockIntervalPrm,balanceNeutrinoLockIntervalPrm,minWavesSwapAmountPrm,minNeutrinoSwapAmountPrm,neutrinoOutFeePartPrm,wavesOutFeePartPrm) = {
739+func constructorV1 (neutrinoAssetIdPrm,bondAssetIdPrm,auctionContractPrm,liquidationContractPrm,rpdContractPrm,nodeOracleProviderPubKeyPrm,balanceWavesLockIntervalPrm,balanceNeutrinoLockIntervalPrm,minWavesSwapAmountPrm,minNeutrinoSwapAmountPrm,neutrinoOutFeePartPrm,wavesOutFeePartPrm) = {
671740 let checkCaller = thisOnly(i)
672741 if ((checkCaller == checkCaller))
673742 then if ((size(i.payments) != 0))
674743 then throw("no payments allowed")
675- 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)]
744+ 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(MinTokenSwapAmountKey("WAVES"), minWavesSwapAmountPrm), IntegerEntry(MinNeutrinoSwapAmountKey, minNeutrinoSwapAmountPrm), IntegerEntry(NeutrinoOutFeePartKey, neutrinoOutFeePartPrm), IntegerEntry(WavesOutFeePartKey, wavesOutFeePartPrm)]
676745 else throw("Strict value is not equal to itself.")
677746 }
678747
679748
680749
681750 @Callable(i)
682751 func constructorV2 (mathContract,nsbtStakingContract,swapsTimeframeBlocks) = {
683752 let checkCaller = thisOnly(i)
684753 if ((checkCaller == checkCaller))
685754 then if ((size(i.payments) != 0))
686755 then throw("no payments allowed")
687756 else [StringEntry(MathContractKey, mathContract), StringEntry(NsbtStakingContractKey, nsbtStakingContract), IntegerEntry(swapsTimeframeKEY(), swapsTimeframeBlocks)]
688757 else throw("Strict value is not equal to itself.")
689758 }
690759
691760
692761
693762 @Callable(i)
694-func swapWavesToNeutrino () = if ((size(i.payments) != 1))
695- then throw("swapWavesToNeutrino require only one payment")
763+func constructorV3 (assetsWeightsMins,dParam,kParam,bParam,deltaParam) = {
764+ let checkCaller = thisOnly(i)
765+ if ((checkCaller == checkCaller))
766+ then if ((size(i.payments) != 0))
767+ then throw("no payments allowed")
768+ else {
769+ func prepare (acc,item) = {
770+ let parts = split(item, "_")
771+ let assetId = parts[0]
772+ let weight = parseIntValue(parts[1])
773+ let minVal = parseIntValue(parts[2])
774+ $Tuple2((acc._1 :+ assetId), ((acc._2 :+ IntegerEntry(basketWeightByAssetKey(assetId), weight)) :+ IntegerEntry(MinTokenSwapAmountKey(assetId), minVal)))
775+ }
776+
777+ let r = {
778+ let $l = assetsWeightsMins
779+ let $s = size($l)
780+ let $acc0 = $Tuple2(nil, nil)
781+ func $f0_1 ($a,$i) = if (($i >= $s))
782+ then $a
783+ else prepare($a, $l[$i])
784+
785+ func $f0_2 ($a,$i) = if (($i >= $s))
786+ then $a
787+ else throw("List size exceeds 10")
788+
789+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
790+ }
791+ (((((r._2 :+ IntegerEntry(basketDKey(), dParam)) :+ IntegerEntry(basketKKey(), kParam)) :+ IntegerEntry(basketBKey(), bParam)) :+ IntegerEntry(basketLogbDeltaKey(), log(deltaParam, 6, bParam, 6, 6, HALFUP))) :+ StringEntry(basketAssetsKey(), makeString(r._1, SEP)))
792+ }
793+ else throw("Strict value is not equal to itself.")
794+ }
795+
796+
797+
798+@Callable(i)
799+func swapTokenToNeutrino () = if ((size(i.payments) != 1))
800+ then throw("swapTokenToNeutrino require only one payment")
696801 else {
697802 let pmt = value(i.payments[0])
698- if (isDefined(pmt.assetId))
699- then throw("Only Waves token is allowed for swapping.")
803+ let basketAssets = value(getString(basketAssetsKey()))
804+ let pmtAssetIdStr = toBase58String(valueOrElse(pmt.assetId, WAVESID))
805+ if (!(contains(basketAssets, pmtAssetIdStr)))
806+ then throw(((pmtAssetIdStr + " is not one of basket tokens:") + basketAssets))
700807 else {
701808 let userAddress = toString(i.caller)
702809 let txId58 = toBase58String(i.transactionId)
703- let swapParamsSTRUCT = asSwapParamsSTRUCT(invoke(this, "swapParamsByUserSYSREADONLY", [userAddress, 0], nil))
704- let commonSwapResult = commonSwap("waves", pmt.amount, userAddress, txId58, swapParamsSTRUCT)
705- commonSwapResult
810+ let totalLocked = totalLockedREAD("outNeutrino", pmtAssetIdStr)
811+ let pmtAmount = pmt.amount
812+ let saveTotalLocked = invoke(this, "internalSaveInteger", [totalLockedKEY("outNeutrino", pmtAssetIdStr), (totalLocked + pmtAmount)], nil)
813+ if ((saveTotalLocked == saveTotalLocked))
814+ then commonSwap("outNeutrino", pmtAmount, pmtAssetIdStr, userAddress, txId58)
815+ else throw("Strict value is not equal to itself.")
706816 }
707817 }
708818
709819
710820
711821 @Callable(i)
712-func swapNeutrinoToWaves () = if ((size(i.payments) != 1))
713- then throw("swapNeutrinoToWaves require only one payment")
822+func swapNeutrinoToBasket () = if ((size(i.payments) != 1))
823+ then throw("swapNeutrinoToBasket require only one payment")
714824 else {
715825 let pmt = value(i.payments[0])
716826 if ((pmt.assetId != neutrinoAssetId))
717827 then throw("Only appropriate Neutrino tokens are allowed for swapping.")
718828 else {
719829 let userAddress = toString(i.caller)
720830 let txId58 = toBase58String(i.transactionId)
721- let swapParamsSTRUCT = asSwapParamsSTRUCT(invoke(this, "swapParamsByUserSYSREADONLY", [userAddress, 0], nil))
722- let commonSwapResult = commonSwap("neutrino", pmt.amount, userAddress, txId58, swapParamsSTRUCT)
723- commonSwapResult
831+ let neutrinoAssetIdStr = toBase58String(neutrinoAssetId)
832+ let totalLocked = totalLockedREAD("outMulti", neutrinoAssetIdStr)
833+ let pmtAmount = pmt.amount
834+ let saveTotalLocked = invoke(this, "internalSaveInteger", [totalLockedKEY("outMulti", neutrinoAssetIdStr), (totalLocked + pmtAmount)], nil)
835+ if ((saveTotalLocked == saveTotalLocked))
836+ then commonSwap("outMulti", pmt.amount, neutrinoAssetIdStr, userAddress, txId58)
837+ else throw("Strict value is not equal to itself.")
724838 }
725839 }
840+
841+
842+
843+@Callable(i)
844+func internalSaveInteger (key,amount) = if ((i.caller != this))
845+ then throw("internalSaveInteger is not public method")
846+ else [IntegerEntry(key, amount)]
726847
727848
728849
729850 @Callable(i)
730851 func withdraw (account,index,swapTxId) = {
731852 let txId = toBase58String(i.transactionId)
732853 if ((size(i.payments) != 0))
733854 then throw("no payments allowed")
734855 else {
735856 let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
736857 let BR = asInt(neutrinoMetrics[nMetricIdxBR])
737- let commonTuple = commonWithdraw(account, index, swapTxId, txId, neutrinoMetrics)
738- let state = commonTuple._1
739- let fee = commonTuple._2
740- let unleaseAmt = commonTuple._3
741- let unleaseInvOrEmpty = invoke(this, "internalUnleaseAndLease", [unleaseAmt], nil)
742- if ((unleaseInvOrEmpty == unleaseInvOrEmpty))
743- then {
744- let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", ["", 0, 0], nil))
745- let gnsbtAmtTotal = asInt(gnsbtData[1])
746- let gnsbtAmtFromSurfTotal = asInt(asAnyList(gnsbtData[3])[3])
747- let surfFeeAmt1 = if ((gnsbtAmtTotal != 0))
748- then fraction(fee.amount, gnsbtAmtFromSurfTotal, gnsbtAmtTotal)
749- else 0
750- let surfFeeAmt2 = if ((gnsbtAmtTotal != 0))
751- then fraction(fee.amount, (PAULI - BR), PAULI)
752- else 0
753- let surfFeeAmt = max([surfFeeAmt1, surfFeeAmt2])
754- let nsbtFeeAmt = (fee.amount - surfFeeAmt)
755- let surfDeposit = if ((surfFeeAmt > 0))
756- then {
757- let surfInv = invoke(surfStakingContract, "deposit", nil, [AttachedPayment(fee.assetId, surfFeeAmt)])
758- if ((surfInv == surfInv))
759- then nil
760- else throw("Strict value is not equal to itself.")
761- }
762- else nil
763- if ((surfDeposit == surfDeposit))
764- then {
765- let nsbtDeposit = if ((nsbtFeeAmt > 0))
766- then {
767- let nsbtInv = invoke(nsbtStakingContract, "deposit", nil, [AttachedPayment(fee.assetId, nsbtFeeAmt)])
768- if ((nsbtInv == nsbtInv))
769- then nil
770- else throw("Strict value is not equal to itself.")
771- }
772- else nil
773- if ((nsbtDeposit == nsbtDeposit))
774- then state
775- else throw("Strict value is not equal to itself.")
776- }
777- else throw("Strict value is not equal to itself.")
778- }
779- else throw("Strict value is not equal to itself.")
858+ let userAddress = addressFromStringValue(account)
859+ let dataArray = swapDataFailOrREAD(account, swapTxId)
860+ let selfUnlockHeight = parseIntValue(dataArray[sIdxSelfUnlockHeight])
861+ let swapType = dataArray[sIdxSwapType]
862+ let inAmount = parseIntValue(dataArray[sIdxInAmount])
863+ let swapStatus = dataArray[sIdxStatus]
864+ let startHeight = parseIntValue(dataArray[sIdxStartHeight])
865+ let inAsset = dataArray[sIdxInAsset]
866+ let totalLocked = totalLockedREAD(swapType, inAsset)
867+ let totalLockedByUser = totalLockedByUserREAD(swapType, account, inAsset)
868+ let unlockHeight = selfUnlockHeight
869+ let indexHeight = getHeightPriceByIndex(index)
870+ let prevIndexHeight = getHeightPriceByIndex((index - 1))
871+ let priceByIndex = getPriceHistory(indexHeight)
872+ if (isBlocked)
873+ then emergencyShutdownFAIL()
874+ else if ((swapStatus != "PENDING"))
875+ then throw("swap has been already processed")
876+ else if ((unlockHeight > height))
877+ then throw((("please wait for: " + toString(unlockHeight)) + " block height to withdraw funds"))
878+ else if (if (if ((index > priceIndex))
879+ then true
880+ else (unlockHeight > indexHeight))
881+ then true
882+ else if ((prevIndexHeight != 0))
883+ then (prevIndexHeight >= unlockHeight)
884+ else false)
885+ then priceIndexFAIL(index, priceIndex, indexHeight, unlockHeight, prevIndexHeight)
886+ else {
887+ let withdrawTuple = calcWithdraw(swapType, inAmount, priceByIndex, neutrinoMetrics, inAsset)
888+ let outNetAmount = withdrawTuple._1
889+ let outAssetId = withdrawTuple._2
890+ let outSurfAmt = withdrawTuple._3
891+ let unleaseAmt = withdrawTuple._5
892+ let outFeeAmount = withdrawTuple._6
893+ let outAmtGross = withdrawTuple._7
894+ let withdrawPrice = withdrawTuple._8
895+ let withdrawBasket = withdrawTuple._9
896+ if (if ((swapType == "outNeutrino"))
897+ then (0 >= outAmtGross)
898+ else false)
899+ then throw("balance equals zero")
900+ else {
901+ let surfCondition = if ((outSurfAmt > 0))
902+ then {
903+ let issueResult = invoke(auctionContract, "issueSurf", [outSurfAmt, account], nil)
904+ if ((issueResult == issueResult))
905+ then 0
906+ else throw("Strict value is not equal to itself.")
907+ }
908+ else 0
909+ if ((surfCondition == surfCondition))
910+ then {
911+ let unleaseInvOrEmpty = invoke(this, "internalUnleaseAndLease", [unleaseAmt], nil)
912+ if ((unleaseInvOrEmpty == unleaseInvOrEmpty))
913+ then {
914+ let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", ["", 0, 0], nil))
915+ let gnsbtAmtTotal = asInt(gnsbtData[1])
916+ let gnsbtAmtFromSurfTotal = asInt(asAnyList(gnsbtData[3])[3])
917+ let commonActions = [IntegerEntry(totalLockedByUserKEY(swapType, account, inAsset), (totalLockedByUser - inAmount)), IntegerEntry(totalLockedKEY(swapType, inAsset), (totalLocked - inAmount)), StringEntry(swapKEY(account, swapTxId), finishSwapDATA(dataArray, withdrawPrice, outNetAmount, outFeeAmount, unlockHeight, index, txId, outSurfAmt, BR, withdrawBasket, inAsset))]
918+ func deposits (surfFees,nsbtFees,surfPayments,nsbtPayments) = {
919+ let surfDeposit = if ((surfFees > 0))
920+ then asInt(invoke(surfStakingContract, "deposit", nil, surfPayments))
921+ else 0
922+ let nsbtDeposit = if ((nsbtFees > 0))
923+ then asInt(invoke(nsbtStakingContract, "deposit", nil, nsbtPayments))
924+ else 0
925+ (surfDeposit + nsbtDeposit)
926+ }
927+
928+ func divideFees (feeAmount) = {
929+ let surfAmt1 = if ((gnsbtAmtTotal != 0))
930+ then fraction(feeAmount, gnsbtAmtFromSurfTotal, gnsbtAmtTotal)
931+ else 0
932+ let surfAmt2 = if ((gnsbtAmtTotal != 0))
933+ then fraction(feeAmount, (MULT6 - BR), MULT6)
934+ else 0
935+ let surfAmt = max([surfAmt1, surfAmt2])
936+ let nsbtAmt = (feeAmount - surfAmt)
937+[surfAmt, nsbtAmt]
938+ }
939+
940+ let transfers = if ((swapType == "outMulti"))
941+ then {
942+ let basket = split_4C(withdrawBasket, "_")
943+ func looper (acc,item) = {
944+ let it = split(item, LISTSEP)
945+ let tempAssetId = fromBase58String(it[0])
946+ let assetId = if ((tempAssetId == WAVESID))
947+ then unit
948+ else tempAssetId
949+ let netAmount = parseIntValue(it[2])
950+ let feeAmount = parseIntValue(it[3])
951+ let fees = divideFees(feeAmount)
952+ $Tuple5((acc._1 :+ ScriptTransfer(userAddress, netAmount, assetId)), (acc._2 :+ AttachedPayment(assetId, fees[0])), (acc._3 :+ AttachedPayment(assetId, fees[1])), (acc._4 + fees[0]), (acc._5 + fees[1]))
953+ }
954+
955+ let r = {
956+ let $l = basket
957+ let $s = size($l)
958+ let $acc0 = $Tuple5(nil, nil, nil, 0, 0)
959+ func $f0_1 ($a,$i) = if (($i >= $s))
960+ then $a
961+ else looper($a, $l[$i])
962+
963+ func $f0_2 ($a,$i) = if (($i >= $s))
964+ then $a
965+ else throw("List size exceeds 10")
966+
967+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
968+ }
969+ let depoResult = deposits(r._4, r._5, r._2, r._3)
970+ $Tuple2(r._1, depoResult)
971+ }
972+ else {
973+ let fees = divideFees(outFeeAmount)
974+ let depoResult = deposits(fees[0], fees[1], [AttachedPayment(outAssetId, fees[0])], [AttachedPayment(outAssetId, fees[1])])
975+ $Tuple2([ScriptTransfer(userAddress, outNetAmount, outAssetId)], depoResult)
976+ }
977+ $Tuple2((commonActions ++ transfers._1), transfers._2)
978+ }
979+ else throw("Strict value is not equal to itself.")
980+ }
981+ else throw("Strict value is not equal to itself.")
982+ }
983+ }
780984 }
781985 }
782986
783987
784988
785989 @Callable(i)
786990 func internalUnleaseAndLease (unleaseAmount) = if ((i.caller != this))
787991 then throw("internalUnleaseAndLease is not public method")
788992 else prepareUnleaseAndLease(unleaseAmount)
789993
790994
791995
792996 @Callable(i)
793997 func transferUsdnToUser (amount,addr) = if ((i.caller != auctionContract))
794998 then throw("Only auction contract is authorized")
795999 else [ScriptTransfer(addressFromStringValue(addr), amount, neutrinoAssetId)]
7961000
7971001
7981002
7991003 @Callable(i)
8001004 func acceptWaves () = if (if ((i.caller != auctionContract))
8011005 then (i.caller != govContract)
8021006 else false)
8031007 then throw("Currently only auction and governance contracts are allowed to call")
8041008 else $Tuple2(prepareUnleaseAndLease(0), "success")
8051009
8061010
8071011
8081012 @Callable(i)
8091013 func approveLeasings (nListS,groupNum,lAmt) = {
8101014 let nIdxs = [0, 1, 2, 3, 4, 5, 6, 7]
8111015 let mngPubS = valueOrElse(getString("%s%s__cfg__leasingManagerPub"), "7AUMX54ukYMYvPmma7yoFf5NjZhs4Bu5nz3Ez9EV8sur")
8121016 let mngPub = fromBase58String(mngPubS)
8131017 let nodeRegAddrStr = valueOrElse(getString("%s%s__cfg__nodesRegistryAddress"), "3P9vKqQKjUdmpXAfiWau8krREYAY1Xr69pE")
8141018 let nodeRegAddr = addressFromStringValue(nodeRegAddrStr)
8151019 let lGroupNodeListKEY = getLeaseGroupNodeListKey(groupNum)
8161020 let lGrNodeOpt = getString(this, lGroupNodeListKEY)
8171021 if (isDefined(lGrNodeOpt))
8181022 then throw((("group " + toString(groupNum)) + " already initialized"))
8191023 else {
8201024 let nList = split(nListS, SEP)
8211025 let expCount = size(nIdxs)
8221026 if ((i.callerPublicKey != mngPub))
8231027 then throw("approveLeasings not authorized")
8241028 else {
825- let $t03578935851 = readNodeInfo(0)
826- let nAddr0 = $t03578935851._1
827- let lAmtKEY0 = $t03578935851._2
828- let lAmt0 = $t03578935851._3
829- let lIdKEY0 = $t03578935851._4
830- let lId0 = $t03578935851._5
1029+ let $t04446644528 = readNodeInfo(0)
1030+ let nAddr0 = $t04446644528._1
1031+ let lAmtKEY0 = $t04446644528._2
1032+ let lAmt0 = $t04446644528._3
1033+ let lIdKEY0 = $t04446644528._4
1034+ let lId0 = $t04446644528._5
8311035 let newL0 = Lease(nAddr0, (lAmt0 - (lAmt * expCount)))
8321036 let validation = invoke(nodeRegAddr, "validateAndApproveLeasings", [nListS], nil)
8331037 if ((validation == validation))
8341038 then {
8351039 func forEachNodeValidateAndGenerateLease (a,i) = {
8361040 let node = nList[i]
8371041 let la = Lease(addressFromStringValue(node), lAmt)
8381042 (a ++ [la, BinaryEntry(getLeaseIdByAddressKey(node), lcalc(la)), IntegerEntry(getLeaseAmountByAddressKey(node), lAmt)])
8391043 }
8401044
8411045 ([StringEntry(lGroupNodeListKEY, nListS), BinaryEntry(lIdKEY0, lcalc(newL0)), IntegerEntry(lAmtKEY0, newL0.amount), LeaseCancel(lId0), newL0] ++ {
8421046 let $l = nIdxs
8431047 let $s = size($l)
8441048 let $acc0 = nil
8451049 func $f0_1 ($a,$i) = if (($i >= $s))
8461050 then $a
8471051 else forEachNodeValidateAndGenerateLease($a, $l[$i])
8481052
8491053 func $f0_2 ($a,$i) = if (($i >= $s))
8501054 then $a
8511055 else throw("List size exceeds 8")
8521056
8531057 $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)
8541058 })
8551059 }
8561060 else throw("Strict value is not equal to itself.")
8571061 }
8581062 }
8591063 }
8601064
8611065
8621066
8631067 @Callable(i)
8641068 func rebalanceLeasings (amount,groupNum) = {
8651069 let nIdxs = [0, 1, 2, 3, 4, 5, 6, 7]
8661070 let mngPubS = valueOrElse(getString("%s%s__cfg__leasingManagerPub"), "7AUMX54ukYMYvPmma7yoFf5NjZhs4Bu5nz3Ez9EV8sur")
8671071 let mngPub = fromBase58String(mngPubS)
8681072 let lGroupNodeListKEY = getLeaseGroupNodeListKey(groupNum)
8691073 let nListS = getStringOrFail(this, lGroupNodeListKEY)
8701074 let nList = split(nListS, SEP)
8711075 if ((i.callerPublicKey != mngPub))
8721076 then throw("rebalanceLeasings not authorized")
8731077 else {
8741078 let unleaseAmt = ((amount / size(nList)) + 1)
875- let $t03709137153 = readNodeInfo(0)
876- let nAddr0 = $t03709137153._1
877- let lAmtKEY0 = $t03709137153._2
878- let lAmt0 = $t03709137153._3
879- let lIdKEY0 = $t03709137153._4
880- let lId0 = $t03709137153._5
1079+ let $t04576845830 = readNodeInfo(0)
1080+ let nAddr0 = $t04576845830._1
1081+ let lAmtKEY0 = $t04576845830._2
1082+ let lAmt0 = $t04576845830._3
1083+ let lIdKEY0 = $t04576845830._4
1084+ let lId0 = $t04576845830._5
8811085 let newL0 = Lease(nAddr0, (lAmt0 + (unleaseAmt * size(nList))))
8821086 func forEachNodeDoUnlease (a,i) = {
8831087 let node = nList[i]
8841088 let lIdKEY = getLeaseIdByAddressKey(node)
8851089 let lId = getBinaryValue(this, lIdKEY)
8861090 let lAmtKEY = getLeaseAmountByAddressKey(node)
8871091 let lAmt = getIntegerValue(this, lAmtKEY)
8881092 let ula = LeaseCancel(value(lId))
8891093 let la = Lease(addressFromStringValue(node), (lAmt - unleaseAmt))
8901094 (a ++ [LeaseCancel(value(lId)), la, BinaryEntry(lIdKEY, lcalc(la)), IntegerEntry(lAmtKEY, la.amount)])
8911095 }
8921096
8931097 ({
8941098 let $l = nIdxs
8951099 let $s = size($l)
8961100 let $acc0 = nil
8971101 func $f0_1 ($a,$i) = if (($i >= $s))
8981102 then $a
8991103 else forEachNodeDoUnlease($a, $l[$i])
9001104
9011105 func $f0_2 ($a,$i) = if (($i >= $s))
9021106 then $a
9031107 else throw("List size exceeds 8")
9041108
9051109 $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)
9061110 } ++ [BinaryEntry(lIdKEY0, lcalc(newL0)), IntegerEntry(lAmtKEY0, newL0.amount), LeaseCancel(lId0), newL0])
9071111 }
9081112 }
9091113
9101114
9111115
9121116 @Callable(i)
9131117 func swapParamsByUserSYSREADONLY (userAddressStr,gnsbtDiff) = {
9141118 let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", [userAddressStr, 0, 0], nil))
9151119 let gnsbtAmt = (asInt(gnsbtData[0]) + gnsbtDiff)
9161120 let gnsbtAmtTotal = (asInt(gnsbtData[1]) + gnsbtDiff)
9171121 let swapLimitData = asAnyList(invoke(mathContract, "calcSwapLimitREADONLY", [gnsbtAmt], nil))
918- let wavesSwapLimitInUsdnMax = asInt(swapLimitData[0])
919- let wavesSwapLimitMax = asInt(swapLimitData[1])
1122+ let tokenSwapLimitInUsdMax = asInt(swapLimitData[0])
9201123 let usdnSwapLimitMax = asInt(swapLimitData[2])
9211124 let lastSwapHeight = valueOrElse(getInteger(this, keyUserLastSwapHeight(userAddressStr)), 0)
9221125 let swapLimitTimelifeBlocks = swapsTimeframeREAD()
9231126 let passedBlocksAfterLastSwap = (height - lastSwapHeight)
9241127 let isSwapTimelifeNew = (passedBlocksAfterLastSwap >= swapLimitTimelifeBlocks)
9251128 let swapLimitSpentInUsdn = if (isSwapTimelifeNew)
9261129 then 0
9271130 else valueOrElse(getInteger(this, keySwapUserSpentInPeriod(userAddressStr)), 0)
9281131 let blcks2LmtReset = if (isSwapTimelifeNew)
9291132 then 0
9301133 else (swapLimitTimelifeBlocks - passedBlocksAfterLastSwap)
931- $Tuple2(nil, $Tuple7(wavesSwapLimitInUsdnMax, swapLimitSpentInUsdn, blcks2LmtReset, gnsbtAmt, gnsbtAmtTotal, wavesSwapLimitMax, usdnSwapLimitMax))
1134+ $Tuple2(nil, $Tuple7(tokenSwapLimitInUsdMax, swapLimitSpentInUsdn, blcks2LmtReset, gnsbtAmt, gnsbtAmtTotal, 0, usdnSwapLimitMax))
9321135 }
9331136
9341137
9351138
9361139 @Callable(i)
937-func calcWithdrawResultSYSREADONLY (swapType,inAmount,price) = {
1140+func calcWithdrawResultSYSREADONLY (swapType,inAmount,price,inAsset) = {
9381141 let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
939- $Tuple2(nil, calcWithdraw(swapType, inAmount, price, neutrinoMetrics))
1142+ $Tuple2(nil, calcWithdraw(swapType, inAmount, price, neutrinoMetrics, inAsset))
9401143 }
9411144
9421145
9431146
9441147 @Callable(i)
9451148 func replaceCommunityNode (oldAddrStr,newAddrStr,groupNum,penaltyAmount) = {
9461149 let mngPubS = valueOrElse(getString("%s%s__cfg__leasingManagerPub"), "7AUMX54ukYMYvPmma7yoFf5NjZhs4Bu5nz3Ez9EV8sur")
9471150 let mngPub = fromBase58String(mngPubS)
9481151 if ((i.callerPublicKey != mngPub))
9491152 then throw("replaceCommunityNode not authorized")
9501153 else {
9511154 let groupKey = getLeaseGroupNodeListKey(groupNum)
9521155 let groupNodeListS = getStringOrFail(this, groupKey)
9531156 if (!(contains(groupNodeListS, oldAddrStr)))
9541157 then throw(((("Group " + toString(groupNum)) + " does not contain address ") + oldAddrStr))
9551158 else {
9561159 let doReplace = invoke(nodeRegistryContract, "replaceApprovedNode", [oldAddrStr, newAddrStr, groupNum, penaltyAmount], nil)
9571160 if ((doReplace == doReplace))
9581161 then {
9591162 let oldLeaseIdKey = getLeaseIdByAddressKey(oldAddrStr)
9601163 let oldLeaseAmtKey = getLeaseAmountByAddressKey(oldAddrStr)
9611164 let leaseAmt = getIntegerValue(oldLeaseAmtKey)
9621165 let newLeaseIdKey = getLeaseIdByAddressKey(newAddrStr)
9631166 let newLeaseAmtKey = getLeaseAmountByAddressKey(newAddrStr)
9641167 let newLease = Lease(addressFromStringValue(newAddrStr), leaseAmt)
9651168 let updatedGroupNodeListS = makeString(split(groupNodeListS, oldAddrStr), newAddrStr)
9661169 $Tuple2([LeaseCancel(getBinaryValue(oldLeaseIdKey)), DeleteEntry(oldLeaseIdKey), DeleteEntry(oldLeaseAmtKey), StringEntry(groupKey, updatedGroupNodeListS), newLease, BinaryEntry(newLeaseIdKey, lcalc(newLease)), IntegerEntry(newLeaseAmtKey, leaseAmt)], unit)
9671170 }
9681171 else throw("Strict value is not equal to itself.")
9691172 }
9701173 }
9711174 }
9721175
9731176
9741177 @Verifier(tx)
9751178 func verify () = {
9761179 let pubKeyAdminsListStr = makeString(["GJdLSaLiv5K7xuejac8mcRcHoyo3dPrESrvktG3a6MAR", "EYwZmURd5KKaQRBjsVa6g8DPisFoS6SovRJtFiL5gMHU", "DtmAfuDdCrHK8spdAeAYzq6MsZegeD9gnsrpuTRkCbVA", "5WRXFSjwcTbNfKcJs8ZqXmSSWYsSVJUtMvMqZj5hH4Nc"], SEP)
9771180 let pubKeyAdminsList = split(valueOrElse(getString(controlContract, "%s__multisig"), pubKeyAdminsListStr), SEP)
9781181 let count = ((((if (sigVerify(tx.bodyBytes, tx.proofs[0], fromBase58String(pubKeyAdminsList[0])))
9791182 then 1
9801183 else 0) + (if (sigVerify(tx.bodyBytes, tx.proofs[1], fromBase58String(pubKeyAdminsList[1])))
9811184 then 1
9821185 else 0)) + (if (sigVerify(tx.bodyBytes, tx.proofs[2], fromBase58String(pubKeyAdminsList[2])))
9831186 then 1
9841187 else 0)) + (if (sigVerify(tx.bodyBytes, tx.proofs[3], fromBase58String(pubKeyAdminsList[3])))
9851188 then 2
9861189 else 0))
9871190 if (if (isBlocked)
9881191 then (getStringValue(controlContract, "is_blocked_caller") == toString(govContract))
9891192 else false)
9901193 then validateUpdate(tx)
9911194 else match tx {
9921195 case sponsorTx: SponsorFeeTransaction =>
9931196 if (checkIsValidMinSponsoredFee(sponsorTx))
9941197 then (count >= 3)
9951198 else false
9961199 case _ =>
9971200 (count >= 3)
9981201 }
9991202 }
10001203

github/deemru/w8io/786bc32 
196.40 ms