tx · 2XfrgjiabnwbsVbRzC5VwMBMLtKD9hRUb4FbuiYBBrB4

3P9VPwVfNj3dDevQZt1Z951A4K57cmQmCgk:  -0.05400000 Waves

2024.04.17 17:07 [4132827] smart account 3P9VPwVfNj3dDevQZt1Z951A4K57cmQmCgk > SELF 0.00000000 Waves

{ "type": 13, "id": "2XfrgjiabnwbsVbRzC5VwMBMLtKD9hRUb4FbuiYBBrB4", "fee": 5400000, "feeAssetId": null, "timestamp": 1713362848579, "version": 2, "chainId": 87, "sender": "3P9VPwVfNj3dDevQZt1Z951A4K57cmQmCgk", "senderPublicKey": "5WWJdfUCEJiV2rQg7doQMAoeYbi3LoAAUxDoF15BPZUZ", "proofs": [ "5hSYVMoRtUgL8ytTbk6K7GchsmY6Cit4NKBjq6vC9bbNXEQJHA2Yd4gVERazyzVqtGNK4e7N2jK1DrkmHsynCgEP" ], "script": "base64:BgJbCAISCAoGCAgICAgBEgASABIDCgEEEgMKAQQSABIDCgEIEgMKAQESABIDCgEIEgQKAggBEgUKAwgIARIDCgEIEgMKAQESBwoFCAgIAQESABIDCgEIEgUKAwgICFMAB1ZFUlNJT04CDVBaLTEuMi4yIFBST0QACWNvbmZpZ1N0cgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzAg1jb25maWdBZGRyZXNzAiMzUFBFQlJnNHMyYWYyclEyWmJMdmR1MUhmZDRWbzZRVkRUbwAOQ09ORklHX0FERFJFU1MDCQAAAgUJY29uZmlnU3RyAgAFBHRoaXMJAQdBZGRyZXNzAQkA2QQBBQljb25maWdTdHIAFUFzc2V0c1dlaWdodHNEZWNpbWFscwAEAAVTY2FsZQCQTgAGU2NhbGU4AIDC1y8AB1NjYWxlMTYAgICE/qbe4REACEZlZVNjYWxlAJBOABFQb29sVG9rZW5EZWNpbWFscwAIAA5Qb29sVG9rZW5TY2FsZQkAbAYACgAABRFQb29sVG9rZW5EZWNpbWFscwAAAAAFBkhBTEZVUAAQTUlOX1NURVBTX0FNT1VOVAkBC3ZhbHVlT3JFbHNlAgkAmggCBQ5DT05GSUdfQUREUkVTUwIQbWluX3N0ZXBzX2Ftb3VudAABABBNQVhfU1RFUFNfQU1PVU5UCQELdmFsdWVPckVsc2UCCQCaCAIFDkNPTkZJR19BRERSRVNTAhBtYXhfc3RlcHNfYW1vdW50APQDABJNSU5fU1RFUFNfSU5URVJWQUwJAQt2YWx1ZU9yRWxzZQIJAJoIAgUOQ09ORklHX0FERFJFU1MCEm1pbl9zdGVwc19pbnRlcnZhbAABABJNQVhfU1RFUFNfSU5URVJWQUwJAQt2YWx1ZU9yRWxzZQIJAJoIAgUOQ09ORklHX0FERFJFU1MCEm1heF9zdGVwc19pbnRlcnZhbACQTgAKTUlOX1dFSUdIVAkBC3ZhbHVlT3JFbHNlAgkAmggCBQ5DT05GSUdfQUREUkVTUwIKbWluX3dlaWdodABkAApNQVhfV0VJR0hUCQELdmFsdWVPckVsc2UCCQCaCAIFDkNPTkZJR19BRERSRVNTAgptYXhfd2VpZ2h0AKxNAQ10cnlHZXRJbnRlZ2VyAQNrZXkEByRtYXRjaDAJAJoIAgUEdGhpcwUDa2V5AwkAAQIFByRtYXRjaDACA0ludAQBYgUHJG1hdGNoMAUBYgAAAQx0cnlHZXRCaW5hcnkBA2tleQQHJG1hdGNoMAkAnAgCBQR0aGlzBQNrZXkDCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQBYgUHJG1hdGNoMAUBYgEAAQx0cnlHZXRTdHJpbmcBA2tleQQHJG1hdGNoMAkAnQgCBQR0aGlzBQNrZXkDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFiBQckbWF0Y2gwBQFiAgABE3RyeUdldFN0cmluZ09yVGhyb3cBA2tleQQHJG1hdGNoMAkAnQgCBQR0aGlzBQNrZXkDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFiBQckbWF0Y2gwBQFiCQACAQkArAICAh1ubyBzdWNoIGtleSBpbiBkYXRhIHN0b3JhZ2U6IAUDa2V5AQ5nZXRBc3NldFN0cmluZwEHYXNzZXRJZAQHJG1hdGNoMAUHYXNzZXRJZAMJAAECBQckbWF0Y2gwAgpCeXRlVmVjdG9yBAFiBQckbWF0Y2gwCQDYBAEFAWICBVdBVkVTAQ1nZXRBc3NldEJ5dGVzAQphc3NldElkU3RyAwkAAAIFCmFzc2V0SWRTdHICBVdBVkVTBQR1bml0CQDZBAEFCmFzc2V0SWRTdHIBD2dldFRva2VuQmFsYW5jZQEHYXNzZXRJZAQHJG1hdGNoMAUHYXNzZXRJZAMJAAECBQckbWF0Y2gwAgpCeXRlVmVjdG9yBAF0BQckbWF0Y2gwCQDwBwIFBHRoaXMFAXQICQDvBwEFBHRoaXMJYXZhaWxhYmxlARNhZGRBc3NldEJ5dGVzVG9MaXN0AgVhY2N1bQRpdGVtCQDOCAIFBWFjY3VtCQDMCAIJAQ1nZXRBc3NldEJ5dGVzAQUEaXRlbQUDbmlsARRhZGRBc3NldFdlaWdodFRvTGlzdAIFYWNjdW0EaXRlbQkAzggCBQVhY2N1bQkAzAgCCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdzdGF0aWNfCQEOZ2V0QXNzZXRTdHJpbmcBBQRpdGVtAgdfd2VpZ2h0BQNuaWwBF2FkZEFzc2V0V2VpZ2h0VG9TdHJMaXN0AgVhY2N1bQRpdGVtCQDOCAIFBWFjY3VtCQDMCAIJAKQDAQkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwUEaXRlbQIHX3dlaWdodAUDbmlsARZhZGRBc3NldERlY2ltYWxzVG9MaXN0AgVhY2N1bQRpdGVtCQDOCAIFBWFjY3VtCQDMCAIJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18JAQ5nZXRBc3NldFN0cmluZwEFBGl0ZW0CCV9kZWNpbWFscwUDbmlsARNhZGRBc3NldFNjYWxlVG9MaXN0AgVhY2N1bQRpdGVtCQDOCAIFBWFjY3VtCQDMCAIJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18JAQ5nZXRBc3NldFN0cmluZwEFBGl0ZW0CBl9zY2FsZQUDbmlsAQxhZGRJbnRUb0xpc3QCBWFjY3VtBGl0ZW0JAM4IAgUFYWNjdW0JAMwIAgkBDXBhcnNlSW50VmFsdWUBBQRpdGVtBQNuaWwADnVzZG5Bc3NldElkU3RyCQELdmFsdWVPckVsc2UCCQCdCAIFDkNPTkZJR19BRERSRVNTAg51c2RuQXNzZXRJZFN0cgIsREcyeEZrUGREd0tVb0JrekdBaFF0THBTR3pmWExpQ1lQRXplS0gyQWQyNHAAEHB1enpsZUFzc2V0SWRTdHIJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCEHB1enpsZUFzc2V0SWRTdHICLEhFQjhRYXc5eHJXcFdzOHRIc2lBVFlHQldEQnRQMlM3a2NQQUxyTXU0M0FTAA51c2R0QXNzZXRJZFN0cgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIOdXNkdEFzc2V0SWRTdHICLDM0TjlZY0VFVExXbjkzcVlRNjRFc1AxeDg5dFNydUpVNDRSckVNU1hYRVBKABF1c2R0UHB0QXNzZXRJZFN0cgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIRdXNkdFBwdEFzc2V0SWRTdHICLDl3YzNMWE5BNFRFQnNYeUt0b0xFOW1yYkREN1dNSFh2WHJDalp2YWJMQXNpAA5yb21lQXNzZXRJZFN0cgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIOcm9tZUFzc2V0SWRTdHICLEFQNENiNXhMWUdINlppZ0hyZUNaSG9YcFFUV0RrUHNHMkJIcWZEVXg2dGFKAA93YXZlc0Fzc2V0SWRTdHICBVdBVkVTAAt1c2RuQXNzZXRJZAkA2QQBBQ51c2RuQXNzZXRJZFN0cgANcHV6emxlQXNzZXRJZAkA2QQBBRBwdXp6bGVBc3NldElkU3RyAAt1c2R0QXNzZXRJZAkA2QQBBQ51c2R0QXNzZXRJZFN0cgAOdXNkdFBwdEFzc2V0SWQJANkEAQURdXNkdFBwdEFzc2V0SWRTdHIAC3JvbWVBc3NldElkCQDZBAEFDnJvbWVBc3NldElkU3RyAAx3YXZlc0Fzc2V0SWQFBHVuaXQAFXN1cHBvcnRlZEZlZUFzc2V0c1N0cgkAzAgCBQ51c2RuQXNzZXRJZFN0cgkAzAgCBRBwdXp6bGVBc3NldElkU3RyCQDMCAIFDnVzZHRBc3NldElkU3RyCQDMCAIFEXVzZHRQcHRBc3NldElkU3RyCQDMCAIFD3dhdmVzQXNzZXRJZFN0cgkAzAgCBQ5yb21lQXNzZXRJZFN0cgUDbmlsABFwYXJlbnRQb29sQWRkcmVzcwkBB0FkZHJlc3MBCQDZBAEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCEXBhcmVudFBvb2xBZGRyZXNzAiMzUEZEZ3p1MVV0c3dBa0NNeHFxUWpiVGVIYVg0Y01hYjhLaAANbWFzdGVyQWRkcmVzcwkBB0FkZHJlc3MBCQDZBAEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCDW1hc3RlckFkZHJlc3MCIzNQTGp3SGN6OU5FdWFUbzYzTlpSOUI5b2tRaUtReFpTYm1mAAxtYXN0ZXJQdWJLZXkJANkEAQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIMbWFzdGVyUHViS2V5Aiw0ejhDS1NZUUJLa3p4N1BCYjV1QlAxWVBhNllBSFJOVEFwVzFzUVZIVDVlVQANb3JhY2xlQWRkcmVzcwkBB0FkZHJlc3MBCQDZBAEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCDW9yYWNsZUFkZHJlc3MCIzNQOGQxRTFCTEtvRDUyeTNiUUoxYkRUZDJURDFncGFMbjl0AA5zdGFraW5nQWRkcmVzcwkBB0FkZHJlc3MBCQDZBAEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCDnN0YWtpbmdBZGRyZXNzAiMzUEZUYnl3cXh0RmZ1a1gzSHlUODgxZzRpVzVLNFFMM0ZBUwALZmVlc0FkZHJlc3MJAQdBZGRyZXNzAQkA2QQBCQELdmFsdWVPckVsc2UCCQCdCAIFDkNPTkZJR19BRERSRVNTAgtmZWVzQWRkcmVzcwIjM1BGV0FWS21YamZIWHl6SmIxMmpDYmhQNFVoaTl0NHVXaUQAD3Bvb2xzSHViQWRkcmVzcwkBB0FkZHJlc3MBCQDZBAEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCD3Bvb2xzSHViQWRkcmVzcwIjM1A1WXV0akROQzNoQUJCVnN2ZUZ1WlRUYlE1UGR0U0RCZ2sAEnNodXRkb3duQWRkcmVzc1N0cgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIPc2h1dGRvd25BZGRyZXNzAiMzUEVwdjloUkZXRUVCVTIyV1JuTHN3MWJINFlHdGNVNzI4bwAPbGF5ZXIyQWRkcmVzc2VzCQELdmFsdWVPckVsc2UCCQCdCAIFDkNPTkZJR19BRERSRVNTAg9sYXllcjJBZGRyZXNzZXMCRzNQUjFRdmk5bUhUMzVTd1dFa0xTcXFFMkw4dGhpUExkVldVLDNQUW9CZlVLSGtKQWVHV2hvb0xQN1dTOG92YjU0YXY5SnAyAApnb3ZBZGRyZXNzCQEHQWRkcmVzcwEJANkEAQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIKZ292QWRkcmVzcwIjM1A2dXJvOXhDc0U4dGU3OFFaanpxeTdhcThuYXRTemRjZUMAEWNvbGRNYXN0ZXJBZGRyZXNzCQEHQWRkcmVzcwEJANkEAQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIRY29sZE1hc3RlckFkZHJlc3MCIzNQSzluaFBmUGJNQnlnQjlaZ0hWTUhhUWJTb29qd3JCZnhqAAFUCQENdHJ5R2V0SW50ZWdlcgECE3N0YXRpY190b2tlbnNBbW91bnQACGFzc2V0SWRzCgACJGwJALUJAgkBDHRyeUdldFN0cmluZwECD3N0YXRpY190b2tlbklkcwIBLAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQETYWRkQXNzZXRCeXRlc1RvTGlzdAIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgANQXNzZXRzV2VpZ2h0cwoAAiRsBQhhc3NldElkcwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMV8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEUYWRkQXNzZXRXZWlnaHRUb0xpc3QCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjFfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGYxXzICCQEFJGYxXzECCQEFJGYxXzECCQEFJGYxXzECCQEFJGYxXzECCQEFJGYxXzECCQEFJGYxXzECCQEFJGYxXzECCQEFJGYxXzECCQEFJGYxXzECCQEFJGYxXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoACERlY2ltYWxzCgACJGwFCGFzc2V0SWRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYyXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARZhZGRBc3NldERlY2ltYWxzVG9MaXN0AgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYyXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmMl8yAgkBBSRmMl8xAgkBBSRmMl8xAgkBBSRmMl8xAgkBBSRmMl8xAgkBBSRmMl8xAgkBBSRmMl8xAgkBBSRmMl8xAgkBBSRmMl8xAgkBBSRmMl8xAgkBBSRmMl8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAAZTY2FsZXMKAAIkbAUIYXNzZXRJZHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjNfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBE2FkZEFzc2V0U2NhbGVUb0xpc3QCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjNfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGYzXzICCQEFJGYzXzECCQEFJGYzXzECCQEFJGYzXzECCQEFJGYzXzECCQEFJGYzXzECCQEFJGYzXzECCQEFJGYzXzECCQEFJGYzXzECCQEFJGYzXzECCQEFJGYzXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoAA0ZlZQkBDXRyeUdldEludGVnZXIBAgpzdGF0aWNfZmVlAAxlYXJuZWRBc3NldHMFCGFzc2V0SWRzAQppc1NodXRkb3duAAQPc2h1dGRvd25BZGRyZXNzCQCmCAEFEnNodXRkb3duQWRkcmVzc1N0cgMJAAACBQ9zaHV0ZG93bkFkZHJlc3MFBHVuaXQHBAckbWF0Y2gwCQCbCAIJAQV2YWx1ZQEFD3NodXRkb3duQWRkcmVzcwILaXNfc2h1dGRvd24DCQABAgUHJG1hdGNoMAIHQm9vbGVhbgQBeAUHJG1hdGNoMAUBeAcBFmdldEN1cnJlbnRUb2tlbkJhbGFuY2UBCHRva2VuTnVtBAp0b2tlbklkU3RyCQEOZ2V0QXNzZXRTdHJpbmcBCQCRAwIFCGFzc2V0SWRzBQh0b2tlbk51bQkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHZ2xvYmFsXwUKdG9rZW5JZFN0cgIIX2JhbGFuY2UBCGdldEtNdWx0AAQHJG1hdGNoMAkAnwgBAgxzdGF0aWNfS011bHQDCQABAgUHJG1hdGNoMAIDSW50BAF4BQckbWF0Y2gwBQF4BQdTY2FsZTE2ARJzYXZlQ3VycmVudFdlaWdodHMABAphc3NldElkc0xpCQC1CQIJAQx0cnlHZXRTdHJpbmcBAg9zdGF0aWNfdG9rZW5JZHMCASwKAQFzAgVhY2N1bQdhc3NldElkCQDOCAIFBWFjY3VtCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgICFnJlYmFsYW5jZV9zdGFydFdlaWdodF8FB2Fzc2V0SWQJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18FB2Fzc2V0SWQCB193ZWlnaHQFA25pbAoAAiRsBQphc3NldElkc0xpCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQFzAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY0XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNF8yAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKARlnZXRWaXJ0dWFsUG9vbFRva2VuQW1vdW50AAkAawMJAQ10cnlHZXRJbnRlZ2VyAQIXZ2xvYmFsX3Bvb2xUb2tlbl9hbW91bnQJAQhnZXRLTXVsdAAFB1NjYWxlMTYBEGNhbGN1bGF0ZVBJc3N1ZWQCBmFtb3VudAd0b2tlbklkBAdQc3VwcGx5CQEZZ2V0VmlydHVhbFBvb2xUb2tlbkFtb3VudAAEB0JhbGFuY2UJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB2dsb2JhbF8JAQ5nZXRBc3NldFN0cmluZwEFB3Rva2VuSWQCCF9iYWxhbmNlBAJ0MQkAbgQFBmFtb3VudAUHUHN1cHBseQUHQmFsYW5jZQUERE9XTgUCdDEBDWdldE1pblBJc3N1ZWQBCHBheW1lbnRzCgEHaGFuZGxlcgIFYWNjdW0HY3VycmVudAQHUElzc3VlZAkBEGNhbGN1bGF0ZVBJc3N1ZWQCCAUHY3VycmVudAZhbW91bnQIBQdjdXJyZW50B2Fzc2V0SWQDCQAAAgUHUElzc3VlZAAACQACAQIkb25lIG9mIHRoZSB0b2tlbnMgYW1vdW50cyBpcyB0b28gbG93AwMJAAACBQVhY2N1bQAABgkAZgIFBWFjY3VtBQdQSXNzdWVkBQdQSXNzdWVkBQVhY2N1bQQJbWluUElzc2VkCgACJGwFCHBheW1lbnRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAAACgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQdoYW5kbGVyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY0XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNF8yAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKBQltaW5QSXNzZWQBEmNhbGN1bGF0ZVVzZG5WYWx1ZQQHYXNzZXRJZAZhbW91bnQIYUJhbGFuY2UQZ2l2ZW5Vc2RuQmFsYW5jZQQKdXNkbkluUG9vbAkAzwgCBQhhc3NldElkcwULdXNkbkFzc2V0SWQEDHB1enpsZUluUG9vbAkAzwgCBQhhc3NldElkcwUNcHV6emxlQXNzZXRJZAQKdXNkdEluUG9vbAkAzwgCBQhhc3NldElkcwULdXNkdEFzc2V0SWQEDXVzZHRQcHRJblBvb2wJAM8IAgUIYXNzZXRJZHMFDnVzZHRQcHRBc3NldElkBAt3YXZlc0luUG9vbAkAzwgCBQhhc3NldElkcwUEdW5pdAQLYXNzZXRXZWlnaHQJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18JAQ5nZXRBc3NldFN0cmluZwEFB2Fzc2V0SWQCB193ZWlnaHQEC2ZlZUFzc2V0U3RyCQEMdHJ5R2V0U3RyaW5nAQIPc3RhdGljX2ZlZVRva2VuAwkAAAIFC2ZlZUFzc2V0U3RyBRBwdXp6bGVBc3NldElkU3RyBAxwdXp6bGVXZWlnaHQJAJEDAgUNQXNzZXRzV2VpZ2h0cwkBBXZhbHVlAQkAzwgCBQhhc3NldElkcwUNcHV6emxlQXNzZXRJZAQNcHV6emxlQmFsYW5jZQkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHZ2xvYmFsXwUQcHV6emxlQXNzZXRJZFN0cgIIX2JhbGFuY2UEDmFtb3VudEluUHV6emxlCQBrAwUGYW1vdW50CQBpAgUNcHV6emxlQmFsYW5jZQUMcHV6emxlV2VpZ2h0CQBpAgUIYUJhbGFuY2UFC2Fzc2V0V2VpZ2h0BAtwdXp6bGVQcmljZQkBEUBleHRyTmF0aXZlKDEwNTApAgURcGFyZW50UG9vbEFkZHJlc3MCFmdsb2JhbF9sYXN0UHV6emxlUHJpY2UJAGsDCQBoAgUOYW1vdW50SW5QdXp6bGUFC3B1enpsZVByaWNlAAEFBlNjYWxlOAMJAAACBQtmZWVBc3NldFN0cgUOdXNkdEFzc2V0SWRTdHIECnVzZHRXZWlnaHQJAJEDAgUNQXNzZXRzV2VpZ2h0cwkBBXZhbHVlAQUKdXNkdEluUG9vbAQLdXNkdEJhbGFuY2UJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB2dsb2JhbF8FDnVzZHRBc3NldElkU3RyAghfYmFsYW5jZQkAawMFBmFtb3VudAkAaQIFC3VzZHRCYWxhbmNlBQp1c2R0V2VpZ2h0CQBpAgUIYUJhbGFuY2UFC2Fzc2V0V2VpZ2h0AwkAAAIFC2ZlZUFzc2V0U3RyBRF1c2R0UHB0QXNzZXRJZFN0cgQKdXNkdFdlaWdodAkAkQMCBQ1Bc3NldHNXZWlnaHRzCQEFdmFsdWUBBQ11c2R0UHB0SW5Qb29sBAt1c2R0QmFsYW5jZQkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHZ2xvYmFsXwURdXNkdFBwdEFzc2V0SWRTdHICCF9iYWxhbmNlCQBrAwUGYW1vdW50CQBpAgULdXNkdEJhbGFuY2UFCnVzZHRXZWlnaHQJAGkCBQhhQmFsYW5jZQULYXNzZXRXZWlnaHQDCQAAAgULZmVlQXNzZXRTdHIFDnVzZG5Bc3NldElkU3RyBAp1c2RuV2VpZ2h0CQCRAwIFDUFzc2V0c1dlaWdodHMJAQV2YWx1ZQEJAM8IAgUIYXNzZXRJZHMFC3VzZG5Bc3NldElkBAt1c2RuQmFsYW5jZQQHJG1hdGNoMAUQZ2l2ZW5Vc2RuQmFsYW5jZQMJAAECBQckbWF0Y2gwAgNJbnQEAXgFByRtYXRjaDAFEGdpdmVuVXNkbkJhbGFuY2UJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB2dsb2JhbF8JAQ5nZXRBc3NldFN0cmluZwEFC3VzZG5Bc3NldElkAghfYmFsYW5jZQkAawMFBmFtb3VudAkAaQIJAQV2YWx1ZQEFC3VzZG5CYWxhbmNlBQp1c2RuV2VpZ2h0CQBpAgUIYUJhbGFuY2UFC2Fzc2V0V2VpZ2h0BAt3YXZlc1dlaWdodAC4FwQId0JhbGFuY2UJAGkCCQENdHJ5R2V0SW50ZWdlcgECFGdsb2JhbF9XQVZFU19iYWxhbmNlADIJAGsDBQZhbW91bnQJAGkCBQh3QmFsYW5jZQULd2F2ZXNXZWlnaHQJAGkCBQhhQmFsYW5jZQULYXNzZXRXZWlnaHQBEmdldFByaWNlRnJvbU9yYWNsZQEKYXNzZXRJZFN0cgQHJG1hdGNoMAkAmggCBQ1vcmFjbGVBZGRyZXNzCQCsAgIFCmFzc2V0SWRTdHICB190d2FwNUIDCQABAgUHJG1hdGNoMAIDSW50BAF4BQckbWF0Y2gwBQF4AAABEWNhbGN1bGF0ZVVzZFZhbHVlAwdhc3NldElkBmFtb3VudAhhQmFsYW5jZQQLYXNzZXRXZWlnaHQJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18JAQ5nZXRBc3NldFN0cmluZwEFB2Fzc2V0SWQCB193ZWlnaHQEC2ZlZUFzc2V0U3RyCQEMdHJ5R2V0U3RyaW5nAQIPc3RhdGljX2ZlZVRva2VuBA1mZWVBc3NldFNjYWxlCQERQGV4dHJOYXRpdmUoMTA1MCkCBQR0aGlzCQCsAgIJAKwCAgIHc3RhdGljXwULZmVlQXNzZXRTdHICBl9zY2FsZQQLZmVlQXNzZXROdW0JAQV2YWx1ZQEJAM8IAgUIYXNzZXRJZHMJAQ1nZXRBc3NldEJ5dGVzAQULZmVlQXNzZXRTdHIEDmZlZUFzc2V0V2VpZ2h0CQCRAwIFDUFzc2V0c1dlaWdodHMFC2ZlZUFzc2V0TnVtBA9mZWVBc3NldEJhbGFuY2UJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB2dsb2JhbF8FC2ZlZUFzc2V0U3RyAghfYmFsYW5jZQQNdmFsSW5GZWVBc3NldAkAawMFBmFtb3VudAkAaQIFD2ZlZUFzc2V0QmFsYW5jZQUOZmVlQXNzZXRXZWlnaHQJAGkCBQhhQmFsYW5jZQULYXNzZXRXZWlnaHQEDWZlZUFzc2V0UHJpY2UJARJnZXRQcmljZUZyb21PcmFjbGUBBQtmZWVBc3NldFN0cgkAawMFDXZhbEluRmVlQXNzZXQFDWZlZUFzc2V0UHJpY2UFDWZlZUFzc2V0U2NhbGUBE2NoZWNrVG9rZW5zVmFsaWRpdHkBCHBheW1lbnRzCgEIaGFuZGxlcjECBWFjY3VtB3BheW1lbnQJAM4IAgUFYWNjdW0JAMwIAggFB3BheW1lbnQHYXNzZXRJZAUDbmlsBANpZHMKAAIkbAUIcGF5bWVudHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjRfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBCGhhbmRsZXIxAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY0XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNF8yAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAwkAAAIFA2lkcwUDaWRzCgEIaGFuZGxlcjICBWFjY3VtB2Fzc2V0SWQDCQECIT0CCQDPCAIFA2lkcwUHYXNzZXRJZAUEdW5pdAkAZAIFBWFjY3VtAAEJAAIBCQCsAgICFGFzc2V0IG5vdCBhdHRhY2hlZDogCQEOZ2V0QXNzZXRTdHJpbmcBBQdhc3NldElkBAZjaGVja3MKAAIkbAUIYXNzZXRJZHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwAAAKAQUkZjVfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBCGhhbmRsZXIyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY1XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNV8yAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAwkAAAIFBmNoZWNrcwUGY2hlY2tzBgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgETaGFuZGxlUG9vbFRva2Vuc0FkZAQHUElzc3VlZAhwYXltZW50cwt1c2VyQWRkcmVzcwpuZWVkQ2hhbmdlCgEVZ2V0VG9rZW5QYXltZW50QW1vdW50AQd0b2tlbklkCgEHaGFuZGxlcgIFYWNjdW0HcGF5bWVudAMJAAACCAUHcGF5bWVudAdhc3NldElkBQd0b2tlbklkCAUHcGF5bWVudAZhbW91bnQFBWFjY3VtCgACJGwFCHBheW1lbnRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAAACgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQdoYW5kbGVyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY0XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNF8yAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKCgERaGFuZGxlVG9rZW5DaGFuZ2UCBWFjY3VtB3Rva2VuSWQEAkJrCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdnbG9iYWxfCQEOZ2V0QXNzZXRTdHJpbmcBBQd0b2tlbklkAghfYmFsYW5jZQQHUFN1cHBseQkBGWdldFZpcnR1YWxQb29sVG9rZW5BbW91bnQABA10b2tlbkRlY2ltYWxzCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdzdGF0aWNfCQEOZ2V0QXNzZXRTdHJpbmcBBQd0b2tlbklkAgZfc2NhbGUEAmExCQC9AgQJALkCAgkAtgIBCQBkAgUHUFN1cHBseQUHUElzc3VlZAkAtgIBBQZTY2FsZTgJALYCAQUNdG9rZW5EZWNpbWFscwkAtgIBBQdQU3VwcGx5BQdDRUlMSU5HBAJEawkAoAMBCQC9AgQJALgCAgUCYTEJALkCAgkAtgIBBQ10b2tlbkRlY2ltYWxzCQC2AgEFBlNjYWxlOAkAtgIBBQJCawkAuQICCQC2AgEFDXRva2VuRGVjaW1hbHMJALYCAQUGU2NhbGU4BQdDRUlMSU5HBA1wYXltZW50QW1vdW50CQEVZ2V0VG9rZW5QYXltZW50QW1vdW50AQUHdG9rZW5JZAQIdG9SZXR1cm4JAGUCBQ1wYXltZW50QW1vdW50BQJEawQBdAMDBQpuZWVkQ2hhbmdlCQBmAgUIdG9SZXR1cm4AAAcJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwULdXNlckFkZHJlc3MFCHRvUmV0dXJuBQd0b2tlbklkBQNuaWwFA25pbAkAzggCCQDOCAIFBWFjY3VtBQF0CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgIHZ2xvYmFsXwkBDmdldEFzc2V0U3RyaW5nAQUHdG9rZW5JZAIIX2JhbGFuY2UJAGQCBQJCawUCRGsFA25pbAoAAiRsBQhhc3NldElkcwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmNF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQERaGFuZGxlVG9rZW5DaGFuZ2UCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjRfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY0XzICCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoBFmhhbmRsZVBvb2xUb2tlbnNSZWRlZW0CCVBSZWRlZW1lZAt1c2VyQWRkcmVzcwoBEWhhbmRsZVRva2VuUmVkZWVtAgVhY2N1bQd0b2tlbklkBAJCawkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHZ2xvYmFsXwkBDmdldEFzc2V0U3RyaW5nAQUHdG9rZW5JZAIIX2JhbGFuY2UEB1BTdXBwbHkJARlnZXRWaXJ0dWFsUG9vbFRva2VuQW1vdW50AAQNdG9rZW5EZWNpbWFscwkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwkBDmdldEFzc2V0U3RyaW5nAQUHdG9rZW5JZAIGX3NjYWxlBAZwc3VwcGwJAL0CBAkAuQICCQC2AgEJAGUCBQdQU3VwcGx5BQlQUmVkZWVtZWQJALYCAQUGU2NhbGU4CQC2AgEFBlNjYWxlOAkAtgIBBQdQU3VwcGx5BQRET1dOBAZhbW91bnQJAKADAQkAvQIECQC4AgIJALYCAQUHU2NhbGUxNgUGcHN1cHBsCQC2AgEFAkJrCQC2AgEFB1NjYWxlMTYFB0NFSUxJTkcJAM4IAgUFYWNjdW0JAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICAgdnbG9iYWxfCQEOZ2V0QXNzZXRTdHJpbmcBBQd0b2tlbklkAghfYmFsYW5jZQkAZQIFAkJrBQZhbW91bnQJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwULdXNlckFkZHJlc3MFBmFtb3VudAUHdG9rZW5JZAUDbmlsCgACJGwFCGFzc2V0SWRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARFoYW5kbGVUb2tlblJlZGVlbQIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjRfMgIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgESY2FsY3VsYXRlT3V0QW1vdW50BQhBbW91bnRJbgdhc3NldEluCGFzc2V0T3V0CUJhbGFuY2VJbgpCYWxhbmNlT3V0BAdJbmRleEluCQEFdmFsdWUBCQDPCAIFCGFzc2V0SWRzBQdhc3NldEluBAhJbmRleE91dAkBBXZhbHVlAQkAzwgCBQhhc3NldElkcwUIYXNzZXRPdXQDCQAAAgUHSW5kZXhJbgUISW5kZXhPdXQFCEFtb3VudEluCQBuBAUKQmFsYW5jZU91dAkAZQIJAGgCBQZTY2FsZTgFBlNjYWxlOAkAoAMBCQB2BgkAvQIECQC5AgIJALYCAQUJQmFsYW5jZUluCQC2AgEAkE4JALYCAQkAaAIFBlNjYWxlOAUGU2NhbGU4CQC5AgIJALYCAQkAZAIFCUJhbGFuY2VJbgUIQW1vdW50SW4JALYCAQCQTgUGSEFMRlVQABAJALYCAQkAawMJAJEDAgUNQXNzZXRzV2VpZ2h0cwUHSW5kZXhJbgCAoJSljR0JAJEDAgUNQXNzZXRzV2VpZ2h0cwUISW5kZXhPdXQADAAQBQdDRUlMSU5HCQBoAgUGU2NhbGU4BQZTY2FsZTgFCEhBTEZFVkVOAR1jYWxjdWxhdGVDdXJyZW50QXNzZXRJbnRlcmVzdAQHYXNzZXRJZAphc3NldElkU3RyCGFCYWxhbmNlFnRva2VuRWFybmluZ3NMYXN0Q2hlY2sEC3RvdGFsU3Rha2VkCQENdHJ5R2V0SW50ZWdlcgECEmdsb2JhbF9pbmRleFN0YWtlZAQVdG9rZW5CYWxhbmNlTGFzdENoZWNrBRZ0b2tlbkVhcm5pbmdzTGFzdENoZWNrBBNjdXJyZW50QmFsYW5jZURlbHRhCQBlAgkBD2dldFRva2VuQmFsYW5jZQEFB2Fzc2V0SWQFCGFCYWxhbmNlBBRjdXJyZW50VG9rZW5FYXJuaW5ncwMJAGYCBRNjdXJyZW50QmFsYW5jZURlbHRhBRV0b2tlbkJhbGFuY2VMYXN0Q2hlY2sFE2N1cnJlbnRCYWxhbmNlRGVsdGEFFXRva2VuQmFsYW5jZUxhc3RDaGVjawQLbmV3RWFybmluZ3MJAGUCBRRjdXJyZW50VG9rZW5FYXJuaW5ncwUVdG9rZW5CYWxhbmNlTGFzdENoZWNrBAtuZXdJbnRlcmVzdAMJAAACBQt0b3RhbFN0YWtlZAAAAAAJAGsDBQtuZXdFYXJuaW5ncwUGU2NhbGU4BQt0b3RhbFN0YWtlZAQRbGFzdENoZWNrSW50ZXJlc3QJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICEWdsb2JhbF9sYXN0Q2hlY2tfBQphc3NldElkU3RyAglfaW50ZXJlc3QJAGQCBRFsYXN0Q2hlY2tJbnRlcmVzdAULbmV3SW50ZXJlc3QBC2NsYWltUmVzdWx0AQdhZGRyZXNzBAphZGRyZXNzU3RyCQClCAEFB2FkZHJlc3MEDHB1enpsZUFtb3VudAkBDXRyeUdldEludGVnZXIBCQCsAgIFCmFkZHJlc3NTdHICDF9pbmRleFN0YWtlZAoBB2hhbmRsZXICBWFjY3VtB2Fzc2V0SWQECmFzc2V0SWRTdHIJAQ5nZXRBc3NldFN0cmluZwEFB2Fzc2V0SWQECGFCYWxhbmNlCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdnbG9iYWxfCQEOZ2V0QXNzZXRTdHJpbmcBBQdhc3NldElkAghfYmFsYW5jZQQWdG9rZW5FYXJuaW5nc0xhc3RDaGVjawkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIRZ2xvYmFsX2xhc3RDaGVja18FCmFzc2V0SWRTdHICCV9lYXJuaW5ncwQUY3VycmVudFRva2VuSW50ZXJlc3QJAR1jYWxjdWxhdGVDdXJyZW50QXNzZXRJbnRlcmVzdAQFB2Fzc2V0SWQFCmFzc2V0SWRTdHIFCGFCYWxhbmNlBRZ0b2tlbkVhcm5pbmdzTGFzdENoZWNrBBRjdXJyZW50VG9rZW5FYXJuaW5ncwkAlgMBCQDMCAIFFnRva2VuRWFybmluZ3NMYXN0Q2hlY2sJAMwIAgkAZQIJAQ9nZXRUb2tlbkJhbGFuY2UBBQdhc3NldElkBQhhQmFsYW5jZQUDbmlsBAxyZXdhcmRBbW91bnQJAGsDBQxwdXp6bGVBbW91bnQJAGUCBRRjdXJyZW50VG9rZW5JbnRlcmVzdAkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgkArAICBQphZGRyZXNzU3RyAgtfbGFzdENoZWNrXwUKYXNzZXRJZFN0cgIJX2ludGVyZXN0BQZTY2FsZTgECHRyYW5zZmVyAwkAAAIFDHJld2FyZEFtb3VudAAABQNuaWwJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwUHYWRkcmVzcwUMcmV3YXJkQW1vdW50BQdhc3NldElkBQNuaWwJAJQKAgkAzggCCQDOCAIIBQVhY2N1bQJfMQUIdHJhbnNmZXIJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICAhFnbG9iYWxfbGFzdENoZWNrXwUKYXNzZXRJZFN0cgIJX2Vhcm5pbmdzCQBlAgUUY3VycmVudFRva2VuRWFybmluZ3MFDHJld2FyZEFtb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgICEWdsb2JhbF9sYXN0Q2hlY2tfBQphc3NldElkU3RyAglfaW50ZXJlc3QFFGN1cnJlbnRUb2tlbkludGVyZXN0CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgkArAICBQphZGRyZXNzU3RyAgtfbGFzdENoZWNrXwUKYXNzZXRJZFN0cgIJX2ludGVyZXN0BRRjdXJyZW50VG9rZW5JbnRlcmVzdAUDbmlsCQBkAggFBWFjY3VtAl8yCQERY2FsY3VsYXRlVXNkVmFsdWUDBQdhc3NldElkBQxyZXdhcmRBbW91bnQFCGFCYWxhbmNlBAVhY2N1bQoAAiRsBQxlYXJuZWRBc3NldHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwCQCUCgIFA25pbAAACgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQdoYW5kbGVyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY0XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNF8yAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKCQCUCgIJAM4IAggFBWFjY3VtAl8xCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIFCmFkZHJlc3NTdHICEV9jbGFpbWVkUmV3YXJkVVNECQBkAgkBDXRyeUdldEludGVnZXIBCQCsAgIFCmFkZHJlc3NTdHICEV9jbGFpbWVkUmV3YXJkVVNECAUFYWNjdW0CXzIJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgUKYWRkcmVzc1N0cgIKX2xhc3RDbGFpbQgFCWxhc3RCbG9jawl0aW1lc3RhbXAFA25pbAgFBWFjY3VtAl8yARBpbmRleFN0YWtlUmVzdWx0AgphZGRyZXNzU3RyBmFtb3VudAQCbGkICQELY2xhaW1SZXN1bHQBCQERQGV4dHJOYXRpdmUoMTA2MikBBQphZGRyZXNzU3RyAl8xCQDOCAIFAmxpCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIFCmFkZHJlc3NTdHICDF9pbmRleFN0YWtlZAkAZAIJAQ10cnlHZXRJbnRlZ2VyAQkArAICBQphZGRyZXNzU3RyAgxfaW5kZXhTdGFrZWQFBmFtb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgISZ2xvYmFsX2luZGV4U3Rha2VkCQBkAgkBDXRyeUdldEludGVnZXIBAhJnbG9iYWxfaW5kZXhTdGFrZWQFBmFtb3VudAUDbmlsAQNzdW0CBWFjY3VtAW4JAGQCBQVhY2N1bQkBDXBhcnNlSW50VmFsdWUBBQFuAQ1jaGVja0ZlZUFzc2V0AgVhY2N1bQRuZXh0AwMJAQIhPQIJAM8IAgUVc3VwcG9ydGVkRmVlQXNzZXRzU3RyBQRuZXh0BQR1bml0CQAAAgUFYWNjdW0CAAcFBG5leHQFBWFjY3VtARJnZXRUbXBSZWJhbGFuY2VJZHMBDW5ld0Fzc2V0SWRzTGkEEWN1cnJlbnRBc3NldElkc0xpCQC1CQIJAQx0cnlHZXRTdHJpbmcBAg9zdGF0aWNfdG9rZW5JZHMCASwEBnJlc3VsdAUNbmV3QXNzZXRJZHNMaQoBAWYCBWFjY3VtB2Fzc2V0SWQDCQAAAgkAzwgCBQZyZXN1bHQFB2Fzc2V0SWQFBHVuaXQJAM4IAgUFYWNjdW0JAMwIAgUHYXNzZXRJZAUDbmlsBQVhY2N1bQoAAiRsBRFjdXJyZW50QXNzZXRJZHNMaQoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFBnJlc3VsdAoBBSRmNF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEBZgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjRfMgIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgERY2hlY2tUb2tlbnNDaGFuZ2UBDW5ld0Fzc2V0SWRzTGkEEWN1cnJlbnRBc3NldElkc0xpCQC1CQIJAQx0cnlHZXRTdHJpbmcBAg9zdGF0aWNfdG9rZW5JZHMCASwKAQNyZW0CBWFjY3VtB2Fzc2V0SWQDCQAAAgkAzwgCBQ1uZXdBc3NldElkc0xpBQdhc3NldElkBQR1bml0CQBkAgUFYWNjdW0AAQUFYWNjdW0KAQNhZGQCBWFjY3VtB2Fzc2V0SWQDCQAAAgkAzwgCBRFjdXJyZW50QXNzZXRJZHNMaQUHYXNzZXRJZAUEdW5pdAkAZAIFBWFjY3VtAAEFBWFjY3VtBAdyZW1vdmVkCgACJGwFEWN1cnJlbnRBc3NldElkc0xpCgACJHMJAJADAQUCJGwKAAUkYWNjMAAACgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQNyZW0CBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjRfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY0XzICCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoEBWFkZGVkCgACJGwFDW5ld0Fzc2V0SWRzTGkKAAIkcwkAkAMBBQIkbAoABSRhY2MwAAAKAQUkZjVfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBA2FkZAIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNV8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjVfMgIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgkAZAIFB3JlbW92ZWQFBWFkZGVkARB2YWxpZGF0ZVBheW1lbnRzAgphc3NldHNMaXN0CHBheW1lbnRzCgEQZ2V0UGF5bWVudEFzc2V0cwIFYWNjdW0EbmV4dAMJAGcCAAAIBQRuZXh0BmFtb3VudAkAAgEJAKwCAgkArAICCQCsAgICG1RvbyBsb3cgcGF5bWVudCBhbW91bnQgZm9yIAkBDmdldEFzc2V0U3RyaW5nAQgFBG5leHQHYXNzZXRJZAICOiAJAKQDAQgFBG5leHQGYW1vdW50CQDOCAIFBWFjY3VtCQDMCAIJAQ5nZXRBc3NldFN0cmluZwEIBQRuZXh0B2Fzc2V0SWQFA25pbAQLcGF5bWVudExpc3QKAAIkbAUIcGF5bWVudHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjRfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBEGdldFBheW1lbnRBc3NldHMCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjRfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY0XzICCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoKAQJmMQIFYWNjdW0EbmV4dAMJAAACCQDPCAIFCmFzc2V0c0xpc3QFBG5leHQFBHVuaXQJAAIBCQCsAgIJAKwCAgUEbmV4dAI5IGFzc2V0IGlzIHByZXNlbnQgaW4gcGF5bWVudHMsIGJ1dCBpcyBub3QgaW4gbmV3IGFzc2V0czogCQC5CQIFCmFzc2V0c0xpc3QCASwJAGQCBQVhY2N1bQABCgECZjICBWFjY3VtBG5leHQDCQAAAgkAzwgCBQtwYXltZW50TGlzdAUEbmV4dAUEdW5pdAkAAgEJAKwCAgkArAICBQRuZXh0AjkgYXNzZXQgaXMgcHJlc2VudCBpbiBuZXcgYXNzZXRzLCBidXQgaXMgbm90IGluIHBheW1lbnRzOiAJALkJAgULcGF5bWVudExpc3QCASwJAGQCBQVhY2N1bQABBAJhMQoAAiRsBQtwYXltZW50TGlzdAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAAAAoBBSRmNV8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQECZjECBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjVfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY1XzICCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoEAmEyCgACJGwFCmFzc2V0c0xpc3QKAAIkcwkAkAMBBQIkbAoABSRhY2MwAAAKAQUkZjZfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBAmYyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY2XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNl8yAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKCQBkAgUCYTEFAmEyAQ92YWxpZGF0ZVdlaWdodHMBB3dlaWdodHMKAQF2AgVhY2N1bQF3BAR3SW50CQETdmFsdWVPckVycm9yTWVzc2FnZQIJALYJAQUBdwkArAICAhVXcm9uZyB3ZWlnaHQgZm9ybWF0OiAFAXcDAwkAZgIFCk1JTl9XRUlHSFQFBHdJbnQGCQBmAgUEd0ludAUKTUFYX1dFSUdIVAkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICAhpXZWlnaHQgc2hvdWxkIGJlIGluIHJhbmdlIAkApAMBBQpNSU5fV0VJR0hUAgMgLSAJAKQDAQUKTUFYX1dFSUdIVAILLCBjdXJyZW50OiAFAXcFBWFjY3VtCgACJGwFB3dlaWdodHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwAAAKAQUkZjRfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBAXYCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjRfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY0XzICCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoSAWkBB3ByZUluaXQGC2Fzc2V0SWRzU3RyD2Fzc2V0V2VpZ2h0c1N0cg5iYXNlVG9rZW5JZFN0cgpwb29sRG9tYWluCXBvb2xPd25lcgNmZWUEEHBvb2xPd25lckFkZHJlc3MJAQdBZGRyZXNzAQkA2QQBBQlwb29sT3duZXIEDWFzc2V0SWRzU3RyTGkJALUJAgULYXNzZXRJZHNTdHICASwECmFzc2V0SWRzTGkKAAIkbAUNYXNzZXRJZHNTdHJMaQoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmNF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQETYWRkQXNzZXRCeXRlc1RvTGlzdAIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjRfMgIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgQLZmVlQXNzZXRTdHIKAAIkbAUNYXNzZXRJZHNTdHJMaQoAAiRzCQCQAwEFAiRsCgAFJGFjYzACAAoBBSRmNV8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQENY2hlY2tGZWVBc3NldAIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNV8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjVfMgIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgMJAQppc1NodXRkb3duAAkAAgECE2NvbnRyYWN0IGlzIG9uIHN0b3ADCQECIT0CBQR0aGlzCAUBaQZjYWxsZXIJAAIBAgphZG1pbiBvbmx5AwkAAAIFC2ZlZUFzc2V0U3RyAgAJAAIBAkFwb29sIG11c3QgaGF2ZSBvbmUgb2YgdGhlIHN1cHBvcnRlZCBmZWUgYXNzZXRzIGluIHRoZSBjb21wb3NpdGlvbgMJAGYCCQCxAgEFCnBvb2xEb21haW4ADQkAAgECFXRvbyBsYXJnZSBwb29sIGRvbWFpbgMDCQBmAgUDZmVlAPQDBgkAZgIAAAUDZmVlCQACAQItZmVlIHZhbHVlIG11c3QgYmUgYmV0d2VlbiA1MCBhbmQgNTAwICgwLjUtNSUpBBFhc3NldFdlaWdodHNTdHJMaQkAtQkCBQ9hc3NldFdlaWdodHNTdHICASwED2Fzc2V0V2VpZ2h0c1N1bQoAAiRsBRFhc3NldFdlaWdodHNTdHJMaQoAAiRzCQCQAwEFAiRsCgAFJGFjYzAAAAoBBSRmNl8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEDc3VtAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY2XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNl8yAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKCgETYWRkVG9rZW5EYXRhRW50cmllcwIFYWNjdW0IYXNzZXROdW0DCQBnAgUIYXNzZXROdW0JAJADAQUKYXNzZXRJZHNMaQUFYWNjdW0EDWFzc2V0RGVjaW1hbHMEByRtYXRjaDAJAJEDAgUKYXNzZXRJZHNMaQUIYXNzZXROdW0DCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQBeAUHJG1hdGNoMAgJAQV2YWx1ZQEJAOwHAQUBeAhkZWNpbWFscwAICQDOCAIFBWFjY3VtCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgIHc3RhdGljXwkAkQMCBQ1hc3NldElkc1N0ckxpBQhhc3NldE51bQIGX3NjYWxlCQBsBgAKAAAFDWFzc2V0RGVjaW1hbHMAAAAABQRET1dOCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgIHc3RhdGljXwkAkQMCBQ1hc3NldElkc1N0ckxpBQhhc3NldE51bQIJX2RlY2ltYWxzBQ1hc3NldERlY2ltYWxzCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgIHc3RhdGljXwkAkQMCBQ1hc3NldElkc1N0ckxpBQhhc3NldE51bQIHX3dlaWdodAkBBXZhbHVlAQkAtgkBCQCRAwIFEWFzc2V0V2VpZ2h0c1N0ckxpBQhhc3NldE51bQUDbmlsAwkBAiE9AgUPYXNzZXRXZWlnaHRzU3VtAJBOCQACAQIrc3VtIG9mIHRva2VuIHdlaWdodHMgbXVzdCBiZSBlcXVhbCB0byAxMDAwMAkAzggCCgACJGwJAMwIAgAACQDMCAIAAQkAzAgCAAIJAMwIAgADCQDMCAIABAkAzAgCAAUJAMwIAgAGCQDMCAIABwkAzAgCAAgJAMwIAgAJBQNuaWwKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjdfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBE2FkZFRva2VuRGF0YUVudHJpZXMCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjdfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY3XzICCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoJAMwIAgkBC1N0cmluZ0VudHJ5AgIPc3RhdGljX3Rva2VuSWRzBQthc3NldElkc1N0cgkAzAgCCQELU3RyaW5nRW50cnkCAg9zdGF0aWNfZmVlVG9rZW4FC2ZlZUFzc2V0U3RyCQDMCAIJAQtTdHJpbmdFbnRyeQICE3N0YXRpY190b2tlbldlaWdodHMFD2Fzc2V0V2VpZ2h0c1N0cgkAzAgCCQEMSW50ZWdlckVudHJ5AgITc3RhdGljX3Rva2Vuc0Ftb3VudAkAkAMBBQphc3NldElkc0xpCQDMCAIJAQtTdHJpbmdFbnRyeQICEXN0YXRpY19wb29sRG9tYWluBQpwb29sRG9tYWluCQDMCAIJAQtTdHJpbmdFbnRyeQICEnN0YXRpY19iYXNlVG9rZW5JZAUOYmFzZVRva2VuSWRTdHIJAMwIAgkBC1N0cmluZ0VudHJ5AgIQc3RhdGljX3Bvb2xPd25lcgUJcG9vbE93bmVyCQDMCAIJAQxJbnRlZ2VyRW50cnkCAgpzdGF0aWNfZmVlBQNmZWUJAMwIAgkBDEludGVnZXJFbnRyeQICDHN0YXRpY19LTXVsdAUHU2NhbGUxNgkAzAgCCQEMSW50ZWdlckVudHJ5AgITZ2xvYmFsX3dhc1ByZUluaXRlZAABBQNuaWwBaQEGZGVJbml0AAMJAQppc1NodXRkb3duAAkAAgECE2NvbnRyYWN0IGlzIG9uIHN0b3ADCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAAIBAgphZG1pbiBvbmx5CQDMCAIJAQxJbnRlZ2VyRW50cnkCAhBnbG9iYWxfd2FzSW5pdGVkAAAFA25pbAFpAQRpbml0AAoBC3ByZXBhcmVMaXN0AAoBB2hhbmRsZXICBWFjY3VtAW4JAM4IAgUFYWNjdW0JAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICAgdnbG9iYWxfCQEOZ2V0QXNzZXRTdHJpbmcBCAUBbgdhc3NldElkAghfYmFsYW5jZQgFAW4GYW1vdW50BQNuaWwKAAIkbAgFAWkIcGF5bWVudHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjRfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBB2hhbmRsZXICBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjRfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY0XzICCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoKARljYWxjdWxhdGVQb29sVG9rZW5zQW1vdW50AQhwYXltZW50cwoBB2hhbmRsZXICBWFjY3VtA3BtdAQHYXNzZXRJZAgFA3BtdAdhc3NldElkCgEIaGFuZGxlcjICBWFjY3VtAW4DCQAAAgUBbgUHYXNzZXRJZAkBBXZhbHVlAQkAzwgCBQhhc3NldElkcwUBbgUFYWNjdW0EBVRva2VuCgACJGwFCGFzc2V0SWRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAABCgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQhoYW5kbGVyMgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjRfMgIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgkAawMFBWFjY3VtCQBsBggFA3BtdAZhbW91bnQJAJEDAgUIRGVjaW1hbHMFBVRva2VuCQCRAwIFDUFzc2V0c1dlaWdodHMFBVRva2VuBRVBc3NldHNXZWlnaHRzRGVjaW1hbHMACAUFRkxPT1IFBlNjYWxlOAoAAiRsBQhwYXltZW50cwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFDlBvb2xUb2tlblNjYWxlCgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQdoYW5kbGVyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY0XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNF8yAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAwkBCmlzU2h1dGRvd24ACQACAQITY29udHJhY3QgaXMgb24gc3RvcAMJAGYCCQENdHJ5R2V0SW50ZWdlcgECEGdsb2JhbF93YXNJbml0ZWQAAAkAAgECE3Bvb2wgYWxyZWFkeSBpbml0ZWQEEWluaXRpYWxQb29sVG9rZW5zCQEZY2FsY3VsYXRlUG9vbFRva2Vuc0Ftb3VudAEIBQFpCHBheW1lbnRzAwkAAAIFEWluaXRpYWxQb29sVG9rZW5zAAAJAAIBAjJ5b3UgbmVlZCBhIGJpZ2dlciB0b2tlbnMgYW1vdW50IHRvIGxhdW5jaCB0aGUgcG9vbAQOcG9vbFRva2VuSXNzdWUJAMMIBwkArAICAgNQWiAJAQx0cnlHZXRTdHJpbmcBAhFzdGF0aWNfcG9vbERvbWFpbgIdUHV6emxlIFN3YXA6IHBvb2wgaW5kZXggdG9rZW4FEWluaXRpYWxQb29sVG9rZW5zBRFQb29sVG9rZW5EZWNpbWFscwYFBHVuaXQAAAQLcG9vbFRva2VuSWQJALgIAQUOcG9vbFRva2VuSXNzdWUJAM4IAgkBC3ByZXBhcmVMaXN0AAkAzAgCBQ5wb29sVG9rZW5Jc3N1ZQkAzAgCCQEMSW50ZWdlckVudHJ5AgIXZ2xvYmFsX3Bvb2xUb2tlbl9hbW91bnQFEWluaXRpYWxQb29sVG9rZW5zCQDMCAIJAQxJbnRlZ2VyRW50cnkCAhBnbG9iYWxfd2FzSW5pdGVkAAEJAMwIAgkBC0JpbmFyeUVudHJ5AgITZ2xvYmFsX3Bvb2xUb2tlbl9pZAULcG9vbFRva2VuSWQJAMwIAgkBC1N0cmluZ0VudHJ5AgIWc3RhdGljX3Bvb2xUb2tlbl9pZFN0cgkBDmdldEFzc2V0U3RyaW5nAQULcG9vbFRva2VuSWQJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkApQgBCAUBaQZjYWxsZXICDF9pbmRleFN0YWtlZAURaW5pdGlhbFBvb2xUb2tlbnMJAMwIAgkBDEludGVnZXJFbnRyeQICEmdsb2JhbF9pbmRleFN0YWtlZAURaW5pdGlhbFBvb2xUb2tlbnMFA25pbAFpAQ1nZW5lcmF0ZUluZGV4AQpuZWVkQ2hhbmdlAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwUBVAkAAgEJAKwCAgI7eW91IG5lZWQgdG8gYXR0YWNoIGFsbCBwb29sIHRva2Vucy4gYW1vdW50IG9mIHBvb2wgdG9rZW5zOiAJAKQDAQUBVAMJAQEhAQkBE2NoZWNrVG9rZW5zVmFsaWRpdHkBCAUBaQhwYXltZW50cwkAAgECFXdyb25nIGFzc2V0cyBhdHRhY2hlZAQNUElzc3VlZE5vTXVsdAkBDWdldE1pblBJc3N1ZWQBCAUBaQhwYXltZW50cwQGcmVzdWx0CQETaGFuZGxlUG9vbFRva2Vuc0FkZAQFDVBJc3N1ZWROb011bHQIBQFpCHBheW1lbnRzCAUBaQxvcmlnaW5DYWxsZXIFCm5lZWRDaGFuZ2UED1BJc3N1ZWRXaXRoTXVsdAkAbgQFDVBJc3N1ZWROb011bHQFB1NjYWxlMTYJAQhnZXRLTXVsdAAFBERPV04EB3JlaXNzdWUJAQdSZWlzc3VlAwkBEUBleHRyTmF0aXZlKDEwNTcpAQITZ2xvYmFsX3Bvb2xUb2tlbl9pZAUPUElzc3VlZFdpdGhNdWx0BgkAlAoCCQDOCAIFBnJlc3VsdAkAzAgCBQdyZWlzc3VlCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMIBQFpBmNhbGxlcgUPUElzc3VlZFdpdGhNdWx0CQEMdHJ5R2V0QmluYXJ5AQITZ2xvYmFsX3Bvb2xUb2tlbl9pZAkAzAgCCQEMSW50ZWdlckVudHJ5AgIXZ2xvYmFsX3Bvb2xUb2tlbl9hbW91bnQJAGQCCQENdHJ5R2V0SW50ZWdlcgECF2dsb2JhbF9wb29sVG9rZW5fYW1vdW50BQ9QSXNzdWVkV2l0aE11bHQFA25pbAUPUElzc3VlZFdpdGhNdWx0AWkBC3JlZGVlbUluZGV4AQxzZW5kVG9PcmlnaW4EA3BtdAkAkQMCCAUBaQhwYXltZW50cwAAAwkBAiE9AggFA3BtdAdhc3NldElkCQEMdHJ5R2V0QmluYXJ5AQITZ2xvYmFsX3Bvb2xUb2tlbl9pZAkAAgECHnBsZWFzZSBhdHRhY2ggcG9vbCBzaGFyZSB0b2tlbgMJAQppc1NodXRkb3duAAkAAgECE2NvbnRyYWN0IGlzIG9uIHN0b3AEEVBSZWRlZW1lZFdpdGhNdWx0CAUDcG10BmFtb3VudAQTUFJlZGVlbWVkV2l0aE5vTXVsdAkAbgQFEVBSZWRlZW1lZFdpdGhNdWx0CQEIZ2V0S011bHQABQdTY2FsZTE2BQRET1dOBAZyZXN1bHQJARZoYW5kbGVQb29sVG9rZW5zUmVkZWVtAgUTUFJlZGVlbWVkV2l0aE5vTXVsdAMFDHNlbmRUb09yaWdpbggFAWkMb3JpZ2luQ2FsbGVyCAUBaQZjYWxsZXIJAM4IAgUGcmVzdWx0CQDMCAIJAQRCdXJuAgkBDHRyeUdldEJpbmFyeQECE2dsb2JhbF9wb29sVG9rZW5faWQFEVBSZWRlZW1lZFdpdGhNdWx0CQDMCAIJAQxJbnRlZ2VyRW50cnkCAhdnbG9iYWxfcG9vbFRva2VuX2Ftb3VudAkAZQIJAQ10cnlHZXRJbnRlZ2VyAQIXZ2xvYmFsX3Bvb2xUb2tlbl9hbW91bnQFEVBSZWRlZW1lZFdpdGhNdWx0BQNuaWwBaQEKc3Rha2VJbmRleAAECmFkZHJlc3NTdHIJAKUIAQgFAWkMb3JpZ2luQ2FsbGVyBANwbXQJAJEDAggFAWkIcGF5bWVudHMAAAMJAQIhPQIJAQV2YWx1ZQEIBQNwbXQHYXNzZXRJZAkBDHRyeUdldEJpbmFyeQECE2dsb2JhbF9wb29sVG9rZW5faWQJAAIBAhR3cm9uZyBhc3NldCBhdHRhY2hlZAkBEGluZGV4U3Rha2VSZXN1bHQCBQphZGRyZXNzU3RyCAUDcG10BmFtb3VudAFpAQ1zdGFrZUluZGV4Rm9yAQphZGRyZXNzU3RyBANwbXQJAJEDAggFAWkIcGF5bWVudHMAAAMJAQIhPQIJAQV2YWx1ZQEIBQNwbXQHYXNzZXRJZAkBDHRyeUdldEJpbmFyeQECE2dsb2JhbF9wb29sVG9rZW5faWQJAAIBAhR3cm9uZyBhc3NldCBhdHRhY2hlZAkBEGluZGV4U3Rha2VSZXN1bHQCBQphZGRyZXNzU3RyCAUDcG10BmFtb3VudAFpAQx1bnN0YWtlSW5kZXgBC2luZGV4QW1vdW50BAphZGRyZXNzU3RyAwkBAiE9AgkAswkCBQ9sYXllcjJBZGRyZXNzZXMJAKUIAQgFAWkGY2FsbGVyBQR1bml0CQClCAEIBQFpDG9yaWdpbkNhbGxlcgkApQgBCAUBaQZjYWxsZXIEDmluZGV4QXZhaWxhYmxlCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgUKYWRkcmVzc1N0cgIMX2luZGV4U3Rha2VkAwkBCmlzU2h1dGRvd24ACQACAQITY29udHJhY3QgaXMgb24gc3RvcAMJAGYCBQtpbmRleEFtb3VudAUOaW5kZXhBdmFpbGFibGUJAAIBAiV5b3UgZG9uJ3QgaGF2ZSBpbmRleCB0b2tlbnMgYXZhaWxhYmxlAwkBCmlzU2h1dGRvd24ACQACAQITY29udHJhY3QgaXMgb24gc3RvcAkAzggCCAkBC2NsYWltUmVzdWx0AQkBEUBleHRyTmF0aXZlKDEwNjIpAQUKYWRkcmVzc1N0cgJfMQkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICBQphZGRyZXNzU3RyAgxfaW5kZXhTdGFrZWQJAGUCBQ5pbmRleEF2YWlsYWJsZQULaW5kZXhBbW91bnQJAMwIAgkBDEludGVnZXJFbnRyeQICEmdsb2JhbF9pbmRleFN0YWtlZAkAZQIJAQ10cnlHZXRJbnRlZ2VyAQISZ2xvYmFsX2luZGV4U3Rha2VkBQtpbmRleEFtb3VudAkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCAUBaQZjYWxsZXIFC2luZGV4QW1vdW50CQERQGV4dHJOYXRpdmUoMTA1NykBAhNnbG9iYWxfcG9vbFRva2VuX2lkBQNuaWwBaQERY2xhaW1JbmRleFJld2FyZHMAAwkBCmlzU2h1dGRvd24ACQACAQITY29udHJhY3QgaXMgb24gc3RvcAkBC2NsYWltUmVzdWx0AQgFAWkGY2FsbGVyAWkBDWV2YWx1YXRlQ2xhaW0BBHVzZXIJAJQKAgUDbmlsCAkBC2NsYWltUmVzdWx0AQkBEUBleHRyTmF0aXZlKDEwNjIpAQUEdXNlcgJfMgFpAQRzd2FwAghhc3NldE91dAdtaW5pbXVtBANwbXQDCQAAAgkAkAMBCAUBaQhwYXltZW50cwABCQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAAJAAIBAiFwbGVhc2UgYXR0YWNoIGV4YWN0bHkgb25lIHBheW1lbnQECEFtb3VudEluCQEFdmFsdWUBCAkAkQMCCAUBaQhwYXltZW50cwAABmFtb3VudAQHQXNzZXRJbggFA3BtdAdhc3NldElkBAhBc3NldE91dAkBDWdldEFzc2V0Qnl0ZXMBBQhhc3NldE91dAQHYXNzZXRJbgkBDmdldEFzc2V0U3RyaW5nAQUHQXNzZXRJbgQHc2NhbGVJbgkAaQIFBlNjYWxlOAkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwUHYXNzZXRJbgIGX3NjYWxlBAhzY2FsZU91dAkAaQIFBlNjYWxlOAkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwUIYXNzZXRPdXQCBl9zY2FsZQQOZmVlQXNzZXRPdXRTdHIJAQx0cnlHZXRTdHJpbmcBAg9zdGF0aWNfZmVlVG9rZW4EC2ZlZUFzc2V0T3V0AwkAAAIFDmZlZUFzc2V0T3V0U3RyAgAFC3VzZG5Bc3NldElkCQENZ2V0QXNzZXRCeXRlcwEFDmZlZUFzc2V0T3V0U3RyBA5Bc3NldEluQmFsYW5jZQkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHZ2xvYmFsXwkBDmdldEFzc2V0U3RyaW5nAQUHQXNzZXRJbgIIX2JhbGFuY2UED0Fzc2V0T3V0QmFsYW5jZQkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHZ2xvYmFsXwUIYXNzZXRPdXQCCF9iYWxhbmNlBBRBc3NldEluQmFsYW5jZVNjYWxlZAkAaAIFDkFzc2V0SW5CYWxhbmNlBQdzY2FsZUluBBVBc3NldE91dEJhbGFuY2VTY2FsZWQJAGgCBQ9Bc3NldE91dEJhbGFuY2UFCHNjYWxlT3V0BAtmZWVBbW91bnRJbgkAawMFCEFtb3VudEluBQNGZWUFCEZlZVNjYWxlBA1jbGVhbkFtb3VudEluCQBlAgUIQW1vdW50SW4FC2ZlZUFtb3VudEluBBNjbGVhbkFtb3VudEluU2NhbGVkCQBoAgUNY2xlYW5BbW91bnRJbgUHc2NhbGVJbgQKQW1vdW50T3V0MQkBEmNhbGN1bGF0ZU91dEFtb3VudAUFE2NsZWFuQW1vdW50SW5TY2FsZWQFB0Fzc2V0SW4FCEFzc2V0T3V0BRRBc3NldEluQmFsYW5jZVNjYWxlZAUVQXNzZXRPdXRCYWxhbmNlU2NhbGVkBAlBbW91bnRPdXQJAGsDBQpBbW91bnRPdXQxAAEFCHNjYWxlT3V0BBBBc3NldE91dEJhbGFuY2UyCQBlAgUPQXNzZXRPdXRCYWxhbmNlBQlBbW91bnRPdXQED0Fzc2V0SW5CYWxhbmNlMgkAZAIFDkFzc2V0SW5CYWxhbmNlBQ1jbGVhbkFtb3VudEluBBJmZWVBc3NldE91dEJhbGFuY2UDCQAAAgULZmVlQXNzZXRPdXQFB0Fzc2V0SW4FD0Fzc2V0SW5CYWxhbmNlMgMJAAACBQtmZWVBc3NldE91dAUIQXNzZXRPdXQFEEFzc2V0T3V0QmFsYW5jZTIJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB2dsb2JhbF8JAQ5nZXRBc3NldFN0cmluZwEFC2ZlZUFzc2V0T3V0AghfYmFsYW5jZQQMZmVlQW1vdW50T3V0CQESY2FsY3VsYXRlT3V0QW1vdW50BQULZmVlQW1vdW50SW4FB0Fzc2V0SW4FC2ZlZUFzc2V0T3V0BQ5Bc3NldEluQmFsYW5jZQUSZmVlQXNzZXRPdXRCYWxhbmNlAwkAZgIFB21pbmltdW0FCUFtb3VudE91dAkAAgECKWFtb3VudCB0byByZWNpZXZlIGlzIGxvd2VyIHRoYW4gZ2l2ZW4gb25lAwkAAAIFCEFzc2V0T3V0BQdBc3NldEluCQACAQIYdGhpcyBzd2FwIGlzIG5vdCBhbGxvd2VkAwkAZgIAAAkAZQIFD0Fzc2V0T3V0QmFsYW5jZQUJQW1vdW50T3V0CQACAQIbY29udHJhY3QgaXMgb3V0IG9mIHJlc2VydmVzAwkBCmlzU2h1dGRvd24ACQACAQITY29udHJhY3QgaXMgb24gc3RvcAQKY3JlYXRvckZlZQkAawMFDGZlZUFtb3VudE91dAABAAoEC3Byb3RvY29sRmVlCQBrAwUMZmVlQW1vdW50T3V0AAQACgQMbmV3QmFsYW5jZUluBQ9Bc3NldEluQmFsYW5jZTIEDW5ld0JhbGFuY2VPdXQJAGUCBRBBc3NldE91dEJhbGFuY2UyAwkAAAIFCEFzc2V0T3V0BQtmZWVBc3NldE91dAUMZmVlQW1vdW50T3V0AAAEEm5ld0JhbGFuY2VGZWVBc3NldAMDCQECIT0CBQtmZWVBc3NldE91dAUHQXNzZXRJbgkBAiE9AgULZmVlQXNzZXRPdXQFCEFzc2V0T3V0BwkAZQIFEmZlZUFzc2V0T3V0QmFsYW5jZQUMZmVlQW1vdW50T3V0BQR1bml0BA1hc3NldEluQ2hhbmdlCQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgICB2dsb2JhbF8JAQ5nZXRBc3NldFN0cmluZwEFB0Fzc2V0SW4CCF9iYWxhbmNlBQxuZXdCYWxhbmNlSW4EDmFzc2V0T3V0Q2hhbmdlCQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgICB2dsb2JhbF8FCGFzc2V0T3V0AghfYmFsYW5jZQUNbmV3QmFsYW5jZU91dAQRZmVlQXNzZXRPdXRDaGFuZ2UDCQECIT0CBRJuZXdCYWxhbmNlRmVlQXNzZXQFBHVuaXQJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgIHZ2xvYmFsXwkBDmdldEFzc2V0U3RyaW5nAQULZmVlQXNzZXRPdXQCCF9iYWxhbmNlCQEFdmFsdWUBBRJuZXdCYWxhbmNlRmVlQXNzZXQJAQtTdHJpbmdFbnRyeQICBWhlbGxvAgV3b3JsZAQMdm9sdW1lVXBkYXRlCQESY2FsY3VsYXRlVXNkblZhbHVlBAUHQXNzZXRJbgUIQW1vdW50SW4FDkFzc2V0SW5CYWxhbmNlBRJmZWVBc3NldE91dEJhbGFuY2UED3ZvbHVtZVVzZFVwZGF0ZQkBEWNhbGN1bGF0ZVVzZFZhbHVlAwUHQXNzZXRJbgUIQW1vdW50SW4FDkFzc2V0SW5CYWxhbmNlCQCUCgIJAMwIAgUOYXNzZXRPdXRDaGFuZ2UJAMwIAgUNYXNzZXRJbkNoYW5nZQkAzAgCBRFmZWVBc3NldE91dENoYW5nZQkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCAUBaQZjYWxsZXIFCUFtb3VudE91dAUIQXNzZXRPdXQJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwkBEUBleHRyTmF0aXZlKDEwNjIpAQkBDHRyeUdldFN0cmluZwECEHN0YXRpY19wb29sT3duZXIFCmNyZWF0b3JGZWUFC2ZlZUFzc2V0T3V0CQDMCAIJAQxJbnRlZ2VyRW50cnkCAhRnbG9iYWxfZWFybmVkQnlPd25lcgkAZAIJAQ10cnlHZXRJbnRlZ2VyAQIUZ2xvYmFsX2Vhcm5lZEJ5T3duZXIFCmNyZWF0b3JGZWUJAMwIAgkBDEludGVnZXJFbnRyeQICDWdsb2JhbF92b2x1bWUJAGQCCQENdHJ5R2V0SW50ZWdlcgECDWdsb2JhbF92b2x1bWUFDHZvbHVtZVVwZGF0ZQkAzAgCCQEMSW50ZWdlckVudHJ5AgIRZ2xvYmFsX3ZvbHVtZV91c2QJAGQCCQENdHJ5R2V0SW50ZWdlcgECEWdsb2JhbF92b2x1bWVfdXNkBQ92b2x1bWVVc2RVcGRhdGUJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwULZmVlc0FkZHJlc3MFC3Byb3RvY29sRmVlBQtmZWVBc3NldE91dAUDbmlsBQlBbW91bnRPdXQBaQEMc3dhcFJlYWRPbmx5Awdhc3NldEluCGFzc2V0T3V0CEFtb3VudEluBAdBc3NldEluCQENZ2V0QXNzZXRCeXRlcwEFB2Fzc2V0SW4ECEFzc2V0T3V0CQENZ2V0QXNzZXRCeXRlcwEFCGFzc2V0T3V0BAdzY2FsZUluCQBpAgUGU2NhbGU4CQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdzdGF0aWNfBQdhc3NldEluAgZfc2NhbGUECHNjYWxlT3V0CQBpAgUGU2NhbGU4CQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdzdGF0aWNfBQhhc3NldE91dAIGX3NjYWxlBA5mZWVBc3NldE91dFN0cgkBDHRyeUdldFN0cmluZwECD3N0YXRpY19mZWVUb2tlbgQLZmVlQXNzZXRPdXQDCQAAAgUOZmVlQXNzZXRPdXRTdHICAAULdXNkbkFzc2V0SWQJAQ1nZXRBc3NldEJ5dGVzAQUOZmVlQXNzZXRPdXRTdHIEDkFzc2V0SW5CYWxhbmNlCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdnbG9iYWxfCQEOZ2V0QXNzZXRTdHJpbmcBBQdBc3NldEluAghfYmFsYW5jZQQPQXNzZXRPdXRCYWxhbmNlCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdnbG9iYWxfBQhhc3NldE91dAIIX2JhbGFuY2UEFEFzc2V0SW5CYWxhbmNlU2NhbGVkCQBoAgUOQXNzZXRJbkJhbGFuY2UFB3NjYWxlSW4EFUFzc2V0T3V0QmFsYW5jZVNjYWxlZAkAaAIFD0Fzc2V0T3V0QmFsYW5jZQUIc2NhbGVPdXQEC2ZlZUFtb3VudEluCQBrAwUIQW1vdW50SW4FA0ZlZQUIRmVlU2NhbGUEDWNsZWFuQW1vdW50SW4JAGUCBQhBbW91bnRJbgULZmVlQW1vdW50SW4EE2NsZWFuQW1vdW50SW5TY2FsZWQJAGgCBQ1jbGVhbkFtb3VudEluBQdzY2FsZUluBApBbW91bnRPdXQxCQESY2FsY3VsYXRlT3V0QW1vdW50BQUTY2xlYW5BbW91bnRJblNjYWxlZAUHQXNzZXRJbgUIQXNzZXRPdXQFFEFzc2V0SW5CYWxhbmNlU2NhbGVkBRVBc3NldE91dEJhbGFuY2VTY2FsZWQECUFtb3VudE91dAkAawMFCkFtb3VudE91dDEAAQUIc2NhbGVPdXQEEEFzc2V0T3V0QmFsYW5jZTIJAGUCBQ9Bc3NldE91dEJhbGFuY2UFCUFtb3VudE91dAQPQXNzZXRJbkJhbGFuY2UyCQBkAgUOQXNzZXRJbkJhbGFuY2UFDWNsZWFuQW1vdW50SW4EEmZlZUFzc2V0T3V0QmFsYW5jZQMJAAACBQtmZWVBc3NldE91dAUHQXNzZXRJbgUPQXNzZXRJbkJhbGFuY2UyAwkAAAIFC2ZlZUFzc2V0T3V0BQhBc3NldE91dAUQQXNzZXRPdXRCYWxhbmNlMgkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHZ2xvYmFsXwkBDmdldEFzc2V0U3RyaW5nAQULZmVlQXNzZXRPdXQCCF9iYWxhbmNlBAxmZWVBbW91bnRPdXQJARJjYWxjdWxhdGVPdXRBbW91bnQFBQtmZWVBbW91bnRJbgUHQXNzZXRJbgULZmVlQXNzZXRPdXQFDkFzc2V0SW5CYWxhbmNlBRJmZWVBc3NldE91dEJhbGFuY2UDCQAAAgUIQXNzZXRPdXQFB0Fzc2V0SW4JAAIBAhh0aGlzIHN3YXAgaXMgbm90IGFsbG93ZWQDCQBmAgAACQBlAgUPQXNzZXRPdXRCYWxhbmNlBQlBbW91bnRPdXQJAAIBAhtjb250cmFjdCBpcyBvdXQgb2YgcmVzZXJ2ZXMDCQEKaXNTaHV0ZG93bgAJAAIBAhNjb250cmFjdCBpcyBvbiBzdG9wCQCUCgIFA25pbAUJQW1vdW50T3V0AWkBEXRyYW5zZmVyT3duZXJzaGlwAQ9uZXdPd25lckFkZHJlc3MDCQECIT0CCQClCAEIBQFpBmNhbGxlcgkBDHRyeUdldFN0cmluZwECEHN0YXRpY19wb29sT3duZXIJAAIBAid0aGlzIGNhbGwgYXZhaWxhYmxlIG9ubHkgZm9yIHBvb2wgb3duZXIJAMwIAgkBC1N0cmluZ0VudHJ5AgIQc3RhdGljX3Bvb2xPd25lcgUPbmV3T3duZXJBZGRyZXNzBQNuaWwBaQEGc2V0RmVlAQZuZXdGZWUDCQECIT0CCQClCAEIBQFpBmNhbGxlcgkBDHRyeUdldFN0cmluZwECEHN0YXRpY19wb29sT3duZXIJAAIBAid0aGlzIGNhbGwgYXZhaWxhYmxlIG9ubHkgZm9yIHBvb2wgb3duZXIDCQBmAgABCQELdmFsdWVPckVsc2UCCQCaCAIFCmdvdkFkZHJlc3MJAKwCAgILYXBwcm92ZWRUeF8JANgEAQgFAWkNdHJhbnNhY3Rpb25JZAAACQACAQIzdGhpcyB0cmFuc2FjdGlvbiBuZWVkcyBhcHByb3ZhbCBmcm9tIHB1enpsZSBuZXR3b3JrCQDMCAIJAQxJbnRlZ2VyRW50cnkCAgpzdGF0aWNfZmVlBQZuZXdGZWUFA25pbAFpARJzZXRSZWJhbGFuY2luZ1BsYW4FC2Fzc2V0SWRzU3RyD2Fzc2V0V2VpZ2h0c1N0cg5iYXNlVG9rZW5JZFN0cgtzdGVwc0Ftb3VudA1zdGVwc0ludGVydmFsAwkBAiE9AggFAWkGY2FsbGVyCQERQGV4dHJOYXRpdmUoMTA2MikBCQEMdHJ5R2V0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MQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgQNdmFsaWRQYXltZW50cwkBEHZhbGlkYXRlUGF5bWVudHMCBQthZGRlZEFzc2V0cwgFAWkIcGF5bWVudHMEDHZhbGlkV2VpZ2h0cwkBD3ZhbGlkYXRlV2VpZ2h0cwEFFG5ld0Fzc2V0V2VpZ2h0c1N0ckxpAwkAAAIFDHZhbGlkV2VpZ2h0cwUMdmFsaWRXZWlnaHRzAwkBAiE9AgUNdmFsaWRQYXltZW50cwkAZAIJAJADAQULYWRkZWRBc3NldHMJAJADAQgFAWkIcGF5bWVudHMJAAIBAjFQYXltZW50cyBub3QgcHJlc2VudCBvciBzb21ldGhpbmcgd3Jvbmcgd2l0aCB0aGVtAwkBAiE9AgkAkAMBBRBuZXdBc3NldElkc1N0ckxpCQCQAwEFFG5ld0Fzc2V0V2VpZ2h0c1N0ckxpCQACAQIxYXNzZXRJZHMgYW5kIGFzc2V0V2VpZ2h0cyBzaG91bGQgaGF2ZSBzYW1lIGxlbmd0aAMJAQIhPQIFDXZhbGlkUGF5bWVudHMJAGQCCQCQAwEFC2FkZGVkQXNzZXRzCQCQAwEIBQFpCHBheW1lbnRzCQACAQIxUGF5bWVudHMgbm90IHByZXNlbnQgb3Igc29tZXRoaW5nIHdyb25nIHdpdGggdGhlbQMJAAACBQtmZWVBc3NldFN0cgIACQACAQJBcG9vbCBtdXN0IGhhdmUgb25lIG9mIHRoZSBzdXBwb3J0ZWQgZmVlIGFzc2V0cyBpbiB0aGUgY29tcG9zaXRpb24DCQAAAgkAzwgCBRBuZXdBc3NldElkc1N0ckxpBQ5iYXNlVG9rZW5JZFN0cgUEdW5pdAkAAgECKWJhc2VUb2tlbklkIHNob3VsZCBiZSBwcmVzZW50IGluIGFzc2V0SWRzAwMJAGYCBRBNSU5fU1RFUFNfQU1PVU5UBQtzdGVwc0Ftb3VudAYJAGYCBQtzdGVwc0Ftb3VudAUQTUFYX1NURVBTX0FNT1VOVAkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICAh9TdGVwcyBhbW91bnQgc2hvdWxkIGJlIGJldHdlZW4gCQCkAwEFEE1JTl9TVEVQU19BTU9VTlQCBSBhbmQgCQCkAwEFEE1BWF9TVEVQU19BTU9VTlQCCywgY3VycmVudDogCQCkAwEFC3N0ZXBzQW1vdW50AwMJAGYCBRJNSU5fU1RFUFNfSU5URVJWQUwFDXN0ZXBzSW50ZXJ2YWwGCQBmAgUNc3RlcHNJbnRlcnZhbAUSTUFYX1NURVBTX0lOVEVSVkFMCQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgICIVN0ZXBzIGludGVydmFsIHNob3VsZCBiZSBiZXR3ZWVuIAkApAMBBRJNSU5fU1RFUFNfSU5URVJWQUwCBSBhbmQgCQCkAwEFEk1BWF9TVEVQU19JTlRFUlZBTAILLCBjdXJyZW50OiAJAKQDAQUNc3RlcHNJbnRlcnZhbAMJAQIhPQIFD2Fzc2V0V2VpZ2h0c1N1bQCQTgkAAgEJAKwCAgI2c3VtIG9mIHRva2VuIHdlaWdodHMgbXVzdCBiZSBlcXVhbCB0byAxMDAwMCwgY3VycmVudDogCQCkAwEFD2Fzc2V0V2VpZ2h0c1N1bQoBAWYCBWFjY3VtCmFzc2V0SWRTdHIECW9sZFdlaWdodAkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwUKYXNzZXRJZFN0cgIHX3dlaWdodAQJbmV3V2VpZ2h0AwkAAAIJAM8IAgUQbmV3QXNzZXRJZHNTdHJMaQUKYXNzZXRJZFN0cgUEdW5pdAAACQENcGFyc2VJbnRWYWx1ZQEJAQV2YWx1ZQEJAJEDAgUUbmV3QXNzZXRXZWlnaHRzU3RyTGkJAQV2YWx1ZQEJAM8IAgUQbmV3QXNzZXRJZHNTdHJMaQUKYXNzZXRJZFN0cgQMZGVsdGFQZXJTdGVwCQBrAwkAZQIFCW5ld1dlaWdodAUJb2xkV2VpZ2h0AJBOBQtzdGVwc0Ftb3VudAkAzggCBQVhY2N1bQkAzAgCCQCkAwEFDGRlbHRhUGVyU3RlcAUDbmlsBA10bXBBc3NldElkc0xpCQESZ2V0VG1wUmViYWxhbmNlSWRzAQUQbmV3QXNzZXRJZHNTdHJMaQQLYXNzZXREZWx0YXMKAAIkbAUNdG1wQXNzZXRJZHNMaQoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmOF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEBZgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmOF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjhfMgIJAQUkZjhfMQIJAQUkZjhfMQIJAQUkZjhfMQIJAQUkZjhfMQIJAQUkZjhfMQIJAQUkZjhfMQIJAQUkZjhfMQIJAQUkZjhfMQIJAQUkZjhfMQIJAQUkZjhfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgQObmV3VG9rZW5zQWRkZWQJAGYCCQERY2hlY2tUb2tlbnNDaGFuZ2UBBRBuZXdBc3NldElkc1N0ckxpAAAKARJyZWNvcmRBc3NldFBheW1lbnQCBWFjY3VtBG5leHQJAM4IAgUFYWNjdW0JAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgIacmViYWxhbmNlX2F0dGFjaGVkUGF5bWVudF8JAQ5nZXRBc3NldFN0cmluZwEIBQRuZXh0B2Fzc2V0SWQIBQRuZXh0BmFtb3VudAUDbmlsBA5wYXltZW50RW50cmllcwoAAiRsCAUBaQhwYXltZW50cwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmOV8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEScmVjb3JkQXNzZXRQYXltZW50AgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY5XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmOV8yAgkBBSRmOV8xAgkBBSRmOV8xAgkBBSRmOV8xAgkBBSRmOV8xAgkBBSRmOV8xAgkBBSRmOV8xAgkBBSRmOV8xAgkBBSRmOV8xAgkBBSRmOV8xAgkBBSRmOV8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKBAxzdG9yZVdlaWdodHMJARJzYXZlQ3VycmVudFdlaWdodHMABAxub3RpZnlJbnZva2UJAPwHBAUPcG9vbHNIdWJBZGRyZXNzAhBub3RpZnlQb29sQ2hhbmdlBQNuaWwFA25pbAMJAAACBQxub3RpZnlJbnZva2UFDG5vdGlmeUludm9rZQkAzggCCQDOCAIJAMwIAgkBC1N0cmluZ0VudHJ5AgIVcmViYWxhbmNlX2FkZGVkQXNzZXRzCQC5CQIFC2FkZGVkQXNzZXRzAgEsCQDMCAIJAQtTdHJpbmdFbnRyeQICF3JlYmFsYW5jZV9yZW1vdmVkQXNzZXRzCQC5CQIFDXJlbW92ZWRBc3NldHMCASwJAMwIAgkBC1N0cmluZ0VudHJ5AgIVdG1wX3JlYmFsYW5jZUFzc2V0SWRzCQC5CQIFDXRtcEFzc2V0SWRzTGkCASwJAMwIAgkBDEJvb2xlYW5FbnRyeQICFHJlYmFsYW5jZV9pblByb2dyZXNzBgkAzAgCCQEMQm9vbGVhbkVudHJ5AgIYcmViYWxhbmNlX25ld1Rva2Vuc0FkZGVkBQ5uZXdUb2tlbnNBZGRlZAkAzAgCCQEMSW50ZWdlckVudHJ5AgITcmViYWxhbmNlX3N0ZXBzRG9uZQAACQDMCAIJAQxJbnRlZ2VyRW50cnkCAhhyZWJhbGFuY2VfbGFzdFN0ZXBIZWlnaHQFBmhlaWdodAkAzAgCCQEMSW50ZWdlckVudHJ5AgIVcmViYWxhbmNlX3N0ZXBzQW1vdW50BQtzdGVwc0Ftb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgIXcmViYWxhbmNlX3N0ZXBzSW50ZXJ2YWwFDXN0ZXBzSW50ZXJ2YWwJAMwIAgkBC1N0cmluZ0VudHJ5AgIScmViYWxhbmNlX2Fzc2V0SWRzBQthc3NldElkc1N0cgkAzAgCCQELU3RyaW5nRW50cnkCAhhyZWJhbGFuY2VfbmV3QmFzZVRva2VuSWQFDmJhc2VUb2tlbklkU3RyCQDMCAIJAQtTdHJpbmdFbnRyeQICFXJlYmFsYW5jZV9hc3NldERlbHRhcwkAuQkCBQthc3NldERlbHRhcwIBLAUDbmlsBQ5wYXltZW50RW50cmllcwUMc3RvcmVXZWlnaHRzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBD3N0ZXBSZWJhbGFuY2luZwADCQEBIQEJAQt2YWx1ZU9yRWxzZQIJAJsIAgUEdGhpcwIUcmViYWxhbmNlX2luUHJvZ3Jlc3MHCQACAQIabm8gcmViYWxhbmNpbmcgaW4gcHJvZ3Jlc3MEDmxhc3RTdGVwSGVpZ2h0CQERQGV4dHJOYXRpdmUoMTA1NSkBAhhyZWJhbGFuY2VfbGFzdFN0ZXBIZWlnaHQEDHN0ZXBJbnRlcnZhbAkBEUBleHRyTmF0aXZlKDEwNTUpAQIXcmViYWxhbmNlX3N0ZXBzSW50ZXJ2YWwECXN0ZXBzRG9uZQkBEUBleHRyTmF0aXZlKDEwNTUpAQITcmViYWxhbmNlX3N0ZXBzRG9uZQQObmV4dFN0ZXBIZWlnaHQJAGQCBQ5sYXN0U3RlcEhlaWdodAUMc3RlcEludGVydmFsAwkAZgIFDm5leHRTdGVwSGVpZ2h0BQZoZWlnaHQJAAIBAhFjYW4ndCBiZSBkb25lIHlldAQLYXNzZXREZWx0YXMJALUJAgkBEUBleHRyTmF0aXZlKDEwNTgpAQIVcmViYWxhbmNlX2Fzc2V0RGVsdGFzAgEsBA5uZXdBc3NldElkc1N0cgkBEUBleHRyTmF0aXZlKDEwNTgpAQIVdG1wX3JlYmFsYW5jZUFzc2V0SWRzBAtuZXdBc3NldElkcwkAtQkCBQ5uZXdBc3NldElkc1N0cgIBLAoBAWYCBWFjY3VtCmFzc2V0SWRTdHIJAM4IAgUFYWNjdW0JAMwIAgkApAMBCQBuBAkAZAIJAGgCCQELdmFsdWVPckVsc2UCCQCfCAEJAKwCAgIWcmViYWxhbmNlX3N0YXJ0V2VpZ2h0XwUKYXNzZXRJZFN0cgAAAJBOCQBoAgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFC2Fzc2V0RGVsdGFzCQEFdmFsdWUBCQDPCAIFC25ld0Fzc2V0SWRzBQphc3NldElkU3RyCQBkAgUJc3RlcHNEb25lAAEAAQCQTgUGSEFMRlVQBQNuaWwECW5ld1NoYXJlcwkAuQkCCgACJGwFC25ld0Fzc2V0SWRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQFmAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY0XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNF8yAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAgEsBA5uZXdUb2tlbnNBZGRlZAkBEUBleHRyTmF0aXZlKDEwNTYpAQIYcmViYWxhbmNlX25ld1Rva2Vuc0FkZGVkBANpbnYDAwUObmV3VG9rZW5zQWRkZWQJAAACBQlzdGVwc0RvbmUAAAcJAPwHBAUEdGhpcwIaZG9SZWJhbGFuY2luZ1dpdGhOZXdUb2tlbnMJAMwIAgUObmV3QXNzZXRJZHNTdHIJAMwIAgUJbmV3U2hhcmVzCQDMCAIJARFAZXh0ck5hdGl2ZSgxMDU4KQECGHJlYmFsYW5jZV9uZXdCYXNlVG9rZW5JZAUDbmlsBQNuaWwJAPwHBAUEdGhpcwINZG9SZWJhbGFuY2luZwkAzAgCBQluZXdTaGFyZXMFA25pbAUDbmlsAwkAAAIFA2ludgUDaW52BAxub3RpZnlJbnZva2UJAPwHBAUPcG9vbHNIdWJBZGRyZXNzAhBub3RpZnlQb29sQ2hhbmdlBQNuaWwFA25pbAMJAAACBQxub3RpZnlJbnZva2UFDG5vdGlmeUludm9rZQQKaXNGaW5pc2hlZAkAZwIJAGQCBQlzdGVwc0RvbmUAAQkBEUBleHRyTmF0aXZlKDEwNTUpAQIVcmViYWxhbmNlX3N0ZXBzQW1vdW50BAdhY3Rpb25zCQDMCAIJAQxCb29sZWFuRW50cnkCAhRyZWJhbGFuY2VfaW5Qcm9ncmVzcwkBASEBBQppc0ZpbmlzaGVkCQDMCAIJAQxJbnRlZ2VyRW50cnkCAhNyZWJhbGFuY2Vfc3RlcHNEb25lCQBkAgUJc3RlcHNEb25lAAEJAMwIAgkBDEludGVnZXJFbnRyeQICGHJlYmFsYW5jZV9sYXN0U3RlcEhlaWdodAUGaGVpZ2h0BQNuaWwDCQAAAgUJc3RlcHNEb25lAAAJAM4IAgUHYWN0aW9ucwkAzAgCCQELU3RyaW5nRW50cnkCAg9zdGF0aWNfdG9rZW5JZHMFDm5ld0Fzc2V0SWRzU3RyBQNuaWwDBQppc0ZpbmlzaGVkBA9yZW1vdmVkQXNzZXRzTGkJALUJAgkBDHRyeUdldFN0cmluZwECF3JlYmFsYW5jZV9yZW1vdmVkQXNzZXRzAgEsCgEGcm1EYXRhAgVhY2N1bQdhc3NldElkCQDOCAIFBWFjY3VtCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgkArAICAgdzdGF0aWNfBQdhc3NldElkAgZfc2NhbGUJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICCQCsAgICB3N0YXRpY18FB2Fzc2V0SWQCCV9kZWNpbWFscwkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgIJAKwCAgIHc3RhdGljXwUHYXNzZXRJZAIHX3dlaWdodAkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgIJAKwCAgIHZ2xvYmFsXwUHYXNzZXRJZAIIX2JhbGFuY2UJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICAhpyZWJhbGFuY2VfYXR0YWNoZWRQYXltZW50XwUHYXNzZXRJZAUDbmlsBAJybQoAAiRsBQ9yZW1vdmVkQXNzZXRzTGkKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjVfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBBnJtRGF0YQIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNV8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjVfMgIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgQNYWRkZWRBc3NldHNMaQkAtQkCCQEMdHJ5R2V0U3RyaW5nAQIVcmViYWxhbmNlX2FkZGVkQXNzZXRzAgEsCgERYWRkUmVtb3ZlUGF5bWVudHMCBWFjY3VtB2Fzc2V0SWQJAM4IAgUFYWNjdW0JAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICAhpyZWJhbGFuY2VfYXR0YWNoZWRQYXltZW50XwUHYXNzZXRJZAUDbmlsBApybVBheW1lbnRzCgACJGwFDWFkZGVkQXNzZXRzTGkKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjZfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBEWFkZFJlbW92ZVBheW1lbnRzAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY2XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNl8yAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKBBFmaW5hbEFzc2V0c0lkc1N0cgkBDHRyeUdldFN0cmluZwECEnJlYmFsYW5jZV9hc3NldElkcwQQQXNzZXRzV2VpZ2h0c1N0cgoAAiRsCQC1CQIFEWZpbmFsQXNzZXRzSWRzU3RyAgEsCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGY3XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARdhZGRBc3NldFdlaWdodFRvU3RyTGlzdAIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmN18yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjdfMgIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgkAzggCCQDOCAIJAM4IAgUHYWN0aW9ucwUCcm0FCnJtUGF5bWVudHMJAMwIAgkBC1N0cmluZ0VudHJ5AgIPc3RhdGljX3Rva2VuSWRzBRFmaW5hbEFzc2V0c0lkc1N0cgkAzAgCCQELU3RyaW5nRW50cnkCAhNzdGF0aWNfdG9rZW5XZWlnaHRzCQC5CQIFEEFzc2V0c1dlaWdodHNTdHICASwJAMwIAgkBDEludGVnZXJFbnRyeQICE3N0YXRpY190b2tlbnNBbW91bnQJAJADAQkAtQkCBRFmaW5hbEFzc2V0c0lkc1N0cgIBLAUDbmlsBBFmaW5hbEFzc2V0c0lkc1N0cgkBDHRyeUdldFN0cmluZwECEnJlYmFsYW5jZV9hc3NldElkcwQQQXNzZXRzV2VpZ2h0c1N0cgoAAiRsCQC1CQIFEWZpbmFsQXNzZXRzSWRzU3RyAgEsCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGY1XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARdhZGRBc3NldFdlaWdodFRvU3RyTGlzdAIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNV8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjVfMgIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgkAzggCBQdhY3Rpb25zCQDMCAIJAQtTdHJpbmdFbnRyeQICE3N0YXRpY190b2tlbldlaWdodHMJALkJAgUQQXNzZXRzV2VpZ2h0c1N0cgIBLAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDWRvUmViYWxhbmNpbmcBD2Fzc2V0V2VpZ2h0c1N0cgQRYXNzZXRXZWlnaHRzU3RyTGkJALUJAgUPYXNzZXRXZWlnaHRzU3RyAgEsBA9hc3NldFdlaWdodHNTdW0KAAIkbAURYXNzZXRXZWlnaHRzU3RyTGkKAAIkcwkAkAMBBQIkbAoABSRhY2MwAAAKAQUkZjRfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBA3N1bQIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjRfMgIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgQNYXNzZXRJZHNTdHJMaQkAtQkCCQEMdHJ5R2V0U3RyaW5nAQIPc3RhdGljX3Rva2VuSWRzAgEsAwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIidGhpcyBjYWxsIGF2YWlsYWJsZSBvbmx5IGZvciBhZG1pbgQIb2xkS011bHQJAQhnZXRLTXVsdAAKAQdoYW5kbGVyAgRwYXJzB2Fzc2V0SWQEBWFjY3VtCAUEcGFycwJfMQQKYXNzZXRJZFN0cgkBDmdldEFzc2V0U3RyaW5nAQUHYXNzZXRJZAoBCGhhbmRsZXIyAgVhY2N1bQFuAwkAAAIFAW4FB2Fzc2V0SWQJAQV2YWx1ZQEJAM8IAgUIYXNzZXRJZHMFAW4FBWFjY3VtBAVUb2tlbgoAAiRsBQhhc3NldElkcwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAAAQoBBSRmNV8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEIaGFuZGxlcjICBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjVfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY1XzICCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoEB2JhbGFuY2UJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB2dsb2JhbF8FCmFzc2V0SWRTdHICCF9iYWxhbmNlBAZ3ZWlnaHQDCQAAAggFBHBhcnMCXzICA25ldwkBDXBhcnNlSW50VmFsdWUBCQCRAwIFEWFzc2V0V2VpZ2h0c1N0ckxpBQVUb2tlbgkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwUKYXNzZXRJZFN0cgIHX3dlaWdodAkAlAoCCQBrAwUFYWNjdW0JAGwGBQdiYWxhbmNlCQCR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JGY2XzICCQEFJGY2XzECCQEFJGY2XzECCQEFJGY2XzECCQEFJGY2XzECCQEFJGY2XzECCQEFJGY2XzECCQEFJGY2XzECCQEFJGY2XzECCQEFJGY2XzECCQEFJGY2XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoDCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAAIBCQCsAgICJHRoaXMgY2FsbCBhdmFpbGFibGUgb25seSBmb3IgYWRtaW4sIAkApQgBCAUBaQZjYWxsZXIECG9sZEtNdWx0CQEIZ2V0S011bHQABARvbGRLCQEZZ2V0VmlydHVhbFBvb2xUb2tlbkFtb3VudAAKARJteWx0aXBseUFzc2V0c0ZvcksCBHBhcnMHYXNzZXRJZAoBDGZpbmRBc3NldE51bQIFYWNjdW0BbgMJAAACBQFuBQdhc3NldElkCQEFdmFsdWUBCQDPCAIFC25ld0Fzc2V0SWRzBQFuBQVhY2N1bQQIY3VycmVudEsFBHBhcnMECmFzc2V0SWRTdHIJAQ5nZXRBc3NldFN0cmluZwEFB2Fzc2V0SWQECFRva2VuTnVtCgACJGwFC25ld0Fzc2V0SWRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAABCgEFJGY3XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQxmaW5kQXNzZXROdW0CBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjdfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY3XzICCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoEBndlaWdodAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFFG5ld0Fzc2V0V2VpZ2h0c1N0ckxpBQhUb2tlbk51bQQOYmFsYW5jZUluU3RhdGUJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB2dsb2JhbF8FCmFzc2V0SWRTdHICCF9iYWxhbmNlBBBiYWxhbmNlSW5QYXltZW50CQCRAwIFEGF0dGFjaGVkQmFsYW5jZXMFCFRva2VuTnVtBAdiYWxhbmNlCQBkAgUOYmFsYW5jZUluU3RhdGUFEGJhbGFuY2VJblBheW1lbnQEDWFzc2V0RGVjaW1hbHMDCQAAAgUHYXNzZXRJZAUEdW5pdAAICAkBBXZhbHVlAQkA7AcBCQEFdmFsdWUBBQdhc3NldElkCGRlY2ltYWxzAwkAZwIAAAUHYmFsYW5jZQkAAgEJAKwCAgJEeW91IG5lZWQgdG8gYXR0YWNoIGFsbCBuZXcgYXNzZXRzIGluIHBheW1lbnQuIHRoaXMgYXNzZXQgaXMgbWlzc2VkOiAFCmFzc2V0SWRTdHIJAGsDBQhjdXJyZW50SwkAbAYFB2JhbGFuY2UFDWFzc2V0RGVjaW1hbHMFBndlaWdodAUVQXNzZXRzV2VpZ2h0c0RlY2ltYWxzAAgFBUZMT09SBQZTY2FsZTgEBG5ld0sKAAIkbAULbmV3QXNzZXRJZHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQ5Qb29sVG9rZW5TY2FsZQoBBSRmN18xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQESbXlsdGlwbHlBc3NldHNGb3JLAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY3XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmN18yAgkBBSRmN18xAgkBBSRmN18xAgkBBSRmN18xAgkBBSRmN18xAgkBBSRmN18xAgkBBSRmN18xAgkBBSRmN18xAgkBBSRmN18xAgkBBSRmN18xAgkBBSRmN18xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKBAhuZXdLTXVsdAkAawMFCG9sZEtNdWx0BQRuZXdLBQRvbGRLCgETYWRkVG9rZW5EYXRhRW50cmllcwIFYWNjdW0IYXNzZXROdW0ECmFzc2V0SWRTdHIJAJEDAgUQbmV3QXNzZXRJZHNTdHJMaQUIYXNzZXROdW0EB2Fzc2V0SWQJAJEDAgULbmV3QXNzZXRJZHMFCGFzc2V0TnVtBA1hc3NldERlY2ltYWxzAwkAAAIFB2Fzc2V0SWQFBHVuaXQACAgJAQV2YWx1ZQEJAOwHAQkBBXZhbHVlAQUHYXNzZXRJZAhkZWNpbWFscwQMbmV3QXNzZXREYXRhAwkBAiE9AgkAzwgCBQthZGRlZEFzc2V0cwUKYXNzZXRJZFN0cgUEdW5pdAkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgICB2dsb2JhbF8FCmFzc2V0SWRTdHICCF9iYWxhbmNlCQCRAwIFEGF0dGFjaGVkQmFsYW5jZXMFCGFzc2V0TnVtCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgIHc3RhdGljXwUKYXNzZXRJZFN0cgIGX3NjYWxlCQBsBgAKAAAFDWFzc2V0RGVjaW1hbHMAAAAABQRET1dOCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgIHc3RhdGljXwUKYXNzZXRJZFN0cgIJX2RlY2ltYWxzBQ1hc3NldERlY2ltYWxzBQNuaWwFA25pbAMJAGcCBQhhc3NldE51bQkAkAMBBRRuZXdBc3NldFdlaWdodHNTdHJMaQUFYWNjdW0JAM4IAgkAzggCBQVhY2N1bQkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgICB3N0YXRpY18FCmFzc2V0SWRTdHICB193ZWlnaHQJAQV2YWx1ZQEJALYJAQkAkQMCBRRuZXdBc3NldFdlaWdodHNTdHJMaQUIYXNzZXROdW0FA25pbAUMbmV3QXNzZXREYXRhCQDOCAIKAAIkbAkAzAgCAAAJAMwIAgABCQDMCAIAAgkAzAgCAAMJAMwIAgAECQDMCAIABQkAzAgCAAYJAMwIAgAHCQDMCAIACAkAzAgCAAkFA25pbAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmOF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQETYWRkVG9rZW5EYXRhRW50cmllcwIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmOF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjhfMgIJAQUkZjhfMQIJAQUkZjhfMQIJAQUkZjhfMQIJAQUkZjhfMQIJAQUkZjhfMQIJAQUkZjhfMQIJAQUkZjhfMQIJAQUkZjhfMQIJAQUkZjhfMQIJAQUkZjhfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgkAzAgCCQELU3RyaW5nRW50cnkCAg9zdGF0aWNfdG9rZW5JZHMFC2Fzc2V0SWRzU3RyCQDMCAIJAQtTdHJpbmdFbnRyeQICD3N0YXRpY19mZWVUb2tlbgULZmVlQXNzZXRTdHIJAMwIAgkBC1N0cmluZ0VudHJ5AgITc3RhdGljX3Rva2VuV2VpZ2h0cwUPYXNzZXRXZWlnaHRzU3RyCQDMCAIJAQxJbnRlZ2VyRW50cnkCAhNzdGF0aWNfdG9rZW5zQW1vdW50CQCQAwEFC25ld0Fzc2V0SWRzCQDMCAIJAQxJbnRlZ2VyRW50cnkCAgxzdGF0aWNfS011bHQFCG5ld0tNdWx0BQNuaWwBAnR4AQZ2ZXJpZnkAAwMJAAACCQELdmFsdWVPckVsc2UCCQCfCAECE2dsb2JhbF93YXNQcmVJbml0ZWQAAAAAAwkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAAgFAnR4D3NlbmRlclB1YmxpY0tleQYJAPQDAwgFAnR4CWJvZHlCeXRlcwkAkQMCCAUCdHgGcHJvb2ZzAAAFDG1hc3RlclB1YktleQcGBAckbWF0Y2gwBQJ0eAMJAAECBQckbWF0Y2gwAhRTZXRTY3JpcHRUcmFuc2FjdGlvbgQCdHgFByRtYXRjaDAECnNjcmlwdEZ1bGwJAQV2YWx1ZQEIBQJ0eAZzY3JpcHQEBGhhc2gJANgEAQkA9wMBBQpzY3JpcHRGdWxsAwkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAAUMbWFzdGVyUHViS2V5CQBmAgkBC3ZhbHVlT3JFbHNlAgkAmggCBRFjb2xkTWFzdGVyQWRkcmVzcwkArAICAg9hcHByb3ZlZFNjcmlwdF8FBGhhc2gAAAUGaGVpZ2h0BwMJAPQDAwgFAnR4CWJvZHlCeXRlcwkAkQMCCAUCdHgGcHJvb2ZzAAAFDG1hc3RlclB1YktleQkAZgIJAQt2YWx1ZU9yRWxzZQIJAJoIAgURY29sZE1hc3RlckFkZHJlc3MJAKwCAgILYXBwcm92ZWRUeF8JANgEAQgFAnR4AmlkAAAAAAfLEohL", "height": 4132827, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 62ArpabJF1tCWGCda4z9nHDBeyYrwRfMpNgjUVw78fVR Next: AjJCErZPLPWoC31Tbq8GH2PTjVHzLjkxSgTjFnTUgqiE Diff:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let usdnAssetId = base58'DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p'
4+let VERSION = "PZ-1.2.2 PROD"
55
6-let puzzleAssetId = base58'HEB8Qaw9xrWpWs8tHsiATYGBWDBtP2S7kcPALrMu43AS'
6+let configStr = valueOrElse(getString(this, "configAddress"), "3PPEBRg4s2af2rQ2ZbLvdu1Hfd4Vo6QVDTo")
77
8-let usdtAssetId = base58'34N9YcEETLWn93qYQ64EsP1x89tSruJU44RrEMSXXEPJ'
8+let CONFIG_ADDRESS = if ((configStr == ""))
9+ then this
10+ else Address(fromBase58String(configStr))
911
10-let usdtPptAssetId = base58'9wc3LXNA4TEBsXyKtoLE9mrbDD7WMHXvXrCjZvabLAsi'
12+let AssetsWeightsDecimals = 4
1113
12-let usdnAssetIdStr = "DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p"
14+let Scale = 10000
1315
14-let puzzleAssetIdStr = "HEB8Qaw9xrWpWs8tHsiATYGBWDBtP2S7kcPALrMu43AS"
16+let Scale8 = 100000000
1517
16-let usdtAssetIdStr = "34N9YcEETLWn93qYQ64EsP1x89tSruJU44RrEMSXXEPJ"
18+let Scale16 = 10000000000000000
1719
18-let usdtPptAssetIdStr = "9wc3LXNA4TEBsXyKtoLE9mrbDD7WMHXvXrCjZvabLAsi"
20+let FeeScale = 10000
1921
20-let parentPoolAddress = Address(base58'3PFDgzu1UtswAkCMxqqQjbTeHaX4cMab8Kh')
22+let PoolTokenDecimals = 8
2123
22-let masterAddress = Address(base58'3PLjwHcz9NEuaTo63NZR9B9okQiKQxZSbmf')
24+let PoolTokenScale = pow(10, 0, PoolTokenDecimals, 0, 0, HALFUP)
2325
24-let masterPubKey = base58'4z8CKSYQBKkzx7PBb5uBP1YPa6YAHRNTApW1sQVHT5eU'
26+let MIN_STEPS_AMOUNT = valueOrElse(getInteger(CONFIG_ADDRESS, "min_steps_amount"), 1)
27+
28+let MAX_STEPS_AMOUNT = valueOrElse(getInteger(CONFIG_ADDRESS, "max_steps_amount"), 500)
29+
30+let MIN_STEPS_INTERVAL = valueOrElse(getInteger(CONFIG_ADDRESS, "min_steps_interval"), 1)
31+
32+let MAX_STEPS_INTERVAL = valueOrElse(getInteger(CONFIG_ADDRESS, "max_steps_interval"), 10000)
33+
34+let MIN_WEIGHT = valueOrElse(getInteger(CONFIG_ADDRESS, "min_weight"), 100)
35+
36+let MAX_WEIGHT = valueOrElse(getInteger(CONFIG_ADDRESS, "max_weight"), 9900)
2537
2638 func tryGetInteger (key) = match getInteger(this, key) {
2739 case b: Int =>
4759 }
4860
4961
62+func tryGetStringOrThrow (key) = match getString(this, key) {
63+ case b: String =>
64+ b
65+ case _ =>
66+ throw(("no such key in data storage: " + key))
67+}
68+
69+
5070 func getAssetString (assetId) = match assetId {
5171 case b: ByteVector =>
5272 toBase58String(b)
6080 else fromBase58String(assetIdStr)
6181
6282
83+func getTokenBalance (assetId) = match assetId {
84+ case t: ByteVector =>
85+ assetBalance(this, t)
86+ case _ =>
87+ wavesBalance(this).available
88+}
89+
90+
6391 func addAssetBytesToList (accum,item) = (accum ++ [getAssetBytes(item)])
6492
6593
6694 func addAssetWeightToList (accum,item) = (accum ++ [tryGetInteger((("static_" + getAssetString(item)) + "_weight"))])
95+
96+
97+func addAssetWeightToStrList (accum,item) = (accum ++ [toString(tryGetInteger((("static_" + item) + "_weight")))])
6798
6899
69100 func addAssetDecimalsToList (accum,item) = (accum ++ [tryGetInteger((("static_" + getAssetString(item)) + "_decimals"))])
74105
75106 func addIntToList (accum,item) = (accum ++ [parseIntValue(item)])
76107
108+
109+let usdnAssetIdStr = valueOrElse(getString(CONFIG_ADDRESS, "usdnAssetIdStr"), "DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p")
110+
111+let puzzleAssetIdStr = valueOrElse(getString(CONFIG_ADDRESS, "puzzleAssetIdStr"), "HEB8Qaw9xrWpWs8tHsiATYGBWDBtP2S7kcPALrMu43AS")
112+
113+let usdtAssetIdStr = valueOrElse(getString(CONFIG_ADDRESS, "usdtAssetIdStr"), "34N9YcEETLWn93qYQ64EsP1x89tSruJU44RrEMSXXEPJ")
114+
115+let usdtPptAssetIdStr = valueOrElse(getString(CONFIG_ADDRESS, "usdtPptAssetIdStr"), "9wc3LXNA4TEBsXyKtoLE9mrbDD7WMHXvXrCjZvabLAsi")
116+
117+let romeAssetIdStr = valueOrElse(getString(CONFIG_ADDRESS, "romeAssetIdStr"), "AP4Cb5xLYGH6ZigHreCZHoXpQTWDkPsG2BHqfDUx6taJ")
118+
119+let wavesAssetIdStr = "WAVES"
120+
121+let usdnAssetId = fromBase58String(usdnAssetIdStr)
122+
123+let puzzleAssetId = fromBase58String(puzzleAssetIdStr)
124+
125+let usdtAssetId = fromBase58String(usdtAssetIdStr)
126+
127+let usdtPptAssetId = fromBase58String(usdtPptAssetIdStr)
128+
129+let romeAssetId = fromBase58String(romeAssetIdStr)
130+
131+let wavesAssetId = unit
132+
133+let supportedFeeAssetsStr = [usdnAssetIdStr, puzzleAssetIdStr, usdtAssetIdStr, usdtPptAssetIdStr, wavesAssetIdStr, romeAssetIdStr]
134+
135+let parentPoolAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "parentPoolAddress"), "3PFDgzu1UtswAkCMxqqQjbTeHaX4cMab8Kh")))
136+
137+let masterAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "masterAddress"), "3PLjwHcz9NEuaTo63NZR9B9okQiKQxZSbmf")))
138+
139+let masterPubKey = fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "masterPubKey"), "4z8CKSYQBKkzx7PBb5uBP1YPa6YAHRNTApW1sQVHT5eU"))
140+
141+let oracleAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "oracleAddress"), "3P8d1E1BLKoD52y3bQJ1bDTd2TD1gpaLn9t")))
142+
143+let stakingAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "stakingAddress"), "3PFTbywqxtFfukX3HyT881g4iW5K4QL3FAS")))
144+
145+let feesAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "feesAddress"), "3PFWAVKmXjfHXyzJb12jCbhP4Uhi9t4uWiD")))
146+
147+let poolsHubAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "poolsHubAddress"), "3P5YutjDNC3hABBVsveFuZTTbQ5PdtSDBgk")))
148+
149+let shutdownAddressStr = valueOrElse(getString(CONFIG_ADDRESS, "shutdownAddress"), "3PEpv9hRFWEEBU22WRnLsw1bH4YGtcU728o")
150+
151+let layer2Addresses = valueOrElse(getString(CONFIG_ADDRESS, "layer2Addresses"), "3PR1Qvi9mHT35SwWEkLSqqE2L8thiPLdVWU,3PQoBfUKHkJAeGWhooLP7WS8ovb54av9Jp2")
152+
153+let govAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "govAddress"), "3P6uro9xCsE8te78QZjzqy7aq8natSzdceC")))
154+
155+let coldMasterAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "coldMasterAddress"), "3PK9nhPfPbMBygB9ZgHVMHaQbSoojwrBfxj")))
77156
78157 let T = tryGetInteger("static_tokensAmount")
79158
139218
140219 let Fee = tryGetInteger("static_fee")
141220
142-let AssetsWeightsDecimals = 4
143-
144-let Scale = 10000
145-
146-let Scale8 = 100000000
147-
148-let FeeScale = 10000
149-
150-let PoolTokenDecimals = 8
151-
152-let PoolTokenScale = pow(10, 0, PoolTokenDecimals, 0, 0, HALFUP)
153-
154221 let earnedAssets = assetIds
155222
156-func isShutdown () = match getBoolean(Address(base58'3PEpv9hRFWEEBU22WRnLsw1bH4YGtcU728o'), "is_shutdown") {
157- case x: Boolean =>
223+func isShutdown () = {
224+ let shutdownAddress = addressFromString(shutdownAddressStr)
225+ if ((shutdownAddress == unit))
226+ then false
227+ else match getBoolean(value(shutdownAddress), "is_shutdown") {
228+ case x: Boolean =>
229+ x
230+ case _ =>
231+ false
232+ }
233+ }
234+
235+
236+func getCurrentTokenBalance (tokenNum) = {
237+ let tokenIdStr = getAssetString(assetIds[tokenNum])
238+ tryGetInteger((("global_" + tokenIdStr) + "_balance"))
239+ }
240+
241+
242+func getKMult () = match getInteger("static_KMult") {
243+ case x: Int =>
158244 x
159245 case _ =>
160- false
246+ Scale16
161247 }
162248
163249
164-func getCurrentTokenBalance (tokenType) = {
165- let tokenId = getAssetString(assetIds[tokenType])
166- tryGetInteger((("global_" + tokenId) + "_balance"))
250+func saveCurrentWeights () = {
251+ let assetIdsLi = split(tryGetString("static_tokenIds"), ",")
252+ func s (accum,assetId) = (accum ++ [IntegerEntry(("rebalance_startWeight_" + assetId), tryGetInteger((("static_" + assetId) + "_weight")))])
253+
254+ let $l = assetIdsLi
255+ let $s = size($l)
256+ let $acc0 = nil
257+ func $f4_1 ($a,$i) = if (($i >= $s))
258+ then $a
259+ else s($a, $l[$i])
260+
261+ func $f4_2 ($a,$i) = if (($i >= $s))
262+ then $a
263+ else throw("List size exceeds 10")
264+
265+ $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
167266 }
168267
169268
269+func getVirtualPoolTokenAmount () = fraction(tryGetInteger("global_poolToken_amount"), getKMult(), Scale16)
270+
271+
170272 func calculatePIssued (amount,tokenId) = {
171- let Psupply = tryGetInteger("global_poolToken_amount")
273+ let Psupply = getVirtualPoolTokenAmount()
172274 let Balance = tryGetInteger((("global_" + getAssetString(tokenId)) + "_balance"))
173- fraction(amount, Psupply, Balance, DOWN)
275+ let t1 = fraction(amount, Psupply, Balance, DOWN)
276+ t1
174277 }
175278
176279
251354 }
252355
253356
357+func getPriceFromOracle (assetIdStr) = match getInteger(oracleAddress, (assetIdStr + "_twap5B")) {
358+ case x: Int =>
359+ x
360+ case _ =>
361+ 0
362+}
363+
364+
365+func calculateUsdValue (assetId,amount,aBalance) = {
366+ let assetWeight = tryGetInteger((("static_" + getAssetString(assetId)) + "_weight"))
367+ let feeAssetStr = tryGetString("static_feeToken")
368+ let feeAssetScale = getIntegerValue(this, (("static_" + feeAssetStr) + "_scale"))
369+ let feeAssetNum = value(indexOf(assetIds, getAssetBytes(feeAssetStr)))
370+ let feeAssetWeight = AssetsWeights[feeAssetNum]
371+ let feeAssetBalance = tryGetInteger((("global_" + feeAssetStr) + "_balance"))
372+ let valInFeeAsset = fraction(amount, (feeAssetBalance / feeAssetWeight), (aBalance / assetWeight))
373+ let feeAssetPrice = getPriceFromOracle(feeAssetStr)
374+ fraction(valInFeeAsset, feeAssetPrice, feeAssetScale)
375+ }
376+
377+
254378 func checkTokensValidity (payments) = {
255379 func handler1 (accum,payment) = (accum ++ [payment.assetId])
256380
318442
319443 func handleTokenChange (accum,tokenId) = {
320444 let Bk = tryGetInteger((("global_" + getAssetString(tokenId)) + "_balance"))
321- let PSupply = tryGetInteger("global_poolToken_amount")
445+ let PSupply = getVirtualPoolTokenAmount()
322446 let tokenDecimals = tryGetInteger((("static_" + getAssetString(tokenId)) + "_scale"))
323- let Dk = fraction((fraction((PSupply + PIssued), tokenDecimals, PSupply, CEILING) - tokenDecimals), Bk, tokenDecimals, CEILING)
447+ let a1 = fraction((toBigInt((PSupply + PIssued)) * toBigInt(Scale8)), toBigInt(tokenDecimals), toBigInt(PSupply), CEILING)
448+ let Dk = toInt(fraction((a1 - (toBigInt(tokenDecimals) * toBigInt(Scale8))), toBigInt(Bk), (toBigInt(tokenDecimals) * toBigInt(Scale8)), CEILING))
324449 let paymentAmount = getTokenPaymentAmount(tokenId)
325- let toReturn = ((if ((paymentAmount != 0))
326- then paymentAmount
327- else 0) - Dk)
450+ let toReturn = (paymentAmount - Dk)
328451 let t = if (if (needChange)
329452 then (toReturn > 0)
330453 else false)
351474 func handlePoolTokensRedeem (PRedeemed,userAddress) = {
352475 func handleTokenRedeem (accum,tokenId) = {
353476 let Bk = tryGetInteger((("global_" + getAssetString(tokenId)) + "_balance"))
354- let PSupply = tryGetInteger("global_poolToken_amount")
477+ let PSupply = getVirtualPoolTokenAmount()
355478 let tokenDecimals = tryGetInteger((("static_" + getAssetString(tokenId)) + "_scale"))
356- let amount = toInt(fraction((toBigInt(Scale8) - fraction(toBigInt((PSupply - PRedeemed)), toBigInt(Scale8), toBigInt(PSupply), CEILING)), toBigInt(Bk), toBigInt(Scale8), DOWN))
479+ let psuppl = fraction((toBigInt((PSupply - PRedeemed)) * toBigInt(Scale8)), toBigInt(Scale8), toBigInt(PSupply), DOWN)
480+ let amount = toInt(fraction((toBigInt(Scale16) - psuppl), toBigInt(Bk), toBigInt(Scale16), CEILING))
357481 (accum ++ [IntegerEntry((("global_" + getAssetString(tokenId)) + "_balance"), (Bk - amount)), ScriptTransfer(userAddress, amount, tokenId)])
358482 }
359483
377501 let IndexOut = value(indexOf(assetIds, assetOut))
378502 if ((IndexIn == IndexOut))
379503 then AmountIn
380- else fraction(BalanceOut, ((Scale8 * Scale8) - toInt(pow(fraction(toBigInt(BalanceIn), toBigInt((Scale8 * Scale8)), toBigInt((BalanceIn + AmountIn)), HALFUP), 16, toBigInt(fraction(AssetsWeights[IndexIn], 10000, AssetsWeights[IndexOut])), 4, 16, CEILING))), (Scale8 * Scale8), DOWN)
504+ else fraction(BalanceOut, ((Scale8 * Scale8) - toInt(pow(fraction((toBigInt(BalanceIn) * toBigInt(10000)), toBigInt((Scale8 * Scale8)), (toBigInt((BalanceIn + AmountIn)) * toBigInt(10000)), HALFUP), 16, toBigInt(fraction(AssetsWeights[IndexIn], 1000000000000, AssetsWeights[IndexOut])), 12, 16, CEILING))), (Scale8 * Scale8), HALFEVEN)
381505 }
382-
383-
384-func getTokenBalance (assetId) = match assetId {
385- case t: ByteVector =>
386- assetBalance(this, t)
387- case _ =>
388- wavesBalance(this).available
389-}
390506
391507
392508 func calculateCurrentAssetInterest (assetId,assetIdStr,aBalance,tokenEarningsLastCheck) = {
418534 let transfer = if ((rewardAmount == 0))
419535 then nil
420536 else [ScriptTransfer(address, rewardAmount, assetId)]
421- $Tuple2(((accum._1 ++ transfer) ++ [IntegerEntry((("global_lastCheck_" + assetIdStr) + "_earnings"), (currentTokenEarnings - rewardAmount)), IntegerEntry((("global_lastCheck_" + assetIdStr) + "_interest"), currentTokenInterest), IntegerEntry((((addressStr + "_lastCheck_") + assetIdStr) + "_interest"), currentTokenInterest)]), (accum._2 + calculateUsdnValue(assetId, rewardAmount, aBalance, unit)))
537+ $Tuple2(((accum._1 ++ transfer) ++ [IntegerEntry((("global_lastCheck_" + assetIdStr) + "_earnings"), (currentTokenEarnings - rewardAmount)), IntegerEntry((("global_lastCheck_" + assetIdStr) + "_interest"), currentTokenInterest), IntegerEntry((((addressStr + "_lastCheck_") + assetIdStr) + "_interest"), currentTokenInterest)]), (accum._2 + calculateUsdValue(assetId, rewardAmount, aBalance)))
422538 }
423539
424540 let accum = {
435551
436552 $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
437553 }
438- $Tuple2((accum._1 ++ [IntegerEntry((addressStr + "_claimedRewardValue"), (tryGetInteger((addressStr + "_claimedRewardValue")) + accum._2)), IntegerEntry((addressStr + "_lastClaim"), lastBlock.timestamp)]), accum._2)
554+ $Tuple2((accum._1 ++ [IntegerEntry((addressStr + "_claimedRewardUSD"), (tryGetInteger((addressStr + "_claimedRewardUSD")) + accum._2)), IntegerEntry((addressStr + "_lastClaim"), lastBlock.timestamp)]), accum._2)
439555 }
440556
441557
448564 func sum (accum,n) = (accum + parseIntValue(n))
449565
450566
567+func checkFeeAsset (accum,next) = if (if ((indexOf(supportedFeeAssetsStr, next) != unit))
568+ then (accum == "")
569+ else false)
570+ then next
571+ else accum
572+
573+
574+func getTmpRebalanceIds (newAssetIdsLi) = {
575+ let currentAssetIdsLi = split(tryGetString("static_tokenIds"), ",")
576+ let result = newAssetIdsLi
577+ func f (accum,assetId) = if ((indexOf(result, assetId) == unit))
578+ then (accum ++ [assetId])
579+ else accum
580+
581+ let $l = currentAssetIdsLi
582+ let $s = size($l)
583+ let $acc0 = result
584+ func $f4_1 ($a,$i) = if (($i >= $s))
585+ then $a
586+ else f($a, $l[$i])
587+
588+ func $f4_2 ($a,$i) = if (($i >= $s))
589+ then $a
590+ else throw("List size exceeds 10")
591+
592+ $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
593+ }
594+
595+
596+func checkTokensChange (newAssetIdsLi) = {
597+ let currentAssetIdsLi = split(tryGetString("static_tokenIds"), ",")
598+ func rem (accum,assetId) = if ((indexOf(newAssetIdsLi, assetId) == unit))
599+ then (accum + 1)
600+ else accum
601+
602+ func add (accum,assetId) = if ((indexOf(currentAssetIdsLi, assetId) == unit))
603+ then (accum + 1)
604+ else accum
605+
606+ let removed = {
607+ let $l = currentAssetIdsLi
608+ let $s = size($l)
609+ let $acc0 = 0
610+ func $f4_1 ($a,$i) = if (($i >= $s))
611+ then $a
612+ else rem($a, $l[$i])
613+
614+ func $f4_2 ($a,$i) = if (($i >= $s))
615+ then $a
616+ else throw("List size exceeds 10")
617+
618+ $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
619+ }
620+ let added = {
621+ let $l = newAssetIdsLi
622+ let $s = size($l)
623+ let $acc0 = 0
624+ func $f5_1 ($a,$i) = if (($i >= $s))
625+ then $a
626+ else add($a, $l[$i])
627+
628+ func $f5_2 ($a,$i) = if (($i >= $s))
629+ then $a
630+ else throw("List size exceeds 10")
631+
632+ $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
633+ }
634+ (removed + added)
635+ }
636+
637+
638+func validatePayments (assetsList,payments) = {
639+ func getPaymentAssets (accum,next) = if ((0 >= next.amount))
640+ then throw(((("Too low payment amount for " + getAssetString(next.assetId)) + ": ") + toString(next.amount)))
641+ else (accum ++ [getAssetString(next.assetId)])
642+
643+ let paymentList = {
644+ let $l = payments
645+ let $s = size($l)
646+ let $acc0 = nil
647+ func $f4_1 ($a,$i) = if (($i >= $s))
648+ then $a
649+ else getPaymentAssets($a, $l[$i])
650+
651+ func $f4_2 ($a,$i) = if (($i >= $s))
652+ then $a
653+ else throw("List size exceeds 10")
654+
655+ $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
656+ }
657+ func f1 (accum,next) = if ((indexOf(assetsList, next) == unit))
658+ then throw(((next + " asset is present in payments, but is not in new assets: ") + makeString(assetsList, ",")))
659+ else (accum + 1)
660+
661+ func f2 (accum,next) = if ((indexOf(paymentList, next) == unit))
662+ then throw(((next + " asset is present in new assets, but is not in payments: ") + makeString(paymentList, ",")))
663+ else (accum + 1)
664+
665+ let a1 = {
666+ let $l = paymentList
667+ let $s = size($l)
668+ let $acc0 = 0
669+ func $f5_1 ($a,$i) = if (($i >= $s))
670+ then $a
671+ else f1($a, $l[$i])
672+
673+ func $f5_2 ($a,$i) = if (($i >= $s))
674+ then $a
675+ else throw("List size exceeds 10")
676+
677+ $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
678+ }
679+ let a2 = {
680+ let $l = assetsList
681+ let $s = size($l)
682+ let $acc0 = 0
683+ func $f6_1 ($a,$i) = if (($i >= $s))
684+ then $a
685+ else f2($a, $l[$i])
686+
687+ func $f6_2 ($a,$i) = if (($i >= $s))
688+ then $a
689+ else throw("List size exceeds 10")
690+
691+ $f6_2($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
692+ }
693+ (a1 + a2)
694+ }
695+
696+
697+func validateWeights (weights) = {
698+ func v (accum,w) = {
699+ let wInt = valueOrErrorMessage(parseInt(w), ("Wrong weight format: " + w))
700+ if (if ((MIN_WEIGHT > wInt))
701+ then true
702+ else (wInt > MAX_WEIGHT))
703+ then throw(((((("Weight should be in range " + toString(MIN_WEIGHT)) + " - ") + toString(MAX_WEIGHT)) + ", current: ") + w))
704+ else accum
705+ }
706+
707+ let $l = weights
708+ let $s = size($l)
709+ let $acc0 = 0
710+ func $f4_1 ($a,$i) = if (($i >= $s))
711+ then $a
712+ else v($a, $l[$i])
713+
714+ func $f4_2 ($a,$i) = if (($i >= $s))
715+ then $a
716+ else throw("List size exceeds 10")
717+
718+ $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
719+ }
720+
721+
451722 @Callable(i)
452723 func preInit (assetIdsStr,assetWeightsStr,baseTokenIdStr,poolDomain,poolOwner,fee) = {
453724 let poolOwnerAddress = Address(fromBase58String(poolOwner))
725+ let assetIdsStrLi = split(assetIdsStr, ",")
726+ let assetIdsLi = {
727+ let $l = assetIdsStrLi
728+ let $s = size($l)
729+ let $acc0 = nil
730+ func $f4_1 ($a,$i) = if (($i >= $s))
731+ then $a
732+ else addAssetBytesToList($a, $l[$i])
733+
734+ func $f4_2 ($a,$i) = if (($i >= $s))
735+ then $a
736+ else throw("List size exceeds 10")
737+
738+ $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
739+ }
740+ let feeAssetStr = {
741+ let $l = assetIdsStrLi
742+ let $s = size($l)
743+ let $acc0 = ""
744+ func $f5_1 ($a,$i) = if (($i >= $s))
745+ then $a
746+ else checkFeeAsset($a, $l[$i])
747+
748+ func $f5_2 ($a,$i) = if (($i >= $s))
749+ then $a
750+ else throw("List size exceeds 10")
751+
752+ $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
753+ }
454754 if (isShutdown())
455755 then throw("contract is on stop")
456756 else if ((this != i.caller))
457757 then throw("admin only")
458- else if ((size(poolDomain) > 13))
459- then throw("too large pool domain")
460- else if (if ((fee > 500))
461- then true
462- else (50 > fee))
463- then throw("fee value must be between 50 and 500 (0.5-5%)")
464- else if (if (if (if (if ((indexOf(assetIdsStr, puzzleAssetIdStr) == unit))
465- then (indexOf(assetIdsStr, usdnAssetIdStr) == unit)
466- else false)
467- then (indexOf(assetIdsStr, usdtAssetIdStr) == unit)
468- else false)
469- then (indexOf(assetIdsStr, "WAVES") == unit)
470- else false)
471- then (indexOf(assetIdsStr, usdtPptAssetIdStr) == unit)
472- else false)
473- then throw("pool must have USDT-WXG, USDT-PPT, USDN, WAVES or PUZZLE in the composition")
758+ else if ((feeAssetStr == ""))
759+ then throw("pool must have one of the supported fee assets in the composition")
760+ else if ((size(poolDomain) > 13))
761+ then throw("too large pool domain")
762+ else if (if ((fee > 500))
763+ then true
764+ else (0 > fee))
765+ then throw("fee value must be between 50 and 500 (0.5-5%)")
474766 else {
475- let assetIdsStrLi = split(assetIdsStr, ",")
476- let assetIdsLi = {
477- let $l = assetIdsStrLi
478- let $s = size($l)
479- let $acc0 = nil
480- func $f4_1 ($a,$i) = if (($i >= $s))
481- then $a
482- else addAssetBytesToList($a, $l[$i])
483-
484- func $f4_2 ($a,$i) = if (($i >= $s))
485- then $a
486- else throw("List size exceeds 10")
487-
488- $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
489- }
490767 let assetWeightsStrLi = split(assetWeightsStr, ",")
491768 let assetWeightsSum = {
492769 let $l = assetWeightsStrLi
493770 let $s = size($l)
494771 let $acc0 = 0
495- func $f5_1 ($a,$i) = if (($i >= $s))
772+ func $f6_1 ($a,$i) = if (($i >= $s))
496773 then $a
497774 else sum($a, $l[$i])
498775
499- func $f5_2 ($a,$i) = if (($i >= $s))
776+ func $f6_2 ($a,$i) = if (($i >= $s))
500777 then $a
501778 else throw("List size exceeds 10")
502779
503- $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
780+ $f6_2($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
504781 }
505- let feeAssetStr = if ((indexOf(assetIdsStr, usdnAssetIdStr) != unit))
506- then usdnAssetIdStr
507- else if ((indexOf(assetIdsStr, "WAVES") != unit))
508- then "WAVES"
509- else if ((indexOf(assetIdsStr, usdtAssetIdStr) != unit))
510- then usdtAssetIdStr
511- else if ((indexOf(assetIdsStr, puzzleAssetIdStr) != unit))
512- then puzzleAssetIdStr
513- else usdtPptAssetIdStr
514782 func addTokenDataEntries (accum,assetNum) = if ((assetNum >= size(assetIdsLi)))
515783 then accum
516784 else {
529797 let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
530798 let $s = size($l)
531799 let $acc0 = nil
532- func $f6_1 ($a,$i) = if (($i >= $s))
800+ func $f7_1 ($a,$i) = if (($i >= $s))
533801 then $a
534802 else addTokenDataEntries($a, $l[$i])
535803
536- func $f6_2 ($a,$i) = if (($i >= $s))
804+ func $f7_2 ($a,$i) = if (($i >= $s))
537805 then $a
538806 else throw("List size exceeds 10")
539807
540- $f6_2($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
541- } ++ [StringEntry("static_tokenIds", assetIdsStr), StringEntry("static_feeToken", feeAssetStr), StringEntry("static_tokenWeights", assetWeightsStr), IntegerEntry("static_tokensAmount", size(assetIdsLi)), StringEntry("static_poolDomain", poolDomain), StringEntry("static_baseTokenId", baseTokenIdStr), StringEntry("static_poolOwner", poolOwner), IntegerEntry("static_fee", fee)])
808+ $f7_2($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
809+ } ++ [StringEntry("static_tokenIds", assetIdsStr), StringEntry("static_feeToken", feeAssetStr), StringEntry("static_tokenWeights", assetWeightsStr), IntegerEntry("static_tokensAmount", size(assetIdsLi)), StringEntry("static_poolDomain", poolDomain), StringEntry("static_baseTokenId", baseTokenIdStr), StringEntry("static_poolOwner", poolOwner), IntegerEntry("static_fee", fee), IntegerEntry("static_KMult", Scale16), IntegerEntry("global_wasPreInited", 1)])
542810 }
543811 }
544812
634902 else if (!(checkTokensValidity(i.payments)))
635903 then throw("wrong assets attached")
636904 else {
637- let PIssued = getMinPIssued(i.payments)
638- let reissue = Reissue(getBinaryValue("global_poolToken_id"), PIssued, true)
639- let result = handlePoolTokensAdd(PIssued, i.payments, i.originCaller, needChange)
640- $Tuple2((result ++ [reissue, ScriptTransfer(i.caller, PIssued, tryGetBinary("global_poolToken_id")), IntegerEntry("global_poolToken_amount", (tryGetInteger("global_poolToken_amount") + PIssued))]), PIssued)
905+ let PIssuedNoMult = getMinPIssued(i.payments)
906+ let result = handlePoolTokensAdd(PIssuedNoMult, i.payments, i.originCaller, needChange)
907+ let PIssuedWithMult = fraction(PIssuedNoMult, Scale16, getKMult(), DOWN)
908+ let reissue = Reissue(getBinaryValue("global_poolToken_id"), PIssuedWithMult, true)
909+ $Tuple2((result ++ [reissue, ScriptTransfer(i.caller, PIssuedWithMult, tryGetBinary("global_poolToken_id")), IntegerEntry("global_poolToken_amount", (tryGetInteger("global_poolToken_amount") + PIssuedWithMult))]), PIssuedWithMult)
641910 }
911+
912+
913+
914+@Callable(i)
915+func redeemIndex (sendToOrigin) = {
916+ let pmt = i.payments[0]
917+ if ((pmt.assetId != tryGetBinary("global_poolToken_id")))
918+ then throw("please attach pool share token")
919+ else if (isShutdown())
920+ then throw("contract is on stop")
921+ else {
922+ let PRedeemedWithMult = pmt.amount
923+ let PRedeemedWithNoMult = fraction(PRedeemedWithMult, getKMult(), Scale16, DOWN)
924+ let result = handlePoolTokensRedeem(PRedeemedWithNoMult, if (sendToOrigin)
925+ then i.originCaller
926+ else i.caller)
927+ (result ++ [Burn(tryGetBinary("global_poolToken_id"), PRedeemedWithMult), IntegerEntry("global_poolToken_amount", (tryGetInteger("global_poolToken_amount") - PRedeemedWithMult))])
928+ }
929+ }
642930
643931
644932
654942
655943
656944 @Callable(i)
657-func unstakeIndex (puzzleAmount) = {
658- let addressStr = toString(i.originCaller)
659- let puzzleAvailable = tryGetInteger((addressStr + "_indexStaked"))
945+func stakeIndexFor (addressStr) = {
946+ let pmt = i.payments[0]
947+ if ((value(pmt.assetId) != tryGetBinary("global_poolToken_id")))
948+ then throw("wrong asset attached")
949+ else indexStakeResult(addressStr, pmt.amount)
950+ }
951+
952+
953+
954+@Callable(i)
955+func unstakeIndex (indexAmount) = {
956+ let addressStr = if ((indexOf(layer2Addresses, toString(i.caller)) != unit))
957+ then toString(i.originCaller)
958+ else toString(i.caller)
959+ let indexAvailable = tryGetInteger((addressStr + "_indexStaked"))
660960 if (isShutdown())
661961 then throw("contract is on stop")
662- else if ((puzzleAmount > puzzleAvailable))
962+ else if ((indexAmount > indexAvailable))
663963 then throw("you don't have index tokens available")
664964 else if (isShutdown())
665965 then throw("contract is on stop")
666- else (claimResult(i.originCaller)._1 ++ [IntegerEntry((addressStr + "_indexStaked"), (puzzleAvailable - puzzleAmount)), IntegerEntry("global_indexStaked", (tryGetInteger("global_indexStaked") - puzzleAmount)), ScriptTransfer(i.caller, puzzleAmount, getBinaryValue("global_poolToken_id"))])
966+ else (claimResult(addressFromStringValue(addressStr))._1 ++ [IntegerEntry((addressStr + "_indexStaked"), (indexAvailable - indexAmount)), IntegerEntry("global_indexStaked", (tryGetInteger("global_indexStaked") - indexAmount)), ScriptTransfer(i.caller, indexAmount, getBinaryValue("global_poolToken_id"))])
667967 }
668968
669969
681981
682982
683983 @Callable(i)
684-func redeemIndex (sendToOrigin) = {
685- let pmt = i.payments[0]
686- if ((pmt.assetId != tryGetBinary("global_poolToken_id")))
687- then throw("please attach pool share token")
688- else if (isShutdown())
689- then throw("contract is on stop")
690- else {
691- let PRedeemed = pmt.amount
692- let result = handlePoolTokensRedeem(PRedeemed, if (sendToOrigin)
693- then i.originCaller
694- else i.caller)
695- (result ++ [Burn(tryGetBinary("global_poolToken_id"), PRedeemed), IntegerEntry("global_poolToken_amount", (tryGetInteger("global_poolToken_amount") - PRedeemed))])
696- }
697- }
698-
699-
700-
701-@Callable(i)
702984 func swap (assetOut,minimum) = {
703985 let pmt = if ((size(i.payments) == 1))
704986 then value(i.payments[0])
706988 let AmountIn = value(i.payments[0].amount)
707989 let AssetIn = pmt.assetId
708990 let AssetOut = getAssetBytes(assetOut)
991+ let assetIn = getAssetString(AssetIn)
992+ let scaleIn = (Scale8 / tryGetInteger((("static_" + assetIn) + "_scale")))
993+ let scaleOut = (Scale8 / tryGetInteger((("static_" + assetOut) + "_scale")))
709994 let feeAssetOutStr = tryGetString("static_feeToken")
710995 let feeAssetOut = if ((feeAssetOutStr == ""))
711996 then usdnAssetId
712997 else getAssetBytes(feeAssetOutStr)
713998 let AssetInBalance = tryGetInteger((("global_" + getAssetString(AssetIn)) + "_balance"))
714999 let AssetOutBalance = tryGetInteger((("global_" + assetOut) + "_balance"))
1000+ let AssetInBalanceScaled = (AssetInBalance * scaleIn)
1001+ let AssetOutBalanceScaled = (AssetOutBalance * scaleOut)
7151002 let feeAmountIn = fraction(AmountIn, Fee, FeeScale)
7161003 let cleanAmountIn = (AmountIn - feeAmountIn)
717- let AmountOut = calculateOutAmount(cleanAmountIn, AssetIn, AssetOut, AssetInBalance, AssetOutBalance)
1004+ let cleanAmountInScaled = (cleanAmountIn * scaleIn)
1005+ let AmountOut1 = calculateOutAmount(cleanAmountInScaled, AssetIn, AssetOut, AssetInBalanceScaled, AssetOutBalanceScaled)
1006+ let AmountOut = fraction(AmountOut1, 1, scaleOut)
7181007 let AssetOutBalance2 = (AssetOutBalance - AmountOut)
7191008 let AssetInBalance2 = (AssetInBalance + cleanAmountIn)
7201009 let feeAssetOutBalance = if ((feeAssetOut == AssetIn))
7341023 else {
7351024 let creatorFee = fraction(feeAmountOut, 1, 10)
7361025 let protocolFee = fraction(feeAmountOut, 4, 10)
737- let stakingTopUp = if (if ((feeAssetOut == usdnAssetId))
738- then true
739- else (feeAssetOut == puzzleAssetId))
740- then reentrantInvoke(Address(base58'3PFTbywqxtFfukX3HyT881g4iW5K4QL3FAS'), "topUpReward", nil, [AttachedPayment(feeAssetOut, protocolFee)])
1026+ let newBalanceIn = AssetInBalance2
1027+ let newBalanceOut = (AssetOutBalance2 - (if ((AssetOut == feeAssetOut))
1028+ then feeAmountOut
1029+ else 0))
1030+ let newBalanceFeeAsset = if (if ((feeAssetOut != AssetIn))
1031+ then (feeAssetOut != AssetOut)
1032+ else false)
1033+ then (feeAssetOutBalance - feeAmountOut)
7411034 else unit
742- if ((stakingTopUp == stakingTopUp))
743- then {
744- let newBalanceIn = AssetInBalance2
745- let newBalanceOut = (AssetOutBalance2 - (if ((AssetOut == feeAssetOut))
746- then feeAmountOut
747- else 0))
748- let newBalanceFeeAsset = if (if ((feeAssetOut != AssetIn))
749- then (feeAssetOut != AssetOut)
750- else false)
751- then (feeAssetOutBalance - feeAmountOut)
752- else unit
753- let assetInChange = IntegerEntry((("global_" + getAssetString(AssetIn)) + "_balance"), newBalanceIn)
754- let assetOutChange = IntegerEntry((("global_" + assetOut) + "_balance"), newBalanceOut)
755- let feeAssetOutChange = if ((newBalanceFeeAsset != unit))
756- then IntegerEntry((("global_" + getAssetString(feeAssetOut)) + "_balance"), value(newBalanceFeeAsset))
757- else StringEntry("hello", "world")
758- let volumeUpdate = calculateUsdnValue(AssetIn, AmountIn, AssetInBalance, feeAssetOutBalance)
759- $Tuple2(([assetOutChange, assetInChange, feeAssetOutChange, ScriptTransfer(i.caller, AmountOut, AssetOut), ScriptTransfer(addressFromStringValue(tryGetString("static_poolOwner")), creatorFee, feeAssetOut), IntegerEntry("global_earnedByOwner", (tryGetInteger("global_earnedByOwner") + creatorFee)), IntegerEntry("global_volume", (tryGetInteger("global_volume") + volumeUpdate))] ++ (if ((stakingTopUp == unit))
760- then [ScriptTransfer(Address(base58'3PFWAVKmXjfHXyzJb12jCbhP4Uhi9t4uWiD'), protocolFee, feeAssetOut)]
761- else nil)), AmountOut)
762- }
763- else throw("Strict value is not equal to itself.")
1035+ let assetInChange = IntegerEntry((("global_" + getAssetString(AssetIn)) + "_balance"), newBalanceIn)
1036+ let assetOutChange = IntegerEntry((("global_" + assetOut) + "_balance"), newBalanceOut)
1037+ let feeAssetOutChange = if ((newBalanceFeeAsset != unit))
1038+ then IntegerEntry((("global_" + getAssetString(feeAssetOut)) + "_balance"), value(newBalanceFeeAsset))
1039+ else StringEntry("hello", "world")
1040+ let volumeUpdate = calculateUsdnValue(AssetIn, AmountIn, AssetInBalance, feeAssetOutBalance)
1041+ let volumeUsdUpdate = calculateUsdValue(AssetIn, AmountIn, AssetInBalance)
1042+ $Tuple2([assetOutChange, assetInChange, feeAssetOutChange, ScriptTransfer(i.caller, AmountOut, AssetOut), ScriptTransfer(addressFromStringValue(tryGetString("static_poolOwner")), creatorFee, feeAssetOut), IntegerEntry("global_earnedByOwner", (tryGetInteger("global_earnedByOwner") + creatorFee)), IntegerEntry("global_volume", (tryGetInteger("global_volume") + volumeUpdate)), IntegerEntry("global_volume_usd", (tryGetInteger("global_volume_usd") + volumeUsdUpdate)), ScriptTransfer(feesAddress, protocolFee, feeAssetOut)], AmountOut)
7641043 }
1044+ }
1045+
1046+
1047+
1048+@Callable(i)
1049+func swapReadOnly (assetIn,assetOut,AmountIn) = {
1050+ let AssetIn = getAssetBytes(assetIn)
1051+ let AssetOut = getAssetBytes(assetOut)
1052+ let scaleIn = (Scale8 / tryGetInteger((("static_" + assetIn) + "_scale")))
1053+ let scaleOut = (Scale8 / tryGetInteger((("static_" + assetOut) + "_scale")))
1054+ let feeAssetOutStr = tryGetString("static_feeToken")
1055+ let feeAssetOut = if ((feeAssetOutStr == ""))
1056+ then usdnAssetId
1057+ else getAssetBytes(feeAssetOutStr)
1058+ let AssetInBalance = tryGetInteger((("global_" + getAssetString(AssetIn)) + "_balance"))
1059+ let AssetOutBalance = tryGetInteger((("global_" + assetOut) + "_balance"))
1060+ let AssetInBalanceScaled = (AssetInBalance * scaleIn)
1061+ let AssetOutBalanceScaled = (AssetOutBalance * scaleOut)
1062+ let feeAmountIn = fraction(AmountIn, Fee, FeeScale)
1063+ let cleanAmountIn = (AmountIn - feeAmountIn)
1064+ let cleanAmountInScaled = (cleanAmountIn * scaleIn)
1065+ let AmountOut1 = calculateOutAmount(cleanAmountInScaled, AssetIn, AssetOut, AssetInBalanceScaled, AssetOutBalanceScaled)
1066+ let AmountOut = fraction(AmountOut1, 1, scaleOut)
1067+ let AssetOutBalance2 = (AssetOutBalance - AmountOut)
1068+ let AssetInBalance2 = (AssetInBalance + cleanAmountIn)
1069+ let feeAssetOutBalance = if ((feeAssetOut == AssetIn))
1070+ then AssetInBalance2
1071+ else if ((feeAssetOut == AssetOut))
1072+ then AssetOutBalance2
1073+ else tryGetInteger((("global_" + getAssetString(feeAssetOut)) + "_balance"))
1074+ let feeAmountOut = calculateOutAmount(feeAmountIn, AssetIn, feeAssetOut, AssetInBalance, feeAssetOutBalance)
1075+ if ((AssetOut == AssetIn))
1076+ then throw("this swap is not allowed")
1077+ else if ((0 > (AssetOutBalance - AmountOut)))
1078+ then throw("contract is out of reserves")
1079+ else if (isShutdown())
1080+ then throw("contract is on stop")
1081+ else $Tuple2(nil, AmountOut)
7651082 }
7661083
7671084
7721089 else [StringEntry("static_poolOwner", newOwnerAddress)]
7731090
7741091
1092+
1093+@Callable(i)
1094+func setFee (newFee) = if ((toString(i.caller) != tryGetString("static_poolOwner")))
1095+ then throw("this call available only for pool owner")
1096+ else if ((1 > valueOrElse(getInteger(govAddress, ("approvedTx_" + toBase58String(i.transactionId))), 0)))
1097+ then throw("this transaction needs approval from puzzle network")
1098+ else [IntegerEntry("static_fee", newFee)]
1099+
1100+
1101+
1102+@Callable(i)
1103+func setRebalancingPlan (assetIdsStr,assetWeightsStr,baseTokenIdStr,stepsAmount,stepsInterval) = if ((i.caller != addressFromStringValue(tryGetString("static_poolOwner"))))
1104+ then throw("this call available only for pool owner")
1105+ else if ((1 > valueOrElse(getInteger(govAddress, ("approvedTx_" + toBase58String(i.transactionId))), 0)))
1106+ then throw("this transaction needs approval from puzzle network")
1107+ else if (valueOrElse(getBoolean(this, "rebalance_inProgress"), false))
1108+ then throw("rebalancing in progress")
1109+ else {
1110+ let newAssetWeightsStrLi = split(assetWeightsStr, ",")
1111+ let newAssetIdsStrLi = split(assetIdsStr, ",")
1112+ let feeAssetStr = {
1113+ let $l = newAssetIdsStrLi
1114+ let $s = size($l)
1115+ let $acc0 = ""
1116+ func $f4_1 ($a,$i) = if (($i >= $s))
1117+ then $a
1118+ else checkFeeAsset($a, $l[$i])
1119+
1120+ func $f4_2 ($a,$i) = if (($i >= $s))
1121+ then $a
1122+ else throw("List size exceeds 10")
1123+
1124+ $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1125+ }
1126+ let assetWeightsSum = {
1127+ let $l = newAssetWeightsStrLi
1128+ let $s = size($l)
1129+ let $acc0 = 0
1130+ func $f5_1 ($a,$i) = if (($i >= $s))
1131+ then $a
1132+ else sum($a, $l[$i])
1133+
1134+ func $f5_2 ($a,$i) = if (($i >= $s))
1135+ then $a
1136+ else throw("List size exceeds 10")
1137+
1138+ $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1139+ }
1140+ let oldAssetIds = getStringValue("static_tokenIds")
1141+ let oldAssetIdsLi = split(oldAssetIds, ",")
1142+ func findAdded (accum,next) = if ((indexOf(oldAssetIdsLi, next) == unit))
1143+ then (accum ++ [next])
1144+ else accum
1145+
1146+ func findRemoved (accum,next) = if ((indexOf(newAssetIdsStrLi, next) == unit))
1147+ then (accum ++ [next])
1148+ else accum
1149+
1150+ let addedAssets = {
1151+ let $l = newAssetIdsStrLi
1152+ let $s = size($l)
1153+ let $acc0 = nil
1154+ func $f6_1 ($a,$i) = if (($i >= $s))
1155+ then $a
1156+ else findAdded($a, $l[$i])
1157+
1158+ func $f6_2 ($a,$i) = if (($i >= $s))
1159+ then $a
1160+ else throw("List size exceeds 10")
1161+
1162+ $f6_2($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1163+ }
1164+ let removedAssets = {
1165+ let $l = oldAssetIdsLi
1166+ let $s = size($l)
1167+ let $acc0 = nil
1168+ func $f7_1 ($a,$i) = if (($i >= $s))
1169+ then $a
1170+ else findRemoved($a, $l[$i])
1171+
1172+ func $f7_2 ($a,$i) = if (($i >= $s))
1173+ then $a
1174+ else throw("List size exceeds 10")
1175+
1176+ $f7_2($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1177+ }
1178+ let validPayments = validatePayments(addedAssets, i.payments)
1179+ let validWeights = validateWeights(newAssetWeightsStrLi)
1180+ if ((validWeights == validWeights))
1181+ then if ((validPayments != (size(addedAssets) + size(i.payments))))
1182+ then throw("Payments not present or something wrong with them")
1183+ else if ((size(newAssetIdsStrLi) != size(newAssetWeightsStrLi)))
1184+ then throw("assetIds and assetWeights should have same length")
1185+ else if ((validPayments != (size(addedAssets) + size(i.payments))))
1186+ then throw("Payments not present or something wrong with them")
1187+ else if ((feeAssetStr == ""))
1188+ then throw("pool must have one of the supported fee assets in the composition")
1189+ else if ((indexOf(newAssetIdsStrLi, baseTokenIdStr) == unit))
1190+ then throw("baseTokenId should be present in assetIds")
1191+ else if (if ((MIN_STEPS_AMOUNT > stepsAmount))
1192+ then true
1193+ else (stepsAmount > MAX_STEPS_AMOUNT))
1194+ then throw(((((("Steps amount should be between " + toString(MIN_STEPS_AMOUNT)) + " and ") + toString(MAX_STEPS_AMOUNT)) + ", current: ") + toString(stepsAmount)))
1195+ else if (if ((MIN_STEPS_INTERVAL > stepsInterval))
1196+ then true
1197+ else (stepsInterval > MAX_STEPS_INTERVAL))
1198+ then throw(((((("Steps interval should be between " + toString(MIN_STEPS_INTERVAL)) + " and ") + toString(MAX_STEPS_INTERVAL)) + ", current: ") + toString(stepsInterval)))
1199+ else if ((assetWeightsSum != 10000))
1200+ then throw(("sum of token weights must be equal to 10000, current: " + toString(assetWeightsSum)))
1201+ else {
1202+ func f (accum,assetIdStr) = {
1203+ let oldWeight = tryGetInteger((("static_" + assetIdStr) + "_weight"))
1204+ let newWeight = if ((indexOf(newAssetIdsStrLi, assetIdStr) == unit))
1205+ then 0
1206+ else parseIntValue(value(newAssetWeightsStrLi[value(indexOf(newAssetIdsStrLi, assetIdStr))]))
1207+ let deltaPerStep = fraction((newWeight - oldWeight), 10000, stepsAmount)
1208+ (accum ++ [toString(deltaPerStep)])
1209+ }
1210+
1211+ let tmpAssetIdsLi = getTmpRebalanceIds(newAssetIdsStrLi)
1212+ let assetDeltas = {
1213+ let $l = tmpAssetIdsLi
1214+ let $s = size($l)
1215+ let $acc0 = nil
1216+ func $f8_1 ($a,$i) = if (($i >= $s))
1217+ then $a
1218+ else f($a, $l[$i])
1219+
1220+ func $f8_2 ($a,$i) = if (($i >= $s))
1221+ then $a
1222+ else throw("List size exceeds 10")
1223+
1224+ $f8_2($f8_1($f8_1($f8_1($f8_1($f8_1($f8_1($f8_1($f8_1($f8_1($f8_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1225+ }
1226+ let newTokensAdded = (checkTokensChange(newAssetIdsStrLi) > 0)
1227+ func recordAssetPayment (accum,next) = (accum ++ [IntegerEntry(("rebalance_attachedPayment_" + getAssetString(next.assetId)), next.amount)])
1228+
1229+ let paymentEntries = {
1230+ let $l = i.payments
1231+ let $s = size($l)
1232+ let $acc0 = nil
1233+ func $f9_1 ($a,$i) = if (($i >= $s))
1234+ then $a
1235+ else recordAssetPayment($a, $l[$i])
1236+
1237+ func $f9_2 ($a,$i) = if (($i >= $s))
1238+ then $a
1239+ else throw("List size exceeds 10")
1240+
1241+ $f9_2($f9_1($f9_1($f9_1($f9_1($f9_1($f9_1($f9_1($f9_1($f9_1($f9_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1242+ }
1243+ let storeWeights = saveCurrentWeights()
1244+ let notifyInvoke = invoke(poolsHubAddress, "notifyPoolChange", nil, nil)
1245+ if ((notifyInvoke == notifyInvoke))
1246+ then (([StringEntry("rebalance_addedAssets", makeString(addedAssets, ",")), StringEntry("rebalance_removedAssets", makeString(removedAssets, ",")), StringEntry("tmp_rebalanceAssetIds", makeString(tmpAssetIdsLi, ",")), BooleanEntry("rebalance_inProgress", true), BooleanEntry("rebalance_newTokensAdded", newTokensAdded), IntegerEntry("rebalance_stepsDone", 0), IntegerEntry("rebalance_lastStepHeight", height), IntegerEntry("rebalance_stepsAmount", stepsAmount), IntegerEntry("rebalance_stepsInterval", stepsInterval), StringEntry("rebalance_assetIds", assetIdsStr), StringEntry("rebalance_newBaseTokenId", baseTokenIdStr), StringEntry("rebalance_assetDeltas", makeString(assetDeltas, ","))] ++ paymentEntries) ++ storeWeights)
1247+ else throw("Strict value is not equal to itself.")
1248+ }
1249+ else throw("Strict value is not equal to itself.")
1250+ }
1251+
1252+
1253+
1254+@Callable(i)
1255+func stepRebalancing () = if (!(valueOrElse(getBoolean(this, "rebalance_inProgress"), false)))
1256+ then throw("no rebalancing in progress")
1257+ else {
1258+ let lastStepHeight = getIntegerValue("rebalance_lastStepHeight")
1259+ let stepInterval = getIntegerValue("rebalance_stepsInterval")
1260+ let stepsDone = getIntegerValue("rebalance_stepsDone")
1261+ let nextStepHeight = (lastStepHeight + stepInterval)
1262+ if ((nextStepHeight > height))
1263+ then throw("can't be done yet")
1264+ else {
1265+ let assetDeltas = split(getStringValue("rebalance_assetDeltas"), ",")
1266+ let newAssetIdsStr = getStringValue("tmp_rebalanceAssetIds")
1267+ let newAssetIds = split(newAssetIdsStr, ",")
1268+ func f (accum,assetIdStr) = (accum ++ [toString(fraction(((valueOrElse(getInteger(("rebalance_startWeight_" + assetIdStr)), 0) * 10000) + (parseIntValue(assetDeltas[value(indexOf(newAssetIds, assetIdStr))]) * (stepsDone + 1))), 1, 10000, HALFUP))])
1269+
1270+ let newShares = makeString({
1271+ let $l = newAssetIds
1272+ let $s = size($l)
1273+ let $acc0 = nil
1274+ func $f4_1 ($a,$i) = if (($i >= $s))
1275+ then $a
1276+ else f($a, $l[$i])
1277+
1278+ func $f4_2 ($a,$i) = if (($i >= $s))
1279+ then $a
1280+ else throw("List size exceeds 10")
1281+
1282+ $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1283+ }, ",")
1284+ let newTokensAdded = getBooleanValue("rebalance_newTokensAdded")
1285+ let inv = if (if (newTokensAdded)
1286+ then (stepsDone == 0)
1287+ else false)
1288+ then invoke(this, "doRebalancingWithNewTokens", [newAssetIdsStr, newShares, getStringValue("rebalance_newBaseTokenId")], nil)
1289+ else invoke(this, "doRebalancing", [newShares], nil)
1290+ if ((inv == inv))
1291+ then {
1292+ let notifyInvoke = invoke(poolsHubAddress, "notifyPoolChange", nil, nil)
1293+ if ((notifyInvoke == notifyInvoke))
1294+ then {
1295+ let isFinished = ((stepsDone + 1) >= getIntegerValue("rebalance_stepsAmount"))
1296+ let actions = [BooleanEntry("rebalance_inProgress", !(isFinished)), IntegerEntry("rebalance_stepsDone", (stepsDone + 1)), IntegerEntry("rebalance_lastStepHeight", height)]
1297+ if ((stepsDone == 0))
1298+ then (actions ++ [StringEntry("static_tokenIds", newAssetIdsStr)])
1299+ else if (isFinished)
1300+ then {
1301+ let removedAssetsLi = split(tryGetString("rebalance_removedAssets"), ",")
1302+ func rmData (accum,assetId) = (accum ++ [DeleteEntry((("static_" + assetId) + "_scale")), DeleteEntry((("static_" + assetId) + "_decimals")), DeleteEntry((("static_" + assetId) + "_weight")), DeleteEntry((("global_" + assetId) + "_balance")), DeleteEntry(("rebalance_attachedPayment_" + assetId))])
1303+
1304+ let rm = {
1305+ let $l = removedAssetsLi
1306+ let $s = size($l)
1307+ let $acc0 = nil
1308+ func $f5_1 ($a,$i) = if (($i >= $s))
1309+ then $a
1310+ else rmData($a, $l[$i])
1311+
1312+ func $f5_2 ($a,$i) = if (($i >= $s))
1313+ then $a
1314+ else throw("List size exceeds 10")
1315+
1316+ $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1317+ }
1318+ let addedAssetsLi = split(tryGetString("rebalance_addedAssets"), ",")
1319+ func addRemovePayments (accum,assetId) = (accum ++ [DeleteEntry(("rebalance_attachedPayment_" + assetId))])
1320+
1321+ let rmPayments = {
1322+ let $l = addedAssetsLi
1323+ let $s = size($l)
1324+ let $acc0 = nil
1325+ func $f6_1 ($a,$i) = if (($i >= $s))
1326+ then $a
1327+ else addRemovePayments($a, $l[$i])
1328+
1329+ func $f6_2 ($a,$i) = if (($i >= $s))
1330+ then $a
1331+ else throw("List size exceeds 10")
1332+
1333+ $f6_2($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1334+ }
1335+ let finalAssetsIdsStr = tryGetString("rebalance_assetIds")
1336+ let AssetsWeightsStr = {
1337+ let $l = split(finalAssetsIdsStr, ",")
1338+ let $s = size($l)
1339+ let $acc0 = nil
1340+ func $f7_1 ($a,$i) = if (($i >= $s))
1341+ then $a
1342+ else addAssetWeightToStrList($a, $l[$i])
1343+
1344+ func $f7_2 ($a,$i) = if (($i >= $s))
1345+ then $a
1346+ else throw("List size exceeds 10")
1347+
1348+ $f7_2($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1349+ }
1350+ (((actions ++ rm) ++ rmPayments) ++ [StringEntry("static_tokenIds", finalAssetsIdsStr), StringEntry("static_tokenWeights", makeString(AssetsWeightsStr, ",")), IntegerEntry("static_tokensAmount", size(split(finalAssetsIdsStr, ",")))])
1351+ }
1352+ else {
1353+ let finalAssetsIdsStr = tryGetString("rebalance_assetIds")
1354+ let AssetsWeightsStr = {
1355+ let $l = split(finalAssetsIdsStr, ",")
1356+ let $s = size($l)
1357+ let $acc0 = nil
1358+ func $f5_1 ($a,$i) = if (($i >= $s))
1359+ then $a
1360+ else addAssetWeightToStrList($a, $l[$i])
1361+
1362+ func $f5_2 ($a,$i) = if (($i >= $s))
1363+ then $a
1364+ else throw("List size exceeds 10")
1365+
1366+ $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1367+ }
1368+ (actions ++ [StringEntry("static_tokenWeights", makeString(AssetsWeightsStr, ","))])
1369+ }
1370+ }
1371+ else throw("Strict value is not equal to itself.")
1372+ }
1373+ else throw("Strict value is not equal to itself.")
1374+ }
1375+ }
1376+
1377+
1378+
1379+@Callable(i)
1380+func doRebalancing (assetWeightsStr) = {
1381+ let assetWeightsStrLi = split(assetWeightsStr, ",")
1382+ let assetWeightsSum = {
1383+ let $l = assetWeightsStrLi
1384+ let $s = size($l)
1385+ let $acc0 = 0
1386+ func $f4_1 ($a,$i) = if (($i >= $s))
1387+ then $a
1388+ else sum($a, $l[$i])
1389+
1390+ func $f4_2 ($a,$i) = if (($i >= $s))
1391+ then $a
1392+ else throw("List size exceeds 10")
1393+
1394+ $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1395+ }
1396+ let assetIdsStrLi = split(tryGetString("static_tokenIds"), ",")
1397+ if ((i.caller != this))
1398+ then throw("this call available only for admin")
1399+ else {
1400+ let oldKMult = getKMult()
1401+ func handler (pars,assetId) = {
1402+ let accum = pars._1
1403+ let assetIdStr = getAssetString(assetId)
1404+ func handler2 (accum,n) = if ((n == assetId))
1405+ then value(indexOf(assetIds, n))
1406+ else accum
1407+
1408+ let Token = {
1409+ let $l = assetIds
1410+ let $s = size($l)
1411+ let $acc0 = 1
1412+ func $f5_1 ($a,$i) = if (($i >= $s))
1413+ then $a
1414+ else handler2($a, $l[$i])
1415+
1416+ func $f5_2 ($a,$i) = if (($i >= $s))
1417+ then $a
1418+ else throw("List size exceeds 10")
1419+
1420+ $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1421+ }
1422+ let balance = tryGetInteger((("global_" + assetIdStr) + "_balance"))
1423+ let weight = if ((pars._2 == "new"))
1424+ then parseIntValue(assetWeightsStrLi[Token])
1425+ else tryGetInteger((("static_" + assetIdStr) + "_weight"))
1426+ $Tuple2(fraction(accum, pow(balance, Decimals[Token], weight, AssetsWeightsDecimals, 8, FLOOR), Scale8), pars._2)
1427+ }
1428+
1429+ let newK = ( let $l = assetIds
1430+ let $s = size($l)
1431+ let $acc0 = $Tuple2(PoolTokenScale, "new")
1432+ func $f5_1 ($a,$i) = if (($i >= $s))
1433+ then $a
1434+ else handler($a, $l[$i])
1435+
1436+ func $f5_2 ($a,$i) = if (($i >= $s))
1437+ then $a
1438+ else throw("List size exceeds 10")
1439+
1440+ $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10))._1
1441+ let oldK = ( let $l = assetIds
1442+ let $s = size($l)
1443+ let $acc0 = $Tuple2(PoolTokenScale, "old")
1444+ func $f6_1 ($a,$i) = if (($i >= $s))
1445+ then $a
1446+ else handler($a, $l[$i])
1447+
1448+ func $f6_2 ($a,$i) = if (($i >= $s))
1449+ then $a
1450+ else throw("List size exceeds 10")
1451+
1452+ $f6_2($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10))._1
1453+ let newKMult = fraction(oldKMult, newK, oldK)
1454+ func addTokenDataEntries (accum,assetNum) = if ((assetNum >= size(assetWeightsStrLi)))
1455+ then accum
1456+ else (accum ++ [IntegerEntry((("static_" + assetIdsStrLi[assetNum]) + "_weight"), value(parseInt(assetWeightsStrLi[assetNum])))])
1457+
1458+ ({
1459+ let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1460+ let $s = size($l)
1461+ let $acc0 = nil
1462+ func $f7_1 ($a,$i) = if (($i >= $s))
1463+ then $a
1464+ else addTokenDataEntries($a, $l[$i])
1465+
1466+ func $f7_2 ($a,$i) = if (($i >= $s))
1467+ then $a
1468+ else throw("List size exceeds 10")
1469+
1470+ $f7_2($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1471+ } ++ [IntegerEntry("static_KMult", newKMult)])
1472+ }
1473+ }
1474+
1475+
1476+
1477+@Callable(i)
1478+func doRebalancingWithNewTokens (assetIdsStr,assetWeightsStr,baseTokenIdStr) = {
1479+ let newAssetWeightsStrLi = split(assetWeightsStr, ",")
1480+ let prevAssetIdsStrLi = split(tryGetString("static_tokenIds"), ",")
1481+ let newAssetIdsStrLi = split(assetIdsStr, ",")
1482+ let newAssetIds = {
1483+ let $l = newAssetIdsStrLi
1484+ let $s = size($l)
1485+ let $acc0 = nil
1486+ func $f4_1 ($a,$i) = if (($i >= $s))
1487+ then $a
1488+ else addAssetBytesToList($a, $l[$i])
1489+
1490+ func $f4_2 ($a,$i) = if (($i >= $s))
1491+ then $a
1492+ else throw("List size exceeds 10")
1493+
1494+ $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1495+ }
1496+ let feeAssetStr = {
1497+ let $l = newAssetIdsStrLi
1498+ let $s = size($l)
1499+ let $acc0 = ""
1500+ func $f5_1 ($a,$i) = if (($i >= $s))
1501+ then $a
1502+ else checkFeeAsset($a, $l[$i])
1503+
1504+ func $f5_2 ($a,$i) = if (($i >= $s))
1505+ then $a
1506+ else throw("List size exceeds 10")
1507+
1508+ $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1509+ }
1510+ let addedAssets = split(tryGetString("rebalance_addedAssets"), ",")
1511+ func findAssetPayment (assetId) = valueOrElse(getInteger(("rebalance_attachedPayment_" + getAssetString(assetId))), 0)
1512+
1513+ func addAssetBalanceToLi (li,assetId) = (li ++ [findAssetPayment(assetId)])
1514+
1515+ let attachedBalances = {
1516+ let $l = newAssetIds
1517+ let $s = size($l)
1518+ let $acc0 = nil
1519+ func $f6_1 ($a,$i) = if (($i >= $s))
1520+ then $a
1521+ else addAssetBalanceToLi($a, $l[$i])
1522+
1523+ func $f6_2 ($a,$i) = if (($i >= $s))
1524+ then $a
1525+ else throw("List size exceeds 10")
1526+
1527+ $f6_2($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1528+ }
1529+ if ((i.caller != this))
1530+ then throw(("this call available only for admin, " + toString(i.caller)))
1531+ else {
1532+ let oldKMult = getKMult()
1533+ let oldK = getVirtualPoolTokenAmount()
1534+ func myltiplyAssetsForK (pars,assetId) = {
1535+ func findAssetNum (accum,n) = if ((n == assetId))
1536+ then value(indexOf(newAssetIds, n))
1537+ else accum
1538+
1539+ let currentK = pars
1540+ let assetIdStr = getAssetString(assetId)
1541+ let TokenNum = {
1542+ let $l = newAssetIds
1543+ let $s = size($l)
1544+ let $acc0 = 1
1545+ func $f7_1 ($a,$i) = if (($i >= $s))
1546+ then $a
1547+ else findAssetNum($a, $l[$i])
1548+
1549+ func $f7_2 ($a,$i) = if (($i >= $s))
1550+ then $a
1551+ else throw("List size exceeds 10")
1552+
1553+ $f7_2($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1554+ }
1555+ let weight = parseIntValue(newAssetWeightsStrLi[TokenNum])
1556+ let balanceInState = tryGetInteger((("global_" + assetIdStr) + "_balance"))
1557+ let balanceInPayment = attachedBalances[TokenNum]
1558+ let balance = (balanceInState + balanceInPayment)
1559+ let assetDecimals = if ((assetId == unit))
1560+ then 8
1561+ else value(assetInfo(value(assetId))).decimals
1562+ if ((0 >= balance))
1563+ then throw(("you need to attach all new assets in payment. this asset is missed: " + assetIdStr))
1564+ else fraction(currentK, pow(balance, assetDecimals, weight, AssetsWeightsDecimals, 8, FLOOR), Scale8)
1565+ }
1566+
1567+ let newK = {
1568+ let $l = newAssetIds
1569+ let $s = size($l)
1570+ let $acc0 = PoolTokenScale
1571+ func $f7_1 ($a,$i) = if (($i >= $s))
1572+ then $a
1573+ else myltiplyAssetsForK($a, $l[$i])
1574+
1575+ func $f7_2 ($a,$i) = if (($i >= $s))
1576+ then $a
1577+ else throw("List size exceeds 10")
1578+
1579+ $f7_2($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1580+ }
1581+ let newKMult = fraction(oldKMult, newK, oldK)
1582+ func addTokenDataEntries (accum,assetNum) = {
1583+ let assetIdStr = newAssetIdsStrLi[assetNum]
1584+ let assetId = newAssetIds[assetNum]
1585+ let assetDecimals = if ((assetId == unit))
1586+ then 8
1587+ else value(assetInfo(value(assetId))).decimals
1588+ let newAssetData = if ((indexOf(addedAssets, assetIdStr) != unit))
1589+ then [IntegerEntry((("global_" + assetIdStr) + "_balance"), attachedBalances[assetNum]), IntegerEntry((("static_" + assetIdStr) + "_scale"), pow(10, 0, assetDecimals, 0, 0, DOWN)), IntegerEntry((("static_" + assetIdStr) + "_decimals"), assetDecimals)]
1590+ else nil
1591+ if ((assetNum >= size(newAssetWeightsStrLi)))
1592+ then accum
1593+ else ((accum ++ [IntegerEntry((("static_" + assetIdStr) + "_weight"), value(parseInt(newAssetWeightsStrLi[assetNum])))]) ++ newAssetData)
1594+ }
1595+
1596+ ({
1597+ let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1598+ let $s = size($l)
1599+ let $acc0 = nil
1600+ func $f8_1 ($a,$i) = if (($i >= $s))
1601+ then $a
1602+ else addTokenDataEntries($a, $l[$i])
1603+
1604+ func $f8_2 ($a,$i) = if (($i >= $s))
1605+ then $a
1606+ else throw("List size exceeds 10")
1607+
1608+ $f8_2($f8_1($f8_1($f8_1($f8_1($f8_1($f8_1($f8_1($f8_1($f8_1($f8_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1609+ } ++ [StringEntry("static_tokenIds", assetIdsStr), StringEntry("static_feeToken", feeAssetStr), StringEntry("static_tokenWeights", assetWeightsStr), IntegerEntry("static_tokensAmount", size(newAssetIds)), IntegerEntry("static_KMult", newKMult)])
1610+ }
1611+ }
1612+
1613+
7751614 @Verifier(tx)
776-func verify () = if (isShutdown())
777- then false
778- else if (sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey))
1615+func verify () = if (if ((valueOrElse(getInteger("global_wasPreInited"), 0) == 0))
1616+ then if (sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey))
7791617 then true
7801618 else sigVerify(tx.bodyBytes, tx.proofs[0], masterPubKey)
1619+ else false)
1620+ then true
1621+ else match tx {
1622+ case tx: SetScriptTransaction =>
1623+ let scriptFull = value(tx.script)
1624+ let hash = toBase58String(sha256(scriptFull))
1625+ if (sigVerify(tx.bodyBytes, tx.proofs[0], masterPubKey))
1626+ then (valueOrElse(getInteger(coldMasterAddress, ("approvedScript_" + hash)), 0) > height)
1627+ else false
1628+ case _ =>
1629+ if (sigVerify(tx.bodyBytes, tx.proofs[0], masterPubKey))
1630+ then (valueOrElse(getInteger(coldMasterAddress, ("approvedTx_" + toBase58String(tx.id))), 0) > 0)
1631+ else false
1632+ }
7811633
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let usdnAssetId = base58'DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p'
4+let VERSION = "PZ-1.2.2 PROD"
55
6-let puzzleAssetId = base58'HEB8Qaw9xrWpWs8tHsiATYGBWDBtP2S7kcPALrMu43AS'
6+let configStr = valueOrElse(getString(this, "configAddress"), "3PPEBRg4s2af2rQ2ZbLvdu1Hfd4Vo6QVDTo")
77
8-let usdtAssetId = base58'34N9YcEETLWn93qYQ64EsP1x89tSruJU44RrEMSXXEPJ'
8+let CONFIG_ADDRESS = if ((configStr == ""))
9+ then this
10+ else Address(fromBase58String(configStr))
911
10-let usdtPptAssetId = base58'9wc3LXNA4TEBsXyKtoLE9mrbDD7WMHXvXrCjZvabLAsi'
12+let AssetsWeightsDecimals = 4
1113
12-let usdnAssetIdStr = "DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p"
14+let Scale = 10000
1315
14-let puzzleAssetIdStr = "HEB8Qaw9xrWpWs8tHsiATYGBWDBtP2S7kcPALrMu43AS"
16+let Scale8 = 100000000
1517
16-let usdtAssetIdStr = "34N9YcEETLWn93qYQ64EsP1x89tSruJU44RrEMSXXEPJ"
18+let Scale16 = 10000000000000000
1719
18-let usdtPptAssetIdStr = "9wc3LXNA4TEBsXyKtoLE9mrbDD7WMHXvXrCjZvabLAsi"
20+let FeeScale = 10000
1921
20-let parentPoolAddress = Address(base58'3PFDgzu1UtswAkCMxqqQjbTeHaX4cMab8Kh')
22+let PoolTokenDecimals = 8
2123
22-let masterAddress = Address(base58'3PLjwHcz9NEuaTo63NZR9B9okQiKQxZSbmf')
24+let PoolTokenScale = pow(10, 0, PoolTokenDecimals, 0, 0, HALFUP)
2325
24-let masterPubKey = base58'4z8CKSYQBKkzx7PBb5uBP1YPa6YAHRNTApW1sQVHT5eU'
26+let MIN_STEPS_AMOUNT = valueOrElse(getInteger(CONFIG_ADDRESS, "min_steps_amount"), 1)
27+
28+let MAX_STEPS_AMOUNT = valueOrElse(getInteger(CONFIG_ADDRESS, "max_steps_amount"), 500)
29+
30+let MIN_STEPS_INTERVAL = valueOrElse(getInteger(CONFIG_ADDRESS, "min_steps_interval"), 1)
31+
32+let MAX_STEPS_INTERVAL = valueOrElse(getInteger(CONFIG_ADDRESS, "max_steps_interval"), 10000)
33+
34+let MIN_WEIGHT = valueOrElse(getInteger(CONFIG_ADDRESS, "min_weight"), 100)
35+
36+let MAX_WEIGHT = valueOrElse(getInteger(CONFIG_ADDRESS, "max_weight"), 9900)
2537
2638 func tryGetInteger (key) = match getInteger(this, key) {
2739 case b: Int =>
2840 b
2941 case _ =>
3042 0
3143 }
3244
3345
3446 func tryGetBinary (key) = match getBinary(this, key) {
3547 case b: ByteVector =>
3648 b
3749 case _ =>
3850 base58''
3951 }
4052
4153
4254 func tryGetString (key) = match getString(this, key) {
4355 case b: String =>
4456 b
4557 case _ =>
4658 ""
4759 }
4860
4961
62+func tryGetStringOrThrow (key) = match getString(this, key) {
63+ case b: String =>
64+ b
65+ case _ =>
66+ throw(("no such key in data storage: " + key))
67+}
68+
69+
5070 func getAssetString (assetId) = match assetId {
5171 case b: ByteVector =>
5272 toBase58String(b)
5373 case _ =>
5474 "WAVES"
5575 }
5676
5777
5878 func getAssetBytes (assetIdStr) = if ((assetIdStr == "WAVES"))
5979 then unit
6080 else fromBase58String(assetIdStr)
6181
6282
83+func getTokenBalance (assetId) = match assetId {
84+ case t: ByteVector =>
85+ assetBalance(this, t)
86+ case _ =>
87+ wavesBalance(this).available
88+}
89+
90+
6391 func addAssetBytesToList (accum,item) = (accum ++ [getAssetBytes(item)])
6492
6593
6694 func addAssetWeightToList (accum,item) = (accum ++ [tryGetInteger((("static_" + getAssetString(item)) + "_weight"))])
95+
96+
97+func addAssetWeightToStrList (accum,item) = (accum ++ [toString(tryGetInteger((("static_" + item) + "_weight")))])
6798
6899
69100 func addAssetDecimalsToList (accum,item) = (accum ++ [tryGetInteger((("static_" + getAssetString(item)) + "_decimals"))])
70101
71102
72103 func addAssetScaleToList (accum,item) = (accum ++ [tryGetInteger((("static_" + getAssetString(item)) + "_scale"))])
73104
74105
75106 func addIntToList (accum,item) = (accum ++ [parseIntValue(item)])
76107
108+
109+let usdnAssetIdStr = valueOrElse(getString(CONFIG_ADDRESS, "usdnAssetIdStr"), "DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p")
110+
111+let puzzleAssetIdStr = valueOrElse(getString(CONFIG_ADDRESS, "puzzleAssetIdStr"), "HEB8Qaw9xrWpWs8tHsiATYGBWDBtP2S7kcPALrMu43AS")
112+
113+let usdtAssetIdStr = valueOrElse(getString(CONFIG_ADDRESS, "usdtAssetIdStr"), "34N9YcEETLWn93qYQ64EsP1x89tSruJU44RrEMSXXEPJ")
114+
115+let usdtPptAssetIdStr = valueOrElse(getString(CONFIG_ADDRESS, "usdtPptAssetIdStr"), "9wc3LXNA4TEBsXyKtoLE9mrbDD7WMHXvXrCjZvabLAsi")
116+
117+let romeAssetIdStr = valueOrElse(getString(CONFIG_ADDRESS, "romeAssetIdStr"), "AP4Cb5xLYGH6ZigHreCZHoXpQTWDkPsG2BHqfDUx6taJ")
118+
119+let wavesAssetIdStr = "WAVES"
120+
121+let usdnAssetId = fromBase58String(usdnAssetIdStr)
122+
123+let puzzleAssetId = fromBase58String(puzzleAssetIdStr)
124+
125+let usdtAssetId = fromBase58String(usdtAssetIdStr)
126+
127+let usdtPptAssetId = fromBase58String(usdtPptAssetIdStr)
128+
129+let romeAssetId = fromBase58String(romeAssetIdStr)
130+
131+let wavesAssetId = unit
132+
133+let supportedFeeAssetsStr = [usdnAssetIdStr, puzzleAssetIdStr, usdtAssetIdStr, usdtPptAssetIdStr, wavesAssetIdStr, romeAssetIdStr]
134+
135+let parentPoolAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "parentPoolAddress"), "3PFDgzu1UtswAkCMxqqQjbTeHaX4cMab8Kh")))
136+
137+let masterAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "masterAddress"), "3PLjwHcz9NEuaTo63NZR9B9okQiKQxZSbmf")))
138+
139+let masterPubKey = fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "masterPubKey"), "4z8CKSYQBKkzx7PBb5uBP1YPa6YAHRNTApW1sQVHT5eU"))
140+
141+let oracleAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "oracleAddress"), "3P8d1E1BLKoD52y3bQJ1bDTd2TD1gpaLn9t")))
142+
143+let stakingAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "stakingAddress"), "3PFTbywqxtFfukX3HyT881g4iW5K4QL3FAS")))
144+
145+let feesAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "feesAddress"), "3PFWAVKmXjfHXyzJb12jCbhP4Uhi9t4uWiD")))
146+
147+let poolsHubAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "poolsHubAddress"), "3P5YutjDNC3hABBVsveFuZTTbQ5PdtSDBgk")))
148+
149+let shutdownAddressStr = valueOrElse(getString(CONFIG_ADDRESS, "shutdownAddress"), "3PEpv9hRFWEEBU22WRnLsw1bH4YGtcU728o")
150+
151+let layer2Addresses = valueOrElse(getString(CONFIG_ADDRESS, "layer2Addresses"), "3PR1Qvi9mHT35SwWEkLSqqE2L8thiPLdVWU,3PQoBfUKHkJAeGWhooLP7WS8ovb54av9Jp2")
152+
153+let govAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "govAddress"), "3P6uro9xCsE8te78QZjzqy7aq8natSzdceC")))
154+
155+let coldMasterAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "coldMasterAddress"), "3PK9nhPfPbMBygB9ZgHVMHaQbSoojwrBfxj")))
77156
78157 let T = tryGetInteger("static_tokensAmount")
79158
80159 let assetIds = {
81160 let $l = split(tryGetString("static_tokenIds"), ",")
82161 let $s = size($l)
83162 let $acc0 = nil
84163 func $f0_1 ($a,$i) = if (($i >= $s))
85164 then $a
86165 else addAssetBytesToList($a, $l[$i])
87166
88167 func $f0_2 ($a,$i) = if (($i >= $s))
89168 then $a
90169 else throw("List size exceeds 10")
91170
92171 $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)
93172 }
94173
95174 let AssetsWeights = {
96175 let $l = assetIds
97176 let $s = size($l)
98177 let $acc0 = nil
99178 func $f1_1 ($a,$i) = if (($i >= $s))
100179 then $a
101180 else addAssetWeightToList($a, $l[$i])
102181
103182 func $f1_2 ($a,$i) = if (($i >= $s))
104183 then $a
105184 else throw("List size exceeds 10")
106185
107186 $f1_2($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
108187 }
109188
110189 let Decimals = {
111190 let $l = assetIds
112191 let $s = size($l)
113192 let $acc0 = nil
114193 func $f2_1 ($a,$i) = if (($i >= $s))
115194 then $a
116195 else addAssetDecimalsToList($a, $l[$i])
117196
118197 func $f2_2 ($a,$i) = if (($i >= $s))
119198 then $a
120199 else throw("List size exceeds 10")
121200
122201 $f2_2($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($f2_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
123202 }
124203
125204 let Scales = {
126205 let $l = assetIds
127206 let $s = size($l)
128207 let $acc0 = nil
129208 func $f3_1 ($a,$i) = if (($i >= $s))
130209 then $a
131210 else addAssetScaleToList($a, $l[$i])
132211
133212 func $f3_2 ($a,$i) = if (($i >= $s))
134213 then $a
135214 else throw("List size exceeds 10")
136215
137216 $f3_2($f3_1($f3_1($f3_1($f3_1($f3_1($f3_1($f3_1($f3_1($f3_1($f3_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
138217 }
139218
140219 let Fee = tryGetInteger("static_fee")
141220
142-let AssetsWeightsDecimals = 4
143-
144-let Scale = 10000
145-
146-let Scale8 = 100000000
147-
148-let FeeScale = 10000
149-
150-let PoolTokenDecimals = 8
151-
152-let PoolTokenScale = pow(10, 0, PoolTokenDecimals, 0, 0, HALFUP)
153-
154221 let earnedAssets = assetIds
155222
156-func isShutdown () = match getBoolean(Address(base58'3PEpv9hRFWEEBU22WRnLsw1bH4YGtcU728o'), "is_shutdown") {
157- case x: Boolean =>
223+func isShutdown () = {
224+ let shutdownAddress = addressFromString(shutdownAddressStr)
225+ if ((shutdownAddress == unit))
226+ then false
227+ else match getBoolean(value(shutdownAddress), "is_shutdown") {
228+ case x: Boolean =>
229+ x
230+ case _ =>
231+ false
232+ }
233+ }
234+
235+
236+func getCurrentTokenBalance (tokenNum) = {
237+ let tokenIdStr = getAssetString(assetIds[tokenNum])
238+ tryGetInteger((("global_" + tokenIdStr) + "_balance"))
239+ }
240+
241+
242+func getKMult () = match getInteger("static_KMult") {
243+ case x: Int =>
158244 x
159245 case _ =>
160- false
246+ Scale16
161247 }
162248
163249
164-func getCurrentTokenBalance (tokenType) = {
165- let tokenId = getAssetString(assetIds[tokenType])
166- tryGetInteger((("global_" + tokenId) + "_balance"))
250+func saveCurrentWeights () = {
251+ let assetIdsLi = split(tryGetString("static_tokenIds"), ",")
252+ func s (accum,assetId) = (accum ++ [IntegerEntry(("rebalance_startWeight_" + assetId), tryGetInteger((("static_" + assetId) + "_weight")))])
253+
254+ let $l = assetIdsLi
255+ let $s = size($l)
256+ let $acc0 = nil
257+ func $f4_1 ($a,$i) = if (($i >= $s))
258+ then $a
259+ else s($a, $l[$i])
260+
261+ func $f4_2 ($a,$i) = if (($i >= $s))
262+ then $a
263+ else throw("List size exceeds 10")
264+
265+ $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
167266 }
168267
169268
269+func getVirtualPoolTokenAmount () = fraction(tryGetInteger("global_poolToken_amount"), getKMult(), Scale16)
270+
271+
170272 func calculatePIssued (amount,tokenId) = {
171- let Psupply = tryGetInteger("global_poolToken_amount")
273+ let Psupply = getVirtualPoolTokenAmount()
172274 let Balance = tryGetInteger((("global_" + getAssetString(tokenId)) + "_balance"))
173- fraction(amount, Psupply, Balance, DOWN)
275+ let t1 = fraction(amount, Psupply, Balance, DOWN)
276+ t1
174277 }
175278
176279
177280 func getMinPIssued (payments) = {
178281 func handler (accum,current) = {
179282 let PIssued = calculatePIssued(current.amount, current.assetId)
180283 if ((PIssued == 0))
181284 then throw("one of the tokens amounts is too low")
182285 else if (if ((accum == 0))
183286 then true
184287 else (accum > PIssued))
185288 then PIssued
186289 else accum
187290 }
188291
189292 let minPIssed = {
190293 let $l = payments
191294 let $s = size($l)
192295 let $acc0 = 0
193296 func $f4_1 ($a,$i) = if (($i >= $s))
194297 then $a
195298 else handler($a, $l[$i])
196299
197300 func $f4_2 ($a,$i) = if (($i >= $s))
198301 then $a
199302 else throw("List size exceeds 10")
200303
201304 $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
202305 }
203306 minPIssed
204307 }
205308
206309
207310 func calculateUsdnValue (assetId,amount,aBalance,givenUsdnBalance) = {
208311 let usdnInPool = indexOf(assetIds, usdnAssetId)
209312 let puzzleInPool = indexOf(assetIds, puzzleAssetId)
210313 let usdtInPool = indexOf(assetIds, usdtAssetId)
211314 let usdtPptInPool = indexOf(assetIds, usdtPptAssetId)
212315 let wavesInPool = indexOf(assetIds, unit)
213316 let assetWeight = tryGetInteger((("static_" + getAssetString(assetId)) + "_weight"))
214317 let feeAssetStr = tryGetString("static_feeToken")
215318 if ((feeAssetStr == puzzleAssetIdStr))
216319 then {
217320 let puzzleWeight = AssetsWeights[value(indexOf(assetIds, puzzleAssetId))]
218321 let puzzleBalance = tryGetInteger((("global_" + puzzleAssetIdStr) + "_balance"))
219322 let amountInPuzzle = fraction(amount, (puzzleBalance / puzzleWeight), (aBalance / assetWeight))
220323 let puzzlePrice = getIntegerValue(parentPoolAddress, "global_lastPuzzlePrice")
221324 fraction((amountInPuzzle * puzzlePrice), 1, Scale8)
222325 }
223326 else if ((feeAssetStr == usdtAssetIdStr))
224327 then {
225328 let usdtWeight = AssetsWeights[value(usdtInPool)]
226329 let usdtBalance = tryGetInteger((("global_" + usdtAssetIdStr) + "_balance"))
227330 fraction(amount, (usdtBalance / usdtWeight), (aBalance / assetWeight))
228331 }
229332 else if ((feeAssetStr == usdtPptAssetIdStr))
230333 then {
231334 let usdtWeight = AssetsWeights[value(usdtPptInPool)]
232335 let usdtBalance = tryGetInteger((("global_" + usdtPptAssetIdStr) + "_balance"))
233336 fraction(amount, (usdtBalance / usdtWeight), (aBalance / assetWeight))
234337 }
235338 else if ((feeAssetStr == usdnAssetIdStr))
236339 then {
237340 let usdnWeight = AssetsWeights[value(indexOf(assetIds, usdnAssetId))]
238341 let usdnBalance = match givenUsdnBalance {
239342 case x: Int =>
240343 givenUsdnBalance
241344 case _ =>
242345 tryGetInteger((("global_" + getAssetString(usdnAssetId)) + "_balance"))
243346 }
244347 fraction(amount, (value(usdnBalance) / usdnWeight), (aBalance / assetWeight))
245348 }
246349 else {
247350 let wavesWeight = 3000
248351 let wBalance = (tryGetInteger("global_WAVES_balance") / 50)
249352 fraction(amount, (wBalance / wavesWeight), (aBalance / assetWeight))
250353 }
251354 }
252355
253356
357+func getPriceFromOracle (assetIdStr) = match getInteger(oracleAddress, (assetIdStr + "_twap5B")) {
358+ case x: Int =>
359+ x
360+ case _ =>
361+ 0
362+}
363+
364+
365+func calculateUsdValue (assetId,amount,aBalance) = {
366+ let assetWeight = tryGetInteger((("static_" + getAssetString(assetId)) + "_weight"))
367+ let feeAssetStr = tryGetString("static_feeToken")
368+ let feeAssetScale = getIntegerValue(this, (("static_" + feeAssetStr) + "_scale"))
369+ let feeAssetNum = value(indexOf(assetIds, getAssetBytes(feeAssetStr)))
370+ let feeAssetWeight = AssetsWeights[feeAssetNum]
371+ let feeAssetBalance = tryGetInteger((("global_" + feeAssetStr) + "_balance"))
372+ let valInFeeAsset = fraction(amount, (feeAssetBalance / feeAssetWeight), (aBalance / assetWeight))
373+ let feeAssetPrice = getPriceFromOracle(feeAssetStr)
374+ fraction(valInFeeAsset, feeAssetPrice, feeAssetScale)
375+ }
376+
377+
254378 func checkTokensValidity (payments) = {
255379 func handler1 (accum,payment) = (accum ++ [payment.assetId])
256380
257381 let ids = {
258382 let $l = payments
259383 let $s = size($l)
260384 let $acc0 = nil
261385 func $f4_1 ($a,$i) = if (($i >= $s))
262386 then $a
263387 else handler1($a, $l[$i])
264388
265389 func $f4_2 ($a,$i) = if (($i >= $s))
266390 then $a
267391 else throw("List size exceeds 10")
268392
269393 $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
270394 }
271395 if ((ids == ids))
272396 then {
273397 func handler2 (accum,assetId) = if ((indexOf(ids, assetId) != unit))
274398 then (accum + 1)
275399 else throw(("asset not attached: " + getAssetString(assetId)))
276400
277401 let checks = {
278402 let $l = assetIds
279403 let $s = size($l)
280404 let $acc0 = 0
281405 func $f5_1 ($a,$i) = if (($i >= $s))
282406 then $a
283407 else handler2($a, $l[$i])
284408
285409 func $f5_2 ($a,$i) = if (($i >= $s))
286410 then $a
287411 else throw("List size exceeds 10")
288412
289413 $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
290414 }
291415 if ((checks == checks))
292416 then true
293417 else throw("Strict value is not equal to itself.")
294418 }
295419 else throw("Strict value is not equal to itself.")
296420 }
297421
298422
299423 func handlePoolTokensAdd (PIssued,payments,userAddress,needChange) = {
300424 func getTokenPaymentAmount (tokenId) = {
301425 func handler (accum,payment) = if ((payment.assetId == tokenId))
302426 then payment.amount
303427 else accum
304428
305429 let $l = payments
306430 let $s = size($l)
307431 let $acc0 = 0
308432 func $f4_1 ($a,$i) = if (($i >= $s))
309433 then $a
310434 else handler($a, $l[$i])
311435
312436 func $f4_2 ($a,$i) = if (($i >= $s))
313437 then $a
314438 else throw("List size exceeds 10")
315439
316440 $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
317441 }
318442
319443 func handleTokenChange (accum,tokenId) = {
320444 let Bk = tryGetInteger((("global_" + getAssetString(tokenId)) + "_balance"))
321- let PSupply = tryGetInteger("global_poolToken_amount")
445+ let PSupply = getVirtualPoolTokenAmount()
322446 let tokenDecimals = tryGetInteger((("static_" + getAssetString(tokenId)) + "_scale"))
323- let Dk = fraction((fraction((PSupply + PIssued), tokenDecimals, PSupply, CEILING) - tokenDecimals), Bk, tokenDecimals, CEILING)
447+ let a1 = fraction((toBigInt((PSupply + PIssued)) * toBigInt(Scale8)), toBigInt(tokenDecimals), toBigInt(PSupply), CEILING)
448+ let Dk = toInt(fraction((a1 - (toBigInt(tokenDecimals) * toBigInt(Scale8))), toBigInt(Bk), (toBigInt(tokenDecimals) * toBigInt(Scale8)), CEILING))
324449 let paymentAmount = getTokenPaymentAmount(tokenId)
325- let toReturn = ((if ((paymentAmount != 0))
326- then paymentAmount
327- else 0) - Dk)
450+ let toReturn = (paymentAmount - Dk)
328451 let t = if (if (needChange)
329452 then (toReturn > 0)
330453 else false)
331454 then [ScriptTransfer(userAddress, toReturn, tokenId)]
332455 else nil
333456 ((accum ++ t) ++ [IntegerEntry((("global_" + getAssetString(tokenId)) + "_balance"), (Bk + Dk))])
334457 }
335458
336459 let $l = assetIds
337460 let $s = size($l)
338461 let $acc0 = nil
339462 func $f4_1 ($a,$i) = if (($i >= $s))
340463 then $a
341464 else handleTokenChange($a, $l[$i])
342465
343466 func $f4_2 ($a,$i) = if (($i >= $s))
344467 then $a
345468 else throw("List size exceeds 10")
346469
347470 $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
348471 }
349472
350473
351474 func handlePoolTokensRedeem (PRedeemed,userAddress) = {
352475 func handleTokenRedeem (accum,tokenId) = {
353476 let Bk = tryGetInteger((("global_" + getAssetString(tokenId)) + "_balance"))
354- let PSupply = tryGetInteger("global_poolToken_amount")
477+ let PSupply = getVirtualPoolTokenAmount()
355478 let tokenDecimals = tryGetInteger((("static_" + getAssetString(tokenId)) + "_scale"))
356- let amount = toInt(fraction((toBigInt(Scale8) - fraction(toBigInt((PSupply - PRedeemed)), toBigInt(Scale8), toBigInt(PSupply), CEILING)), toBigInt(Bk), toBigInt(Scale8), DOWN))
479+ let psuppl = fraction((toBigInt((PSupply - PRedeemed)) * toBigInt(Scale8)), toBigInt(Scale8), toBigInt(PSupply), DOWN)
480+ let amount = toInt(fraction((toBigInt(Scale16) - psuppl), toBigInt(Bk), toBigInt(Scale16), CEILING))
357481 (accum ++ [IntegerEntry((("global_" + getAssetString(tokenId)) + "_balance"), (Bk - amount)), ScriptTransfer(userAddress, amount, tokenId)])
358482 }
359483
360484 let $l = assetIds
361485 let $s = size($l)
362486 let $acc0 = nil
363487 func $f4_1 ($a,$i) = if (($i >= $s))
364488 then $a
365489 else handleTokenRedeem($a, $l[$i])
366490
367491 func $f4_2 ($a,$i) = if (($i >= $s))
368492 then $a
369493 else throw("List size exceeds 10")
370494
371495 $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
372496 }
373497
374498
375499 func calculateOutAmount (AmountIn,assetIn,assetOut,BalanceIn,BalanceOut) = {
376500 let IndexIn = value(indexOf(assetIds, assetIn))
377501 let IndexOut = value(indexOf(assetIds, assetOut))
378502 if ((IndexIn == IndexOut))
379503 then AmountIn
380- else fraction(BalanceOut, ((Scale8 * Scale8) - toInt(pow(fraction(toBigInt(BalanceIn), toBigInt((Scale8 * Scale8)), toBigInt((BalanceIn + AmountIn)), HALFUP), 16, toBigInt(fraction(AssetsWeights[IndexIn], 10000, AssetsWeights[IndexOut])), 4, 16, CEILING))), (Scale8 * Scale8), DOWN)
504+ else fraction(BalanceOut, ((Scale8 * Scale8) - toInt(pow(fraction((toBigInt(BalanceIn) * toBigInt(10000)), toBigInt((Scale8 * Scale8)), (toBigInt((BalanceIn + AmountIn)) * toBigInt(10000)), HALFUP), 16, toBigInt(fraction(AssetsWeights[IndexIn], 1000000000000, AssetsWeights[IndexOut])), 12, 16, CEILING))), (Scale8 * Scale8), HALFEVEN)
381505 }
382-
383-
384-func getTokenBalance (assetId) = match assetId {
385- case t: ByteVector =>
386- assetBalance(this, t)
387- case _ =>
388- wavesBalance(this).available
389-}
390506
391507
392508 func calculateCurrentAssetInterest (assetId,assetIdStr,aBalance,tokenEarningsLastCheck) = {
393509 let totalStaked = tryGetInteger("global_indexStaked")
394510 let tokenBalanceLastCheck = tokenEarningsLastCheck
395511 let currentBalanceDelta = (getTokenBalance(assetId) - aBalance)
396512 let currentTokenEarnings = if ((currentBalanceDelta > tokenBalanceLastCheck))
397513 then currentBalanceDelta
398514 else tokenBalanceLastCheck
399515 let newEarnings = (currentTokenEarnings - tokenBalanceLastCheck)
400516 let newInterest = if ((totalStaked == 0))
401517 then 0
402518 else fraction(newEarnings, Scale8, totalStaked)
403519 let lastCheckInterest = tryGetInteger((("global_lastCheck_" + assetIdStr) + "_interest"))
404520 (lastCheckInterest + newInterest)
405521 }
406522
407523
408524 func claimResult (address) = {
409525 let addressStr = toString(address)
410526 let puzzleAmount = tryGetInteger((addressStr + "_indexStaked"))
411527 func handler (accum,assetId) = {
412528 let assetIdStr = getAssetString(assetId)
413529 let aBalance = tryGetInteger((("global_" + getAssetString(assetId)) + "_balance"))
414530 let tokenEarningsLastCheck = tryGetInteger((("global_lastCheck_" + assetIdStr) + "_earnings"))
415531 let currentTokenInterest = calculateCurrentAssetInterest(assetId, assetIdStr, aBalance, tokenEarningsLastCheck)
416532 let currentTokenEarnings = max([tokenEarningsLastCheck, (getTokenBalance(assetId) - aBalance)])
417533 let rewardAmount = fraction(puzzleAmount, (currentTokenInterest - tryGetInteger((((addressStr + "_lastCheck_") + assetIdStr) + "_interest"))), Scale8)
418534 let transfer = if ((rewardAmount == 0))
419535 then nil
420536 else [ScriptTransfer(address, rewardAmount, assetId)]
421- $Tuple2(((accum._1 ++ transfer) ++ [IntegerEntry((("global_lastCheck_" + assetIdStr) + "_earnings"), (currentTokenEarnings - rewardAmount)), IntegerEntry((("global_lastCheck_" + assetIdStr) + "_interest"), currentTokenInterest), IntegerEntry((((addressStr + "_lastCheck_") + assetIdStr) + "_interest"), currentTokenInterest)]), (accum._2 + calculateUsdnValue(assetId, rewardAmount, aBalance, unit)))
537+ $Tuple2(((accum._1 ++ transfer) ++ [IntegerEntry((("global_lastCheck_" + assetIdStr) + "_earnings"), (currentTokenEarnings - rewardAmount)), IntegerEntry((("global_lastCheck_" + assetIdStr) + "_interest"), currentTokenInterest), IntegerEntry((((addressStr + "_lastCheck_") + assetIdStr) + "_interest"), currentTokenInterest)]), (accum._2 + calculateUsdValue(assetId, rewardAmount, aBalance)))
422538 }
423539
424540 let accum = {
425541 let $l = earnedAssets
426542 let $s = size($l)
427543 let $acc0 = $Tuple2(nil, 0)
428544 func $f4_1 ($a,$i) = if (($i >= $s))
429545 then $a
430546 else handler($a, $l[$i])
431547
432548 func $f4_2 ($a,$i) = if (($i >= $s))
433549 then $a
434550 else throw("List size exceeds 10")
435551
436552 $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
437553 }
438- $Tuple2((accum._1 ++ [IntegerEntry((addressStr + "_claimedRewardValue"), (tryGetInteger((addressStr + "_claimedRewardValue")) + accum._2)), IntegerEntry((addressStr + "_lastClaim"), lastBlock.timestamp)]), accum._2)
554+ $Tuple2((accum._1 ++ [IntegerEntry((addressStr + "_claimedRewardUSD"), (tryGetInteger((addressStr + "_claimedRewardUSD")) + accum._2)), IntegerEntry((addressStr + "_lastClaim"), lastBlock.timestamp)]), accum._2)
439555 }
440556
441557
442558 func indexStakeResult (addressStr,amount) = {
443559 let li = claimResult(addressFromStringValue(addressStr))._1
444560 (li ++ [IntegerEntry((addressStr + "_indexStaked"), (tryGetInteger((addressStr + "_indexStaked")) + amount)), IntegerEntry("global_indexStaked", (tryGetInteger("global_indexStaked") + amount))])
445561 }
446562
447563
448564 func sum (accum,n) = (accum + parseIntValue(n))
449565
450566
567+func checkFeeAsset (accum,next) = if (if ((indexOf(supportedFeeAssetsStr, next) != unit))
568+ then (accum == "")
569+ else false)
570+ then next
571+ else accum
572+
573+
574+func getTmpRebalanceIds (newAssetIdsLi) = {
575+ let currentAssetIdsLi = split(tryGetString("static_tokenIds"), ",")
576+ let result = newAssetIdsLi
577+ func f (accum,assetId) = if ((indexOf(result, assetId) == unit))
578+ then (accum ++ [assetId])
579+ else accum
580+
581+ let $l = currentAssetIdsLi
582+ let $s = size($l)
583+ let $acc0 = result
584+ func $f4_1 ($a,$i) = if (($i >= $s))
585+ then $a
586+ else f($a, $l[$i])
587+
588+ func $f4_2 ($a,$i) = if (($i >= $s))
589+ then $a
590+ else throw("List size exceeds 10")
591+
592+ $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
593+ }
594+
595+
596+func checkTokensChange (newAssetIdsLi) = {
597+ let currentAssetIdsLi = split(tryGetString("static_tokenIds"), ",")
598+ func rem (accum,assetId) = if ((indexOf(newAssetIdsLi, assetId) == unit))
599+ then (accum + 1)
600+ else accum
601+
602+ func add (accum,assetId) = if ((indexOf(currentAssetIdsLi, assetId) == unit))
603+ then (accum + 1)
604+ else accum
605+
606+ let removed = {
607+ let $l = currentAssetIdsLi
608+ let $s = size($l)
609+ let $acc0 = 0
610+ func $f4_1 ($a,$i) = if (($i >= $s))
611+ then $a
612+ else rem($a, $l[$i])
613+
614+ func $f4_2 ($a,$i) = if (($i >= $s))
615+ then $a
616+ else throw("List size exceeds 10")
617+
618+ $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
619+ }
620+ let added = {
621+ let $l = newAssetIdsLi
622+ let $s = size($l)
623+ let $acc0 = 0
624+ func $f5_1 ($a,$i) = if (($i >= $s))
625+ then $a
626+ else add($a, $l[$i])
627+
628+ func $f5_2 ($a,$i) = if (($i >= $s))
629+ then $a
630+ else throw("List size exceeds 10")
631+
632+ $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
633+ }
634+ (removed + added)
635+ }
636+
637+
638+func validatePayments (assetsList,payments) = {
639+ func getPaymentAssets (accum,next) = if ((0 >= next.amount))
640+ then throw(((("Too low payment amount for " + getAssetString(next.assetId)) + ": ") + toString(next.amount)))
641+ else (accum ++ [getAssetString(next.assetId)])
642+
643+ let paymentList = {
644+ let $l = payments
645+ let $s = size($l)
646+ let $acc0 = nil
647+ func $f4_1 ($a,$i) = if (($i >= $s))
648+ then $a
649+ else getPaymentAssets($a, $l[$i])
650+
651+ func $f4_2 ($a,$i) = if (($i >= $s))
652+ then $a
653+ else throw("List size exceeds 10")
654+
655+ $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
656+ }
657+ func f1 (accum,next) = if ((indexOf(assetsList, next) == unit))
658+ then throw(((next + " asset is present in payments, but is not in new assets: ") + makeString(assetsList, ",")))
659+ else (accum + 1)
660+
661+ func f2 (accum,next) = if ((indexOf(paymentList, next) == unit))
662+ then throw(((next + " asset is present in new assets, but is not in payments: ") + makeString(paymentList, ",")))
663+ else (accum + 1)
664+
665+ let a1 = {
666+ let $l = paymentList
667+ let $s = size($l)
668+ let $acc0 = 0
669+ func $f5_1 ($a,$i) = if (($i >= $s))
670+ then $a
671+ else f1($a, $l[$i])
672+
673+ func $f5_2 ($a,$i) = if (($i >= $s))
674+ then $a
675+ else throw("List size exceeds 10")
676+
677+ $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
678+ }
679+ let a2 = {
680+ let $l = assetsList
681+ let $s = size($l)
682+ let $acc0 = 0
683+ func $f6_1 ($a,$i) = if (($i >= $s))
684+ then $a
685+ else f2($a, $l[$i])
686+
687+ func $f6_2 ($a,$i) = if (($i >= $s))
688+ then $a
689+ else throw("List size exceeds 10")
690+
691+ $f6_2($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
692+ }
693+ (a1 + a2)
694+ }
695+
696+
697+func validateWeights (weights) = {
698+ func v (accum,w) = {
699+ let wInt = valueOrErrorMessage(parseInt(w), ("Wrong weight format: " + w))
700+ if (if ((MIN_WEIGHT > wInt))
701+ then true
702+ else (wInt > MAX_WEIGHT))
703+ then throw(((((("Weight should be in range " + toString(MIN_WEIGHT)) + " - ") + toString(MAX_WEIGHT)) + ", current: ") + w))
704+ else accum
705+ }
706+
707+ let $l = weights
708+ let $s = size($l)
709+ let $acc0 = 0
710+ func $f4_1 ($a,$i) = if (($i >= $s))
711+ then $a
712+ else v($a, $l[$i])
713+
714+ func $f4_2 ($a,$i) = if (($i >= $s))
715+ then $a
716+ else throw("List size exceeds 10")
717+
718+ $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
719+ }
720+
721+
451722 @Callable(i)
452723 func preInit (assetIdsStr,assetWeightsStr,baseTokenIdStr,poolDomain,poolOwner,fee) = {
453724 let poolOwnerAddress = Address(fromBase58String(poolOwner))
725+ let assetIdsStrLi = split(assetIdsStr, ",")
726+ let assetIdsLi = {
727+ let $l = assetIdsStrLi
728+ let $s = size($l)
729+ let $acc0 = nil
730+ func $f4_1 ($a,$i) = if (($i >= $s))
731+ then $a
732+ else addAssetBytesToList($a, $l[$i])
733+
734+ func $f4_2 ($a,$i) = if (($i >= $s))
735+ then $a
736+ else throw("List size exceeds 10")
737+
738+ $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
739+ }
740+ let feeAssetStr = {
741+ let $l = assetIdsStrLi
742+ let $s = size($l)
743+ let $acc0 = ""
744+ func $f5_1 ($a,$i) = if (($i >= $s))
745+ then $a
746+ else checkFeeAsset($a, $l[$i])
747+
748+ func $f5_2 ($a,$i) = if (($i >= $s))
749+ then $a
750+ else throw("List size exceeds 10")
751+
752+ $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
753+ }
454754 if (isShutdown())
455755 then throw("contract is on stop")
456756 else if ((this != i.caller))
457757 then throw("admin only")
458- else if ((size(poolDomain) > 13))
459- then throw("too large pool domain")
460- else if (if ((fee > 500))
461- then true
462- else (50 > fee))
463- then throw("fee value must be between 50 and 500 (0.5-5%)")
464- else if (if (if (if (if ((indexOf(assetIdsStr, puzzleAssetIdStr) == unit))
465- then (indexOf(assetIdsStr, usdnAssetIdStr) == unit)
466- else false)
467- then (indexOf(assetIdsStr, usdtAssetIdStr) == unit)
468- else false)
469- then (indexOf(assetIdsStr, "WAVES") == unit)
470- else false)
471- then (indexOf(assetIdsStr, usdtPptAssetIdStr) == unit)
472- else false)
473- then throw("pool must have USDT-WXG, USDT-PPT, USDN, WAVES or PUZZLE in the composition")
758+ else if ((feeAssetStr == ""))
759+ then throw("pool must have one of the supported fee assets in the composition")
760+ else if ((size(poolDomain) > 13))
761+ then throw("too large pool domain")
762+ else if (if ((fee > 500))
763+ then true
764+ else (0 > fee))
765+ then throw("fee value must be between 50 and 500 (0.5-5%)")
474766 else {
475- let assetIdsStrLi = split(assetIdsStr, ",")
476- let assetIdsLi = {
477- let $l = assetIdsStrLi
478- let $s = size($l)
479- let $acc0 = nil
480- func $f4_1 ($a,$i) = if (($i >= $s))
481- then $a
482- else addAssetBytesToList($a, $l[$i])
483-
484- func $f4_2 ($a,$i) = if (($i >= $s))
485- then $a
486- else throw("List size exceeds 10")
487-
488- $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
489- }
490767 let assetWeightsStrLi = split(assetWeightsStr, ",")
491768 let assetWeightsSum = {
492769 let $l = assetWeightsStrLi
493770 let $s = size($l)
494771 let $acc0 = 0
495- func $f5_1 ($a,$i) = if (($i >= $s))
772+ func $f6_1 ($a,$i) = if (($i >= $s))
496773 then $a
497774 else sum($a, $l[$i])
498775
499- func $f5_2 ($a,$i) = if (($i >= $s))
776+ func $f6_2 ($a,$i) = if (($i >= $s))
500777 then $a
501778 else throw("List size exceeds 10")
502779
503- $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
780+ $f6_2($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
504781 }
505- let feeAssetStr = if ((indexOf(assetIdsStr, usdnAssetIdStr) != unit))
506- then usdnAssetIdStr
507- else if ((indexOf(assetIdsStr, "WAVES") != unit))
508- then "WAVES"
509- else if ((indexOf(assetIdsStr, usdtAssetIdStr) != unit))
510- then usdtAssetIdStr
511- else if ((indexOf(assetIdsStr, puzzleAssetIdStr) != unit))
512- then puzzleAssetIdStr
513- else usdtPptAssetIdStr
514782 func addTokenDataEntries (accum,assetNum) = if ((assetNum >= size(assetIdsLi)))
515783 then accum
516784 else {
517785 let assetDecimals = match assetIdsLi[assetNum] {
518786 case x: ByteVector =>
519787 value(assetInfo(x)).decimals
520788 case _ =>
521789 8
522790 }
523791 (accum ++ [IntegerEntry((("static_" + assetIdsStrLi[assetNum]) + "_scale"), pow(10, 0, assetDecimals, 0, 0, DOWN)), IntegerEntry((("static_" + assetIdsStrLi[assetNum]) + "_decimals"), assetDecimals), IntegerEntry((("static_" + assetIdsStrLi[assetNum]) + "_weight"), value(parseInt(assetWeightsStrLi[assetNum])))])
524792 }
525793
526794 if ((assetWeightsSum != 10000))
527795 then throw("sum of token weights must be equal to 10000")
528796 else ({
529797 let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
530798 let $s = size($l)
531799 let $acc0 = nil
532- func $f6_1 ($a,$i) = if (($i >= $s))
800+ func $f7_1 ($a,$i) = if (($i >= $s))
533801 then $a
534802 else addTokenDataEntries($a, $l[$i])
535803
536- func $f6_2 ($a,$i) = if (($i >= $s))
804+ func $f7_2 ($a,$i) = if (($i >= $s))
537805 then $a
538806 else throw("List size exceeds 10")
539807
540- $f6_2($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
541- } ++ [StringEntry("static_tokenIds", assetIdsStr), StringEntry("static_feeToken", feeAssetStr), StringEntry("static_tokenWeights", assetWeightsStr), IntegerEntry("static_tokensAmount", size(assetIdsLi)), StringEntry("static_poolDomain", poolDomain), StringEntry("static_baseTokenId", baseTokenIdStr), StringEntry("static_poolOwner", poolOwner), IntegerEntry("static_fee", fee)])
808+ $f7_2($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
809+ } ++ [StringEntry("static_tokenIds", assetIdsStr), StringEntry("static_feeToken", feeAssetStr), StringEntry("static_tokenWeights", assetWeightsStr), IntegerEntry("static_tokensAmount", size(assetIdsLi)), StringEntry("static_poolDomain", poolDomain), StringEntry("static_baseTokenId", baseTokenIdStr), StringEntry("static_poolOwner", poolOwner), IntegerEntry("static_fee", fee), IntegerEntry("static_KMult", Scale16), IntegerEntry("global_wasPreInited", 1)])
542810 }
543811 }
544812
545813
546814
547815 @Callable(i)
548816 func deInit () = if (isShutdown())
549817 then throw("contract is on stop")
550818 else if ((i.caller != this))
551819 then throw("admin only")
552820 else [IntegerEntry("global_wasInited", 0)]
553821
554822
555823
556824 @Callable(i)
557825 func init () = {
558826 func prepareList () = {
559827 func handler (accum,n) = (accum ++ [IntegerEntry((("global_" + getAssetString(n.assetId)) + "_balance"), n.amount)])
560828
561829 let $l = i.payments
562830 let $s = size($l)
563831 let $acc0 = nil
564832 func $f4_1 ($a,$i) = if (($i >= $s))
565833 then $a
566834 else handler($a, $l[$i])
567835
568836 func $f4_2 ($a,$i) = if (($i >= $s))
569837 then $a
570838 else throw("List size exceeds 10")
571839
572840 $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
573841 }
574842
575843 func calculatePoolTokensAmount (payments) = {
576844 func handler (accum,pmt) = {
577845 let assetId = pmt.assetId
578846 func handler2 (accum,n) = if ((n == assetId))
579847 then value(indexOf(assetIds, n))
580848 else accum
581849
582850 let Token = {
583851 let $l = assetIds
584852 let $s = size($l)
585853 let $acc0 = 1
586854 func $f4_1 ($a,$i) = if (($i >= $s))
587855 then $a
588856 else handler2($a, $l[$i])
589857
590858 func $f4_2 ($a,$i) = if (($i >= $s))
591859 then $a
592860 else throw("List size exceeds 10")
593861
594862 $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
595863 }
596864 fraction(accum, pow(pmt.amount, Decimals[Token], AssetsWeights[Token], AssetsWeightsDecimals, 8, FLOOR), Scale8)
597865 }
598866
599867 let $l = payments
600868 let $s = size($l)
601869 let $acc0 = PoolTokenScale
602870 func $f4_1 ($a,$i) = if (($i >= $s))
603871 then $a
604872 else handler($a, $l[$i])
605873
606874 func $f4_2 ($a,$i) = if (($i >= $s))
607875 then $a
608876 else throw("List size exceeds 10")
609877
610878 $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
611879 }
612880
613881 if (isShutdown())
614882 then throw("contract is on stop")
615883 else if ((tryGetInteger("global_wasInited") > 0))
616884 then throw("pool already inited")
617885 else {
618886 let initialPoolTokens = calculatePoolTokensAmount(i.payments)
619887 if ((initialPoolTokens == 0))
620888 then throw("you need a bigger tokens amount to launch the pool")
621889 else {
622890 let poolTokenIssue = Issue(("PZ " + tryGetString("static_poolDomain")), "Puzzle Swap: pool index token", initialPoolTokens, PoolTokenDecimals, true, unit, 0)
623891 let poolTokenId = calculateAssetId(poolTokenIssue)
624892 (prepareList() ++ [poolTokenIssue, IntegerEntry("global_poolToken_amount", initialPoolTokens), IntegerEntry("global_wasInited", 1), BinaryEntry("global_poolToken_id", poolTokenId), StringEntry("static_poolToken_idStr", getAssetString(poolTokenId)), IntegerEntry((toString(i.caller) + "_indexStaked"), initialPoolTokens), IntegerEntry("global_indexStaked", initialPoolTokens)])
625893 }
626894 }
627895 }
628896
629897
630898
631899 @Callable(i)
632900 func generateIndex (needChange) = if ((size(i.payments) != T))
633901 then throw(("you need to attach all pool tokens. amount of pool tokens: " + toString(T)))
634902 else if (!(checkTokensValidity(i.payments)))
635903 then throw("wrong assets attached")
636904 else {
637- let PIssued = getMinPIssued(i.payments)
638- let reissue = Reissue(getBinaryValue("global_poolToken_id"), PIssued, true)
639- let result = handlePoolTokensAdd(PIssued, i.payments, i.originCaller, needChange)
640- $Tuple2((result ++ [reissue, ScriptTransfer(i.caller, PIssued, tryGetBinary("global_poolToken_id")), IntegerEntry("global_poolToken_amount", (tryGetInteger("global_poolToken_amount") + PIssued))]), PIssued)
905+ let PIssuedNoMult = getMinPIssued(i.payments)
906+ let result = handlePoolTokensAdd(PIssuedNoMult, i.payments, i.originCaller, needChange)
907+ let PIssuedWithMult = fraction(PIssuedNoMult, Scale16, getKMult(), DOWN)
908+ let reissue = Reissue(getBinaryValue("global_poolToken_id"), PIssuedWithMult, true)
909+ $Tuple2((result ++ [reissue, ScriptTransfer(i.caller, PIssuedWithMult, tryGetBinary("global_poolToken_id")), IntegerEntry("global_poolToken_amount", (tryGetInteger("global_poolToken_amount") + PIssuedWithMult))]), PIssuedWithMult)
641910 }
911+
912+
913+
914+@Callable(i)
915+func redeemIndex (sendToOrigin) = {
916+ let pmt = i.payments[0]
917+ if ((pmt.assetId != tryGetBinary("global_poolToken_id")))
918+ then throw("please attach pool share token")
919+ else if (isShutdown())
920+ then throw("contract is on stop")
921+ else {
922+ let PRedeemedWithMult = pmt.amount
923+ let PRedeemedWithNoMult = fraction(PRedeemedWithMult, getKMult(), Scale16, DOWN)
924+ let result = handlePoolTokensRedeem(PRedeemedWithNoMult, if (sendToOrigin)
925+ then i.originCaller
926+ else i.caller)
927+ (result ++ [Burn(tryGetBinary("global_poolToken_id"), PRedeemedWithMult), IntegerEntry("global_poolToken_amount", (tryGetInteger("global_poolToken_amount") - PRedeemedWithMult))])
928+ }
929+ }
642930
643931
644932
645933 @Callable(i)
646934 func stakeIndex () = {
647935 let addressStr = toString(i.originCaller)
648936 let pmt = i.payments[0]
649937 if ((value(pmt.assetId) != tryGetBinary("global_poolToken_id")))
650938 then throw("wrong asset attached")
651939 else indexStakeResult(addressStr, pmt.amount)
652940 }
653941
654942
655943
656944 @Callable(i)
657-func unstakeIndex (puzzleAmount) = {
658- let addressStr = toString(i.originCaller)
659- let puzzleAvailable = tryGetInteger((addressStr + "_indexStaked"))
945+func stakeIndexFor (addressStr) = {
946+ let pmt = i.payments[0]
947+ if ((value(pmt.assetId) != tryGetBinary("global_poolToken_id")))
948+ then throw("wrong asset attached")
949+ else indexStakeResult(addressStr, pmt.amount)
950+ }
951+
952+
953+
954+@Callable(i)
955+func unstakeIndex (indexAmount) = {
956+ let addressStr = if ((indexOf(layer2Addresses, toString(i.caller)) != unit))
957+ then toString(i.originCaller)
958+ else toString(i.caller)
959+ let indexAvailable = tryGetInteger((addressStr + "_indexStaked"))
660960 if (isShutdown())
661961 then throw("contract is on stop")
662- else if ((puzzleAmount > puzzleAvailable))
962+ else if ((indexAmount > indexAvailable))
663963 then throw("you don't have index tokens available")
664964 else if (isShutdown())
665965 then throw("contract is on stop")
666- else (claimResult(i.originCaller)._1 ++ [IntegerEntry((addressStr + "_indexStaked"), (puzzleAvailable - puzzleAmount)), IntegerEntry("global_indexStaked", (tryGetInteger("global_indexStaked") - puzzleAmount)), ScriptTransfer(i.caller, puzzleAmount, getBinaryValue("global_poolToken_id"))])
966+ else (claimResult(addressFromStringValue(addressStr))._1 ++ [IntegerEntry((addressStr + "_indexStaked"), (indexAvailable - indexAmount)), IntegerEntry("global_indexStaked", (tryGetInteger("global_indexStaked") - indexAmount)), ScriptTransfer(i.caller, indexAmount, getBinaryValue("global_poolToken_id"))])
667967 }
668968
669969
670970
671971 @Callable(i)
672972 func claimIndexRewards () = if (isShutdown())
673973 then throw("contract is on stop")
674974 else claimResult(i.caller)
675975
676976
677977
678978 @Callable(i)
679979 func evaluateClaim (user) = $Tuple2(nil, claimResult(addressFromStringValue(user))._2)
680980
681981
682982
683983 @Callable(i)
684-func redeemIndex (sendToOrigin) = {
685- let pmt = i.payments[0]
686- if ((pmt.assetId != tryGetBinary("global_poolToken_id")))
687- then throw("please attach pool share token")
688- else if (isShutdown())
689- then throw("contract is on stop")
690- else {
691- let PRedeemed = pmt.amount
692- let result = handlePoolTokensRedeem(PRedeemed, if (sendToOrigin)
693- then i.originCaller
694- else i.caller)
695- (result ++ [Burn(tryGetBinary("global_poolToken_id"), PRedeemed), IntegerEntry("global_poolToken_amount", (tryGetInteger("global_poolToken_amount") - PRedeemed))])
696- }
697- }
698-
699-
700-
701-@Callable(i)
702984 func swap (assetOut,minimum) = {
703985 let pmt = if ((size(i.payments) == 1))
704986 then value(i.payments[0])
705987 else throw("please attach exactly one payment")
706988 let AmountIn = value(i.payments[0].amount)
707989 let AssetIn = pmt.assetId
708990 let AssetOut = getAssetBytes(assetOut)
991+ let assetIn = getAssetString(AssetIn)
992+ let scaleIn = (Scale8 / tryGetInteger((("static_" + assetIn) + "_scale")))
993+ let scaleOut = (Scale8 / tryGetInteger((("static_" + assetOut) + "_scale")))
709994 let feeAssetOutStr = tryGetString("static_feeToken")
710995 let feeAssetOut = if ((feeAssetOutStr == ""))
711996 then usdnAssetId
712997 else getAssetBytes(feeAssetOutStr)
713998 let AssetInBalance = tryGetInteger((("global_" + getAssetString(AssetIn)) + "_balance"))
714999 let AssetOutBalance = tryGetInteger((("global_" + assetOut) + "_balance"))
1000+ let AssetInBalanceScaled = (AssetInBalance * scaleIn)
1001+ let AssetOutBalanceScaled = (AssetOutBalance * scaleOut)
7151002 let feeAmountIn = fraction(AmountIn, Fee, FeeScale)
7161003 let cleanAmountIn = (AmountIn - feeAmountIn)
717- let AmountOut = calculateOutAmount(cleanAmountIn, AssetIn, AssetOut, AssetInBalance, AssetOutBalance)
1004+ let cleanAmountInScaled = (cleanAmountIn * scaleIn)
1005+ let AmountOut1 = calculateOutAmount(cleanAmountInScaled, AssetIn, AssetOut, AssetInBalanceScaled, AssetOutBalanceScaled)
1006+ let AmountOut = fraction(AmountOut1, 1, scaleOut)
7181007 let AssetOutBalance2 = (AssetOutBalance - AmountOut)
7191008 let AssetInBalance2 = (AssetInBalance + cleanAmountIn)
7201009 let feeAssetOutBalance = if ((feeAssetOut == AssetIn))
7211010 then AssetInBalance2
7221011 else if ((feeAssetOut == AssetOut))
7231012 then AssetOutBalance2
7241013 else tryGetInteger((("global_" + getAssetString(feeAssetOut)) + "_balance"))
7251014 let feeAmountOut = calculateOutAmount(feeAmountIn, AssetIn, feeAssetOut, AssetInBalance, feeAssetOutBalance)
7261015 if ((minimum > AmountOut))
7271016 then throw("amount to recieve is lower than given one")
7281017 else if ((AssetOut == AssetIn))
7291018 then throw("this swap is not allowed")
7301019 else if ((0 > (AssetOutBalance - AmountOut)))
7311020 then throw("contract is out of reserves")
7321021 else if (isShutdown())
7331022 then throw("contract is on stop")
7341023 else {
7351024 let creatorFee = fraction(feeAmountOut, 1, 10)
7361025 let protocolFee = fraction(feeAmountOut, 4, 10)
737- let stakingTopUp = if (if ((feeAssetOut == usdnAssetId))
738- then true
739- else (feeAssetOut == puzzleAssetId))
740- then reentrantInvoke(Address(base58'3PFTbywqxtFfukX3HyT881g4iW5K4QL3FAS'), "topUpReward", nil, [AttachedPayment(feeAssetOut, protocolFee)])
1026+ let newBalanceIn = AssetInBalance2
1027+ let newBalanceOut = (AssetOutBalance2 - (if ((AssetOut == feeAssetOut))
1028+ then feeAmountOut
1029+ else 0))
1030+ let newBalanceFeeAsset = if (if ((feeAssetOut != AssetIn))
1031+ then (feeAssetOut != AssetOut)
1032+ else false)
1033+ then (feeAssetOutBalance - feeAmountOut)
7411034 else unit
742- if ((stakingTopUp == stakingTopUp))
743- then {
744- let newBalanceIn = AssetInBalance2
745- let newBalanceOut = (AssetOutBalance2 - (if ((AssetOut == feeAssetOut))
746- then feeAmountOut
747- else 0))
748- let newBalanceFeeAsset = if (if ((feeAssetOut != AssetIn))
749- then (feeAssetOut != AssetOut)
750- else false)
751- then (feeAssetOutBalance - feeAmountOut)
752- else unit
753- let assetInChange = IntegerEntry((("global_" + getAssetString(AssetIn)) + "_balance"), newBalanceIn)
754- let assetOutChange = IntegerEntry((("global_" + assetOut) + "_balance"), newBalanceOut)
755- let feeAssetOutChange = if ((newBalanceFeeAsset != unit))
756- then IntegerEntry((("global_" + getAssetString(feeAssetOut)) + "_balance"), value(newBalanceFeeAsset))
757- else StringEntry("hello", "world")
758- let volumeUpdate = calculateUsdnValue(AssetIn, AmountIn, AssetInBalance, feeAssetOutBalance)
759- $Tuple2(([assetOutChange, assetInChange, feeAssetOutChange, ScriptTransfer(i.caller, AmountOut, AssetOut), ScriptTransfer(addressFromStringValue(tryGetString("static_poolOwner")), creatorFee, feeAssetOut), IntegerEntry("global_earnedByOwner", (tryGetInteger("global_earnedByOwner") + creatorFee)), IntegerEntry("global_volume", (tryGetInteger("global_volume") + volumeUpdate))] ++ (if ((stakingTopUp == unit))
760- then [ScriptTransfer(Address(base58'3PFWAVKmXjfHXyzJb12jCbhP4Uhi9t4uWiD'), protocolFee, feeAssetOut)]
761- else nil)), AmountOut)
762- }
763- else throw("Strict value is not equal to itself.")
1035+ let assetInChange = IntegerEntry((("global_" + getAssetString(AssetIn)) + "_balance"), newBalanceIn)
1036+ let assetOutChange = IntegerEntry((("global_" + assetOut) + "_balance"), newBalanceOut)
1037+ let feeAssetOutChange = if ((newBalanceFeeAsset != unit))
1038+ then IntegerEntry((("global_" + getAssetString(feeAssetOut)) + "_balance"), value(newBalanceFeeAsset))
1039+ else StringEntry("hello", "world")
1040+ let volumeUpdate = calculateUsdnValue(AssetIn, AmountIn, AssetInBalance, feeAssetOutBalance)
1041+ let volumeUsdUpdate = calculateUsdValue(AssetIn, AmountIn, AssetInBalance)
1042+ $Tuple2([assetOutChange, assetInChange, feeAssetOutChange, ScriptTransfer(i.caller, AmountOut, AssetOut), ScriptTransfer(addressFromStringValue(tryGetString("static_poolOwner")), creatorFee, feeAssetOut), IntegerEntry("global_earnedByOwner", (tryGetInteger("global_earnedByOwner") + creatorFee)), IntegerEntry("global_volume", (tryGetInteger("global_volume") + volumeUpdate)), IntegerEntry("global_volume_usd", (tryGetInteger("global_volume_usd") + volumeUsdUpdate)), ScriptTransfer(feesAddress, protocolFee, feeAssetOut)], AmountOut)
7641043 }
1044+ }
1045+
1046+
1047+
1048+@Callable(i)
1049+func swapReadOnly (assetIn,assetOut,AmountIn) = {
1050+ let AssetIn = getAssetBytes(assetIn)
1051+ let AssetOut = getAssetBytes(assetOut)
1052+ let scaleIn = (Scale8 / tryGetInteger((("static_" + assetIn) + "_scale")))
1053+ let scaleOut = (Scale8 / tryGetInteger((("static_" + assetOut) + "_scale")))
1054+ let feeAssetOutStr = tryGetString("static_feeToken")
1055+ let feeAssetOut = if ((feeAssetOutStr == ""))
1056+ then usdnAssetId
1057+ else getAssetBytes(feeAssetOutStr)
1058+ let AssetInBalance = tryGetInteger((("global_" + getAssetString(AssetIn)) + "_balance"))
1059+ let AssetOutBalance = tryGetInteger((("global_" + assetOut) + "_balance"))
1060+ let AssetInBalanceScaled = (AssetInBalance * scaleIn)
1061+ let AssetOutBalanceScaled = (AssetOutBalance * scaleOut)
1062+ let feeAmountIn = fraction(AmountIn, Fee, FeeScale)
1063+ let cleanAmountIn = (AmountIn - feeAmountIn)
1064+ let cleanAmountInScaled = (cleanAmountIn * scaleIn)
1065+ let AmountOut1 = calculateOutAmount(cleanAmountInScaled, AssetIn, AssetOut, AssetInBalanceScaled, AssetOutBalanceScaled)
1066+ let AmountOut = fraction(AmountOut1, 1, scaleOut)
1067+ let AssetOutBalance2 = (AssetOutBalance - AmountOut)
1068+ let AssetInBalance2 = (AssetInBalance + cleanAmountIn)
1069+ let feeAssetOutBalance = if ((feeAssetOut == AssetIn))
1070+ then AssetInBalance2
1071+ else if ((feeAssetOut == AssetOut))
1072+ then AssetOutBalance2
1073+ else tryGetInteger((("global_" + getAssetString(feeAssetOut)) + "_balance"))
1074+ let feeAmountOut = calculateOutAmount(feeAmountIn, AssetIn, feeAssetOut, AssetInBalance, feeAssetOutBalance)
1075+ if ((AssetOut == AssetIn))
1076+ then throw("this swap is not allowed")
1077+ else if ((0 > (AssetOutBalance - AmountOut)))
1078+ then throw("contract is out of reserves")
1079+ else if (isShutdown())
1080+ then throw("contract is on stop")
1081+ else $Tuple2(nil, AmountOut)
7651082 }
7661083
7671084
7681085
7691086 @Callable(i)
7701087 func transferOwnership (newOwnerAddress) = if ((toString(i.caller) != tryGetString("static_poolOwner")))
7711088 then throw("this call available only for pool owner")
7721089 else [StringEntry("static_poolOwner", newOwnerAddress)]
7731090
7741091
1092+
1093+@Callable(i)
1094+func setFee (newFee) = if ((toString(i.caller) != tryGetString("static_poolOwner")))
1095+ then throw("this call available only for pool owner")
1096+ else if ((1 > valueOrElse(getInteger(govAddress, ("approvedTx_" + toBase58String(i.transactionId))), 0)))
1097+ then throw("this transaction needs approval from puzzle network")
1098+ else [IntegerEntry("static_fee", newFee)]
1099+
1100+
1101+
1102+@Callable(i)
1103+func setRebalancingPlan (assetIdsStr,assetWeightsStr,baseTokenIdStr,stepsAmount,stepsInterval) = if ((i.caller != addressFromStringValue(tryGetString("static_poolOwner"))))
1104+ then throw("this call available only for pool owner")
1105+ else if ((1 > valueOrElse(getInteger(govAddress, ("approvedTx_" + toBase58String(i.transactionId))), 0)))
1106+ then throw("this transaction needs approval from puzzle network")
1107+ else if (valueOrElse(getBoolean(this, "rebalance_inProgress"), false))
1108+ then throw("rebalancing in progress")
1109+ else {
1110+ let newAssetWeightsStrLi = split(assetWeightsStr, ",")
1111+ let newAssetIdsStrLi = split(assetIdsStr, ",")
1112+ let feeAssetStr = {
1113+ let $l = newAssetIdsStrLi
1114+ let $s = size($l)
1115+ let $acc0 = ""
1116+ func $f4_1 ($a,$i) = if (($i >= $s))
1117+ then $a
1118+ else checkFeeAsset($a, $l[$i])
1119+
1120+ func $f4_2 ($a,$i) = if (($i >= $s))
1121+ then $a
1122+ else throw("List size exceeds 10")
1123+
1124+ $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1125+ }
1126+ let assetWeightsSum = {
1127+ let $l = newAssetWeightsStrLi
1128+ let $s = size($l)
1129+ let $acc0 = 0
1130+ func $f5_1 ($a,$i) = if (($i >= $s))
1131+ then $a
1132+ else sum($a, $l[$i])
1133+
1134+ func $f5_2 ($a,$i) = if (($i >= $s))
1135+ then $a
1136+ else throw("List size exceeds 10")
1137+
1138+ $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1139+ }
1140+ let oldAssetIds = getStringValue("static_tokenIds")
1141+ let oldAssetIdsLi = split(oldAssetIds, ",")
1142+ func findAdded (accum,next) = if ((indexOf(oldAssetIdsLi, next) == unit))
1143+ then (accum ++ [next])
1144+ else accum
1145+
1146+ func findRemoved (accum,next) = if ((indexOf(newAssetIdsStrLi, next) == unit))
1147+ then (accum ++ [next])
1148+ else accum
1149+
1150+ let addedAssets = {
1151+ let $l = newAssetIdsStrLi
1152+ let $s = size($l)
1153+ let $acc0 = nil
1154+ func $f6_1 ($a,$i) = if (($i >= $s))
1155+ then $a
1156+ else findAdded($a, $l[$i])
1157+
1158+ func $f6_2 ($a,$i) = if (($i >= $s))
1159+ then $a
1160+ else throw("List size exceeds 10")
1161+
1162+ $f6_2($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1163+ }
1164+ let removedAssets = {
1165+ let $l = oldAssetIdsLi
1166+ let $s = size($l)
1167+ let $acc0 = nil
1168+ func $f7_1 ($a,$i) = if (($i >= $s))
1169+ then $a
1170+ else findRemoved($a, $l[$i])
1171+
1172+ func $f7_2 ($a,$i) = if (($i >= $s))
1173+ then $a
1174+ else throw("List size exceeds 10")
1175+
1176+ $f7_2($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1177+ }
1178+ let validPayments = validatePayments(addedAssets, i.payments)
1179+ let validWeights = validateWeights(newAssetWeightsStrLi)
1180+ if ((validWeights == validWeights))
1181+ then if ((validPayments != (size(addedAssets) + size(i.payments))))
1182+ then throw("Payments not present or something wrong with them")
1183+ else if ((size(newAssetIdsStrLi) != size(newAssetWeightsStrLi)))
1184+ then throw("assetIds and assetWeights should have same length")
1185+ else if ((validPayments != (size(addedAssets) + size(i.payments))))
1186+ then throw("Payments not present or something wrong with them")
1187+ else if ((feeAssetStr == ""))
1188+ then throw("pool must have one of the supported fee assets in the composition")
1189+ else if ((indexOf(newAssetIdsStrLi, baseTokenIdStr) == unit))
1190+ then throw("baseTokenId should be present in assetIds")
1191+ else if (if ((MIN_STEPS_AMOUNT > stepsAmount))
1192+ then true
1193+ else (stepsAmount > MAX_STEPS_AMOUNT))
1194+ then throw(((((("Steps amount should be between " + toString(MIN_STEPS_AMOUNT)) + " and ") + toString(MAX_STEPS_AMOUNT)) + ", current: ") + toString(stepsAmount)))
1195+ else if (if ((MIN_STEPS_INTERVAL > stepsInterval))
1196+ then true
1197+ else (stepsInterval > MAX_STEPS_INTERVAL))
1198+ then throw(((((("Steps interval should be between " + toString(MIN_STEPS_INTERVAL)) + " and ") + toString(MAX_STEPS_INTERVAL)) + ", current: ") + toString(stepsInterval)))
1199+ else if ((assetWeightsSum != 10000))
1200+ then throw(("sum of token weights must be equal to 10000, current: " + toString(assetWeightsSum)))
1201+ else {
1202+ func f (accum,assetIdStr) = {
1203+ let oldWeight = tryGetInteger((("static_" + assetIdStr) + "_weight"))
1204+ let newWeight = if ((indexOf(newAssetIdsStrLi, assetIdStr) == unit))
1205+ then 0
1206+ else parseIntValue(value(newAssetWeightsStrLi[value(indexOf(newAssetIdsStrLi, assetIdStr))]))
1207+ let deltaPerStep = fraction((newWeight - oldWeight), 10000, stepsAmount)
1208+ (accum ++ [toString(deltaPerStep)])
1209+ }
1210+
1211+ let tmpAssetIdsLi = getTmpRebalanceIds(newAssetIdsStrLi)
1212+ let assetDeltas = {
1213+ let $l = tmpAssetIdsLi
1214+ let $s = size($l)
1215+ let $acc0 = nil
1216+ func $f8_1 ($a,$i) = if (($i >= $s))
1217+ then $a
1218+ else f($a, $l[$i])
1219+
1220+ func $f8_2 ($a,$i) = if (($i >= $s))
1221+ then $a
1222+ else throw("List size exceeds 10")
1223+
1224+ $f8_2($f8_1($f8_1($f8_1($f8_1($f8_1($f8_1($f8_1($f8_1($f8_1($f8_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1225+ }
1226+ let newTokensAdded = (checkTokensChange(newAssetIdsStrLi) > 0)
1227+ func recordAssetPayment (accum,next) = (accum ++ [IntegerEntry(("rebalance_attachedPayment_" + getAssetString(next.assetId)), next.amount)])
1228+
1229+ let paymentEntries = {
1230+ let $l = i.payments
1231+ let $s = size($l)
1232+ let $acc0 = nil
1233+ func $f9_1 ($a,$i) = if (($i >= $s))
1234+ then $a
1235+ else recordAssetPayment($a, $l[$i])
1236+
1237+ func $f9_2 ($a,$i) = if (($i >= $s))
1238+ then $a
1239+ else throw("List size exceeds 10")
1240+
1241+ $f9_2($f9_1($f9_1($f9_1($f9_1($f9_1($f9_1($f9_1($f9_1($f9_1($f9_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1242+ }
1243+ let storeWeights = saveCurrentWeights()
1244+ let notifyInvoke = invoke(poolsHubAddress, "notifyPoolChange", nil, nil)
1245+ if ((notifyInvoke == notifyInvoke))
1246+ then (([StringEntry("rebalance_addedAssets", makeString(addedAssets, ",")), StringEntry("rebalance_removedAssets", makeString(removedAssets, ",")), StringEntry("tmp_rebalanceAssetIds", makeString(tmpAssetIdsLi, ",")), BooleanEntry("rebalance_inProgress", true), BooleanEntry("rebalance_newTokensAdded", newTokensAdded), IntegerEntry("rebalance_stepsDone", 0), IntegerEntry("rebalance_lastStepHeight", height), IntegerEntry("rebalance_stepsAmount", stepsAmount), IntegerEntry("rebalance_stepsInterval", stepsInterval), StringEntry("rebalance_assetIds", assetIdsStr), StringEntry("rebalance_newBaseTokenId", baseTokenIdStr), StringEntry("rebalance_assetDeltas", makeString(assetDeltas, ","))] ++ paymentEntries) ++ storeWeights)
1247+ else throw("Strict value is not equal to itself.")
1248+ }
1249+ else throw("Strict value is not equal to itself.")
1250+ }
1251+
1252+
1253+
1254+@Callable(i)
1255+func stepRebalancing () = if (!(valueOrElse(getBoolean(this, "rebalance_inProgress"), false)))
1256+ then throw("no rebalancing in progress")
1257+ else {
1258+ let lastStepHeight = getIntegerValue("rebalance_lastStepHeight")
1259+ let stepInterval = getIntegerValue("rebalance_stepsInterval")
1260+ let stepsDone = getIntegerValue("rebalance_stepsDone")
1261+ let nextStepHeight = (lastStepHeight + stepInterval)
1262+ if ((nextStepHeight > height))
1263+ then throw("can't be done yet")
1264+ else {
1265+ let assetDeltas = split(getStringValue("rebalance_assetDeltas"), ",")
1266+ let newAssetIdsStr = getStringValue("tmp_rebalanceAssetIds")
1267+ let newAssetIds = split(newAssetIdsStr, ",")
1268+ func f (accum,assetIdStr) = (accum ++ [toString(fraction(((valueOrElse(getInteger(("rebalance_startWeight_" + assetIdStr)), 0) * 10000) + (parseIntValue(assetDeltas[value(indexOf(newAssetIds, assetIdStr))]) * (stepsDone + 1))), 1, 10000, HALFUP))])
1269+
1270+ let newShares = makeString({
1271+ let $l = newAssetIds
1272+ let $s = size($l)
1273+ let $acc0 = nil
1274+ func $f4_1 ($a,$i) = if (($i >= $s))
1275+ then $a
1276+ else f($a, $l[$i])
1277+
1278+ func $f4_2 ($a,$i) = if (($i >= $s))
1279+ then $a
1280+ else throw("List size exceeds 10")
1281+
1282+ $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1283+ }, ",")
1284+ let newTokensAdded = getBooleanValue("rebalance_newTokensAdded")
1285+ let inv = if (if (newTokensAdded)
1286+ then (stepsDone == 0)
1287+ else false)
1288+ then invoke(this, "doRebalancingWithNewTokens", [newAssetIdsStr, newShares, getStringValue("rebalance_newBaseTokenId")], nil)
1289+ else invoke(this, "doRebalancing", [newShares], nil)
1290+ if ((inv == inv))
1291+ then {
1292+ let notifyInvoke = invoke(poolsHubAddress, "notifyPoolChange", nil, nil)
1293+ if ((notifyInvoke == notifyInvoke))
1294+ then {
1295+ let isFinished = ((stepsDone + 1) >= getIntegerValue("rebalance_stepsAmount"))
1296+ let actions = [BooleanEntry("rebalance_inProgress", !(isFinished)), IntegerEntry("rebalance_stepsDone", (stepsDone + 1)), IntegerEntry("rebalance_lastStepHeight", height)]
1297+ if ((stepsDone == 0))
1298+ then (actions ++ [StringEntry("static_tokenIds", newAssetIdsStr)])
1299+ else if (isFinished)
1300+ then {
1301+ let removedAssetsLi = split(tryGetString("rebalance_removedAssets"), ",")
1302+ func rmData (accum,assetId) = (accum ++ [DeleteEntry((("static_" + assetId) + "_scale")), DeleteEntry((("static_" + assetId) + "_decimals")), DeleteEntry((("static_" + assetId) + "_weight")), DeleteEntry((("global_" + assetId) + "_balance")), DeleteEntry(("rebalance_attachedPayment_" + assetId))])
1303+
1304+ let rm = {
1305+ let $l = removedAssetsLi
1306+ let $s = size($l)
1307+ let $acc0 = nil
1308+ func $f5_1 ($a,$i) = if (($i >= $s))
1309+ then $a
1310+ else rmData($a, $l[$i])
1311+
1312+ func $f5_2 ($a,$i) = if (($i >= $s))
1313+ then $a
1314+ else throw("List size exceeds 10")
1315+
1316+ $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1317+ }
1318+ let addedAssetsLi = split(tryGetString("rebalance_addedAssets"), ",")
1319+ func addRemovePayments (accum,assetId) = (accum ++ [DeleteEntry(("rebalance_attachedPayment_" + assetId))])
1320+
1321+ let rmPayments = {
1322+ let $l = addedAssetsLi
1323+ let $s = size($l)
1324+ let $acc0 = nil
1325+ func $f6_1 ($a,$i) = if (($i >= $s))
1326+ then $a
1327+ else addRemovePayments($a, $l[$i])
1328+
1329+ func $f6_2 ($a,$i) = if (($i >= $s))
1330+ then $a
1331+ else throw("List size exceeds 10")
1332+
1333+ $f6_2($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1334+ }
1335+ let finalAssetsIdsStr = tryGetString("rebalance_assetIds")
1336+ let AssetsWeightsStr = {
1337+ let $l = split(finalAssetsIdsStr, ",")
1338+ let $s = size($l)
1339+ let $acc0 = nil
1340+ func $f7_1 ($a,$i) = if (($i >= $s))
1341+ then $a
1342+ else addAssetWeightToStrList($a, $l[$i])
1343+
1344+ func $f7_2 ($a,$i) = if (($i >= $s))
1345+ then $a
1346+ else throw("List size exceeds 10")
1347+
1348+ $f7_2($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1349+ }
1350+ (((actions ++ rm) ++ rmPayments) ++ [StringEntry("static_tokenIds", finalAssetsIdsStr), StringEntry("static_tokenWeights", makeString(AssetsWeightsStr, ",")), IntegerEntry("static_tokensAmount", size(split(finalAssetsIdsStr, ",")))])
1351+ }
1352+ else {
1353+ let finalAssetsIdsStr = tryGetString("rebalance_assetIds")
1354+ let AssetsWeightsStr = {
1355+ let $l = split(finalAssetsIdsStr, ",")
1356+ let $s = size($l)
1357+ let $acc0 = nil
1358+ func $f5_1 ($a,$i) = if (($i >= $s))
1359+ then $a
1360+ else addAssetWeightToStrList($a, $l[$i])
1361+
1362+ func $f5_2 ($a,$i) = if (($i >= $s))
1363+ then $a
1364+ else throw("List size exceeds 10")
1365+
1366+ $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1367+ }
1368+ (actions ++ [StringEntry("static_tokenWeights", makeString(AssetsWeightsStr, ","))])
1369+ }
1370+ }
1371+ else throw("Strict value is not equal to itself.")
1372+ }
1373+ else throw("Strict value is not equal to itself.")
1374+ }
1375+ }
1376+
1377+
1378+
1379+@Callable(i)
1380+func doRebalancing (assetWeightsStr) = {
1381+ let assetWeightsStrLi = split(assetWeightsStr, ",")
1382+ let assetWeightsSum = {
1383+ let $l = assetWeightsStrLi
1384+ let $s = size($l)
1385+ let $acc0 = 0
1386+ func $f4_1 ($a,$i) = if (($i >= $s))
1387+ then $a
1388+ else sum($a, $l[$i])
1389+
1390+ func $f4_2 ($a,$i) = if (($i >= $s))
1391+ then $a
1392+ else throw("List size exceeds 10")
1393+
1394+ $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1395+ }
1396+ let assetIdsStrLi = split(tryGetString("static_tokenIds"), ",")
1397+ if ((i.caller != this))
1398+ then throw("this call available only for admin")
1399+ else {
1400+ let oldKMult = getKMult()
1401+ func handler (pars,assetId) = {
1402+ let accum = pars._1
1403+ let assetIdStr = getAssetString(assetId)
1404+ func handler2 (accum,n) = if ((n == assetId))
1405+ then value(indexOf(assetIds, n))
1406+ else accum
1407+
1408+ let Token = {
1409+ let $l = assetIds
1410+ let $s = size($l)
1411+ let $acc0 = 1
1412+ func $f5_1 ($a,$i) = if (($i >= $s))
1413+ then $a
1414+ else handler2($a, $l[$i])
1415+
1416+ func $f5_2 ($a,$i) = if (($i >= $s))
1417+ then $a
1418+ else throw("List size exceeds 10")
1419+
1420+ $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1421+ }
1422+ let balance = tryGetInteger((("global_" + assetIdStr) + "_balance"))
1423+ let weight = if ((pars._2 == "new"))
1424+ then parseIntValue(assetWeightsStrLi[Token])
1425+ else tryGetInteger((("static_" + assetIdStr) + "_weight"))
1426+ $Tuple2(fraction(accum, pow(balance, Decimals[Token], weight, AssetsWeightsDecimals, 8, FLOOR), Scale8), pars._2)
1427+ }
1428+
1429+ let newK = ( let $l = assetIds
1430+ let $s = size($l)
1431+ let $acc0 = $Tuple2(PoolTokenScale, "new")
1432+ func $f5_1 ($a,$i) = if (($i >= $s))
1433+ then $a
1434+ else handler($a, $l[$i])
1435+
1436+ func $f5_2 ($a,$i) = if (($i >= $s))
1437+ then $a
1438+ else throw("List size exceeds 10")
1439+
1440+ $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10))._1
1441+ let oldK = ( let $l = assetIds
1442+ let $s = size($l)
1443+ let $acc0 = $Tuple2(PoolTokenScale, "old")
1444+ func $f6_1 ($a,$i) = if (($i >= $s))
1445+ then $a
1446+ else handler($a, $l[$i])
1447+
1448+ func $f6_2 ($a,$i) = if (($i >= $s))
1449+ then $a
1450+ else throw("List size exceeds 10")
1451+
1452+ $f6_2($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10))._1
1453+ let newKMult = fraction(oldKMult, newK, oldK)
1454+ func addTokenDataEntries (accum,assetNum) = if ((assetNum >= size(assetWeightsStrLi)))
1455+ then accum
1456+ else (accum ++ [IntegerEntry((("static_" + assetIdsStrLi[assetNum]) + "_weight"), value(parseInt(assetWeightsStrLi[assetNum])))])
1457+
1458+ ({
1459+ let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1460+ let $s = size($l)
1461+ let $acc0 = nil
1462+ func $f7_1 ($a,$i) = if (($i >= $s))
1463+ then $a
1464+ else addTokenDataEntries($a, $l[$i])
1465+
1466+ func $f7_2 ($a,$i) = if (($i >= $s))
1467+ then $a
1468+ else throw("List size exceeds 10")
1469+
1470+ $f7_2($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1471+ } ++ [IntegerEntry("static_KMult", newKMult)])
1472+ }
1473+ }
1474+
1475+
1476+
1477+@Callable(i)
1478+func doRebalancingWithNewTokens (assetIdsStr,assetWeightsStr,baseTokenIdStr) = {
1479+ let newAssetWeightsStrLi = split(assetWeightsStr, ",")
1480+ let prevAssetIdsStrLi = split(tryGetString("static_tokenIds"), ",")
1481+ let newAssetIdsStrLi = split(assetIdsStr, ",")
1482+ let newAssetIds = {
1483+ let $l = newAssetIdsStrLi
1484+ let $s = size($l)
1485+ let $acc0 = nil
1486+ func $f4_1 ($a,$i) = if (($i >= $s))
1487+ then $a
1488+ else addAssetBytesToList($a, $l[$i])
1489+
1490+ func $f4_2 ($a,$i) = if (($i >= $s))
1491+ then $a
1492+ else throw("List size exceeds 10")
1493+
1494+ $f4_2($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($f4_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1495+ }
1496+ let feeAssetStr = {
1497+ let $l = newAssetIdsStrLi
1498+ let $s = size($l)
1499+ let $acc0 = ""
1500+ func $f5_1 ($a,$i) = if (($i >= $s))
1501+ then $a
1502+ else checkFeeAsset($a, $l[$i])
1503+
1504+ func $f5_2 ($a,$i) = if (($i >= $s))
1505+ then $a
1506+ else throw("List size exceeds 10")
1507+
1508+ $f5_2($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($f5_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1509+ }
1510+ let addedAssets = split(tryGetString("rebalance_addedAssets"), ",")
1511+ func findAssetPayment (assetId) = valueOrElse(getInteger(("rebalance_attachedPayment_" + getAssetString(assetId))), 0)
1512+
1513+ func addAssetBalanceToLi (li,assetId) = (li ++ [findAssetPayment(assetId)])
1514+
1515+ let attachedBalances = {
1516+ let $l = newAssetIds
1517+ let $s = size($l)
1518+ let $acc0 = nil
1519+ func $f6_1 ($a,$i) = if (($i >= $s))
1520+ then $a
1521+ else addAssetBalanceToLi($a, $l[$i])
1522+
1523+ func $f6_2 ($a,$i) = if (($i >= $s))
1524+ then $a
1525+ else throw("List size exceeds 10")
1526+
1527+ $f6_2($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($f6_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1528+ }
1529+ if ((i.caller != this))
1530+ then throw(("this call available only for admin, " + toString(i.caller)))
1531+ else {
1532+ let oldKMult = getKMult()
1533+ let oldK = getVirtualPoolTokenAmount()
1534+ func myltiplyAssetsForK (pars,assetId) = {
1535+ func findAssetNum (accum,n) = if ((n == assetId))
1536+ then value(indexOf(newAssetIds, n))
1537+ else accum
1538+
1539+ let currentK = pars
1540+ let assetIdStr = getAssetString(assetId)
1541+ let TokenNum = {
1542+ let $l = newAssetIds
1543+ let $s = size($l)
1544+ let $acc0 = 1
1545+ func $f7_1 ($a,$i) = if (($i >= $s))
1546+ then $a
1547+ else findAssetNum($a, $l[$i])
1548+
1549+ func $f7_2 ($a,$i) = if (($i >= $s))
1550+ then $a
1551+ else throw("List size exceeds 10")
1552+
1553+ $f7_2($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1554+ }
1555+ let weight = parseIntValue(newAssetWeightsStrLi[TokenNum])
1556+ let balanceInState = tryGetInteger((("global_" + assetIdStr) + "_balance"))
1557+ let balanceInPayment = attachedBalances[TokenNum]
1558+ let balance = (balanceInState + balanceInPayment)
1559+ let assetDecimals = if ((assetId == unit))
1560+ then 8
1561+ else value(assetInfo(value(assetId))).decimals
1562+ if ((0 >= balance))
1563+ then throw(("you need to attach all new assets in payment. this asset is missed: " + assetIdStr))
1564+ else fraction(currentK, pow(balance, assetDecimals, weight, AssetsWeightsDecimals, 8, FLOOR), Scale8)
1565+ }
1566+
1567+ let newK = {
1568+ let $l = newAssetIds
1569+ let $s = size($l)
1570+ let $acc0 = PoolTokenScale
1571+ func $f7_1 ($a,$i) = if (($i >= $s))
1572+ then $a
1573+ else myltiplyAssetsForK($a, $l[$i])
1574+
1575+ func $f7_2 ($a,$i) = if (($i >= $s))
1576+ then $a
1577+ else throw("List size exceeds 10")
1578+
1579+ $f7_2($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1580+ }
1581+ let newKMult = fraction(oldKMult, newK, oldK)
1582+ func addTokenDataEntries (accum,assetNum) = {
1583+ let assetIdStr = newAssetIdsStrLi[assetNum]
1584+ let assetId = newAssetIds[assetNum]
1585+ let assetDecimals = if ((assetId == unit))
1586+ then 8
1587+ else value(assetInfo(value(assetId))).decimals
1588+ let newAssetData = if ((indexOf(addedAssets, assetIdStr) != unit))
1589+ then [IntegerEntry((("global_" + assetIdStr) + "_balance"), attachedBalances[assetNum]), IntegerEntry((("static_" + assetIdStr) + "_scale"), pow(10, 0, assetDecimals, 0, 0, DOWN)), IntegerEntry((("static_" + assetIdStr) + "_decimals"), assetDecimals)]
1590+ else nil
1591+ if ((assetNum >= size(newAssetWeightsStrLi)))
1592+ then accum
1593+ else ((accum ++ [IntegerEntry((("static_" + assetIdStr) + "_weight"), value(parseInt(newAssetWeightsStrLi[assetNum])))]) ++ newAssetData)
1594+ }
1595+
1596+ ({
1597+ let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1598+ let $s = size($l)
1599+ let $acc0 = nil
1600+ func $f8_1 ($a,$i) = if (($i >= $s))
1601+ then $a
1602+ else addTokenDataEntries($a, $l[$i])
1603+
1604+ func $f8_2 ($a,$i) = if (($i >= $s))
1605+ then $a
1606+ else throw("List size exceeds 10")
1607+
1608+ $f8_2($f8_1($f8_1($f8_1($f8_1($f8_1($f8_1($f8_1($f8_1($f8_1($f8_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
1609+ } ++ [StringEntry("static_tokenIds", assetIdsStr), StringEntry("static_feeToken", feeAssetStr), StringEntry("static_tokenWeights", assetWeightsStr), IntegerEntry("static_tokensAmount", size(newAssetIds)), IntegerEntry("static_KMult", newKMult)])
1610+ }
1611+ }
1612+
1613+
7751614 @Verifier(tx)
776-func verify () = if (isShutdown())
777- then false
778- else if (sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey))
1615+func verify () = if (if ((valueOrElse(getInteger("global_wasPreInited"), 0) == 0))
1616+ then if (sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey))
7791617 then true
7801618 else sigVerify(tx.bodyBytes, tx.proofs[0], masterPubKey)
1619+ else false)
1620+ then true
1621+ else match tx {
1622+ case tx: SetScriptTransaction =>
1623+ let scriptFull = value(tx.script)
1624+ let hash = toBase58String(sha256(scriptFull))
1625+ if (sigVerify(tx.bodyBytes, tx.proofs[0], masterPubKey))
1626+ then (valueOrElse(getInteger(coldMasterAddress, ("approvedScript_" + hash)), 0) > height)
1627+ else false
1628+ case _ =>
1629+ if (sigVerify(tx.bodyBytes, tx.proofs[0], masterPubKey))
1630+ then (valueOrElse(getInteger(coldMasterAddress, ("approvedTx_" + toBase58String(tx.id))), 0) > 0)
1631+ else false
1632+ }
7811633

github/deemru/w8io/3ef1775 
447.58 ms