2024.04.23 15:18 [4141387] smart account 3PDzArEBNXuTmczWH58mH5YMNkTVnYtNLXK > SELF 0.00000000 Waves

{ "type": 13, "id": "GugJBziCbsgBuECjJf7JqPxEt3vfTWbsfrZ12ebZV8EF", "fee": 5400000, "feeAssetId": null, "timestamp": 1713874735039, "version": 2, "chainId": 87, "sender": "3PDzArEBNXuTmczWH58mH5YMNkTVnYtNLXK", "senderPublicKey": "4JokG3LzdXAGdy2ThyRKJiUeRqN8sCQWpL78tAX6SvPD", "proofs": [ "48CpkEDtPJM95uy98av7v4ZSdmwPsXdu6VetgeLRbFaxSmMR1qsF9tuKPNTvwzxny8LFC21PHaCyMh4u53WzeZqw" ], "script": "base64:BgJbCAISCAoGCAgICAgBEgASABIDCgEEEgMKAQQSABIDCgEIEgMKAQESABIDCgEIEgQKAggBEgUKAwgIARIDCgEIEgMKAQESBwoFCAgIAQESABIDCgEIEgUKAwgICFMAB1ZFUlNJT04CDVBaLTEuMi4zIFBST0QACWNvbmZpZ1N0cgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzAg1jb25maWdBZGRyZXNzAiMzUFBFQlJnNHMyYWYyclEyWmJMdmR1MUhmZDRWbzZRVkRUbwAOQ09ORklHX0FERFJFU1MDCQAAAgUJY29uZmlnU3RyAgAFBHRoaXMJAQdBZGRyZXNzAQkA2QQBBQljb25maWdTdHIAFUFzc2V0c1dlaWdodHNEZWNpbWFscwAEAAVTY2FsZQCQTgAGU2NhbGU4AIDC1y8AB1NjYWxlMTYAgICE/qbe4REACEZlZVNjYWxlAJBOABFQb29sVG9rZW5EZWNpbWFscwAIAA5Qb29sVG9rZW5TY2FsZQkAbAYACgAABRFQb29sVG9rZW5EZWNpbWFscwAAAAAFBkhBTEZVUAAQTUlOX1NURVBTX0FNT1VOVAkBC3ZhbHVlT3JFbHNlAgkAmggCBQ5DT05GSUdfQUREUkVTUwIQbWluX3N0ZXBzX2Ftb3VudAABABBNQVhfU1RFUFNfQU1PVU5UCQELdmFsdWVPckVsc2UCCQCaCAIFDkNPTkZJR19BRERSRVNTAhBtYXhfc3RlcHNfYW1vdW50APQDABJNSU5fU1RFUFNfSU5URVJWQUwJAQt2YWx1ZU9yRWxzZQIJAJoIAgUOQ09ORklHX0FERFJFU1MCEm1pbl9zdGVwc19pbnRlcnZhbAABABJNQVhfU1RFUFNfSU5URVJWQUwJAQt2YWx1ZU9yRWxzZQIJAJoIAgUOQ09ORklHX0FERFJFU1MCEm1heF9zdGVwc19pbnRlcnZhbACQTgAKTUlOX1dFSUdIVAkBC3ZhbHVlT3JFbHNlAgkAmggCBQ5DT05GSUdfQUREUkVTUwIKbWluX3dlaWdodABkAApNQVhfV0VJR0hUCQELdmFsdWVPckVsc2UCCQCaCAIFDkNPTkZJR19BRERSRVNTAgptYXhfd2VpZ2h0AKxNAQ10cnlHZXRJbnRlZ2VyAQNrZXkEByRtYXRjaDAJAJoIAgUEdGhpcwUDa2V5AwkAAQIFByRtYXRjaDACA0ludAQBYgUHJG1hdGNoMAUBYgAAAQx0cnlHZXRCaW5hcnkBA2tleQQHJG1hdGNoMAkAnAgCBQR0aGlzBQNrZXkDCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQBYgUHJG1hdGNoMAUBYgEAAQx0cnlHZXRTdHJpbmcBA2tleQQHJG1hdGNoMAkAnQgCBQR0aGlzBQNrZXkDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFiBQckbWF0Y2gwBQFiAgABE3RyeUdldFN0cmluZ09yVGhyb3cBA2tleQQHJG1hdGNoMAkAnQgCBQR0aGlzBQNrZXkDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFiBQckbWF0Y2gwBQFiCQACAQkArAICAh1ubyBzdWNoIGtleSBpbiBkYXRhIHN0b3JhZ2U6IAUDa2V5AQ5nZXRBc3NldFN0cmluZwEHYXNzZXRJZAQHJG1hdGNoMAUHYXNzZXRJZAMJAAECBQckbWF0Y2gwAgpCeXRlVmVjdG9yBAFiBQckbWF0Y2gwCQDYBAEFAWICBVdBVkVTAQ1nZXRBc3NldEJ5dGVzAQphc3NldElkU3RyAwkAAAIFCmFzc2V0SWRTdHICBVdBVkVTBQR1bml0CQDZBAEFCmFzc2V0SWRTdHIBD2dldFRva2VuQmFsYW5jZQEHYXNzZXRJZAQHJG1hdGNoMAUHYXNzZXRJZAMJAAECBQckbWF0Y2gwAgpCeXRlVmVjdG9yBAF0BQckbWF0Y2gwCQDwBwIFBHRoaXMFAXQICQDvBwEFBHRoaXMJYXZhaWxhYmxlARNhZGRBc3NldEJ5dGVzVG9MaXN0AgVhY2N1bQRpdGVtCQDOCAIFBWFjY3VtCQDMCAIJAQ1nZXRBc3NldEJ5dGVzAQUEaXRlbQUDbmlsARRhZGRBc3NldFdlaWdodFRvTGlzdAIFYWNjdW0EaXRlbQkAzggCBQVhY2N1bQkAzAgCCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdzdGF0aWNfCQEOZ2V0QXNzZXRTdHJpbmcBBQRpdGVtAgdfd2VpZ2h0BQNuaWwBF2FkZEFzc2V0V2VpZ2h0VG9TdHJMaXN0AgVhY2N1bQRpdGVtCQDOCAIFBWFjY3VtCQDMCAIJAKQDAQkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwUEaXRlbQIHX3dlaWdodAUDbmlsARZhZGRBc3NldERlY2ltYWxzVG9MaXN0AgVhY2N1bQRpdGVtCQDOCAIFBWFjY3VtCQDMCAIJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18JAQ5nZXRBc3NldFN0cmluZwEFBGl0ZW0CCV9kZWNpbWFscwUDbmlsARNhZGRBc3NldFNjYWxlVG9MaXN0AgVhY2N1bQRpdGVtCQDOCAIFBWFjY3VtCQDMCAIJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18JAQ5nZXRBc3NldFN0cmluZwEFBGl0ZW0CBl9zY2FsZQUDbmlsAQxhZGRJbnRUb0xpc3QCBWFjY3VtBGl0ZW0JAM4IAgUFYWNjdW0JAMwIAgkBDXBhcnNlSW50VmFsdWUBBQRpdGVtBQNuaWwADnVzZG5Bc3NldElkU3RyCQELdmFsdWVPckVsc2UCCQCdCAIFDkNPTkZJR19BRERSRVNTAg51c2RuQXNzZXRJZFN0cgIsREcyeEZrUGREd0tVb0JrekdBaFF0THBTR3pmWExpQ1lQRXplS0gyQWQyNHAAEHB1enpsZUFzc2V0SWRTdHIJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCEHB1enpsZUFzc2V0SWRTdHICLEhFQjhRYXc5eHJXcFdzOHRIc2lBVFlHQldEQnRQMlM3a2NQQUxyTXU0M0FTAA51c2R0QXNzZXRJZFN0cgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIOdXNkdEFzc2V0SWRTdHICLDM0TjlZY0VFVExXbjkzcVlRNjRFc1AxeDg5dFNydUpVNDRSckVNU1hYRVBKABF1c2R0UHB0QXNzZXRJZFN0cgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIRdXNkdFBwdEFzc2V0SWRTdHICLDl3YzNMWE5BNFRFQnNYeUt0b0xFOW1yYkREN1dNSFh2WHJDalp2YWJMQXNpAA5yb21lQXNzZXRJZFN0cgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIOcm9tZUFzc2V0SWRTdHICLEFQNENiNXhMWUdINlppZ0hyZUNaSG9YcFFUV0RrUHNHMkJIcWZEVXg2dGFKAA93YXZlc0Fzc2V0SWRTdHICBVdBVkVTAAt1c2RuQXNzZXRJZAkA2QQBBQ51c2RuQXNzZXRJZFN0cgANcHV6emxlQXNzZXRJZAkA2QQBBRBwdXp6bGVBc3NldElkU3RyAAt1c2R0QXNzZXRJZAkA2QQBBQ51c2R0QXNzZXRJZFN0cgAOdXNkdFBwdEFzc2V0SWQJANkEAQURdXNkdFBwdEFzc2V0SWRTdHIAC3JvbWVBc3NldElkCQDZBAEFDnJvbWVBc3NldElkU3RyAAx3YXZlc0Fzc2V0SWQFBHVuaXQAFXN1cHBvcnRlZEZlZUFzc2V0c1N0cgkAzAgCBQ51c2RuQXNzZXRJZFN0cgkAzAgCBRBwdXp6bGVBc3NldElkU3RyCQDMCAIFDnVzZHRBc3NldElkU3RyCQDMCAIFEXVzZHRQcHRBc3NldElkU3RyCQDMCAIFD3dhdmVzQXNzZXRJZFN0cgkAzAgCBQ5yb21lQXNzZXRJZFN0cgUDbmlsABFwYXJlbnRQb29sQWRkcmVzcwkBB0FkZHJlc3MBCQDZBAEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCEXBhcmVudFBvb2xBZGRyZXNzAiMzUEZEZ3p1MVV0c3dBa0NNeHFxUWpiVGVIYVg0Y01hYjhLaAANbWFzdGVyQWRkcmVzcwkBB0FkZHJlc3MBCQDZBAEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCDW1hc3RlckFkZHJlc3MCIzNQTGp3SGN6OU5FdWFUbzYzTlpSOUI5b2tRaUtReFpTYm1mAAxtYXN0ZXJQdWJLZXkJANkEAQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIMbWFzdGVyUHViS2V5Aiw0ejhDS1NZUUJLa3p4N1BCYjV1QlAxWVBhNllBSFJOVEFwVzFzUVZIVDVlVQANb3JhY2xlQWRkcmVzcwkBB0FkZHJlc3MBCQDZBAEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCDW9yYWNsZUFkZHJlc3MCIzNQOGQxRTFCTEtvRDUyeTNiUUoxYkRUZDJURDFncGFMbjl0AA5zdGFraW5nQWRkcmVzcwkBB0FkZHJlc3MBCQDZBAEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCDnN0YWtpbmdBZGRyZXNzAiMzUEZUYnl3cXh0RmZ1a1gzSHlUODgxZzRpVzVLNFFMM0ZBUwALZmVlc0FkZHJlc3MJAQdBZGRyZXNzAQkA2QQBCQELdmFsdWVPckVsc2UCCQCdCAIFDkNPTkZJR19BRERSRVNTAgtmZWVzQWRkcmVzcwIjM1BGV0FWS21YamZIWHl6SmIxMmpDYmhQNFVoaTl0NHVXaUQAD3Bvb2xzSHViQWRkcmVzcwkBB0FkZHJlc3MBCQDZBAEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCD3Bvb2xzSHViQWRkcmVzcwIjM1A1WXV0akROQzNoQUJCVnN2ZUZ1WlRUYlE1UGR0U0RCZ2sAEnNodXRkb3duQWRkcmVzc1N0cgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIPc2h1dGRvd25BZGRyZXNzAiMzUEVwdjloUkZXRUVCVTIyV1JuTHN3MWJINFlHdGNVNzI4bwAPbGF5ZXIyQWRkcmVzc2VzCQELdmFsdWVPckVsc2UCCQCdCAIFDkNPTkZJR19BRERSRVNTAg9sYXllcjJBZGRyZXNzZXMCRzNQUjFRdmk5bUhUMzVTd1dFa0xTcXFFMkw4dGhpUExkVldVLDNQUW9CZlVLSGtKQWVHV2hvb0xQN1dTOG92YjU0YXY5SnAyAApnb3ZBZGRyZXNzCQEHQWRkcmVzcwEJANkEAQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIKZ292QWRkcmVzcwIjM1A2dXJvOXhDc0U4dGU3OFFaanpxeTdhcThuYXRTemRjZUMAEWNvbGRNYXN0ZXJBZGRyZXNzCQEHQWRkcmVzcwEJANkEAQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIRY29sZE1hc3RlckFkZHJlc3MCIzNQSzluaFBmUGJNQnlnQjlaZ0hWTUhhUWJTb29qd3JCZnhqAAFUCQENdHJ5R2V0SW50ZWdlcgECE3N0YXRpY190b2tlbnNBbW91bnQACGFzc2V0SWRzCgACJGwJALUJAgkBDHRyeUdldFN0cmluZwECD3N0YXRpY190b2tlbklkcwIBLAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQETYWRkQXNzZXRCeXRlc1RvTGlzdAIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgANQXNzZXRzV2VpZ2h0cwoAAiRsBQhhc3NldElkcwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMV8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEUYWRkQXNzZXRXZWlnaHRUb0xpc3QCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjFfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGYxXzICCQEFJGYxXzECCQEFJGYxXzECCQEFJGYxXzECCQEFJGYxXzECCQEFJGYxXzECCQEFJGYxXzECCQEFJGYxXzECCQEFJGYxXzECCQEFJGYxXzECCQEFJGYxXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoACERlY2ltYWxzCgACJGwFCGFzc2V0SWRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYyXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARZhZGRBc3NldERlY2ltYWxzVG9MaXN0AgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYyXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmMl8yAgkBBSRmMl8xAgkBBSRmMl8xAgkBBSRmMl8xAgkBBSRmMl8xAgkBBSRmMl8xAgkBBSRmMl8xAgkBBSRmMl8xAgkBBSRmMl8xAgkBBSRmMl8xAgkBBSRmMl8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAAZTY2FsZXMKAAIkbAUIYXNzZXRJZHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjNfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBE2FkZEFzc2V0U2NhbGVUb0xpc3QCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjNfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGYzXzICCQEFJGYzXzECCQEFJGYzXzECCQEFJGYzXzECCQEFJGYzXzECCQEFJGYzXzECCQEFJGYzXzECCQEFJGYzXzECCQEFJGYzXzECCQEFJGYzXzECCQEFJGYzXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoAA0ZlZQkBDXRyeUdldEludGVnZXIBAgpzdGF0aWNfZmVlAAxlYXJuZWRBc3NldHMFCGFzc2V0SWRzAQppc1NodXRkb3duAAQPc2h1dGRvd25BZGRyZXNzCQCmCAEFEnNodXRkb3duQWRkcmVzc1N0cgMJAAACBQ9zaHV0ZG93bkFkZHJlc3MFBHVuaXQHBAckbWF0Y2gwCQCbCAIJAQV2YWx1ZQEFD3NodXRkb3duQWRkcmVzcwILaXNfc2h1dGRvd24DCQABAgUHJG1hdGNoMAIHQm9vbGVhbgQBeAUHJG1hdGNoMAUBeAcBFmdldEN1cnJlbnRUb2tlbkJhbGFuY2UBCHRva2VuTnVtBAp0b2tlbklkU3RyCQEOZ2V0QXNzZXRTdHJpbmcBCQCRAwIFCGFzc2V0SWRzBQh0b2tlbk51bQkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHZ2xvYmFsXwUKdG9rZW5JZFN0cgIIX2JhbGFuY2UBCGdldEtNdWx0AAQHJG1hdGNoMAkAnwgBAgxzdGF0aWNfS011bHQDCQABAgUHJG1hdGNoMAIDSW50BAF4BQckbWF0Y2gwBQF4BQdTY2FsZTE2ARJzYXZlQ3VycmVudFdlaWdodHMABAphc3NldElkc0xpCQC1CQIJAQx0cnlHZXRTdHJpbmcBAg9zdGF0aWNfdG9rZW5JZHMCASwKAQFzAgVhY2N1bQdhc3NldElkCQDOCAIFBWFjY3VtCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgICFnJlYmFsYW5jZV9zdGFydFdlaWdodF8FB2Fzc2V0SWQJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18FB2Fzc2V0SWQCB193ZWlnaHQFA25pbAoAAiRsBQphc3NldElkc0xpCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQFzAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY0XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNF8yAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKARlnZXRWaXJ0dWFsUG9vbFRva2VuQW1vdW50AAkAawMJAQ10cnlHZXRJbnRlZ2VyAQIXZ2xvYmFsX3Bvb2xUb2tlbl9hbW91bnQJAQhnZXRLTXVsdAAFB1NjYWxlMTYBEGNhbGN1bGF0ZVBJc3N1ZWQCBmFtb3VudAd0b2tlbklkBAdQc3VwcGx5CQEZZ2V0VmlydHVhbFBvb2xUb2tlbkFtb3VudAAEB0JhbGFuY2UJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB2dsb2JhbF8JAQ5nZXRBc3NldFN0cmluZwEFB3Rva2VuSWQCCF9iYWxhbmNlBAJ0MQkAbgQFBmFtb3VudAUHUHN1cHBseQUHQmFsYW5jZQUERE9XTgUCdDEBDWdldE1pblBJc3N1ZWQBCHBheW1lbnRzCgEHaGFuZGxlcgIFYWNjdW0HY3VycmVudAQHUElzc3VlZAkBEGNhbGN1bGF0ZVBJc3N1ZWQCCAUHY3VycmVudAZhbW91bnQIBQdjdXJyZW50B2Fzc2V0SWQDCQAAAgUHUElzc3VlZAAACQACAQIkb25lIG9mIHRoZSB0b2tlbnMgYW1vdW50cyBpcyB0b28gbG93AwMJAAACBQVhY2N1bQAABgkAZgIFBWFjY3VtBQdQSXNzdWVkBQdQSXNzdWVkBQVhY2N1bQQJbWluUElzc2VkCgACJGwFCHBheW1lbnRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAAACgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQdoYW5kbGVyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY0XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNF8yAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKBQltaW5QSXNzZWQBEmNhbGN1bGF0ZVVzZG5WYWx1ZQQHYXNzZXRJZAZhbW91bnQIYUJhbGFuY2UQZ2l2ZW5Vc2RuQmFsYW5jZQQKdXNkbkluUG9vbAkAzwgCBQhhc3NldElkcwULdXNkbkFzc2V0SWQEDHB1enpsZUluUG9vbAkAzwgCBQhhc3NldElkcwUNcHV6emxlQXNzZXRJZAQKdXNkdEluUG9vbAkAzwgCBQhhc3NldElkcwULdXNkdEFzc2V0SWQEDXVzZHRQcHRJblBvb2wJAM8IAgUIYXNzZXRJZHMFDnVzZHRQcHRBc3NldElkBAt3YXZlc0luUG9vbAkAzwgCBQhhc3NldElkcwUEdW5pdAQLYXNzZXRXZWlnaHQJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18JAQ5nZXRBc3NldFN0cmluZwEFB2Fzc2V0SWQCB193ZWlnaHQEC2ZlZUFzc2V0U3RyCQEMdHJ5R2V0U3RyaW5nAQIPc3RhdGljX2ZlZVRva2VuAwkAAAIFC2ZlZUFzc2V0U3RyBRBwdXp6bGVBc3NldElkU3RyBAxwdXp6bGVXZWlnaHQJAJEDAgUNQXNzZXRzV2VpZ2h0cwkBBXZhbHVlAQkAzwgCBQhhc3NldElkcwUNcHV6emxlQXNzZXRJZAQNcHV6emxlQmFsYW5jZQkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHZ2xvYmFsXwUQcHV6emxlQXNzZXRJZFN0cgIIX2JhbGFuY2UEDmFtb3VudEluUHV6emxlCQBrAwUGYW1vdW50CQBpAgUNcHV6emxlQmFsYW5jZQUMcHV6emxlV2VpZ2h0CQBpAgUIYUJhbGFuY2UFC2Fzc2V0V2VpZ2h0BAtwdXp6bGVQcmljZQkBEUBleHRyTmF0aXZlKDEwNTApAgURcGFyZW50UG9vbEFkZHJlc3MCFmdsb2JhbF9sYXN0UHV6emxlUHJpY2UJAGsDCQBoAgUOYW1vdW50SW5QdXp6bGUFC3B1enpsZVByaWNlAAEFBlNjYWxlOAMJAAACBQtmZWVBc3NldFN0cgUOdXNkdEFzc2V0SWRTdHIECnVzZHRXZWlnaHQJAJEDAgUNQXNzZXRzV2VpZ2h0cwkBBXZhbHVlAQUKdXNkdEluUG9vbAQLdXNkdEJhbGFuY2UJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB2dsb2JhbF8FDnVzZHRBc3NldElkU3RyAghfYmFsYW5jZQkAawMFBmFtb3VudAkAaQIFC3VzZHRCYWxhbmNlBQp1c2R0V2VpZ2h0CQBpAgUIYUJhbGFuY2UFC2Fzc2V0V2VpZ2h0AwkAAAIFC2ZlZUFzc2V0U3RyBRF1c2R0UHB0QXNzZXRJZFN0cgQKdXNkdFdlaWdodAkAkQMCBQ1Bc3NldHNXZWlnaHRzCQEFdmFsdWUBBQ11c2R0UHB0SW5Qb29sBAt1c2R0QmFsYW5jZQkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHZ2xvYmFsXwURdXNkdFBwdEFzc2V0SWRTdHICCF9iYWxhbmNlCQBrAwUGYW1vdW50CQBpAgULdXNkdEJhbGFuY2UFCnVzZHRXZWlnaHQJAGkCBQhhQmFsYW5jZQULYXNzZXRXZWlnaHQDCQAAAgULZmVlQXNzZXRTdHIFDnVzZG5Bc3NldElkU3RyBAp1c2RuV2VpZ2h0CQCRAwIFDUFzc2V0c1dlaWdodHMJAQV2YWx1ZQEJAM8IAgUIYXNzZXRJZHMFC3VzZG5Bc3NldElkBAt1c2RuQmFsYW5jZQQHJG1hdGNoMAUQZ2l2ZW5Vc2RuQmFsYW5jZQMJAAECBQckbWF0Y2gwAgNJbnQEAXgFByRtYXRjaDAFEGdpdmVuVXNkbkJhbGFuY2UJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB2dsb2JhbF8JAQ5nZXRBc3NldFN0cmluZwEFC3VzZG5Bc3NldElkAghfYmFsYW5jZQkAawMFBmFtb3VudAkAaQIJAQV2YWx1ZQEFC3VzZG5CYWxhbmNlBQp1c2RuV2VpZ2h0CQBpAgUIYUJhbGFuY2UFC2Fzc2V0V2VpZ2h0BAt3YXZlc1dlaWdodAC4FwQId0JhbGFuY2UJAGkCCQENdHJ5R2V0SW50ZWdlcgECFGdsb2JhbF9XQVZFU19iYWxhbmNlADIJAGsDBQZhbW91bnQJAGkCBQh3QmFsYW5jZQULd2F2ZXNXZWlnaHQJAGkCBQhhQmFsYW5jZQULYXNzZXRXZWlnaHQBEmdldFByaWNlRnJvbU9yYWNsZQEKYXNzZXRJZFN0cgQHJG1hdGNoMAkAmggCBQ1vcmFjbGVBZGRyZXNzCQCsAgIFCmFzc2V0SWRTdHICB190d2FwNUIDCQABAgUHJG1hdGNoMAIDSW50BAF4BQckbWF0Y2gwBQF4AAABEWNhbGN1bGF0ZVVzZFZhbHVlAwdhc3NldElkBmFtb3VudAhhQmFsYW5jZQQLYXNzZXRXZWlnaHQJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18JAQ5nZXRBc3NldFN0cmluZwEFB2Fzc2V0SWQCB193ZWlnaHQEC2ZlZUFzc2V0U3RyCQEMdHJ5R2V0U3RyaW5nAQIPc3RhdGljX2ZlZVRva2VuBA1mZWVBc3NldFNjYWxlCQERQGV4dHJOYXRpdmUoMTA1MCkCBQR0aGlzCQCsAgIJAKwCAgIHc3RhdGljXwULZmVlQXNzZXRTdHICBl9zY2FsZQQLZmVlQXNzZXROdW0JAQV2YWx1ZQEJAM8IAgUIYXNzZXRJZHMJAQ1nZXRBc3NldEJ5dGVzAQULZmVlQXNzZXRTdHIEDmZlZUFzc2V0V2VpZ2h0CQCRAwIFDUFzc2V0c1dlaWdodHMFC2ZlZUFzc2V0TnVtBA9mZWVBc3NldEJhbGFuY2UJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB2dsb2JhbF8FC2ZlZUFzc2V0U3RyAghfYmFsYW5jZQQNdmFsSW5GZWVBc3NldAkAawMFBmFtb3VudAkAaQIFD2ZlZUFzc2V0QmFsYW5jZQUOZmVlQXNzZXRXZWlnaHQJAGkCBQhhQmFsYW5jZQULYXNzZXRXZWlnaHQEDWZlZUFzc2V0UHJpY2UJARJnZXRQcmljZUZyb21PcmFjbGUBBQtmZWVBc3NldFN0cgkAawMFDXZhbEluRmVlQXNzZXQFDWZlZUFzc2V0UHJpY2UFDWZlZUFzc2V0U2NhbGUBE2NoZWNrVG9rZW5zVmFsaWRpdHkBCHBheW1lbnRzCgEIaGFuZGxlcjECBWFjY3VtB3BheW1lbnQJAM4IAgUFYWNjdW0JAMwIAggFB3BheW1lbnQHYXNzZXRJZAUDbmlsBANpZHMKAAIkbAUIcGF5bWVudHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjRfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBCGhhbmRsZXIxAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY0XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNF8yAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAwkAAAIFA2lkcwUDaWRzCgEIaGFuZGxlcjICBWFjY3VtB2Fzc2V0SWQDCQECIT0CCQDPCAIFA2lkcwUHYXNzZXRJZAUEdW5pdAkAZAIFBWFjY3VtAAEJAAIBCQCsAgICFGFzc2V0IG5vdCBhdHRhY2hlZDogCQEOZ2V0QXNzZXRTdHJpbmcBBQdhc3NldElkBAZjaGVja3MKAAIkbAUIYXNzZXRJZHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwAAAKAQUkZjVfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBCGhhbmRsZXIyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY1XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNV8yAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAwkAAAIFBmNoZWNrcwUGY2hlY2tzBgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgETaGFuZGxlUG9vbFRva2Vuc0FkZAQHUElzc3VlZAhwYXltZW50cwt1c2VyQWRkcmVzcwpuZWVkQ2hhbmdlCgEVZ2V0VG9rZW5QYXltZW50QW1vdW50AQd0b2tlbklkCgEHaGFuZGxlcgIFYWNjdW0HcGF5bWVudAMJAAACCAUHcGF5bWVudAdhc3NldElkBQd0b2tlbklkCAUHcGF5bWVudAZhbW91bnQFBWFjY3VtCgACJGwFCHBheW1lbnRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAAACgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQdoYW5kbGVyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY0XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNF8yAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKCgERaGFuZGxlVG9rZW5DaGFuZ2UCBWFjY3VtB3Rva2VuSWQEAkJrCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdnbG9iYWxfCQEOZ2V0QXNzZXRTdHJpbmcBBQd0b2tlbklkAghfYmFsYW5jZQQHUFN1cHBseQkBGWdldFZpcnR1YWxQb29sVG9rZW5BbW91bnQABA10b2tlbkRlY2ltYWxzCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdzdGF0aWNfCQEOZ2V0QXNzZXRTdHJpbmcBBQd0b2tlbklkAgZfc2NhbGUEAmExCQC9AgQJALkCAgkAtgIBCQBkAgUHUFN1cHBseQUHUElzc3VlZAkAtgIBBQZTY2FsZTgJALYCAQUNdG9rZW5EZWNpbWFscwkAtgIBBQdQU3VwcGx5BQdDRUlMSU5HBAJEawkAoAMBCQC9AgQJALgCAgUCYTEJALkCAgkAtgIBBQ10b2tlbkRlY2ltYWxzCQC2AgEFBlNjYWxlOAkAtgIBBQJCawkAuQICCQC2AgEFDXRva2VuRGVjaW1hbHMJALYCAQUGU2NhbGU4BQdDRUlMSU5HBA1wYXltZW50QW1vdW50CQEVZ2V0VG9rZW5QYXltZW50QW1vdW50AQUHdG9rZW5JZAQIdG9SZXR1cm4JAGUCBQ1wYXltZW50QW1vdW50BQJEawQBdAMDBQpuZWVkQ2hhbmdlCQBmAgUIdG9SZXR1cm4AAAcJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwULdXNlckFkZHJlc3MFCHRvUmV0dXJuBQd0b2tlbklkBQNuaWwFA25pbAkAzggCCQDOCAIFBWFjY3VtBQF0CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgIHZ2xvYmFsXwkBDmdldEFzc2V0U3RyaW5nAQUHdG9rZW5JZAIIX2JhbGFuY2UJAGQCBQJCawUCRGsFA25pbAoAAiRsBQhhc3NldElkcwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmNF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQERaGFuZGxlVG9rZW5DaGFuZ2UCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjRfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY0XzICCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoBFmhhbmRsZVBvb2xUb2tlbnNSZWRlZW0CCVBSZWRlZW1lZAt1c2VyQWRkcmVzcwoBEWhhbmRsZVRva2VuUmVkZWVtAgVhY2N1bQd0b2tlbklkBAJCawkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHZ2xvYmFsXwkBDmdldEFzc2V0U3RyaW5nAQUHdG9rZW5JZAIIX2JhbGFuY2UEB1BTdXBwbHkJARlnZXRWaXJ0dWFsUG9vbFRva2VuQW1vdW50AAQNdG9rZW5EZWNpbWFscwkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwkBDmdldEFzc2V0U3RyaW5nAQUHdG9rZW5JZAIGX3NjYWxlBAZwc3VwcGwJAL0CBAkAuQICCQC2AgEJAGUCBQdQU3VwcGx5BQlQUmVkZWVtZWQJALYCAQUGU2NhbGU4CQC2AgEFBlNjYWxlOAkAtgIBBQdQU3VwcGx5BQRET1dOBAZhbW91bnQJAKADAQkAvQIECQC4AgIJALYCAQUHU2NhbGUxNgUGcHN1cHBsCQC2AgEFAkJrCQC2AgEFB1NjYWxlMTYFB0NFSUxJTkcJAM4IAgUFYWNjdW0JAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICAgdnbG9iYWxfCQEOZ2V0QXNzZXRTdHJpbmcBBQd0b2tlbklkAghfYmFsYW5jZQkAZQIFAkJrBQZhbW91bnQJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwULdXNlckFkZHJlc3MFBmFtb3VudAUHdG9rZW5JZAUDbmlsCgACJGwFCGFzc2V0SWRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARFoYW5kbGVUb2tlblJlZGVlbQIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjRfMgIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgESY2FsY3VsYXRlT3V0QW1vdW50BQhBbW91bnRJbgdhc3NldEluCGFzc2V0T3V0CUJhbGFuY2VJbgpCYWxhbmNlT3V0BAdJbmRleEluCQEFdmFsdWUBCQDPCAIFCGFzc2V0SWRzBQdhc3NldEluBAhJbmRleE91dAkBBXZhbHVlAQkAzwgCBQhhc3NldElkcwUIYXNzZXRPdXQDCQAAAgUHSW5kZXhJbgUISW5kZXhPdXQFCEFtb3VudEluCQBuBAUKQmFsYW5jZU91dAkAZQIJAGgCBQZTY2FsZTgFBlNjYWxlOAkAoAMBCQB2BgkAvQIECQC5AgIJALYCAQUJQmFsYW5jZUluCQC2AgEAkE4JALYCAQkAaAIFBlNjYWxlOAUGU2NhbGU4CQC5AgIJALYCAQkAZAIFCUJhbGFuY2VJbgUIQW1vdW50SW4JALYCAQCQTgUGSEFMRlVQABAJALYCAQkAawMJAJEDAgUNQXNzZXRzV2VpZ2h0cwUHSW5kZXhJbgCAoJSljR0JAJEDAgUNQXNzZXRzV2VpZ2h0cwUISW5kZXhPdXQADAAQBQdDRUlMSU5HCQBoAgUGU2NhbGU4BQZTY2FsZTgFCEhBTEZFVkVOAR1jYWxjdWxhdGVDdXJyZW50QXNzZXRJbnRlcmVzdAQHYXNzZXRJZAphc3NldElkU3RyCGFCYWxhbmNlFnRva2VuRWFybmluZ3NMYXN0Q2hlY2sEC3RvdGFsU3Rha2VkCQENdHJ5R2V0SW50ZWdlcgECEmdsb2JhbF9pbmRleFN0YWtlZAQVdG9rZW5CYWxhbmNlTGFzdENoZWNrBRZ0b2tlbkVhcm5pbmdzTGFzdENoZWNrBBNjdXJyZW50QmFsYW5jZURlbHRhCQBlAgkBD2dldFRva2VuQmFsYW5jZQEFB2Fzc2V0SWQFCGFCYWxhbmNlBBRjdXJyZW50VG9rZW5FYXJuaW5ncwMJAGYCBRNjdXJyZW50QmFsYW5jZURlbHRhBRV0b2tlbkJhbGFuY2VMYXN0Q2hlY2sFE2N1cnJlbnRCYWxhbmNlRGVsdGEFFXRva2VuQmFsYW5jZUxhc3RDaGVjawQLbmV3RWFybmluZ3MJAGUCBRRjdXJyZW50VG9rZW5FYXJuaW5ncwUVdG9rZW5CYWxhbmNlTGFzdENoZWNrBAtuZXdJbnRlcmVzdAMJAAACBQt0b3RhbFN0YWtlZAAAAAAJAGsDBQtuZXdFYXJuaW5ncwUGU2NhbGU4BQt0b3RhbFN0YWtlZAQRbGFzdENoZWNrSW50ZXJlc3QJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICEWdsb2JhbF9sYXN0Q2hlY2tfBQphc3NldElkU3RyAglfaW50ZXJlc3QJAGQCBRFsYXN0Q2hlY2tJbnRlcmVzdAULbmV3SW50ZXJlc3QBC2NsYWltUmVzdWx0AQdhZGRyZXNzBAphZGRyZXNzU3RyCQClCAEFB2FkZHJlc3MEDHB1enpsZUFtb3VudAkBDXRyeUdldEludGVnZXIBCQCsAgIFCmFkZHJlc3NTdHICDF9pbmRleFN0YWtlZAoBB2hhbmRsZXICBWFjY3VtB2Fzc2V0SWQECmFzc2V0SWRTdHIJAQ5nZXRBc3NldFN0cmluZwEFB2Fzc2V0SWQECGFCYWxhbmNlCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdnbG9iYWxfCQEOZ2V0QXNzZXRTdHJpbmcBBQdhc3NldElkAghfYmFsYW5jZQQWdG9rZW5FYXJuaW5nc0xhc3RDaGVjawkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIRZ2xvYmFsX2xhc3RDaGVja18FCmFzc2V0SWRTdHICCV9lYXJuaW5ncwQUY3VycmVudFRva2VuSW50ZXJlc3QJAR1jYWxjdWxhdGVDdXJyZW50QXNzZXRJbnRlcmVzdAQFB2Fzc2V0SWQFCmFzc2V0SWRTdHIFCGFCYWxhbmNlBRZ0b2tlbkVhcm5pbmdzTGFzdENoZWNrBBRjdXJyZW50VG9rZW5FYXJuaW5ncwkAlgMBCQDMCAIFFnRva2VuRWFybmluZ3NMYXN0Q2hlY2sJAMwIAgkAZQIJAQ9nZXRUb2tlbkJhbGFuY2UBBQdhc3NldElkBQhhQmFsYW5jZQUDbmlsBAxyZXdhcmRBbW91bnQJAGsDBQxwdXp6bGVBbW91bnQJAGUCBRRjdXJyZW50VG9rZW5JbnRlcmVzdAkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgkArAICBQphZGRyZXNzU3RyAgtfbGFzdENoZWNrXwUKYXNzZXRJZFN0cgIJX2ludGVyZXN0BQZTY2FsZTgECHRyYW5zZmVyAwkAAAIFDHJld2FyZEFtb3VudAAABQNuaWwJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwUHYWRkcmVzcwUMcmV3YXJkQW1vdW50BQdhc3NldElkBQNuaWwJAJQKAgkAzggCCQDOCAIIBQVhY2N1bQJfMQUIdHJhbnNmZXIJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICAhFnbG9iYWxfbGFzdENoZWNrXwUKYXNzZXRJZFN0cgIJX2Vhcm5pbmdzCQBlAgUUY3VycmVudFRva2VuRWFybmluZ3MFDHJld2FyZEFtb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgICEWdsb2JhbF9sYXN0Q2hlY2tfBQphc3NldElkU3RyAglfaW50ZXJlc3QFFGN1cnJlbnRUb2tlbkludGVyZXN0CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgkArAICBQphZGRyZXNzU3RyAgtfbGFzdENoZWNrXwUKYXNzZXRJZFN0cgIJX2ludGVyZXN0BRRjdXJyZW50VG9rZW5JbnRlcmVzdAUDbmlsCQBkAggFBWFjY3VtAl8yCQERY2FsY3VsYXRlVXNkVmFsdWUDBQdhc3NldElkBQxyZXdhcmRBbW91bnQFCGFCYWxhbmNlBAVhY2N1bQoAAiRsBQxlYXJuZWRBc3NldHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwCQCUCgIFA25pbAAACgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQdoYW5kbGVyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY0XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNF8yAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKCQCUCgIJAM4IAggFBWFjY3VtAl8xCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIFCmFkZHJlc3NTdHICEV9jbGFpbWVkUmV3YXJkVVNECQBkAgkBDXRyeUdldEludGVnZXIBCQCsAgIFCmFkZHJlc3NTdHICEV9jbGFpbWVkUmV3YXJkVVNECAUFYWNjdW0CXzIJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgUKYWRkcmVzc1N0cgIKX2xhc3RDbGFpbQgFCWxhc3RCbG9jawl0aW1lc3RhbXAFA25pbAgFBWFjY3VtAl8yARBpbmRleFN0YWtlUmVzdWx0AgphZGRyZXNzU3RyBmFtb3VudAQCbGkICQELY2xhaW1SZXN1bHQBCQERQGV4dHJOYXRpdmUoMTA2MikBBQphZGRyZXNzU3RyAl8xCQDOCAIFAmxpCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIFCmFkZHJlc3NTdHICDF9pbmRleFN0YWtlZAkAZAIJAQ10cnlHZXRJbnRlZ2VyAQkArAICBQphZGRyZXNzU3RyAgxfaW5kZXhTdGFrZWQFBmFtb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgISZ2xvYmFsX2luZGV4U3Rha2VkCQBkAgkBDXRyeUdldEludGVnZXIBAhJnbG9iYWxfaW5kZXhTdGFrZWQFBmFtb3VudAUDbmlsAQNzdW0CBWFjY3VtAW4JAGQCBQVhY2N1bQkBDXBhcnNlSW50VmFsdWUBBQFuAQ1jaGVja0ZlZUFzc2V0AgVhY2N1bQRuZXh0AwMJAQIhPQIJAM8IAgUVc3VwcG9ydGVkRmVlQXNzZXRzU3RyBQRuZXh0BQR1bml0CQAAAgUFYWNjdW0CAAcFBG5leHQFBWFjY3VtARJnZXRUbXBSZWJhbGFuY2VJZHMBDW5ld0Fzc2V0SWRzTGkEEWN1cnJlbnRBc3NldElkc0xpCQC1CQIJAQx0cnlHZXRTdHJpbmcBAg9zdGF0aWNfdG9rZW5JZHMCASwEBnJlc3VsdAUNbmV3QXNzZXRJZHNMaQoBAWYCBWFjY3VtB2Fzc2V0SWQDCQAAAgkAzwgCBQZyZXN1bHQFB2Fzc2V0SWQFBHVuaXQJAM4IAgUFYWNjdW0JAMwIAgUHYXNzZXRJZAUDbmlsBQVhY2N1bQoAAiRsBRFjdXJyZW50QXNzZXRJZHNMaQoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFBnJlc3VsdAoBBSRmNF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEBZgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNF8yAgIkYQIkaQMJAGcCBQIk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JGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoJAMwIAgkBC1N0cmluZ0VudHJ5AgIPc3RhdGljX3Rva2VuSWRzBQthc3NldElkc1N0cgkAzAgCCQELU3RyaW5nRW50cnkCAg9zdGF0aWNfZmVlVG9rZW4FC2ZlZUFzc2V0U3RyCQDMCAIJAQtTdHJpbmdFbnRyeQICE3N0YXRpY190b2tlbldlaWdodHMFD2Fzc2V0V2VpZ2h0c1N0cgkAzAgCCQEMSW50ZWdlckVudHJ5AgITc3RhdGljX3Rva2Vuc0Ftb3VudAkAkAMBBQphc3NldElkc0xpCQDMCAIJAQtTdHJpbmdFbnRyeQICEXN0YXRpY19wb29sRG9tYWluBQpwb29sRG9tYWluCQDMCAIJAQtTdHJpbmdFbnRyeQICEnN0YXRpY19iYXNlVG9rZW5JZAUOYmFzZVRva2VuSWRTdHIJAMwIAgkBC1N0cmluZ0VudHJ5AgIQc3RhdGljX3Bvb2xPd25lcgUJcG9vbE93bmVyCQDMCAIJAQxJbnRlZ2VyRW50cnkCAgpzdGF0aWNfZmVlBQNmZWUJAMwIAgkBDEludGVnZXJFbnRyeQICDHN0YXRpY19LTXVsdAUHU2NhbGUxNgkAzAgCCQEMSW50ZWdlckVudHJ5AgITZ2xvYmFsX3dhc1ByZUluaXRlZAABBQNuaWwBaQEGZGVJbml0AAMJAQppc1NodXRkb3duAAkAAgECE2NvbnRyYWN0IGlzIG9uIHN0b3ADCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAAIBAgphZG1pbiBvbmx5CQDMCAIJAQxJbnRlZ2VyRW50cnkCAhBnbG9iYWxfd2FzSW5pdGVkAAAFA25pbAFpAQRpbml0AAoBC3ByZXBhcmVMaXN0AAoBB2hhbmRsZXICBWFjY3VtAW4JAM4IAgUFYWNjdW0JAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICAgdnbG9iYWxfCQEOZ2V0QXNzZXRTdHJpbmcBCAUBbgdhc3NldElkAghfYmFsYW5jZQgFAW4GYW1vdW50BQNuaWwKAAIkbAgFAWkIcGF5bWVudHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjRfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBB2hhbmRsZXICBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjRfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY0XzICCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoKARljYWxjdWxhdGVQb29sVG9rZW5zQW1vdW50AQhwYXltZW50cwoBB2hhbmRsZXICBWFjY3VtA3BtdAQHYXNzZXRJZAgFA3BtdAdhc3NldElkCgEIaGFuZGxlcjICBWFjY3VtAW4DCQAAAgUBbgUHYXNzZXRJZAkBBXZhbHVlAQkAzwgCBQhhc3NldElkcwUBbgUFYWNjdW0EBVRva2VuCgACJGwFCGFzc2V0SWRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAABCgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQhoYW5kbGVyMgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjRfMgIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgkAawMFBWFjY3VtCQBsBggFA3BtdAZhbW91bnQJAJEDAgUIRGVjaW1hbHMFBVRva2VuCQCRAwIFDUFzc2V0c1dlaWdodHMFBVRva2VuBRVBc3NldHNXZWlnaHRzRGVjaW1hbHMACAUFRkxPT1IFBlNjYWxlOAoAAiRsBQhwYXltZW50cwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFDlBvb2xUb2tlblNjYWxlCgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQdoYW5kbGVyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY0XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNF8yAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAwkBCmlzU2h1dGRvd24ACQACAQITY29udHJhY3QgaXMgb24gc3RvcAMJAGYCCQENdHJ5R2V0SW50ZWdlcgECEGdsb2JhbF93YXNJbml0ZWQAAAkAAgECE3Bvb2wgYWxyZWFkeSBpbml0ZWQEEWluaXRpYWxQb29sVG9rZW5zCQEZY2FsY3VsYXRlUG9vbFRva2Vuc0Ftb3VudAEIBQFpCHBheW1lbnRzAwkAAAIFEWluaXRpYWxQb29sVG9rZW5zAAAJAAIBAjJ5b3UgbmVlZCBhIGJpZ2dlciB0b2tlbnMgYW1vdW50IHRvIGxhdW5jaCB0aGUgcG9vbAQOcG9vbFRva2VuSXNzdWUJAMMIBwkArAICAgNQWiAJAQx0cnlHZXRTdHJpbmcBAhFzdGF0aWNfcG9vbERvbWFpbgIdUHV6emxlIFN3YXA6IHBvb2wgaW5kZXggdG9rZW4FEWluaXRpYWxQb29sVG9rZW5zBRFQb29sVG9rZW5EZWNpbWFscwYFBHVuaXQAAAQLcG9vbFRva2VuSWQJALgIAQUOcG9vbFRva2VuSXNzdWUJAM4IAgkBC3ByZXBhcmVMaXN0AAkAzAgCBQ5wb29sVG9rZW5Jc3N1ZQkAzAgCCQEMSW50ZWdlckVudHJ5AgIXZ2xvYmFsX3Bvb2xUb2tlbl9hbW91bnQFEWluaXRpYWxQb29sVG9rZW5zCQDMCAIJAQxJbnRlZ2VyRW50cnkCAhBnbG9iYWxfd2FzSW5pdGVkAAEJAMwIAgkBC0JpbmFyeUVudHJ5AgITZ2xvYmFsX3Bvb2xUb2tlbl9pZAULcG9vbFRva2VuSWQJAMwIAgkBC1N0cmluZ0VudHJ5AgIWc3RhdGljX3Bvb2xUb2tlbl9pZFN0cgkBDmdldEFzc2V0U3RyaW5nAQULcG9vbFRva2VuSWQJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkApQgBCAUBaQZjYWxsZXICDF9pbmRleFN0YWtlZAURaW5pdGlhbFBvb2xUb2tlbnMJAMwIAgkBDEludGVnZXJFbnRyeQICEmdsb2JhbF9pbmRleFN0YWtlZAURaW5pdGlhbFBvb2xUb2tlbnMFA25pbAFpAQ1nZW5lcmF0ZUluZGV4AQpuZWVkQ2hhbmdlAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwUBVAkAAgEJAKwCAgI7eW91IG5lZWQgdG8gYXR0YWNoIGFsbCBwb29sIHRva2Vucy4gYW1vdW50IG9mIHBvb2wgdG9rZW5zOiAJAKQDAQUBVAMJAQEhAQkBE2NoZWNrVG9rZW5zVmFsaWRpdHkBCAUBaQhwYXltZW50cwkAAgECFXdyb25nIGFzc2V0cyBhdHRhY2hlZAQNUElzc3VlZE5vTXVsdAkBDWdldE1pblBJc3N1ZWQBCAUBaQhwYXltZW50cwQGcmVzdWx0CQETaGFuZGxlUG9vbFRva2Vuc0FkZAQFDVBJc3N1ZWROb011bHQIBQFpCHBheW1lbnRzCAUBaQxvcmlnaW5DYWxsZXIFCm5lZWRDaGFuZ2UED1BJc3N1ZWRXaXRoTXVsdAkAbgQFDVBJc3N1ZWROb011bHQFB1NjYWxlMTYJAQhnZXRLTXVsdAAFBERPV04EB3JlaXNzdWUJAQdSZWlzc3VlAwkBEUBleHRyTmF0aXZlKDEwNTcpAQITZ2xvYmFsX3Bvb2xUb2tlbl9pZAUPUElzc3VlZFdpdGhNdWx0BgkAlAoCCQDOCAIFBnJlc3VsdAkAzAgCBQdyZWlzc3VlCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMIBQFpBmNhbGxlcgUPUElzc3VlZFdpdGhNdWx0CQEMdHJ5R2V0QmluYXJ5AQITZ2xvYmFsX3Bvb2xUb2tlbl9pZAkAzAgCCQEMSW50ZWdlckVudHJ5AgIXZ2xvYmFsX3Bvb2xUb2tlbl9hbW91bnQJAGQCCQENdHJ5R2V0SW50ZWdlcgECF2dsb2JhbF9wb29sVG9rZW5fYW1vdW50BQ9QSXNzdWVkV2l0aE11bHQFA25pbAUPUElzc3VlZFdpdGhNdWx0AWkBC3JlZGVlbUluZGV4AQxzZW5kVG9PcmlnaW4EA3BtdAkAkQMCCAUBaQhwYXltZW50cwAAAwkBAiE9AggFA3BtdAdhc3NldElkCQEMdHJ5R2V0QmluYXJ5AQITZ2xvYmFsX3Bvb2xUb2tlbl9pZAkAAgECHnBsZWFzZSBhdHRhY2ggcG9vbCBzaGFyZSB0b2tlbgMJAQppc1NodXRkb3duAAkAAgECE2NvbnRyYWN0IGlzIG9uIHN0b3AEEVBSZWRlZW1lZFdpdGhNdWx0CAUDcG10BmFtb3VudAQTUFJlZGVlbWVkV2l0aE5vTXVsdAkAbgQFEVBSZWRlZW1lZFdpdGhNdWx0CQEIZ2V0S011bHQABQdTY2FsZTE2BQRET1dOBAZyZXN1bHQJARZoYW5kbGVQb29sVG9rZW5zUmVkZWVtAgUTUFJlZGVlbWVkV2l0aE5vTXVsdAMFDHNlbmRUb09yaWdpbggFAWkMb3JpZ2luQ2FsbGVyCAUBaQZjYWxsZXIJAM4IAgUGcmVzdWx0CQDMCAIJAQRCdXJuAgkBDHRyeUdldEJpbmFyeQECE2dsb2JhbF9wb29sVG9rZW5faWQFEVBSZWRlZW1lZFdpdGhNdWx0CQDMCAIJAQxJbnRlZ2VyRW50cnkCAhdnbG9iYWxfcG9vbFRva2VuX2Ftb3VudAkAZQIJAQ10cnlHZXRJbnRlZ2VyAQIXZ2xvYmFsX3Bvb2xUb2tlbl9hbW91bnQFEVBSZWRlZW1lZFdpdGhNdWx0BQNuaWwBaQEKc3Rha2VJbmRleAAECmFkZHJlc3NTdHIJAKUIAQgFAWkMb3JpZ2luQ2FsbGVyBANwbXQJAJEDAggFAWkIcGF5bWVudHMAAAMJAQIhPQIJAQV2YWx1ZQEIBQNwbXQHYXNzZXRJZAkBDHRyeUdldEJpbmFyeQECE2dsb2JhbF9wb29sVG9rZW5faWQJAAIBAhR3cm9uZyBhc3NldCBhdHRhY2hlZAkBEGluZGV4U3Rha2VSZXN1bHQCBQphZGRyZXNzU3RyCAUDcG10BmFtb3VudAFpAQ1zdGFrZUluZGV4Rm9yAQphZGRyZXNzU3RyBANwbXQJAJEDAggFAWkIcGF5bWVudHMAAAMJAQIhPQIJAQV2YWx1ZQEIBQNwbXQHYXNzZXRJZAkBDHRyeUdldEJpbmFyeQECE2dsb2JhbF9wb29sVG9rZW5faWQJAAIBAhR3cm9uZyBhc3NldCBhdHRhY2hlZAkBEGluZGV4U3Rha2VSZXN1bHQCBQphZGRyZXNzU3RyCAUDcG10BmFtb3VudAFpAQx1bnN0YWtlSW5kZXgBC2luZGV4QW1vdW50BAphZGRyZXNzU3RyAwkBAiE9AgkAswkCBQ9sYXllcjJBZGRyZXNzZXMJAKUIAQgFAWkGY2FsbGVyBQR1bml0CQClCAEIBQFpDG9yaWdpbkNhbGxlcgkApQgBCAUBaQZjYWxsZXIEDmluZGV4QXZhaWxhYmxlCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgUKYWRkcmVzc1N0cgIMX2luZGV4U3Rha2VkAwkBCmlzU2h1dGRvd24ACQACAQITY29udHJhY3QgaXMgb24gc3RvcAMJAGYCBQtpbmRleEFtb3VudAUOaW5kZXhBdmFpbGFibGUJAAIBAiV5b3UgZG9uJ3QgaGF2ZSBpbmRleCB0b2tlbnMgYXZhaWxhYmxlAwkBCmlzU2h1dGRvd24ACQACAQITY29udHJhY3QgaXMgb24gc3RvcAkAzggCCAkBC2NsYWltUmVzdWx0AQkBEUBleHRyTmF0aXZlKDEwNjIpAQUKYWRkcmVzc1N0cgJfMQkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICBQphZGRyZXNzU3RyAgxfaW5kZXhTdGFrZWQJAGUCBQ5pbmRleEF2YWlsYWJsZQULaW5kZXhBbW91bnQJAMwIAgkBDEludGVnZXJFbnRyeQICEmdsb2JhbF9pbmRleFN0YWtlZAkAZQIJAQ10cnlHZXRJbnRlZ2VyAQISZ2xvYmFsX2luZGV4U3Rha2VkBQtpbmRleEFtb3VudAkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCAUBaQZjYWxsZXIFC2luZGV4QW1vdW50CQERQGV4dHJOYXRpdmUoMTA1NykBAhNnbG9iYWxfcG9vbFRva2VuX2lkBQNuaWwBaQERY2xhaW1JbmRleFJld2FyZHMAAwkBCmlzU2h1dGRvd24ACQACAQITY29udHJhY3QgaXMgb24gc3RvcAkBC2NsYWltUmVzdWx0AQgFAWkGY2FsbGVyAWkBDWV2YWx1YXRlQ2xhaW0BBHVzZXIJAJQKAgUDbmlsCAkBC2NsYWltUmVzdWx0AQkBEUBleHRyTmF0aXZlKDEwNjIpAQUEdXNlcgJfMgFpAQRzd2FwAghhc3NldE91dAdtaW5pbXVtBANwbXQDCQAAAgkAkAMBCAUBaQhwYXltZW50cwABCQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAAJAAIBAiFwbGVhc2UgYXR0YWNoIGV4YWN0bHkgb25lIHBheW1lbnQECEFtb3VudEluCQEFdmFsdWUBCAkAkQMCCAUBaQhwYXltZW50cwAABmFtb3VudAQHQXNzZXRJbggFA3BtdAdhc3NldElkBAhBc3NldE91dAkBDWdldEFzc2V0Qnl0ZXMBBQhhc3NldE91dAQHYXNzZXRJbgkBDmdldEFzc2V0U3RyaW5nAQUHQXNzZXRJbgQHc2NhbGVJbgkAaQIFBlNjYWxlOAkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwUHYXNzZXRJbgIGX3NjYWxlBAhzY2FsZU91dAkAaQIFBlNjYWxlOAkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwUIYXNzZXRPdXQCBl9zY2FsZQQOZmVlQXNzZXRPdXRTdHIJAQx0cnlHZXRTdHJpbmcBAg9zdGF0aWNfZmVlVG9rZW4EC2ZlZUFzc2V0T3V0AwkAAAIFDmZlZUFzc2V0T3V0U3RyAgAFC3VzZG5Bc3NldElkCQENZ2V0QXNzZXRCeXRlcwEFDmZlZUFzc2V0T3V0U3RyBA5Bc3NldEluQmFsYW5jZQkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHZ2xvYmFsXwkBDmdldEFzc2V0U3RyaW5nAQUHQXNzZXRJbgIIX2JhbGFuY2UED0Fzc2V0T3V0QmFsYW5jZQkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHZ2xvYmFsXwUIYXNzZXRPdXQCCF9iYWxhbmNlBBRBc3NldEluQmFsYW5jZVNjYWxlZAkAaAIFDkFzc2V0SW5CYWxhbmNlBQdzY2FsZUluBBVBc3NldE91dEJhbGFuY2VTY2FsZWQJAGgCBQ9Bc3NldE91dEJhbGFuY2UFCHNjYWxlT3V0BAtmZWVBbW91bnRJbgkAawMFCEFtb3VudEluBQNGZWUFCEZlZVNjYWxlBA1jbGVhbkFtb3VudEluCQBlAgUIQW1vdW50SW4FC2ZlZUFtb3VudEluBBNjbGVhbkFtb3VudEluU2NhbGVkCQBoAgUNY2xlYW5BbW91bnRJbgUHc2NhbGVJbgQKQW1vdW50T3V0MQkBEmNhbGN1bGF0ZU91dEFtb3VudAUFE2NsZWFuQW1vdW50SW5TY2FsZWQFB0Fzc2V0SW4FCEFzc2V0T3V0BRRBc3NldEluQmFsYW5jZVNjYWxlZAUVQXNzZXRPdXRCYWxhbmNlU2NhbGVkBAlBbW91bnRPdXQJAGsDBQpBbW91bnRPdXQxAAEFCHNjYWxlT3V0BBBBc3NldE91dEJhbGFuY2UyCQBlAgUPQXNzZXRPdXRCYWxhbmNlBQlBbW91bnRPdXQED0Fzc2V0SW5CYWxhbmNlMgkAZAIFDkFzc2V0SW5CYWxhbmNlBQ1jbGVhbkFtb3VudEluBBJmZWVBc3NldE91dEJhbGFuY2UDCQAAAgULZmVlQXNzZXRPdXQFB0Fzc2V0SW4FD0Fzc2V0SW5CYWxhbmNlMgMJAAACBQtmZWVBc3NldE91dAUIQXNzZXRPdXQFEEFzc2V0T3V0QmFsYW5jZTIJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB2dsb2JhbF8JAQ5nZXRBc3NldFN0cmluZwEFC2ZlZUFzc2V0T3V0AghfYmFsYW5jZQQMZmVlQW1vdW50T3V0CQESY2FsY3VsYXRlT3V0QW1vdW50BQULZmVlQW1vdW50SW4FB0Fzc2V0SW4FC2ZlZUFzc2V0T3V0BQ5Bc3NldEluQmFsYW5jZQUSZmVlQXNzZXRPdXRCYWxhbmNlAwkAZgIFB21pbmltdW0FCUFtb3VudE91dAkAAgECKWFtb3VudCB0byByZWNpZXZlIGlzIGxvd2VyIHRoYW4gZ2l2ZW4gb25lAwkAAAIFCEFzc2V0T3V0BQdBc3NldEluCQACAQIYdGhpcyBzd2FwIGlzIG5vdCBhbGxvd2VkAwkAZgIAAAkAZQIFD0Fzc2V0T3V0QmFsYW5jZQUJQW1vdW50T3V0CQACAQIbY29udHJhY3QgaXMgb3V0IG9mIHJlc2VydmVzAwkBCmlzU2h1dGRvd24ACQACAQITY29udHJhY3QgaXMgb24gc3RvcAQKY3JlYXRvckZlZQkAawMFDGZlZUFtb3VudE91dAABAAoEC3Byb3RvY29sRmVlCQBrAwUMZmVlQW1vdW50T3V0AAQACgQMbmV3QmFsYW5jZUluBQ9Bc3NldEluQmFsYW5jZTIEDW5ld0JhbGFuY2VPdXQJAGUCBRBBc3NldE91dEJhbGFuY2UyAwkAAAIFCEFzc2V0T3V0BQtmZWVBc3NldE91dAUMZmVlQW1vdW50T3V0AAAEEm5ld0JhbGFuY2VGZWVBc3NldAMDCQECIT0CBQtmZWVBc3NldE91dAUHQXNzZXRJbgkBAiE9AgULZmVlQXNzZXRPdXQFCEFzc2V0T3V0BwkAZQIFEmZlZUFzc2V0T3V0QmFsYW5jZQUMZmVlQW1vdW50T3V0BQR1bml0BA1hc3NldEluQ2hhbmdlCQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgICB2dsb2JhbF8JAQ5nZXRBc3NldFN0cmluZwEFB0Fzc2V0SW4CCF9iYWxhbmNlBQxuZXdCYWxhbmNlSW4EDmFzc2V0T3V0Q2hhbmdlCQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgICB2dsb2JhbF8FCGFzc2V0T3V0AghfYmFsYW5jZQUNbmV3QmFsYW5jZU91dAQRZmVlQXNzZXRPdXRDaGFuZ2UDCQECIT0CBRJuZXdCYWxhbmNlRmVlQXNzZXQFBHVuaXQJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgIHZ2xvYmFsXwkBDmdldEFzc2V0U3RyaW5nAQULZmVlQXNzZXRPdXQCCF9iYWxhbmNlCQEFdmFsdWUBBRJuZXdCYWxhbmNlRmVlQXNzZXQJAQtTdHJpbmdFbnRyeQICBWhlbGxvAgV3b3JsZAQMdm9sdW1lVXBkYXRlCQESY2FsY3VsYXRlVXNkblZhbHVlBAUHQXNzZXRJbgUIQW1vdW50SW4FDkFzc2V0SW5CYWxhbmNlBRJmZWVBc3NldE91dEJhbGFuY2UED3ZvbHVtZVVzZFVwZGF0ZQkBEWNhbGN1bGF0ZVVzZFZhbHVlAwUHQXNzZXRJbgUIQW1vdW50SW4FDkFzc2V0SW5CYWxhbmNlCQCUCgIJAMwIAgUOYXNzZXRPdXRDaGFuZ2UJAMwIAgUNYXNzZXRJbkNoYW5nZQkAzAgCBRFmZWVBc3NldE91dENoYW5nZQkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCAUBaQZjYWxsZXIFCUFtb3VudE91dAUIQXNzZXRPdXQJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwkBEUBleHRyTmF0aXZlKDEwNjIpAQkBDHRyeUdldFN0cmluZwECEHN0YXRpY19wb29sT3duZXIFCmNyZWF0b3JGZWUFC2ZlZUFzc2V0T3V0CQDMCAIJAQxJbnRlZ2VyRW50cnkCAhRnbG9iYWxfZWFybmVkQnlPd25lcgkAZAIJAQ10cnlHZXRJbnRlZ2VyAQIUZ2xvYmFsX2Vhcm5lZEJ5T3duZXIFCmNyZWF0b3JGZWUJAMwIAgkBDEludGVnZXJFbnRyeQICDWdsb2JhbF92b2x1bWUJAGQCCQENdHJ5R2V0SW50ZWdlcgECDWdsb2JhbF92b2x1bWUFDHZvbHVtZVVwZGF0ZQkAzAgCCQEMSW50ZWdlckVudHJ5AgIRZ2xvYmFsX3ZvbHVtZV91c2QJAGQCCQENdHJ5R2V0SW50ZWdlcgECEWdsb2JhbF92b2x1bWVfdXNkBQ92b2x1bWVVc2RVcGRhdGUJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwULZmVlc0FkZHJlc3MFC3Byb3RvY29sRmVlBQtmZWVBc3NldE91dAUDbmlsBQlBbW91bnRPdXQBaQEMc3dhcFJlYWRPbmx5Awdhc3NldEluCGFzc2V0T3V0CEFtb3VudEluBAdBc3NldEluCQENZ2V0QXNzZXRCeXRlcwEFB2Fzc2V0SW4ECEFzc2V0T3V0CQENZ2V0QXNzZXRCeXRlcwEFCGFzc2V0T3V0BAdzY2FsZUluCQBpAgUGU2NhbGU4CQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdzdGF0aWNfBQdhc3NldEluAgZfc2NhbGUECHNjYWxlT3V0CQBpAgUGU2NhbGU4CQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdzdGF0aWNfBQhhc3NldE91dAIGX3NjYWxlBA5mZWVBc3NldE91dFN0cgkBDHRyeUdldFN0cmluZwECD3N0YXRpY19mZWVUb2tlbgQLZmVlQXNzZXRPdXQDCQAAAgUOZmVlQXNzZXRPdXRTdHICAAULdXNkbkFzc2V0SWQJAQ1nZXRBc3NldEJ5dGVzAQUOZmVlQXNzZXRPdXRTdHIEDkFzc2V0SW5CYWxhbmNlCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdnbG9iYWxfCQEOZ2V0QXNzZXRTdHJpbmcBBQdBc3NldEluAghfYmFsYW5jZQQPQXNzZXRPdXRCYWxhbmNlCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdnbG9iYWxfBQhhc3NldE91dAIIX2JhbGFuY2UEFEFzc2V0SW5CYWxhbmNlU2NhbGVkCQBoAgUOQXNzZXRJbkJhbGFuY2UFB3NjYWxlSW4EFUFzc2V0T3V0QmFsYW5jZVNjYWxlZAkAaAIFD0Fzc2V0T3V0QmFsYW5jZQUIc2NhbGVPdXQEC2ZlZUFtb3VudEluCQBrAwUIQW1vdW50SW4FA0ZlZQUIRmVlU2NhbGUEDWNsZWFuQW1vdW50SW4JAGUCBQhBbW91bnRJbgULZmVlQW1vdW50SW4EE2NsZWFuQW1vdW50SW5TY2FsZWQJAGgCBQ1jbGVhbkFtb3VudEluBQdzY2FsZUluBApBbW91bnRPdXQxCQESY2FsY3VsYXRlT3V0QW1vdW50BQUTY2xlYW5BbW91bnRJblNjYWxlZAUHQXNzZXRJbgUIQXNzZXRPdXQFFEFzc2V0SW5CYWxhbmNlU2NhbGVkBRVBc3NldE91dEJhbGFuY2VTY2FsZWQECUFtb3VudE91dAkAawMFCkFtb3VudE91dDEAAQUIc2NhbGVPdXQEEEFzc2V0T3V0QmFsYW5jZTIJAGUCBQ9Bc3NldE91dEJhbGFuY2UFCUFtb3VudE91dAQPQXNzZXRJbkJhbGFuY2UyCQBkAgUOQXNzZXRJbkJhbGFuY2UFDWNsZWFuQW1vdW50SW4EEmZlZUFzc2V0T3V0QmFsYW5jZQMJAAACBQtmZWVBc3NldE91dAUHQXNzZXRJbgUPQXNzZXRJbkJhbGFuY2UyAwkAAAIFC2ZlZUFzc2V0T3V0BQhBc3NldE91dAUQQXNzZXRPdXRCYWxhbmNlMgkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHZ2xvYmFsXwkBDmdldEFzc2V0U3RyaW5nAQULZmVlQXNzZXRPdXQCCF9iYWxhbmNlBAxmZWVBbW91bnRPdXQJARJjYWxjdWxhdGVPdXRBbW91bnQFBQtmZWVBbW91bnRJbgUHQXNzZXRJbgULZmVlQXNzZXRPdXQFDkFzc2V0SW5CYWxhbmNlBRJmZWVBc3NldE91dEJhbGFuY2UDCQAAAgUIQXNzZXRPdXQFB0Fzc2V0SW4JAAIBAhh0aGlzIHN3YXAgaXMgbm90IGFsbG93ZWQDCQBmAgAACQBlAgUPQXNzZXRPdXRCYWxhbmNlBQlBbW91bnRPdXQJAAIBAhtjb250cmFjdCBpcyBvdXQgb2YgcmVzZXJ2ZXMDCQEKaXNTaHV0ZG93bgAJAAIBAhNjb250cmFjdCBpcyBvbiBzdG9wCQCUCgIFA25pbAUJQW1vdW50T3V0AWkBEXRyYW5zZmVyT3duZXJzaGlwAQ9uZXdPd25lckFkZHJlc3MDCQECIT0CCQClCAEIBQFpBmNhbGxlcgkBDHRyeUdldFN0cmluZwECEHN0YXRpY19wb29sT3duZXIJAAIBAid0aGlzIGNhbGwgYXZhaWxhYmxlIG9ubHkgZm9yIHBvb2wgb3duZXIJAMwIAgkBC1N0cmluZ0VudHJ5AgIQc3RhdGljX3Bvb2xPd25lcgUPbmV3T3duZXJBZGRyZXNzBQNuaWwBaQEGc2V0RmVlAQZuZXdGZWUDCQECIT0CCQClCAEIBQFpBmNhbGxlcgkBDHRyeUdldFN0cmluZwECEHN0YXRpY19wb29sT3duZXIJAAIBAid0aGlzIGNhbGwgYXZhaWxhYmxlIG9ubHkgZm9yIHBvb2wgb3duZXIDCQBmAgABCQELdmFsdWVPckVsc2UCCQCaCAIFCmdvdkFkZHJlc3MJAKwCAgILYXBwcm92ZWRUeF8JANgEAQgFAWkNdHJhbnNhY3Rpb25JZAAACQACAQIzdGhpcyB0cmFuc2FjdGlvbiBuZWVkcyBhcHByb3ZhbCBmcm9tIHB1enpsZSBuZXR3b3JrCQDMCAIJAQxJbnRlZ2VyRW50cnkCAgpzdGF0aWNfZmVlBQZuZXdGZWUFA25pbAFpARJzZXRSZWJhbGFuY2luZ1BsYW4FC2Fzc2V0SWRzU3RyD2Fzc2V0V2VpZ2h0c1N0cg5iYXNlVG9rZW5JZFN0cgtzdGVwc0Ftb3VudA1zdGVwc0ludGVydmFsAwkBAiE9AggFAWkGY2FsbGVyCQERQGV4dHJOYXRpdmUoMTA2MikBCQEMdHJ5R2V0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C2FkZGVkQXNzZXRzCAUBaQhwYXltZW50cwQMdmFsaWRXZWlnaHRzCQEPdmFsaWRhdGVXZWlnaHRzAQUUbmV3QXNzZXRXZWlnaHRzU3RyTGkDCQAAAgUMdmFsaWRXZWlnaHRzBQx2YWxpZFdlaWdodHMDCQECIT0CBQ12YWxpZFBheW1lbnRzCQBkAgkAkAMBBQthZGRlZEFzc2V0cwkAkAMBCAUBaQhwYXltZW50cwkAAgECMVBheW1lbnRzIG5vdCBwcmVzZW50IG9yIHNvbWV0aGluZyB3cm9uZyB3aXRoIHRoZW0DCQECIT0CCQCQAwEFEG5ld0Fzc2V0SWRzU3RyTGkJAJADAQUUbmV3QXNzZXRXZWlnaHRzU3RyTGkJAAIBAjFhc3NldElkcyBhbmQgYXNzZXRXZWlnaHRzIHNob3VsZCBoYXZlIHNhbWUgbGVuZ3RoAwkBAiE9AgUNdmFsaWRQYXltZW50cwkAZAIJAJADAQULYWRkZWRBc3NldHMJAJADAQgFAWkIcGF5bWVudHMJAAIBAjFQYXltZW50cyBub3QgcHJlc2VudCBvciBzb21ldGhpbmcgd3Jvbmcgd2l0aCB0aGVtAwkAAAIFC2ZlZUFzc2V0U3RyAgAJAAIBAkFwb29sIG11c3QgaGF2ZSBvbmUgb2YgdGhlIHN1cHBvcnRlZCBmZWUgYXNzZXRzIGluIHRoZSBjb21wb3NpdGlvbgMJAAACCQDPCAIFEG5ld0Fzc2V0SWRzU3RyTGkFDmJhc2VUb2tlbklkU3RyBQR1bml0CQACAQIpYmFzZVRva2VuSWQgc2hvdWxkIGJlIHByZXNlbnQgaW4gYXNzZXRJZHMDAwkAZgIFEE1JTl9TVEVQU19BTU9VTlQFC3N0ZXBzQW1vdW50BgkAZgIFC3N0ZXBzQW1vdW50BRBNQVhfU1RFUFNfQU1PVU5UCQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgICH1N0ZXBzIGFtb3VudCBzaG91bGQgYmUgYmV0d2VlbiAJAKQDAQUQTUlOX1NURVBTX0FNT1VOVAIFIGFuZCAJAKQDAQUQTUFYX1NURVBTX0FNT1VOVAILLCBjdXJyZW50OiAJAKQDAQULc3RlcHNBbW91bnQDAwkAZgIFEk1JTl9TVEVQU19JTlRFUlZBTAUNc3RlcHNJbnRlcnZhbAYJAGYCBQ1zdGVwc0ludGVydmFsBRJNQVhfU1RFUFNfSU5URVJWQUwJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgIhU3RlcHMgaW50ZXJ2YWwgc2hvdWxkIGJlIGJldHdlZW4gCQCkAwEFEk1JTl9TVEVQU19JTlRFUlZBTAIFIGFuZCAJAKQDAQUSTUFYX1NURVBTX0lOVEVSVkFMAgssIGN1cnJlbnQ6IAkApAMBBQ1zdGVwc0ludGVydmFsAwkBAiE9AgUPYXNzZXRXZWlnaHRzU3VtAJBOCQACAQkArAICAjZzdW0gb2YgdG9rZW4gd2VpZ2h0cyBtdXN0IGJlIGVxdWFsIHRvIDEwMDAwLCBjdXJyZW50OiAJAKQDAQUPYXNzZXRXZWlnaHRzU3VtCgEBZgIFYWNjdW0KYXNzZXRJZFN0cgQJb2xkV2VpZ2h0CQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdzdGF0aWNfBQphc3NldElkU3RyAgdfd2VpZ2h0BAluZXdXZWlnaHQDCQAAAgkAzwgCBRBuZXdBc3NldElkc1N0ckxpBQphc3NldElkU3RyBQR1bml0AAAJAQ1wYXJzZUludFZhbHVlAQkBBXZhbHVlAQkAkQMCBRRuZXdBc3NldFdlaWdodHNTdHJMaQkBBXZhbHVlAQkAzwgCBRBuZXdBc3NldElkc1N0ckxpBQphc3NldElkU3RyBAxkZWx0YVBlclN0ZXAJAGsDCQBlAgUJbmV3V2VpZ2h0BQlvbGRXZWlnaHQAkE4FC3N0ZXBzQW1vdW50CQDOCAIFBWFjY3VtCQDMCAIJAKQDAQUMZGVsdGFQZXJTdGVwBQNuaWwEDXRtcEFzc2V0SWRzTGkJARJnZXRUbXBSZWJhbGFuY2VJZHMBBRBuZXdBc3NldElkc1N0ckxpBAthc3NldERlbHRhcwoAAiRsBQ10bXBBc3NldElkc0xpCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGY4XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQFmAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY4XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmOF8yAgkBBSRmOF8xAgkBBSRmOF8xAgkBBSRmOF8xAgkBBSRmOF8xAgkBBSRmOF8xAgkBBSRmOF8xAgkBBSRmOF8xAgkBBSRmOF8xAgkBBSRmOF8xAgkBBSRmOF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKBA5uZXdUb2tlbnNBZGRlZAkAZgIJARFjaGVja1Rva2Vuc0NoYW5nZQEFEG5ld0Fzc2V0SWRzU3RyTGkAAAoBEnJlY29yZEFzc2V0UGF5bWVudAIFYWNjdW0EbmV4dAkAzggCBQVhY2N1bQkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICAhpyZWJhbGFuY2VfYXR0YWNoZWRQYXltZW50XwkBDmdldEFzc2V0U3RyaW5nAQgFBG5leHQHYXNzZXRJZAgFBG5leHQGYW1vdW50BQNuaWwEDnBheW1lbnRFbnRyaWVzCgACJGwIBQFpCHBheW1lbnRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGY5XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARJyZWNvcmRBc3NldFBheW1lbnQCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjlfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY5XzICCQEFJGY5XzECCQEFJGY5XzECCQEFJGY5XzECCQEFJGY5XzECCQEFJGY5XzECCQEFJGY5XzECCQEFJGY5XzECCQEFJGY5XzECCQEFJGY5XzECCQEFJGY5XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoEDHN0b3JlV2VpZ2h0cwkBEnNhdmVDdXJyZW50V2VpZ2h0cwAEEHJlcXVlc3RHb3ZJbnZva2UJAPwHBAUKZ292QWRkcmVzcwIScmVxdWVzdFJlYmFsYW5jaW5nCQDMCAIJANgEAQgFAWkNdHJhbnNhY3Rpb25JZAUDbmlsBQNuaWwDCQAAAgUQcmVxdWVzdEdvdkludm9rZQUQcmVxdWVzdEdvdkludm9rZQkAzggCCQDOCAIJAMwIAgkBC1N0cmluZ0VudHJ5AgIVcmViYWxhbmNlX2FkZGVkQXNzZXRzCQC5CQIFC2FkZGVkQXNzZXRzAgEsCQDMCAIJAQtTdHJpbmdFbnRyeQICF3JlYmFsYW5jZV9yZW1vdmVkQXNzZXRzCQC5CQIFDXJlbW92ZWRBc3NldHMCASwJAMwIAgkBC1N0cmluZ0VudHJ5AgIVdG1wX3JlYmFsYW5jZUFzc2V0SWRzCQC5CQIFDXRtcEFzc2V0SWRzTGkCASwJAMwIAgkBDEJvb2xlYW5FbnRyeQICFHJlYmFsYW5jZV9pblByb2dyZXNzBgkAzAgCCQEMQm9vbGVhbkVudHJ5AgIYcmViYWxhbmNlX25ld1Rva2Vuc0FkZGVkBQ5uZXdUb2tlbnNBZGRlZAkAzAgCCQEMSW50ZWdlckVudHJ5AgITcmViYWxhbmNlX3N0ZXBzRG9uZQAACQDMCAIJAQxJbnRlZ2VyRW50cnkCAhhyZWJhbGFuY2VfbGFzdFN0ZXBIZWlnaHQFBmhlaWdodAkAzAgCCQEMSW50ZWdlckVudHJ5AgIVcmViYWxhbmNlX3N0ZXBzQW1vdW50BQtzdGVwc0Ftb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgIXcmViYWxhbmNlX3N0ZXBzSW50ZXJ2YWwFDXN0ZXBzSW50ZXJ2YWwJAMwIAgkBC1N0cmluZ0VudHJ5AgIScmViYWxhbmNlX2Fzc2V0SWRzBQthc3NldElkc1N0cgkAzAgCCQELU3RyaW5nRW50cnkCAhhyZWJhbGFuY2VfbmV3QmFzZVRva2VuSWQFDmJhc2VUb2tlbklkU3RyCQDMCAIJAQtTdHJpbmdFbnRyeQICFXJlYmFsYW5jZV9hc3NldERlbHRhcwkAuQkCBQthc3NldERlbHRhcwIBLAUDbmlsBQ5wYXltZW50RW50cmllcwUMc3RvcmVXZWlnaHRzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBD3N0ZXBSZWJhbGFuY2luZwAEBXJlYklkCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ0IAgUKZ292QWRkcmVzcwkArAICAhVwb29sX2xhc3RSZWJhbGFuY2luZ18JAKUIAQUEdGhpcwIscmViYWxhbmNpbmcgaXMgbm90IHJlZ2lzdGVyZWQgYXQgZ292IGFkZHJlc3MDCQEBIQEJAQt2YWx1ZU9yRWxzZQIJAJsIAgUEdGhpcwIUcmViYWxhbmNlX2luUHJvZ3Jlc3MHCQACAQIabm8gcmViYWxhbmNpbmcgaW4gcHJvZ3Jlc3MDCQECIT0CCQELdmFsdWVPckVsc2UCCQCaCAIFCmdvdkFkZHJlc3MJAKwCAgITcmViYWxhbmNpbmdfc3RhdHVzXwUFcmViSWQAAAACCQACAQIzdGhpcyB0cmFuc2FjdGlvbiBuZWVkcyBhcHByb3ZhbCBmcm9tIHB1enpsZSBuZXR3b3JrBA5sYXN0U3RlcEhlaWdodAkBEUBleHRyTmF0aXZlKDEwNTUpAQIYcmViYWxhbmNlX2xhc3RTdGVwSGVpZ2h0BAxzdGVwSW50ZXJ2YWwJARFAZXh0ck5hdGl2ZSgxMDU1KQECF3JlYmFsYW5jZV9zdGVwc0ludGVydmFsBAlzdGVwc0RvbmUJARFAZXh0ck5hdGl2ZSgxMDU1KQECE3JlYmFsYW5jZV9zdGVwc0RvbmUEDm5leHRTdGVwSGVpZ2h0CQBkAgUObGFzdFN0ZXBIZWlnaHQFDHN0ZXBJbnRlcnZhbAMJAGYCBQ5uZXh0U3RlcEhlaWdodAUGaGVpZ2h0CQACAQIRY2FuJ3QgYmUgZG9uZSB5ZXQEC2Fzc2V0RGVsdGFzCQC1CQIJARFAZXh0ck5hdGl2ZSgxMDU4KQECFXJlYmFsYW5jZV9hc3NldERlbHRhcwIBLAQObmV3QXNzZXRJZHNTdHIJARFAZXh0ck5hdGl2ZSgxMDU4KQECFXRtcF9yZWJhbGFuY2VBc3NldElkcwQLbmV3QXNzZXRJZHMJALUJAgUObmV3QXNzZXRJZHNTdHICASwKAQFmAgVhY2N1bQphc3NldElkU3RyCQDOCAIFBWFjY3VtCQDMCAIJAKQDAQkAbgQJAGQCCQBoAgkBC3ZhbHVlT3JFbHNlAgkAnwgBCQCsAgICFnJlYmFsYW5jZV9zdGFydFdlaWdodF8FCmFzc2V0SWRTdHIAAACQTgkAaAIJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQthc3NldERlbHRhcwkBBXZhbHVlAQkAzwgCBQtuZXdBc3NldElkcwUKYXNzZXRJZFN0cgkAZAIFCXN0ZXBzRG9uZQABAAEAkE4FBkhBTEZVUAUDbmlsBAluZXdTaGFyZXMJALkJAgoAAiRsBQtuZXdBc3NldElkcwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmNF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEBZgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjRfMgIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgIBLAQObmV3VG9rZW5zQWRkZWQJARFAZXh0ck5hdGl2ZSgxMDU2KQECGHJlYmFsYW5jZV9uZXdUb2tlbnNBZGRlZAQDaW52AwMFDm5ld1Rva2Vuc0FkZGVkCQAAAgUJc3RlcHNEb25lAAAHCQD8BwQFBHRoaXMCGmRvUmViYWxhbmNpbmdXaXRoTmV3VG9rZW5zCQDMCAIFDm5ld0Fzc2V0SWRzU3RyCQDMCAIFCW5ld1NoYXJlcwkAzAgCCQERQGV4dHJOYXRpdmUoMTA1OCkBAhhyZWJhbGFuY2VfbmV3QmFzZVRva2VuSWQFA25pbAUDbmlsCQD8BwQFBHRoaXMCDWRvUmViYWxhbmNpbmcJAMwIAgUJbmV3U2hhcmVzBQNuaWwFA25pbAMJAAACBQNpbnYFA2ludgQMbm90aWZ5SW52b2tlCQD8BwQFD3Bvb2xzSHViQWRkcmVzcwIQbm90aWZ5UG9vbENoYW5nZQUDbmlsBQNuaWwDCQAAAgUMbm90aWZ5SW52b2tlBQxub3RpZnlJbnZva2UECmlzRmluaXNoZWQJAGcCCQBkAgUJc3RlcHNEb25lAAEJARFAZXh0ck5hdGl2ZSgxMDU1KQECFXJlYmFsYW5jZV9zdGVwc0Ftb3VudAQHYWN0aW9ucwkAzAgCCQEMQm9vbGVhbkVudHJ5AgIUcmViYWxhbmNlX2luUHJvZ3Jlc3MJAQEhAQUKaXNGaW5pc2hlZAkAzAgCCQEMSW50ZWdlckVudHJ5AgITcmViYWxhbmNlX3N0ZXBzRG9uZQkAZAIFCXN0ZXBzRG9uZQABCQDMCAIJAQxJbnRlZ2VyRW50cnkCAhhyZWJhbGFuY2VfbGFzdFN0ZXBIZWlnaHQFBmhlaWdodAUDbmlsAwkAAAIFCXN0ZXBzRG9uZQAACQDOCAIFB2FjdGlvbnMJAMwIAgkBC1N0cmluZ0VudHJ5AgIPc3RhdGljX3Rva2VuSWRzBQ5uZXdBc3NldElkc1N0cgUDbmlsAwUKaXNGaW5pc2hlZAQPcmVtb3ZlZEFzc2V0c0xpCQC1CQIJAQx0cnlHZXRTdHJpbmcBAhdyZWJhbGFuY2VfcmVtb3ZlZEFzc2V0cwIBLAoBBnJtRGF0YQIFYWNjdW0HYXNzZXRJZAkAzggCBQVhY2N1bQkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgIJAKwCAgIHc3RhdGljXwUHYXNzZXRJZAIGX3NjYWxlCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgkArAICAgdzdGF0aWNfBQdhc3NldElkAglfZGVjaW1hbHMJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICCQCsAgICB3N0YXRpY18FB2Fzc2V0SWQCB193ZWlnaHQJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICCQCsAgICB2dsb2JhbF8FB2Fzc2V0SWQCCF9iYWxhbmNlCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgIacmViYWxhbmNlX2F0dGFjaGVkUGF5bWVudF8FB2Fzc2V0SWQFA25pbAQCcm0KAAIkbAUPcmVtb3ZlZEFzc2V0c0xpCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGY1XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQZybURhdGECBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjVfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY1XzICCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoEDWFkZGVkQXNzZXRzTGkJALUJAgkBDHRyeUdldFN0cmluZwECFXJlYmFsYW5jZV9hZGRlZEFzc2V0cwIBLAoBEWFkZFJlbW92ZVBheW1lbnRzAgVhY2N1bQdhc3NldElkCQDOCAIFBWFjY3VtCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgIacmViYWxhbmNlX2F0dGFjaGVkUGF5bWVudF8FB2Fzc2V0SWQFA25pbAQKcm1QYXltZW50cwoAAiRsBQ1hZGRlZEFzc2V0c0xpCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGY2XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARFhZGRSZW1vdmVQYXltZW50cwIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNl8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjZfMgIJAQUkZjZfMQIJAQUkZjZfMQIJAQUkZjZfMQIJAQUkZjZfMQIJAQUkZjZfMQIJAQUkZjZfMQIJAQUkZjZfMQIJAQUkZjZfMQIJAQUkZjZfMQIJAQUkZjZfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgQRZmluYWxBc3NldHNJZHNTdHIJAQx0cnlHZXRTdHJpbmcBAhJyZWJhbGFuY2VfYXNzZXRJZHMEEEFzc2V0c1dlaWdodHNTdHIKAAIkbAkAtQkCBRFmaW5hbEFzc2V0c0lkc1N0cgIBLAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmN18xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEXYWRkQXNzZXRXZWlnaHRUb1N0ckxpc3QCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjdfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY3XzICCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoEBm5vdGlmeQkA/AcEBQpnb3ZBZGRyZXNzAhVub3RpZnlSZWJhbGFuY2luZ0RvbmUJAMwIAgUFcmViSWQFA25pbAUDbmlsAwkAAAIFBm5vdGlmeQUGbm90aWZ5CQDOCAIJAM4IAgkAzggCBQdhY3Rpb25zBQJybQUKcm1QYXltZW50cwkAzAgCCQELU3RyaW5nRW50cnkCAg9zdGF0aWNfdG9rZW5JZHMFEWZpbmFsQXNzZXRzSWRzU3RyCQDMCAIJAQtTdHJpbmdFbnRyeQICE3N0YXRpY190b2tlbldlaWdodHMJALkJAgUQQXNzZXRzV2VpZ2h0c1N0cgIBLAkAzAgCCQEMSW50ZWdlckVudHJ5AgITc3RhdGljX3Rva2Vuc0Ftb3VudAkAkAMBCQC1CQIFEWZpbmFsQXNzZXRzSWRzU3RyAgEsBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4EEWZpbmFsQXNzZXRzSWRzU3RyCQEMdHJ5R2V0U3RyaW5nAQIScmViYWxhbmNlX2Fzc2V0SWRzBBBBc3NldHNXZWlnaHRzU3RyCgACJGwJALUJAgURZmluYWxBc3NldHNJZHNTdHICASwKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjVfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBF2FkZEFzc2V0V2VpZ2h0VG9TdHJMaXN0AgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY1XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNV8yAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgkBBSRmNV8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKCQDOCAIFB2FjdGlvbnMJAMwIAgkBC1N0cmluZ0VudHJ5AgITc3RhdGljX3Rva2VuV2VpZ2h0cwkAuQkCBRBBc3NldHNXZWlnaHRzU3RyAgEsBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQENZG9S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Y2VlZHMgMTAJAQUkZjdfMgIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgQGd2VpZ2h0CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUUbmV3QXNzZXRXZWlnaHRzU3RyTGkFCFRva2VuTnVtBA5iYWxhbmNlSW5TdGF0ZQkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHZ2xvYmFsXwUKYXNzZXRJZFN0cgIIX2JhbGFuY2UEEGJhbGFuY2VJblBheW1lbnQJAJEDAgUQYXR0YWNoZWRCYWxhbmNlcwUIVG9rZW5OdW0EB2JhbGFuY2UJAGQCBQ5iYWxhbmNlSW5TdGF0ZQUQYmFsYW5jZUluUGF5bWVudAQNYXNzZXREZWNpbWFscwMJAAACBQdhc3NldElkBQR1bml0AAgICQEFdmFsdWUBCQDsBwEJAQV2YWx1ZQEFB2Fzc2V0SWQIZGVjaW1hbHMDCQBnAgAABQdiYWxhbmNlCQACAQkArAICAkR5b3UgbmVlZCB0byBhdHRhY2ggYWxsIG5ldyBhc3NldHMgaW4gcGF5bWVudC4gdGhpcyBhc3NldCBpcyBtaXNzZWQ6IAUKYXNzZXRJZFN0cgkAawMFCGN1cnJlbnRLCQBsBgUHYmFsYW5jZQUNYXNzZXREZWNpbWFscwUGd2VpZ2h0BRVBc3NldHNXZWlnaHRzRGVjaW1hbHMACAUFRkxPT1IFBlNjYWxlOAQEbmV3SwoAAiRsBQtuZXdBc3NldElkcwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFDlBvb2xUb2tlblNjYWxlCgEFJGY3XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARJteWx0aXBseUFzc2V0c0ZvcksCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjdfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY3XzICCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECCQEFJGY3XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoECG5ld0tNdWx0CQBrAwUIb2xkS011bHQFBG5ld0sFBG9sZEsKARNhZGRUb2tlbkRhdGFFbnRyaWVzAgVhY2N1bQhhc3NldE51bQQKYXNzZXRJZFN0cgkAkQMCBRBuZXdBc3NldElkc1N0ckxpBQhhc3NldE51bQQHYXNzZXRJZAkAkQMCBQtuZXdBc3NldElkcwUIYXNzZXROdW0EDWFzc2V0RGVjaW1hbHMDCQAAAgUHYXNzZXRJZAUEdW5pdAAICAkBBXZhbHVlAQkA7AcBCQEFdmFsdWUBBQdhc3NldElkCGRlY2ltYWxzBAxuZXdBc3NldERhdGEDCQECIT0CCQDPCAIFC2FkZGVkQXNzZXRzBQphc3NldElkU3RyBQR1bml0CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgIHZ2xvYmFsXwUKYXNzZXRJZFN0cgIIX2JhbGFuY2UJAJEDAgUQYXR0YWNoZWRCYWxhbmNlcwUIYXNzZXROdW0JAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICAgdzdGF0aWNfBQphc3NldElkU3RyAgZfc2NhbGUJAGwGAAoAAAUNYXNzZXREZWNpbWFscwAAAAAFBERPV04JAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICAgdzdGF0aWNfBQphc3NldElkU3RyAglfZGVjaW1hbHMFDWFzc2V0RGVjaW1hbHMFA25pbAUDbmlsAwkAZwIFCGFzc2V0TnVtCQCQAwEFFG5ld0Fzc2V0V2VpZ2h0c1N0ckxpBQVhY2N1bQkAzggCCQDOCAIFBWFjY3VtCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgIHc3RhdGljXwUKYXNzZXRJZFN0cgIHX3dlaWdodAkBBXZhbHVlAQkAtgkBCQCRAwIFFG5ld0Fzc2V0V2VpZ2h0c1N0ckxpBQhhc3NldE51bQUDbmlsBQxuZXdBc3NldERhdGEJAM4IAgoAAiRsCQDMCAIAAAkAzAgCAAEJAMwIAgACCQDMCAIAAwkAzAgCAAQJAMwIAgAFCQDMCAIABgkAzAgCAAcJAMwIAgAICQDMCAIACQUDbmlsCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGY4XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARNhZGRUb2tlbkRhdGFFbnRyaWVzAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY4XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmOF8yAgkBBSRmOF8xAgkBBSRmOF8xAgkBBSRmOF8xAgkBBSRmOF8xAgkBBSRmOF8xAgkBBSRmOF8xAgkBBSRmOF8xAgkBBSRmOF8xAgkBBSRmOF8xAgkBBSRmOF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKCQDMCAIJAQtTdHJpbmdFbnRyeQICD3N0YXRpY190b2tlbklkcwULYXNzZXRJZHNTdHIJAMwIAgkBC1N0cmluZ0VudHJ5AgIPc3RhdGljX2ZlZVRva2VuBQtmZWVBc3NldFN0cgkAzAgCCQELU3RyaW5nRW50cnkCAhNzdGF0aWNfdG9rZW5XZWlnaHRzBQ9hc3NldFdlaWdodHNTdHIJAMwIAgkBDEludGVnZXJFbnRyeQICE3N0YXRpY190b2tlbnNBbW91bnQJAJADAQULbmV3QXNzZXRJZHMJAMwIAgkBDEludGVnZXJFbnRyeQICDHN0YXRpY19LTXVsdAUIbmV3S011bHQFA25pbAECdHgBBnZlcmlmeQADAwkAAAIJAQt2YWx1ZU9yRWxzZQIJAJ8IAQITZ2xvYmFsX3dhc1ByZUluaXRlZAAAAAADCQD0AwMIBQJ0eAlib2R5Qnl0ZXMJAJEDAggFAnR4BnByb29mcwAACAUCdHgPc2VuZGVyUHVibGljS2V5BgkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAAUMbWFzdGVyUHViS2V5BwYEByRtYXRjaDAFAnR4AwkAAQIFByRtYXRjaDACFFNldFNjcmlwdFRyYW5zYWN0aW9uBAJ0eAUHJG1hdGNoMAQKc2NyaXB0RnVsbAkBBXZhbHVlAQgFAnR4BnNjcmlwdAQEaGFzaAkA2AQBCQD3AwEFCnNjcmlwdEZ1bGwDCQD0AwMIBQJ0eAlib2R5Qnl0ZXMJAJEDAggFAnR4BnByb29mcwAABQxtYXN0ZXJQdWJLZXkJAGYCCQELdmFsdWVPckVsc2UCCQCaCAIFEWNvbGRNYXN0ZXJBZGRyZXNzCQCsAgICD2FwcHJvdmVkU2NyaXB0XwUEaGFzaAAABQZoZWlnaHQHAwkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAAUMbWFzdGVyUHViS2V5CQBmAgkBC3ZhbHVlT3JFbHNlAgkAmggCBRFjb2xkTWFzdGVyQWRkcmVzcwkArAICAgthcHByb3ZlZFR4XwkA2AQBCAUCdHgCaWQAAAAAB2vb2Ig=", "height": 4141387, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 631SQxgTTK7XwT9fGXy2m9Q6dRngCzJuV1rUcmTYZuj8 Next: none 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.3 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
208311 let usdnInPool = indexOf(assetIds, usdnAssetId)
209312 let puzzleInPool = indexOf(assetIds, puzzleAssetId)
210313 let usdtInPool = indexOf(assetIds, usdtAssetId)
314+ let usdtPptInPool = indexOf(assetIds, usdtPptAssetId)
211315 let wavesInPool = indexOf(assetIds, unit)
212316 let assetWeight = tryGetInteger((("static_" + getAssetString(assetId)) + "_weight"))
213317 let feeAssetStr = tryGetString("static_feeToken")
225329 let usdtBalance = tryGetInteger((("global_" + usdtAssetIdStr) + "_balance"))
226330 fraction(amount, (usdtBalance / usdtWeight), (aBalance / assetWeight))
227331 }
228- else if ((feeAssetStr == usdnAssetIdStr))
332+ else if ((feeAssetStr == usdtPptAssetIdStr))
229333 then {
230- let usdnWeight = AssetsWeights[value(indexOf(assetIds, usdnAssetId))]
231- let usdnBalance = match givenUsdnBalance {
232- case x: Int =>
233- givenUsdnBalance
234- case _ =>
235- tryGetInteger((("global_" + getAssetString(usdnAssetId)) + "_balance"))
334+ let usdtWeight = AssetsWeights[value(usdtPptInPool)]
335+ let usdtBalance = tryGetInteger((("global_" + usdtPptAssetIdStr) + "_balance"))
336+ fraction(amount, (usdtBalance / usdtWeight), (aBalance / assetWeight))
236337 }
237- fraction(amount, (value(usdnBalance) / usdnWeight), (aBalance / assetWeight))
238- }
239- else {
240- let wavesWeight = 3000
241- let wBalance = (tryGetInteger("global_WAVES_balance") / 50)
242- fraction(amount, (wBalance / wavesWeight), (aBalance / assetWeight))
243- }
338+ else if ((feeAssetStr == usdnAssetIdStr))
339+ then {
340+ let usdnWeight = AssetsWeights[value(indexOf(assetIds, usdnAssetId))]
341+ let usdnBalance = match givenUsdnBalance {
342+ case x: Int =>
343+ givenUsdnBalance
344+ case _ =>
345+ tryGetInteger((("global_" + getAssetString(usdnAssetId)) + "_balance"))
346+ }
347+ fraction(amount, (value(usdnBalance) / usdnWeight), (aBalance / assetWeight))
348+ }
349+ else {
350+ let wavesWeight = 3000
351+ let wBalance = (tryGetInteger("global_WAVES_balance") / 50)
352+ fraction(amount, (wBalance / wavesWeight), (aBalance / assetWeight))
353+ }
354+ }
355+
356+
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)
244375 }
245376
246377
311442
312443 func handleTokenChange (accum,tokenId) = {
313444 let Bk = tryGetInteger((("global_" + getAssetString(tokenId)) + "_balance"))
314- let PSupply = tryGetInteger("global_poolToken_amount")
445+ let PSupply = getVirtualPoolTokenAmount()
315446 let tokenDecimals = tryGetInteger((("static_" + getAssetString(tokenId)) + "_scale"))
316- 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))
317449 let paymentAmount = getTokenPaymentAmount(tokenId)
318- let toReturn = ((if ((paymentAmount != 0))
319- then paymentAmount
320- else 0) - Dk)
450+ let toReturn = (paymentAmount - Dk)
321451 let t = if (if (needChange)
322452 then (toReturn > 0)
323453 else false)
344474 func handlePoolTokensRedeem (PRedeemed,userAddress) = {
345475 func handleTokenRedeem (accum,tokenId) = {
346476 let Bk = tryGetInteger((("global_" + getAssetString(tokenId)) + "_balance"))
347- let PSupply = tryGetInteger("global_poolToken_amount")
477+ let PSupply = getVirtualPoolTokenAmount()
348478 let tokenDecimals = tryGetInteger((("static_" + getAssetString(tokenId)) + "_scale"))
349- 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))
350481 (accum ++ [IntegerEntry((("global_" + getAssetString(tokenId)) + "_balance"), (Bk - amount)), ScriptTransfer(userAddress, amount, tokenId)])
351482 }
352483
370501 let IndexOut = value(indexOf(assetIds, assetOut))
371502 if ((IndexIn == IndexOut))
372503 then AmountIn
373- 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)
374505 }
375-
376-
377-func getTokenBalance (assetId) = match assetId {
378- case t: ByteVector =>
379- assetBalance(this, t)
380- case _ =>
381- wavesBalance(this).available
382-}
383506
384507
385508 func calculateCurrentAssetInterest (assetId,assetIdStr,aBalance,tokenEarningsLastCheck) = {
411534 let transfer = if ((rewardAmount == 0))
412535 then nil
413536 else [ScriptTransfer(address, rewardAmount, assetId)]
414- $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)))
415538 }
416539
417540 let accum = {
428551
429552 $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)
430553 }
431- $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)
432555 }
433556
434557
441564 func sum (accum,n) = (accum + parseIntValue(n))
442565
443566
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+
444722 @Callable(i)
445723 func preInit (assetIdsStr,assetWeightsStr,baseTokenIdStr,poolDomain,poolOwner,fee) = {
446724 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+ }
447754 if (isShutdown())
448755 then throw("contract is on stop")
449756 else if ((this != i.caller))
450757 then throw("admin only")
451- else if ((size(poolDomain) > 13))
452- then throw("too large pool domain")
453- else if (if ((fee > 500))
454- then true
455- else (50 > fee))
456- then throw("fee value must be between 50 and 500 (0.5-5%)")
457- else if (if (if (if (if ((indexOf(assetIdsStr, puzzleAssetIdStr) == unit))
458- then (indexOf(assetIdsStr, usdnAssetIdStr) == unit)
459- else false)
460- then (indexOf(assetIdsStr, usdtAssetIdStr) == unit)
461- else false)
462- then (indexOf(assetIdsStr, "WAVES") == unit)
463- else false)
464- then (indexOf(assetIdsStr, usdtPptAssetIdStr) == unit)
465- else false)
466- 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%)")
467766 else {
468- let assetIdsStrLi = split(assetIdsStr, ",")
469- let assetIdsLi = {
470- let $l = assetIdsStrLi
471- let $s = size($l)
472- let $acc0 = nil
473- func $f4_1 ($a,$i) = if (($i >= $s))
474- then $a
475- else addAssetBytesToList($a, $l[$i])
476-
477- func $f4_2 ($a,$i) = if (($i >= $s))
478- then $a
479- else throw("List size exceeds 10")
480-
481- $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)
482- }
483767 let assetWeightsStrLi = split(assetWeightsStr, ",")
484768 let assetWeightsSum = {
485769 let $l = assetWeightsStrLi
486770 let $s = size($l)
487771 let $acc0 = 0
488- func $f5_1 ($a,$i) = if (($i >= $s))
772+ func $f6_1 ($a,$i) = if (($i >= $s))
489773 then $a
490774 else sum($a, $l[$i])
491775
492- func $f5_2 ($a,$i) = if (($i >= $s))
776+ func $f6_2 ($a,$i) = if (($i >= $s))
493777 then $a
494778 else throw("List size exceeds 10")
495779
496- $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)
497781 }
498- let feeAssetStr = if ((indexOf(assetIdsStr, usdnAssetIdStr) != unit))
499- then usdnAssetIdStr
500- else if ((indexOf(assetIdsStr, "WAVES") != unit))
501- then "WAVES"
502- else if ((indexOf(assetIdsStr, usdtAssetIdStr) != unit))
503- then usdtAssetIdStr
504- else if ((indexOf(assetIdsStr, puzzleAssetIdStr) != unit))
505- then puzzleAssetIdStr
506- else usdtPptAssetIdStr
507782 func addTokenDataEntries (accum,assetNum) = if ((assetNum >= size(assetIdsLi)))
508783 then accum
509784 else {
522797 let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
523798 let $s = size($l)
524799 let $acc0 = nil
525- func $f6_1 ($a,$i) = if (($i >= $s))
800+ func $f7_1 ($a,$i) = if (($i >= $s))
526801 then $a
527802 else addTokenDataEntries($a, $l[$i])
528803
529- func $f6_2 ($a,$i) = if (($i >= $s))
804+ func $f7_2 ($a,$i) = if (($i >= $s))
530805 then $a
531806 else throw("List size exceeds 10")
532807
533- $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)
534- } ++ [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)])
535810 }
536811 }
537812
622897
623898
624899 @Callable(i)
625-func generateIndex (needChange) = if (isShutdown())
626- then throw("contract is on stop")
627- else if ((size(i.payments) != T))
628- then throw(("you need to attach all pool tokens. amount of pool tokens: " + toString(T)))
629- else if (!(checkTokensValidity(i.payments)))
630- then throw("wrong assets attached")
900+func generateIndex (needChange) = if ((size(i.payments) != T))
901+ then throw(("you need to attach all pool tokens. amount of pool tokens: " + toString(T)))
902+ else if (!(checkTokensValidity(i.payments)))
903+ then throw("wrong assets attached")
904+ else {
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)
910+ }
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")
631921 else {
632- let PIssued = getMinPIssued(i.payments)
633- let reissue = Reissue(getBinaryValue("global_poolToken_id"), PIssued, true)
634- let result = handlePoolTokensAdd(PIssued, i.payments, i.originCaller, needChange)
635- $Tuple2((result ++ [reissue, ScriptTransfer(i.caller, PIssued, tryGetBinary("global_poolToken_id")), IntegerEntry("global_poolToken_amount", (tryGetInteger("global_poolToken_amount") + PIssued))]), PIssued)
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))])
636928 }
929+ }
637930
638931
639932
641934 func stakeIndex () = {
642935 let addressStr = toString(i.originCaller)
643936 let pmt = i.payments[0]
644- if (isShutdown())
645- then throw("contract is on stop")
646- else if ((value(pmt.assetId) != tryGetBinary("global_poolToken_id")))
647- then throw("wrong asset attached")
648- else indexStakeResult(addressStr, pmt.amount)
937+ if ((value(pmt.assetId) != tryGetBinary("global_poolToken_id")))
938+ then throw("wrong asset attached")
939+ else indexStakeResult(addressStr, pmt.amount)
649940 }
650941
651942
652943
653944 @Callable(i)
654-func unstakeIndex (puzzleAmount) = {
655- let addressStr = toString(i.originCaller)
656- 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"))
657960 if (isShutdown())
658961 then throw("contract is on stop")
659- else if ((puzzleAmount > puzzleAvailable))
962+ else if ((indexAmount > indexAvailable))
660963 then throw("you don't have index tokens available")
661964 else if (isShutdown())
662965 then throw("contract is on stop")
663- 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"))])
664967 }
665968
666969
678981
679982
680983 @Callable(i)
681-func redeemIndex (sendToOrigin) = {
682- let pmt = i.payments[0]
683- if ((pmt.assetId != tryGetBinary("global_poolToken_id")))
684- then throw("please attach pool share token")
685- else if (isShutdown())
686- then throw("contract is on stop")
687- else {
688- let PRedeemed = pmt.amount
689- let result = handlePoolTokensRedeem(PRedeemed, if (sendToOrigin)
690- then i.originCaller
691- else i.caller)
692- (result ++ [Burn(tryGetBinary("global_poolToken_id"), PRedeemed), IntegerEntry("global_poolToken_amount", (tryGetInteger("global_poolToken_amount") - PRedeemed))])
693- }
694- }
695-
696-
697-
698-@Callable(i)
699984 func swap (assetOut,minimum) = {
700985 let pmt = if ((size(i.payments) == 1))
701986 then value(i.payments[0])
703988 let AmountIn = value(i.payments[0].amount)
704989 let AssetIn = pmt.assetId
705990 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")))
706994 let feeAssetOutStr = tryGetString("static_feeToken")
707995 let feeAssetOut = if ((feeAssetOutStr == ""))
708996 then usdnAssetId
709997 else getAssetBytes(feeAssetOutStr)
710998 let AssetInBalance = tryGetInteger((("global_" + getAssetString(AssetIn)) + "_balance"))
711999 let AssetOutBalance = tryGetInteger((("global_" + assetOut) + "_balance"))
1000+ let AssetInBalanceScaled = (AssetInBalance * scaleIn)
1001+ let AssetOutBalanceScaled = (AssetOutBalance * scaleOut)
7121002 let feeAmountIn = fraction(AmountIn, Fee, FeeScale)
7131003 let cleanAmountIn = (AmountIn - feeAmountIn)
714- 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)
7151007 let AssetOutBalance2 = (AssetOutBalance - AmountOut)
7161008 let AssetInBalance2 = (AssetInBalance + cleanAmountIn)
7171009 let feeAssetOutBalance = if ((feeAssetOut == AssetIn))
7311023 else {
7321024 let creatorFee = fraction(feeAmountOut, 1, 10)
7331025 let protocolFee = fraction(feeAmountOut, 4, 10)
734- let stakingTopUp = if (if ((feeAssetOut == usdnAssetId))
735- then true
736- else (feeAssetOut == puzzleAssetId))
737- 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)
7381034 else unit
739- if ((stakingTopUp == stakingTopUp))
740- then {
741- let newBalanceIn = AssetInBalance2
742- let newBalanceOut = (AssetOutBalance2 - (if ((AssetOut == feeAssetOut))
743- then feeAmountOut
744- else 0))
745- let newBalanceFeeAsset = if (if ((feeAssetOut != AssetIn))
746- then (feeAssetOut != AssetOut)
747- else false)
748- then (feeAssetOutBalance - feeAmountOut)
749- else unit
750- let assetInChange = IntegerEntry((("global_" + getAssetString(AssetIn)) + "_balance"), newBalanceIn)
751- let assetOutChange = IntegerEntry((("global_" + assetOut) + "_balance"), newBalanceOut)
752- let feeAssetOutChange = if ((newBalanceFeeAsset != unit))
753- then IntegerEntry((("global_" + getAssetString(feeAssetOut)) + "_balance"), value(newBalanceFeeAsset))
754- else StringEntry("hello", "world")
755- let volumeUpdate = calculateUsdnValue(AssetIn, AmountIn, AssetInBalance, feeAssetOutBalance)
756- $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))
757- then [ScriptTransfer(Address(base58'3P4kBiU4wr2yV1S5gMfu3MdkVvy7kxXHsKe'), protocolFee, feeAssetOut)]
758- else nil)), AmountOut)
759- }
760- 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)
7611043 }
7621044 }
7631045
7641046
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)
1082+ }
1083+
1084+
1085+
1086+@Callable(i)
1087+func transferOwnership (newOwnerAddress) = if ((toString(i.caller) != tryGetString("static_poolOwner")))
1088+ then throw("this call available only for pool owner")
1089+ else [StringEntry("static_poolOwner", newOwnerAddress)]
1090+
1091+
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 (valueOrElse(getBoolean(this, "rebalance_inProgress"), false))
1106+ then throw("rebalancing in progress")
1107+ else {
1108+ let newAssetWeightsStrLi = split(assetWeightsStr, ",")
1109+ let newAssetIdsStrLi = split(assetIdsStr, ",")
1110+ let feeAssetStr = {
1111+ let $l = newAssetIdsStrLi
1112+ let $s = size($l)
1113+ let $acc0 = ""
1114+ func $f4_1 ($a,$i) = if (($i >= $s))
1115+ then $a
1116+ else checkFeeAsset($a, $l[$i])
1117+
1118+ func $f4_2 ($a,$i) = if (($i >= $s))
1119+ then $a
1120+ else throw("List size exceeds 10")
1121+
1122+ $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)
1123+ }
1124+ let assetWeightsSum = {
1125+ let $l = newAssetWeightsStrLi
1126+ let $s = size($l)
1127+ let $acc0 = 0
1128+ func $f5_1 ($a,$i) = if (($i >= $s))
1129+ then $a
1130+ else sum($a, $l[$i])
1131+
1132+ func $f5_2 ($a,$i) = if (($i >= $s))
1133+ then $a
1134+ else throw("List size exceeds 10")
1135+
1136+ $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)
1137+ }
1138+ let oldAssetIds = getStringValue("static_tokenIds")
1139+ let oldAssetIdsLi = split(oldAssetIds, ",")
1140+ func findAdded (accum,next) = if ((indexOf(oldAssetIdsLi, next) == unit))
1141+ then (accum ++ [next])
1142+ else accum
1143+
1144+ func findRemoved (accum,next) = if ((indexOf(newAssetIdsStrLi, next) == unit))
1145+ then (accum ++ [next])
1146+ else accum
1147+
1148+ let addedAssets = {
1149+ let $l = newAssetIdsStrLi
1150+ let $s = size($l)
1151+ let $acc0 = nil
1152+ func $f6_1 ($a,$i) = if (($i >= $s))
1153+ then $a
1154+ else findAdded($a, $l[$i])
1155+
1156+ func $f6_2 ($a,$i) = if (($i >= $s))
1157+ then $a
1158+ else throw("List size exceeds 10")
1159+
1160+ $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)
1161+ }
1162+ let removedAssets = {
1163+ let $l = oldAssetIdsLi
1164+ let $s = size($l)
1165+ let $acc0 = nil
1166+ func $f7_1 ($a,$i) = if (($i >= $s))
1167+ then $a
1168+ else findRemoved($a, $l[$i])
1169+
1170+ func $f7_2 ($a,$i) = if (($i >= $s))
1171+ then $a
1172+ else throw("List size exceeds 10")
1173+
1174+ $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)
1175+ }
1176+ let validPayments = validatePayments(addedAssets, i.payments)
1177+ let validWeights = validateWeights(newAssetWeightsStrLi)
1178+ if ((validWeights == validWeights))
1179+ then if ((validPayments != (size(addedAssets) + size(i.payments))))
1180+ then throw("Payments not present or something wrong with them")
1181+ else if ((size(newAssetIdsStrLi) != size(newAssetWeightsStrLi)))
1182+ then throw("assetIds and assetWeights should have same length")
1183+ else if ((validPayments != (size(addedAssets) + size(i.payments))))
1184+ then throw("Payments not present or something wrong with them")
1185+ else if ((feeAssetStr == ""))
1186+ then throw("pool must have one of the supported fee assets in the composition")
1187+ else if ((indexOf(newAssetIdsStrLi, baseTokenIdStr) == unit))
1188+ then throw("baseTokenId should be present in assetIds")
1189+ else if (if ((MIN_STEPS_AMOUNT > stepsAmount))
1190+ then true
1191+ else (stepsAmount > MAX_STEPS_AMOUNT))
1192+ then throw(((((("Steps amount should be between " + toString(MIN_STEPS_AMOUNT)) + " and ") + toString(MAX_STEPS_AMOUNT)) + ", current: ") + toString(stepsAmount)))
1193+ else if (if ((MIN_STEPS_INTERVAL > stepsInterval))
1194+ then true
1195+ else (stepsInterval > MAX_STEPS_INTERVAL))
1196+ then throw(((((("Steps interval should be between " + toString(MIN_STEPS_INTERVAL)) + " and ") + toString(MAX_STEPS_INTERVAL)) + ", current: ") + toString(stepsInterval)))
1197+ else if ((assetWeightsSum != 10000))
1198+ then throw(("sum of token weights must be equal to 10000, current: " + toString(assetWeightsSum)))
1199+ else {
1200+ func f (accum,assetIdStr) = {
1201+ let oldWeight = tryGetInteger((("static_" + assetIdStr) + "_weight"))
1202+ let newWeight = if ((indexOf(newAssetIdsStrLi, assetIdStr) == unit))
1203+ then 0
1204+ else parseIntValue(value(newAssetWeightsStrLi[value(indexOf(newAssetIdsStrLi, assetIdStr))]))
1205+ let deltaPerStep = fraction((newWeight - oldWeight), 10000, stepsAmount)
1206+ (accum ++ [toString(deltaPerStep)])
1207+ }
1208+
1209+ let tmpAssetIdsLi = getTmpRebalanceIds(newAssetIdsStrLi)
1210+ let assetDeltas = {
1211+ let $l = tmpAssetIdsLi
1212+ let $s = size($l)
1213+ let $acc0 = nil
1214+ func $f8_1 ($a,$i) = if (($i >= $s))
1215+ then $a
1216+ else f($a, $l[$i])
1217+
1218+ func $f8_2 ($a,$i) = if (($i >= $s))
1219+ then $a
1220+ else throw("List size exceeds 10")
1221+
1222+ $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)
1223+ }
1224+ let newTokensAdded = (checkTokensChange(newAssetIdsStrLi) > 0)
1225+ func recordAssetPayment (accum,next) = (accum ++ [IntegerEntry(("rebalance_attachedPayment_" + getAssetString(next.assetId)), next.amount)])
1226+
1227+ let paymentEntries = {
1228+ let $l = i.payments
1229+ let $s = size($l)
1230+ let $acc0 = nil
1231+ func $f9_1 ($a,$i) = if (($i >= $s))
1232+ then $a
1233+ else recordAssetPayment($a, $l[$i])
1234+
1235+ func $f9_2 ($a,$i) = if (($i >= $s))
1236+ then $a
1237+ else throw("List size exceeds 10")
1238+
1239+ $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)
1240+ }
1241+ let storeWeights = saveCurrentWeights()
1242+ let requestGovInvoke = invoke(govAddress, "requestRebalancing", [toBase58String(i.transactionId)], nil)
1243+ if ((requestGovInvoke == requestGovInvoke))
1244+ 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)
1245+ else throw("Strict value is not equal to itself.")
1246+ }
1247+ else throw("Strict value is not equal to itself.")
1248+ }
1249+
1250+
1251+
1252+@Callable(i)
1253+func stepRebalancing () = {
1254+ let rebId = valueOrErrorMessage(getString(govAddress, ("pool_lastRebalancing_" + toString(this))), "rebalancing is not registered at gov address")
1255+ if (!(valueOrElse(getBoolean(this, "rebalance_inProgress"), false)))
1256+ then throw("no rebalancing in progress")
1257+ else if ((valueOrElse(getInteger(govAddress, ("rebalancing_status_" + rebId)), 0) != 2))
1258+ then throw("this transaction needs approval from puzzle network")
1259+ else {
1260+ let lastStepHeight = getIntegerValue("rebalance_lastStepHeight")
1261+ let stepInterval = getIntegerValue("rebalance_stepsInterval")
1262+ let stepsDone = getIntegerValue("rebalance_stepsDone")
1263+ let nextStepHeight = (lastStepHeight + stepInterval)
1264+ if ((nextStepHeight > height))
1265+ then throw("can't be done yet")
1266+ else {
1267+ let assetDeltas = split(getStringValue("rebalance_assetDeltas"), ",")
1268+ let newAssetIdsStr = getStringValue("tmp_rebalanceAssetIds")
1269+ let newAssetIds = split(newAssetIdsStr, ",")
1270+ 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))])
1271+
1272+ let newShares = makeString({
1273+ let $l = newAssetIds
1274+ let $s = size($l)
1275+ let $acc0 = nil
1276+ func $f4_1 ($a,$i) = if (($i >= $s))
1277+ then $a
1278+ else f($a, $l[$i])
1279+
1280+ func $f4_2 ($a,$i) = if (($i >= $s))
1281+ then $a
1282+ else throw("List size exceeds 10")
1283+
1284+ $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)
1285+ }, ",")
1286+ let newTokensAdded = getBooleanValue("rebalance_newTokensAdded")
1287+ let inv = if (if (newTokensAdded)
1288+ then (stepsDone == 0)
1289+ else false)
1290+ then invoke(this, "doRebalancingWithNewTokens", [newAssetIdsStr, newShares, getStringValue("rebalance_newBaseTokenId")], nil)
1291+ else invoke(this, "doRebalancing", [newShares], nil)
1292+ if ((inv == inv))
1293+ then {
1294+ let notifyInvoke = invoke(poolsHubAddress, "notifyPoolChange", nil, nil)
1295+ if ((notifyInvoke == notifyInvoke))
1296+ then {
1297+ let isFinished = ((stepsDone + 1) >= getIntegerValue("rebalance_stepsAmount"))
1298+ let actions = [BooleanEntry("rebalance_inProgress", !(isFinished)), IntegerEntry("rebalance_stepsDone", (stepsDone + 1)), IntegerEntry("rebalance_lastStepHeight", height)]
1299+ if ((stepsDone == 0))
1300+ then (actions ++ [StringEntry("static_tokenIds", newAssetIdsStr)])
1301+ else if (isFinished)
1302+ then {
1303+ let removedAssetsLi = split(tryGetString("rebalance_removedAssets"), ",")
1304+ 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))])
1305+
1306+ let rm = {
1307+ let $l = removedAssetsLi
1308+ let $s = size($l)
1309+ let $acc0 = nil
1310+ func $f5_1 ($a,$i) = if (($i >= $s))
1311+ then $a
1312+ else rmData($a, $l[$i])
1313+
1314+ func $f5_2 ($a,$i) = if (($i >= $s))
1315+ then $a
1316+ else throw("List size exceeds 10")
1317+
1318+ $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)
1319+ }
1320+ let addedAssetsLi = split(tryGetString("rebalance_addedAssets"), ",")
1321+ func addRemovePayments (accum,assetId) = (accum ++ [DeleteEntry(("rebalance_attachedPayment_" + assetId))])
1322+
1323+ let rmPayments = {
1324+ let $l = addedAssetsLi
1325+ let $s = size($l)
1326+ let $acc0 = nil
1327+ func $f6_1 ($a,$i) = if (($i >= $s))
1328+ then $a
1329+ else addRemovePayments($a, $l[$i])
1330+
1331+ func $f6_2 ($a,$i) = if (($i >= $s))
1332+ then $a
1333+ else throw("List size exceeds 10")
1334+
1335+ $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)
1336+ }
1337+ let finalAssetsIdsStr = tryGetString("rebalance_assetIds")
1338+ let AssetsWeightsStr = {
1339+ let $l = split(finalAssetsIdsStr, ",")
1340+ let $s = size($l)
1341+ let $acc0 = nil
1342+ func $f7_1 ($a,$i) = if (($i >= $s))
1343+ then $a
1344+ else addAssetWeightToStrList($a, $l[$i])
1345+
1346+ func $f7_2 ($a,$i) = if (($i >= $s))
1347+ then $a
1348+ else throw("List size exceeds 10")
1349+
1350+ $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)
1351+ }
1352+ let notify = invoke(govAddress, "notifyRebalancingDone", [rebId], nil)
1353+ if ((notify == notify))
1354+ then (((actions ++ rm) ++ rmPayments) ++ [StringEntry("static_tokenIds", finalAssetsIdsStr), StringEntry("static_tokenWeights", makeString(AssetsWeightsStr, ",")), IntegerEntry("static_tokensAmount", size(split(finalAssetsIdsStr, ",")))])
1355+ else throw("Strict value is not equal to itself.")
1356+ }
1357+ else {
1358+ let finalAssetsIdsStr = tryGetString("rebalance_assetIds")
1359+ let AssetsWeightsStr = {
1360+ let $l = split(finalAssetsIdsStr, ",")
1361+ let $s = size($l)
1362+ let $acc0 = nil
1363+ func $f5_1 ($a,$i) = if (($i >= $s))
1364+ then $a
1365+ else addAssetWeightToStrList($a, $l[$i])
1366+
1367+ func $f5_2 ($a,$i) = if (($i >= $s))
1368+ then $a
1369+ else throw("List size exceeds 10")
1370+
1371+ $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)
1372+ }
1373+ (actions ++ [StringEntry("static_tokenWeights", makeString(AssetsWeightsStr, ","))])
1374+ }
1375+ }
1376+ else throw("Strict value is not equal to itself.")
1377+ }
1378+ else throw("Strict value is not equal to itself.")
1379+ }
1380+ }
1381+ }
1382+
1383+
1384+
1385+@Callable(i)
1386+func doRebalancing (assetWeightsStr) = {
1387+ let assetWeightsStrLi = split(assetWeightsStr, ",")
1388+ let assetWeightsSum = {
1389+ let $l = assetWeightsStrLi
1390+ let $s = size($l)
1391+ let $acc0 = 0
1392+ func $f4_1 ($a,$i) = if (($i >= $s))
1393+ then $a
1394+ else sum($a, $l[$i])
1395+
1396+ func $f4_2 ($a,$i) = if (($i >= $s))
1397+ then $a
1398+ else throw("List size exceeds 10")
1399+
1400+ $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)
1401+ }
1402+ let assetIdsStrLi = split(tryGetString("static_tokenIds"), ",")
1403+ if ((i.caller != this))
1404+ then throw("this call available only for admin")
1405+ else {
1406+ let oldKMult = getKMult()
1407+ func handler (pars,assetId) = {
1408+ let accum = pars._1
1409+ let assetIdStr = getAssetString(assetId)
1410+ func handler2 (accum,n) = if ((n == assetId))
1411+ then value(indexOf(assetIds, n))
1412+ else accum
1413+
1414+ let Token = {
1415+ let $l = assetIds
1416+ let $s = size($l)
1417+ let $acc0 = 1
1418+ func $f5_1 ($a,$i) = if (($i >= $s))
1419+ then $a
1420+ else handler2($a, $l[$i])
1421+
1422+ func $f5_2 ($a,$i) = if (($i >= $s))
1423+ then $a
1424+ else throw("List size exceeds 10")
1425+
1426+ $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)
1427+ }
1428+ let balance = tryGetInteger((("global_" + assetIdStr) + "_balance"))
1429+ let weight = if ((pars._2 == "new"))
1430+ then parseIntValue(assetWeightsStrLi[Token])
1431+ else tryGetInteger((("static_" + assetIdStr) + "_weight"))
1432+ $Tuple2(fraction(accum, pow(balance, Decimals[Token], weight, AssetsWeightsDecimals, 8, FLOOR), Scale8), pars._2)
1433+ }
1434+
1435+ let newK = ( let $l = assetIds
1436+ let $s = size($l)
1437+ let $acc0 = $Tuple2(PoolTokenScale, "new")
1438+ func $f5_1 ($a,$i) = if (($i >= $s))
1439+ then $a
1440+ else handler($a, $l[$i])
1441+
1442+ func $f5_2 ($a,$i) = if (($i >= $s))
1443+ then $a
1444+ else throw("List size exceeds 10")
1445+
1446+ $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
1447+ let oldK = ( let $l = assetIds
1448+ let $s = size($l)
1449+ let $acc0 = $Tuple2(PoolTokenScale, "old")
1450+ func $f6_1 ($a,$i) = if (($i >= $s))
1451+ then $a
1452+ else handler($a, $l[$i])
1453+
1454+ func $f6_2 ($a,$i) = if (($i >= $s))
1455+ then $a
1456+ else throw("List size exceeds 10")
1457+
1458+ $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
1459+ let newKMult = fraction(oldKMult, newK, oldK)
1460+ func addTokenDataEntries (accum,assetNum) = if ((assetNum >= size(assetWeightsStrLi)))
1461+ then accum
1462+ else (accum ++ [IntegerEntry((("static_" + assetIdsStrLi[assetNum]) + "_weight"), value(parseInt(assetWeightsStrLi[assetNum])))])
1463+
1464+ ({
1465+ let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1466+ let $s = size($l)
1467+ let $acc0 = nil
1468+ func $f7_1 ($a,$i) = if (($i >= $s))
1469+ then $a
1470+ else addTokenDataEntries($a, $l[$i])
1471+
1472+ func $f7_2 ($a,$i) = if (($i >= $s))
1473+ then $a
1474+ else throw("List size exceeds 10")
1475+
1476+ $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)
1477+ } ++ [IntegerEntry("static_KMult", newKMult)])
1478+ }
1479+ }
1480+
1481+
1482+
1483+@Callable(i)
1484+func doRebalancingWithNewTokens (assetIdsStr,assetWeightsStr,baseTokenIdStr) = {
1485+ let newAssetWeightsStrLi = split(assetWeightsStr, ",")
1486+ let prevAssetIdsStrLi = split(tryGetString("static_tokenIds"), ",")
1487+ let newAssetIdsStrLi = split(assetIdsStr, ",")
1488+ let newAssetIds = {
1489+ let $l = newAssetIdsStrLi
1490+ let $s = size($l)
1491+ let $acc0 = nil
1492+ func $f4_1 ($a,$i) = if (($i >= $s))
1493+ then $a
1494+ else addAssetBytesToList($a, $l[$i])
1495+
1496+ func $f4_2 ($a,$i) = if (($i >= $s))
1497+ then $a
1498+ else throw("List size exceeds 10")
1499+
1500+ $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)
1501+ }
1502+ let feeAssetStr = {
1503+ let $l = newAssetIdsStrLi
1504+ let $s = size($l)
1505+ let $acc0 = ""
1506+ func $f5_1 ($a,$i) = if (($i >= $s))
1507+ then $a
1508+ else checkFeeAsset($a, $l[$i])
1509+
1510+ func $f5_2 ($a,$i) = if (($i >= $s))
1511+ then $a
1512+ else throw("List size exceeds 10")
1513+
1514+ $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)
1515+ }
1516+ let addedAssets = split(tryGetString("rebalance_addedAssets"), ",")
1517+ func findAssetPayment (assetId) = valueOrElse(getInteger(("rebalance_attachedPayment_" + getAssetString(assetId))), 0)
1518+
1519+ func addAssetBalanceToLi (li,assetId) = (li ++ [findAssetPayment(assetId)])
1520+
1521+ let attachedBalances = {
1522+ let $l = newAssetIds
1523+ let $s = size($l)
1524+ let $acc0 = nil
1525+ func $f6_1 ($a,$i) = if (($i >= $s))
1526+ then $a
1527+ else addAssetBalanceToLi($a, $l[$i])
1528+
1529+ func $f6_2 ($a,$i) = if (($i >= $s))
1530+ then $a
1531+ else throw("List size exceeds 10")
1532+
1533+ $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)
1534+ }
1535+ if ((i.caller != this))
1536+ then throw(("this call available only for admin, " + toString(i.caller)))
1537+ else {
1538+ let oldKMult = getKMult()
1539+ let oldK = getVirtualPoolTokenAmount()
1540+ func myltiplyAssetsForK (pars,assetId) = {
1541+ func findAssetNum (accum,n) = if ((n == assetId))
1542+ then value(indexOf(newAssetIds, n))
1543+ else accum
1544+
1545+ let currentK = pars
1546+ let assetIdStr = getAssetString(assetId)
1547+ let TokenNum = {
1548+ let $l = newAssetIds
1549+ let $s = size($l)
1550+ let $acc0 = 1
1551+ func $f7_1 ($a,$i) = if (($i >= $s))
1552+ then $a
1553+ else findAssetNum($a, $l[$i])
1554+
1555+ func $f7_2 ($a,$i) = if (($i >= $s))
1556+ then $a
1557+ else throw("List size exceeds 10")
1558+
1559+ $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)
1560+ }
1561+ let weight = parseIntValue(newAssetWeightsStrLi[TokenNum])
1562+ let balanceInState = tryGetInteger((("global_" + assetIdStr) + "_balance"))
1563+ let balanceInPayment = attachedBalances[TokenNum]
1564+ let balance = (balanceInState + balanceInPayment)
1565+ let assetDecimals = if ((assetId == unit))
1566+ then 8
1567+ else value(assetInfo(value(assetId))).decimals
1568+ if ((0 >= balance))
1569+ then throw(("you need to attach all new assets in payment. this asset is missed: " + assetIdStr))
1570+ else fraction(currentK, pow(balance, assetDecimals, weight, AssetsWeightsDecimals, 8, FLOOR), Scale8)
1571+ }
1572+
1573+ let newK = {
1574+ let $l = newAssetIds
1575+ let $s = size($l)
1576+ let $acc0 = PoolTokenScale
1577+ func $f7_1 ($a,$i) = if (($i >= $s))
1578+ then $a
1579+ else myltiplyAssetsForK($a, $l[$i])
1580+
1581+ func $f7_2 ($a,$i) = if (($i >= $s))
1582+ then $a
1583+ else throw("List size exceeds 10")
1584+
1585+ $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)
1586+ }
1587+ let newKMult = fraction(oldKMult, newK, oldK)
1588+ func addTokenDataEntries (accum,assetNum) = {
1589+ let assetIdStr = newAssetIdsStrLi[assetNum]
1590+ let assetId = newAssetIds[assetNum]
1591+ let assetDecimals = if ((assetId == unit))
1592+ then 8
1593+ else value(assetInfo(value(assetId))).decimals
1594+ let newAssetData = if ((indexOf(addedAssets, assetIdStr) != unit))
1595+ then [IntegerEntry((("global_" + assetIdStr) + "_balance"), attachedBalances[assetNum]), IntegerEntry((("static_" + assetIdStr) + "_scale"), pow(10, 0, assetDecimals, 0, 0, DOWN)), IntegerEntry((("static_" + assetIdStr) + "_decimals"), assetDecimals)]
1596+ else nil
1597+ if ((assetNum >= size(newAssetWeightsStrLi)))
1598+ then accum
1599+ else ((accum ++ [IntegerEntry((("static_" + assetIdStr) + "_weight"), value(parseInt(newAssetWeightsStrLi[assetNum])))]) ++ newAssetData)
1600+ }
1601+
1602+ ({
1603+ let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1604+ let $s = size($l)
1605+ let $acc0 = nil
1606+ func $f8_1 ($a,$i) = if (($i >= $s))
1607+ then $a
1608+ else addTokenDataEntries($a, $l[$i])
1609+
1610+ func $f8_2 ($a,$i) = if (($i >= $s))
1611+ then $a
1612+ else throw("List size exceeds 10")
1613+
1614+ $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)
1615+ } ++ [StringEntry("static_tokenIds", assetIdsStr), StringEntry("static_feeToken", feeAssetStr), StringEntry("static_tokenWeights", assetWeightsStr), IntegerEntry("static_tokensAmount", size(newAssetIds)), IntegerEntry("static_KMult", newKMult)])
1616+ }
1617+ }
1618+
1619+
7651620 @Verifier(tx)
766-func verify () = if (isShutdown())
767- then false
768- else if (sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey))
1621+func verify () = if (if ((valueOrElse(getInteger("global_wasPreInited"), 0) == 0))
1622+ then if (sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey))
7691623 then true
7701624 else sigVerify(tx.bodyBytes, tx.proofs[0], masterPubKey)
1625+ else false)
1626+ then true
1627+ else match tx {
1628+ case tx: SetScriptTransaction =>
1629+ let scriptFull = value(tx.script)
1630+ let hash = toBase58String(sha256(scriptFull))
1631+ if (sigVerify(tx.bodyBytes, tx.proofs[0], masterPubKey))
1632+ then (valueOrElse(getInteger(coldMasterAddress, ("approvedScript_" + hash)), 0) > height)
1633+ else false
1634+ case _ =>
1635+ if (sigVerify(tx.bodyBytes, tx.proofs[0], masterPubKey))
1636+ then (valueOrElse(getInteger(coldMasterAddress, ("approvedTx_" + toBase58String(tx.id))), 0) > 0)
1637+ else false
1638+ }
7711639
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.3 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)
314+ let usdtPptInPool = indexOf(assetIds, usdtPptAssetId)
211315 let wavesInPool = indexOf(assetIds, unit)
212316 let assetWeight = tryGetInteger((("static_" + getAssetString(assetId)) + "_weight"))
213317 let feeAssetStr = tryGetString("static_feeToken")
214318 if ((feeAssetStr == puzzleAssetIdStr))
215319 then {
216320 let puzzleWeight = AssetsWeights[value(indexOf(assetIds, puzzleAssetId))]
217321 let puzzleBalance = tryGetInteger((("global_" + puzzleAssetIdStr) + "_balance"))
218322 let amountInPuzzle = fraction(amount, (puzzleBalance / puzzleWeight), (aBalance / assetWeight))
219323 let puzzlePrice = getIntegerValue(parentPoolAddress, "global_lastPuzzlePrice")
220324 fraction((amountInPuzzle * puzzlePrice), 1, Scale8)
221325 }
222326 else if ((feeAssetStr == usdtAssetIdStr))
223327 then {
224328 let usdtWeight = AssetsWeights[value(usdtInPool)]
225329 let usdtBalance = tryGetInteger((("global_" + usdtAssetIdStr) + "_balance"))
226330 fraction(amount, (usdtBalance / usdtWeight), (aBalance / assetWeight))
227331 }
228- else if ((feeAssetStr == usdnAssetIdStr))
332+ else if ((feeAssetStr == usdtPptAssetIdStr))
229333 then {
230- let usdnWeight = AssetsWeights[value(indexOf(assetIds, usdnAssetId))]
231- let usdnBalance = match givenUsdnBalance {
232- case x: Int =>
233- givenUsdnBalance
234- case _ =>
235- tryGetInteger((("global_" + getAssetString(usdnAssetId)) + "_balance"))
334+ let usdtWeight = AssetsWeights[value(usdtPptInPool)]
335+ let usdtBalance = tryGetInteger((("global_" + usdtPptAssetIdStr) + "_balance"))
336+ fraction(amount, (usdtBalance / usdtWeight), (aBalance / assetWeight))
236337 }
237- fraction(amount, (value(usdnBalance) / usdnWeight), (aBalance / assetWeight))
238- }
239- else {
240- let wavesWeight = 3000
241- let wBalance = (tryGetInteger("global_WAVES_balance") / 50)
242- fraction(amount, (wBalance / wavesWeight), (aBalance / assetWeight))
243- }
338+ else if ((feeAssetStr == usdnAssetIdStr))
339+ then {
340+ let usdnWeight = AssetsWeights[value(indexOf(assetIds, usdnAssetId))]
341+ let usdnBalance = match givenUsdnBalance {
342+ case x: Int =>
343+ givenUsdnBalance
344+ case _ =>
345+ tryGetInteger((("global_" + getAssetString(usdnAssetId)) + "_balance"))
346+ }
347+ fraction(amount, (value(usdnBalance) / usdnWeight), (aBalance / assetWeight))
348+ }
349+ else {
350+ let wavesWeight = 3000
351+ let wBalance = (tryGetInteger("global_WAVES_balance") / 50)
352+ fraction(amount, (wBalance / wavesWeight), (aBalance / assetWeight))
353+ }
354+ }
355+
356+
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)
244375 }
245376
246377
247378 func checkTokensValidity (payments) = {
248379 func handler1 (accum,payment) = (accum ++ [payment.assetId])
249380
250381 let ids = {
251382 let $l = payments
252383 let $s = size($l)
253384 let $acc0 = nil
254385 func $f4_1 ($a,$i) = if (($i >= $s))
255386 then $a
256387 else handler1($a, $l[$i])
257388
258389 func $f4_2 ($a,$i) = if (($i >= $s))
259390 then $a
260391 else throw("List size exceeds 10")
261392
262393 $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)
263394 }
264395 if ((ids == ids))
265396 then {
266397 func handler2 (accum,assetId) = if ((indexOf(ids, assetId) != unit))
267398 then (accum + 1)
268399 else throw(("asset not attached: " + getAssetString(assetId)))
269400
270401 let checks = {
271402 let $l = assetIds
272403 let $s = size($l)
273404 let $acc0 = 0
274405 func $f5_1 ($a,$i) = if (($i >= $s))
275406 then $a
276407 else handler2($a, $l[$i])
277408
278409 func $f5_2 ($a,$i) = if (($i >= $s))
279410 then $a
280411 else throw("List size exceeds 10")
281412
282413 $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)
283414 }
284415 if ((checks == checks))
285416 then true
286417 else throw("Strict value is not equal to itself.")
287418 }
288419 else throw("Strict value is not equal to itself.")
289420 }
290421
291422
292423 func handlePoolTokensAdd (PIssued,payments,userAddress,needChange) = {
293424 func getTokenPaymentAmount (tokenId) = {
294425 func handler (accum,payment) = if ((payment.assetId == tokenId))
295426 then payment.amount
296427 else accum
297428
298429 let $l = payments
299430 let $s = size($l)
300431 let $acc0 = 0
301432 func $f4_1 ($a,$i) = if (($i >= $s))
302433 then $a
303434 else handler($a, $l[$i])
304435
305436 func $f4_2 ($a,$i) = if (($i >= $s))
306437 then $a
307438 else throw("List size exceeds 10")
308439
309440 $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)
310441 }
311442
312443 func handleTokenChange (accum,tokenId) = {
313444 let Bk = tryGetInteger((("global_" + getAssetString(tokenId)) + "_balance"))
314- let PSupply = tryGetInteger("global_poolToken_amount")
445+ let PSupply = getVirtualPoolTokenAmount()
315446 let tokenDecimals = tryGetInteger((("static_" + getAssetString(tokenId)) + "_scale"))
316- 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))
317449 let paymentAmount = getTokenPaymentAmount(tokenId)
318- let toReturn = ((if ((paymentAmount != 0))
319- then paymentAmount
320- else 0) - Dk)
450+ let toReturn = (paymentAmount - Dk)
321451 let t = if (if (needChange)
322452 then (toReturn > 0)
323453 else false)
324454 then [ScriptTransfer(userAddress, toReturn, tokenId)]
325455 else nil
326456 ((accum ++ t) ++ [IntegerEntry((("global_" + getAssetString(tokenId)) + "_balance"), (Bk + Dk))])
327457 }
328458
329459 let $l = assetIds
330460 let $s = size($l)
331461 let $acc0 = nil
332462 func $f4_1 ($a,$i) = if (($i >= $s))
333463 then $a
334464 else handleTokenChange($a, $l[$i])
335465
336466 func $f4_2 ($a,$i) = if (($i >= $s))
337467 then $a
338468 else throw("List size exceeds 10")
339469
340470 $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)
341471 }
342472
343473
344474 func handlePoolTokensRedeem (PRedeemed,userAddress) = {
345475 func handleTokenRedeem (accum,tokenId) = {
346476 let Bk = tryGetInteger((("global_" + getAssetString(tokenId)) + "_balance"))
347- let PSupply = tryGetInteger("global_poolToken_amount")
477+ let PSupply = getVirtualPoolTokenAmount()
348478 let tokenDecimals = tryGetInteger((("static_" + getAssetString(tokenId)) + "_scale"))
349- 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))
350481 (accum ++ [IntegerEntry((("global_" + getAssetString(tokenId)) + "_balance"), (Bk - amount)), ScriptTransfer(userAddress, amount, tokenId)])
351482 }
352483
353484 let $l = assetIds
354485 let $s = size($l)
355486 let $acc0 = nil
356487 func $f4_1 ($a,$i) = if (($i >= $s))
357488 then $a
358489 else handleTokenRedeem($a, $l[$i])
359490
360491 func $f4_2 ($a,$i) = if (($i >= $s))
361492 then $a
362493 else throw("List size exceeds 10")
363494
364495 $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)
365496 }
366497
367498
368499 func calculateOutAmount (AmountIn,assetIn,assetOut,BalanceIn,BalanceOut) = {
369500 let IndexIn = value(indexOf(assetIds, assetIn))
370501 let IndexOut = value(indexOf(assetIds, assetOut))
371502 if ((IndexIn == IndexOut))
372503 then AmountIn
373- 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)
374505 }
375-
376-
377-func getTokenBalance (assetId) = match assetId {
378- case t: ByteVector =>
379- assetBalance(this, t)
380- case _ =>
381- wavesBalance(this).available
382-}
383506
384507
385508 func calculateCurrentAssetInterest (assetId,assetIdStr,aBalance,tokenEarningsLastCheck) = {
386509 let totalStaked = tryGetInteger("global_indexStaked")
387510 let tokenBalanceLastCheck = tokenEarningsLastCheck
388511 let currentBalanceDelta = (getTokenBalance(assetId) - aBalance)
389512 let currentTokenEarnings = if ((currentBalanceDelta > tokenBalanceLastCheck))
390513 then currentBalanceDelta
391514 else tokenBalanceLastCheck
392515 let newEarnings = (currentTokenEarnings - tokenBalanceLastCheck)
393516 let newInterest = if ((totalStaked == 0))
394517 then 0
395518 else fraction(newEarnings, Scale8, totalStaked)
396519 let lastCheckInterest = tryGetInteger((("global_lastCheck_" + assetIdStr) + "_interest"))
397520 (lastCheckInterest + newInterest)
398521 }
399522
400523
401524 func claimResult (address) = {
402525 let addressStr = toString(address)
403526 let puzzleAmount = tryGetInteger((addressStr + "_indexStaked"))
404527 func handler (accum,assetId) = {
405528 let assetIdStr = getAssetString(assetId)
406529 let aBalance = tryGetInteger((("global_" + getAssetString(assetId)) + "_balance"))
407530 let tokenEarningsLastCheck = tryGetInteger((("global_lastCheck_" + assetIdStr) + "_earnings"))
408531 let currentTokenInterest = calculateCurrentAssetInterest(assetId, assetIdStr, aBalance, tokenEarningsLastCheck)
409532 let currentTokenEarnings = max([tokenEarningsLastCheck, (getTokenBalance(assetId) - aBalance)])
410533 let rewardAmount = fraction(puzzleAmount, (currentTokenInterest - tryGetInteger((((addressStr + "_lastCheck_") + assetIdStr) + "_interest"))), Scale8)
411534 let transfer = if ((rewardAmount == 0))
412535 then nil
413536 else [ScriptTransfer(address, rewardAmount, assetId)]
414- $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)))
415538 }
416539
417540 let accum = {
418541 let $l = earnedAssets
419542 let $s = size($l)
420543 let $acc0 = $Tuple2(nil, 0)
421544 func $f4_1 ($a,$i) = if (($i >= $s))
422545 then $a
423546 else handler($a, $l[$i])
424547
425548 func $f4_2 ($a,$i) = if (($i >= $s))
426549 then $a
427550 else throw("List size exceeds 10")
428551
429552 $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)
430553 }
431- $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)
432555 }
433556
434557
435558 func indexStakeResult (addressStr,amount) = {
436559 let li = claimResult(addressFromStringValue(addressStr))._1
437560 (li ++ [IntegerEntry((addressStr + "_indexStaked"), (tryGetInteger((addressStr + "_indexStaked")) + amount)), IntegerEntry("global_indexStaked", (tryGetInteger("global_indexStaked") + amount))])
438561 }
439562
440563
441564 func sum (accum,n) = (accum + parseIntValue(n))
442565
443566
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+
444722 @Callable(i)
445723 func preInit (assetIdsStr,assetWeightsStr,baseTokenIdStr,poolDomain,poolOwner,fee) = {
446724 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+ }
447754 if (isShutdown())
448755 then throw("contract is on stop")
449756 else if ((this != i.caller))
450757 then throw("admin only")
451- else if ((size(poolDomain) > 13))
452- then throw("too large pool domain")
453- else if (if ((fee > 500))
454- then true
455- else (50 > fee))
456- then throw("fee value must be between 50 and 500 (0.5-5%)")
457- else if (if (if (if (if ((indexOf(assetIdsStr, puzzleAssetIdStr) == unit))
458- then (indexOf(assetIdsStr, usdnAssetIdStr) == unit)
459- else false)
460- then (indexOf(assetIdsStr, usdtAssetIdStr) == unit)
461- else false)
462- then (indexOf(assetIdsStr, "WAVES") == unit)
463- else false)
464- then (indexOf(assetIdsStr, usdtPptAssetIdStr) == unit)
465- else false)
466- 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%)")
467766 else {
468- let assetIdsStrLi = split(assetIdsStr, ",")
469- let assetIdsLi = {
470- let $l = assetIdsStrLi
471- let $s = size($l)
472- let $acc0 = nil
473- func $f4_1 ($a,$i) = if (($i >= $s))
474- then $a
475- else addAssetBytesToList($a, $l[$i])
476-
477- func $f4_2 ($a,$i) = if (($i >= $s))
478- then $a
479- else throw("List size exceeds 10")
480-
481- $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)
482- }
483767 let assetWeightsStrLi = split(assetWeightsStr, ",")
484768 let assetWeightsSum = {
485769 let $l = assetWeightsStrLi
486770 let $s = size($l)
487771 let $acc0 = 0
488- func $f5_1 ($a,$i) = if (($i >= $s))
772+ func $f6_1 ($a,$i) = if (($i >= $s))
489773 then $a
490774 else sum($a, $l[$i])
491775
492- func $f5_2 ($a,$i) = if (($i >= $s))
776+ func $f6_2 ($a,$i) = if (($i >= $s))
493777 then $a
494778 else throw("List size exceeds 10")
495779
496- $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)
497781 }
498- let feeAssetStr = if ((indexOf(assetIdsStr, usdnAssetIdStr) != unit))
499- then usdnAssetIdStr
500- else if ((indexOf(assetIdsStr, "WAVES") != unit))
501- then "WAVES"
502- else if ((indexOf(assetIdsStr, usdtAssetIdStr) != unit))
503- then usdtAssetIdStr
504- else if ((indexOf(assetIdsStr, puzzleAssetIdStr) != unit))
505- then puzzleAssetIdStr
506- else usdtPptAssetIdStr
507782 func addTokenDataEntries (accum,assetNum) = if ((assetNum >= size(assetIdsLi)))
508783 then accum
509784 else {
510785 let assetDecimals = match assetIdsLi[assetNum] {
511786 case x: ByteVector =>
512787 value(assetInfo(x)).decimals
513788 case _ =>
514789 8
515790 }
516791 (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])))])
517792 }
518793
519794 if ((assetWeightsSum != 10000))
520795 then throw("sum of token weights must be equal to 10000")
521796 else ({
522797 let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
523798 let $s = size($l)
524799 let $acc0 = nil
525- func $f6_1 ($a,$i) = if (($i >= $s))
800+ func $f7_1 ($a,$i) = if (($i >= $s))
526801 then $a
527802 else addTokenDataEntries($a, $l[$i])
528803
529- func $f6_2 ($a,$i) = if (($i >= $s))
804+ func $f7_2 ($a,$i) = if (($i >= $s))
530805 then $a
531806 else throw("List size exceeds 10")
532807
533- $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)
534- } ++ [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)])
535810 }
536811 }
537812
538813
539814
540815 @Callable(i)
541816 func deInit () = if (isShutdown())
542817 then throw("contract is on stop")
543818 else if ((i.caller != this))
544819 then throw("admin only")
545820 else [IntegerEntry("global_wasInited", 0)]
546821
547822
548823
549824 @Callable(i)
550825 func init () = {
551826 func prepareList () = {
552827 func handler (accum,n) = (accum ++ [IntegerEntry((("global_" + getAssetString(n.assetId)) + "_balance"), n.amount)])
553828
554829 let $l = i.payments
555830 let $s = size($l)
556831 let $acc0 = nil
557832 func $f4_1 ($a,$i) = if (($i >= $s))
558833 then $a
559834 else handler($a, $l[$i])
560835
561836 func $f4_2 ($a,$i) = if (($i >= $s))
562837 then $a
563838 else throw("List size exceeds 10")
564839
565840 $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)
566841 }
567842
568843 func calculatePoolTokensAmount (payments) = {
569844 func handler (accum,pmt) = {
570845 let assetId = pmt.assetId
571846 func handler2 (accum,n) = if ((n == assetId))
572847 then value(indexOf(assetIds, n))
573848 else accum
574849
575850 let Token = {
576851 let $l = assetIds
577852 let $s = size($l)
578853 let $acc0 = 1
579854 func $f4_1 ($a,$i) = if (($i >= $s))
580855 then $a
581856 else handler2($a, $l[$i])
582857
583858 func $f4_2 ($a,$i) = if (($i >= $s))
584859 then $a
585860 else throw("List size exceeds 10")
586861
587862 $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)
588863 }
589864 fraction(accum, pow(pmt.amount, Decimals[Token], AssetsWeights[Token], AssetsWeightsDecimals, 8, FLOOR), Scale8)
590865 }
591866
592867 let $l = payments
593868 let $s = size($l)
594869 let $acc0 = PoolTokenScale
595870 func $f4_1 ($a,$i) = if (($i >= $s))
596871 then $a
597872 else handler($a, $l[$i])
598873
599874 func $f4_2 ($a,$i) = if (($i >= $s))
600875 then $a
601876 else throw("List size exceeds 10")
602877
603878 $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)
604879 }
605880
606881 if (isShutdown())
607882 then throw("contract is on stop")
608883 else if ((tryGetInteger("global_wasInited") > 0))
609884 then throw("pool already inited")
610885 else {
611886 let initialPoolTokens = calculatePoolTokensAmount(i.payments)
612887 if ((initialPoolTokens == 0))
613888 then throw("you need a bigger tokens amount to launch the pool")
614889 else {
615890 let poolTokenIssue = Issue(("PZ " + tryGetString("static_poolDomain")), "Puzzle Swap: pool index token", initialPoolTokens, PoolTokenDecimals, true, unit, 0)
616891 let poolTokenId = calculateAssetId(poolTokenIssue)
617892 (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)])
618893 }
619894 }
620895 }
621896
622897
623898
624899 @Callable(i)
625-func generateIndex (needChange) = if (isShutdown())
626- then throw("contract is on stop")
627- else if ((size(i.payments) != T))
628- then throw(("you need to attach all pool tokens. amount of pool tokens: " + toString(T)))
629- else if (!(checkTokensValidity(i.payments)))
630- then throw("wrong assets attached")
900+func generateIndex (needChange) = if ((size(i.payments) != T))
901+ then throw(("you need to attach all pool tokens. amount of pool tokens: " + toString(T)))
902+ else if (!(checkTokensValidity(i.payments)))
903+ then throw("wrong assets attached")
904+ else {
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)
910+ }
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")
631921 else {
632- let PIssued = getMinPIssued(i.payments)
633- let reissue = Reissue(getBinaryValue("global_poolToken_id"), PIssued, true)
634- let result = handlePoolTokensAdd(PIssued, i.payments, i.originCaller, needChange)
635- $Tuple2((result ++ [reissue, ScriptTransfer(i.caller, PIssued, tryGetBinary("global_poolToken_id")), IntegerEntry("global_poolToken_amount", (tryGetInteger("global_poolToken_amount") + PIssued))]), PIssued)
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))])
636928 }
929+ }
637930
638931
639932
640933 @Callable(i)
641934 func stakeIndex () = {
642935 let addressStr = toString(i.originCaller)
643936 let pmt = i.payments[0]
644- if (isShutdown())
645- then throw("contract is on stop")
646- else if ((value(pmt.assetId) != tryGetBinary("global_poolToken_id")))
647- then throw("wrong asset attached")
648- else indexStakeResult(addressStr, pmt.amount)
937+ if ((value(pmt.assetId) != tryGetBinary("global_poolToken_id")))
938+ then throw("wrong asset attached")
939+ else indexStakeResult(addressStr, pmt.amount)
649940 }
650941
651942
652943
653944 @Callable(i)
654-func unstakeIndex (puzzleAmount) = {
655- let addressStr = toString(i.originCaller)
656- 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"))
657960 if (isShutdown())
658961 then throw("contract is on stop")
659- else if ((puzzleAmount > puzzleAvailable))
962+ else if ((indexAmount > indexAvailable))
660963 then throw("you don't have index tokens available")
661964 else if (isShutdown())
662965 then throw("contract is on stop")
663- 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"))])
664967 }
665968
666969
667970
668971 @Callable(i)
669972 func claimIndexRewards () = if (isShutdown())
670973 then throw("contract is on stop")
671974 else claimResult(i.caller)
672975
673976
674977
675978 @Callable(i)
676979 func evaluateClaim (user) = $Tuple2(nil, claimResult(addressFromStringValue(user))._2)
677980
678981
679982
680983 @Callable(i)
681-func redeemIndex (sendToOrigin) = {
682- let pmt = i.payments[0]
683- if ((pmt.assetId != tryGetBinary("global_poolToken_id")))
684- then throw("please attach pool share token")
685- else if (isShutdown())
686- then throw("contract is on stop")
687- else {
688- let PRedeemed = pmt.amount
689- let result = handlePoolTokensRedeem(PRedeemed, if (sendToOrigin)
690- then i.originCaller
691- else i.caller)
692- (result ++ [Burn(tryGetBinary("global_poolToken_id"), PRedeemed), IntegerEntry("global_poolToken_amount", (tryGetInteger("global_poolToken_amount") - PRedeemed))])
693- }
694- }
695-
696-
697-
698-@Callable(i)
699984 func swap (assetOut,minimum) = {
700985 let pmt = if ((size(i.payments) == 1))
701986 then value(i.payments[0])
702987 else throw("please attach exactly one payment")
703988 let AmountIn = value(i.payments[0].amount)
704989 let AssetIn = pmt.assetId
705990 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")))
706994 let feeAssetOutStr = tryGetString("static_feeToken")
707995 let feeAssetOut = if ((feeAssetOutStr == ""))
708996 then usdnAssetId
709997 else getAssetBytes(feeAssetOutStr)
710998 let AssetInBalance = tryGetInteger((("global_" + getAssetString(AssetIn)) + "_balance"))
711999 let AssetOutBalance = tryGetInteger((("global_" + assetOut) + "_balance"))
1000+ let AssetInBalanceScaled = (AssetInBalance * scaleIn)
1001+ let AssetOutBalanceScaled = (AssetOutBalance * scaleOut)
7121002 let feeAmountIn = fraction(AmountIn, Fee, FeeScale)
7131003 let cleanAmountIn = (AmountIn - feeAmountIn)
714- 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)
7151007 let AssetOutBalance2 = (AssetOutBalance - AmountOut)
7161008 let AssetInBalance2 = (AssetInBalance + cleanAmountIn)
7171009 let feeAssetOutBalance = if ((feeAssetOut == AssetIn))
7181010 then AssetInBalance2
7191011 else if ((feeAssetOut == AssetOut))
7201012 then AssetOutBalance2
7211013 else tryGetInteger((("global_" + getAssetString(feeAssetOut)) + "_balance"))
7221014 let feeAmountOut = calculateOutAmount(feeAmountIn, AssetIn, feeAssetOut, AssetInBalance, feeAssetOutBalance)
7231015 if ((minimum > AmountOut))
7241016 then throw("amount to recieve is lower than given one")
7251017 else if ((AssetOut == AssetIn))
7261018 then throw("this swap is not allowed")
7271019 else if ((0 > (AssetOutBalance - AmountOut)))
7281020 then throw("contract is out of reserves")
7291021 else if (isShutdown())
7301022 then throw("contract is on stop")
7311023 else {
7321024 let creatorFee = fraction(feeAmountOut, 1, 10)
7331025 let protocolFee = fraction(feeAmountOut, 4, 10)
734- let stakingTopUp = if (if ((feeAssetOut == usdnAssetId))
735- then true
736- else (feeAssetOut == puzzleAssetId))
737- 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)
7381034 else unit
739- if ((stakingTopUp == stakingTopUp))
740- then {
741- let newBalanceIn = AssetInBalance2
742- let newBalanceOut = (AssetOutBalance2 - (if ((AssetOut == feeAssetOut))
743- then feeAmountOut
744- else 0))
745- let newBalanceFeeAsset = if (if ((feeAssetOut != AssetIn))
746- then (feeAssetOut != AssetOut)
747- else false)
748- then (feeAssetOutBalance - feeAmountOut)
749- else unit
750- let assetInChange = IntegerEntry((("global_" + getAssetString(AssetIn)) + "_balance"), newBalanceIn)
751- let assetOutChange = IntegerEntry((("global_" + assetOut) + "_balance"), newBalanceOut)
752- let feeAssetOutChange = if ((newBalanceFeeAsset != unit))
753- then IntegerEntry((("global_" + getAssetString(feeAssetOut)) + "_balance"), value(newBalanceFeeAsset))
754- else StringEntry("hello", "world")
755- let volumeUpdate = calculateUsdnValue(AssetIn, AmountIn, AssetInBalance, feeAssetOutBalance)
756- $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))
757- then [ScriptTransfer(Address(base58'3P4kBiU4wr2yV1S5gMfu3MdkVvy7kxXHsKe'), protocolFee, feeAssetOut)]
758- else nil)), AmountOut)
759- }
760- 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)
7611043 }
7621044 }
7631045
7641046
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)
1082+ }
1083+
1084+
1085+
1086+@Callable(i)
1087+func transferOwnership (newOwnerAddress) = if ((toString(i.caller) != tryGetString("static_poolOwner")))
1088+ then throw("this call available only for pool owner")
1089+ else [StringEntry("static_poolOwner", newOwnerAddress)]
1090+
1091+
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 (valueOrElse(getBoolean(this, "rebalance_inProgress"), false))
1106+ then throw("rebalancing in progress")
1107+ else {
1108+ let newAssetWeightsStrLi = split(assetWeightsStr, ",")
1109+ let newAssetIdsStrLi = split(assetIdsStr, ",")
1110+ let feeAssetStr = {
1111+ let $l = newAssetIdsStrLi
1112+ let $s = size($l)
1113+ let $acc0 = ""
1114+ func $f4_1 ($a,$i) = if (($i >= $s))
1115+ then $a
1116+ else checkFeeAsset($a, $l[$i])
1117+
1118+ func $f4_2 ($a,$i) = if (($i >= $s))
1119+ then $a
1120+ else throw("List size exceeds 10")
1121+
1122+ $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)
1123+ }
1124+ let assetWeightsSum = {
1125+ let $l = newAssetWeightsStrLi
1126+ let $s = size($l)
1127+ let $acc0 = 0
1128+ func $f5_1 ($a,$i) = if (($i >= $s))
1129+ then $a
1130+ else sum($a, $l[$i])
1131+
1132+ func $f5_2 ($a,$i) = if (($i >= $s))
1133+ then $a
1134+ else throw("List size exceeds 10")
1135+
1136+ $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)
1137+ }
1138+ let oldAssetIds = getStringValue("static_tokenIds")
1139+ let oldAssetIdsLi = split(oldAssetIds, ",")
1140+ func findAdded (accum,next) = if ((indexOf(oldAssetIdsLi, next) == unit))
1141+ then (accum ++ [next])
1142+ else accum
1143+
1144+ func findRemoved (accum,next) = if ((indexOf(newAssetIdsStrLi, next) == unit))
1145+ then (accum ++ [next])
1146+ else accum
1147+
1148+ let addedAssets = {
1149+ let $l = newAssetIdsStrLi
1150+ let $s = size($l)
1151+ let $acc0 = nil
1152+ func $f6_1 ($a,$i) = if (($i >= $s))
1153+ then $a
1154+ else findAdded($a, $l[$i])
1155+
1156+ func $f6_2 ($a,$i) = if (($i >= $s))
1157+ then $a
1158+ else throw("List size exceeds 10")
1159+
1160+ $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)
1161+ }
1162+ let removedAssets = {
1163+ let $l = oldAssetIdsLi
1164+ let $s = size($l)
1165+ let $acc0 = nil
1166+ func $f7_1 ($a,$i) = if (($i >= $s))
1167+ then $a
1168+ else findRemoved($a, $l[$i])
1169+
1170+ func $f7_2 ($a,$i) = if (($i >= $s))
1171+ then $a
1172+ else throw("List size exceeds 10")
1173+
1174+ $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)
1175+ }
1176+ let validPayments = validatePayments(addedAssets, i.payments)
1177+ let validWeights = validateWeights(newAssetWeightsStrLi)
1178+ if ((validWeights == validWeights))
1179+ then if ((validPayments != (size(addedAssets) + size(i.payments))))
1180+ then throw("Payments not present or something wrong with them")
1181+ else if ((size(newAssetIdsStrLi) != size(newAssetWeightsStrLi)))
1182+ then throw("assetIds and assetWeights should have same length")
1183+ else if ((validPayments != (size(addedAssets) + size(i.payments))))
1184+ then throw("Payments not present or something wrong with them")
1185+ else if ((feeAssetStr == ""))
1186+ then throw("pool must have one of the supported fee assets in the composition")
1187+ else if ((indexOf(newAssetIdsStrLi, baseTokenIdStr) == unit))
1188+ then throw("baseTokenId should be present in assetIds")
1189+ else if (if ((MIN_STEPS_AMOUNT > stepsAmount))
1190+ then true
1191+ else (stepsAmount > MAX_STEPS_AMOUNT))
1192+ then throw(((((("Steps amount should be between " + toString(MIN_STEPS_AMOUNT)) + " and ") + toString(MAX_STEPS_AMOUNT)) + ", current: ") + toString(stepsAmount)))
1193+ else if (if ((MIN_STEPS_INTERVAL > stepsInterval))
1194+ then true
1195+ else (stepsInterval > MAX_STEPS_INTERVAL))
1196+ then throw(((((("Steps interval should be between " + toString(MIN_STEPS_INTERVAL)) + " and ") + toString(MAX_STEPS_INTERVAL)) + ", current: ") + toString(stepsInterval)))
1197+ else if ((assetWeightsSum != 10000))
1198+ then throw(("sum of token weights must be equal to 10000, current: " + toString(assetWeightsSum)))
1199+ else {
1200+ func f (accum,assetIdStr) = {
1201+ let oldWeight = tryGetInteger((("static_" + assetIdStr) + "_weight"))
1202+ let newWeight = if ((indexOf(newAssetIdsStrLi, assetIdStr) == unit))
1203+ then 0
1204+ else parseIntValue(value(newAssetWeightsStrLi[value(indexOf(newAssetIdsStrLi, assetIdStr))]))
1205+ let deltaPerStep = fraction((newWeight - oldWeight), 10000, stepsAmount)
1206+ (accum ++ [toString(deltaPerStep)])
1207+ }
1208+
1209+ let tmpAssetIdsLi = getTmpRebalanceIds(newAssetIdsStrLi)
1210+ let assetDeltas = {
1211+ let $l = tmpAssetIdsLi
1212+ let $s = size($l)
1213+ let $acc0 = nil
1214+ func $f8_1 ($a,$i) = if (($i >= $s))
1215+ then $a
1216+ else f($a, $l[$i])
1217+
1218+ func $f8_2 ($a,$i) = if (($i >= $s))
1219+ then $a
1220+ else throw("List size exceeds 10")
1221+
1222+ $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)
1223+ }
1224+ let newTokensAdded = (checkTokensChange(newAssetIdsStrLi) > 0)
1225+ func recordAssetPayment (accum,next) = (accum ++ [IntegerEntry(("rebalance_attachedPayment_" + getAssetString(next.assetId)), next.amount)])
1226+
1227+ let paymentEntries = {
1228+ let $l = i.payments
1229+ let $s = size($l)
1230+ let $acc0 = nil
1231+ func $f9_1 ($a,$i) = if (($i >= $s))
1232+ then $a
1233+ else recordAssetPayment($a, $l[$i])
1234+
1235+ func $f9_2 ($a,$i) = if (($i >= $s))
1236+ then $a
1237+ else throw("List size exceeds 10")
1238+
1239+ $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)
1240+ }
1241+ let storeWeights = saveCurrentWeights()
1242+ let requestGovInvoke = invoke(govAddress, "requestRebalancing", [toBase58String(i.transactionId)], nil)
1243+ if ((requestGovInvoke == requestGovInvoke))
1244+ 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)
1245+ else throw("Strict value is not equal to itself.")
1246+ }
1247+ else throw("Strict value is not equal to itself.")
1248+ }
1249+
1250+
1251+
1252+@Callable(i)
1253+func stepRebalancing () = {
1254+ let rebId = valueOrErrorMessage(getString(govAddress, ("pool_lastRebalancing_" + toString(this))), "rebalancing is not registered at gov address")
1255+ if (!(valueOrElse(getBoolean(this, "rebalance_inProgress"), false)))
1256+ then throw("no rebalancing in progress")
1257+ else if ((valueOrElse(getInteger(govAddress, ("rebalancing_status_" + rebId)), 0) != 2))
1258+ then throw("this transaction needs approval from puzzle network")
1259+ else {
1260+ let lastStepHeight = getIntegerValue("rebalance_lastStepHeight")
1261+ let stepInterval = getIntegerValue("rebalance_stepsInterval")
1262+ let stepsDone = getIntegerValue("rebalance_stepsDone")
1263+ let nextStepHeight = (lastStepHeight + stepInterval)
1264+ if ((nextStepHeight > height))
1265+ then throw("can't be done yet")
1266+ else {
1267+ let assetDeltas = split(getStringValue("rebalance_assetDeltas"), ",")
1268+ let newAssetIdsStr = getStringValue("tmp_rebalanceAssetIds")
1269+ let newAssetIds = split(newAssetIdsStr, ",")
1270+ 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))])
1271+
1272+ let newShares = makeString({
1273+ let $l = newAssetIds
1274+ let $s = size($l)
1275+ let $acc0 = nil
1276+ func $f4_1 ($a,$i) = if (($i >= $s))
1277+ then $a
1278+ else f($a, $l[$i])
1279+
1280+ func $f4_2 ($a,$i) = if (($i >= $s))
1281+ then $a
1282+ else throw("List size exceeds 10")
1283+
1284+ $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)
1285+ }, ",")
1286+ let newTokensAdded = getBooleanValue("rebalance_newTokensAdded")
1287+ let inv = if (if (newTokensAdded)
1288+ then (stepsDone == 0)
1289+ else false)
1290+ then invoke(this, "doRebalancingWithNewTokens", [newAssetIdsStr, newShares, getStringValue("rebalance_newBaseTokenId")], nil)
1291+ else invoke(this, "doRebalancing", [newShares], nil)
1292+ if ((inv == inv))
1293+ then {
1294+ let notifyInvoke = invoke(poolsHubAddress, "notifyPoolChange", nil, nil)
1295+ if ((notifyInvoke == notifyInvoke))
1296+ then {
1297+ let isFinished = ((stepsDone + 1) >= getIntegerValue("rebalance_stepsAmount"))
1298+ let actions = [BooleanEntry("rebalance_inProgress", !(isFinished)), IntegerEntry("rebalance_stepsDone", (stepsDone + 1)), IntegerEntry("rebalance_lastStepHeight", height)]
1299+ if ((stepsDone == 0))
1300+ then (actions ++ [StringEntry("static_tokenIds", newAssetIdsStr)])
1301+ else if (isFinished)
1302+ then {
1303+ let removedAssetsLi = split(tryGetString("rebalance_removedAssets"), ",")
1304+ 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))])
1305+
1306+ let rm = {
1307+ let $l = removedAssetsLi
1308+ let $s = size($l)
1309+ let $acc0 = nil
1310+ func $f5_1 ($a,$i) = if (($i >= $s))
1311+ then $a
1312+ else rmData($a, $l[$i])
1313+
1314+ func $f5_2 ($a,$i) = if (($i >= $s))
1315+ then $a
1316+ else throw("List size exceeds 10")
1317+
1318+ $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)
1319+ }
1320+ let addedAssetsLi = split(tryGetString("rebalance_addedAssets"), ",")
1321+ func addRemovePayments (accum,assetId) = (accum ++ [DeleteEntry(("rebalance_attachedPayment_" + assetId))])
1322+
1323+ let rmPayments = {
1324+ let $l = addedAssetsLi
1325+ let $s = size($l)
1326+ let $acc0 = nil
1327+ func $f6_1 ($a,$i) = if (($i >= $s))
1328+ then $a
1329+ else addRemovePayments($a, $l[$i])
1330+
1331+ func $f6_2 ($a,$i) = if (($i >= $s))
1332+ then $a
1333+ else throw("List size exceeds 10")
1334+
1335+ $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)
1336+ }
1337+ let finalAssetsIdsStr = tryGetString("rebalance_assetIds")
1338+ let AssetsWeightsStr = {
1339+ let $l = split(finalAssetsIdsStr, ",")
1340+ let $s = size($l)
1341+ let $acc0 = nil
1342+ func $f7_1 ($a,$i) = if (($i >= $s))
1343+ then $a
1344+ else addAssetWeightToStrList($a, $l[$i])
1345+
1346+ func $f7_2 ($a,$i) = if (($i >= $s))
1347+ then $a
1348+ else throw("List size exceeds 10")
1349+
1350+ $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)
1351+ }
1352+ let notify = invoke(govAddress, "notifyRebalancingDone", [rebId], nil)
1353+ if ((notify == notify))
1354+ then (((actions ++ rm) ++ rmPayments) ++ [StringEntry("static_tokenIds", finalAssetsIdsStr), StringEntry("static_tokenWeights", makeString(AssetsWeightsStr, ",")), IntegerEntry("static_tokensAmount", size(split(finalAssetsIdsStr, ",")))])
1355+ else throw("Strict value is not equal to itself.")
1356+ }
1357+ else {
1358+ let finalAssetsIdsStr = tryGetString("rebalance_assetIds")
1359+ let AssetsWeightsStr = {
1360+ let $l = split(finalAssetsIdsStr, ",")
1361+ let $s = size($l)
1362+ let $acc0 = nil
1363+ func $f5_1 ($a,$i) = if (($i >= $s))
1364+ then $a
1365+ else addAssetWeightToStrList($a, $l[$i])
1366+
1367+ func $f5_2 ($a,$i) = if (($i >= $s))
1368+ then $a
1369+ else throw("List size exceeds 10")
1370+
1371+ $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)
1372+ }
1373+ (actions ++ [StringEntry("static_tokenWeights", makeString(AssetsWeightsStr, ","))])
1374+ }
1375+ }
1376+ else throw("Strict value is not equal to itself.")
1377+ }
1378+ else throw("Strict value is not equal to itself.")
1379+ }
1380+ }
1381+ }
1382+
1383+
1384+
1385+@Callable(i)
1386+func doRebalancing (assetWeightsStr) = {
1387+ let assetWeightsStrLi = split(assetWeightsStr, ",")
1388+ let assetWeightsSum = {
1389+ let $l = assetWeightsStrLi
1390+ let $s = size($l)
1391+ let $acc0 = 0
1392+ func $f4_1 ($a,$i) = if (($i >= $s))
1393+ then $a
1394+ else sum($a, $l[$i])
1395+
1396+ func $f4_2 ($a,$i) = if (($i >= $s))
1397+ then $a
1398+ else throw("List size exceeds 10")
1399+
1400+ $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)
1401+ }
1402+ let assetIdsStrLi = split(tryGetString("static_tokenIds"), ",")
1403+ if ((i.caller != this))
1404+ then throw("this call available only for admin")
1405+ else {
1406+ let oldKMult = getKMult()
1407+ func handler (pars,assetId) = {
1408+ let accum = pars._1
1409+ let assetIdStr = getAssetString(assetId)
1410+ func handler2 (accum,n) = if ((n == assetId))
1411+ then value(indexOf(assetIds, n))
1412+ else accum
1413+
1414+ let Token = {
1415+ let $l = assetIds
1416+ let $s = size($l)
1417+ let $acc0 = 1
1418+ func $f5_1 ($a,$i) = if (($i >= $s))
1419+ then $a
1420+ else handler2($a, $l[$i])
1421+
1422+ func $f5_2 ($a,$i) = if (($i >= $s))
1423+ then $a
1424+ else throw("List size exceeds 10")
1425+
1426+ $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)
1427+ }
1428+ let balance = tryGetInteger((("global_" + assetIdStr) + "_balance"))
1429+ let weight = if ((pars._2 == "new"))
1430+ then parseIntValue(assetWeightsStrLi[Token])
1431+ else tryGetInteger((("static_" + assetIdStr) + "_weight"))
1432+ $Tuple2(fraction(accum, pow(balance, Decimals[Token], weight, AssetsWeightsDecimals, 8, FLOOR), Scale8), pars._2)
1433+ }
1434+
1435+ let newK = ( let $l = assetIds
1436+ let $s = size($l)
1437+ let $acc0 = $Tuple2(PoolTokenScale, "new")
1438+ func $f5_1 ($a,$i) = if (($i >= $s))
1439+ then $a
1440+ else handler($a, $l[$i])
1441+
1442+ func $f5_2 ($a,$i) = if (($i >= $s))
1443+ then $a
1444+ else throw("List size exceeds 10")
1445+
1446+ $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
1447+ let oldK = ( let $l = assetIds
1448+ let $s = size($l)
1449+ let $acc0 = $Tuple2(PoolTokenScale, "old")
1450+ func $f6_1 ($a,$i) = if (($i >= $s))
1451+ then $a
1452+ else handler($a, $l[$i])
1453+
1454+ func $f6_2 ($a,$i) = if (($i >= $s))
1455+ then $a
1456+ else throw("List size exceeds 10")
1457+
1458+ $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
1459+ let newKMult = fraction(oldKMult, newK, oldK)
1460+ func addTokenDataEntries (accum,assetNum) = if ((assetNum >= size(assetWeightsStrLi)))
1461+ then accum
1462+ else (accum ++ [IntegerEntry((("static_" + assetIdsStrLi[assetNum]) + "_weight"), value(parseInt(assetWeightsStrLi[assetNum])))])
1463+
1464+ ({
1465+ let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1466+ let $s = size($l)
1467+ let $acc0 = nil
1468+ func $f7_1 ($a,$i) = if (($i >= $s))
1469+ then $a
1470+ else addTokenDataEntries($a, $l[$i])
1471+
1472+ func $f7_2 ($a,$i) = if (($i >= $s))
1473+ then $a
1474+ else throw("List size exceeds 10")
1475+
1476+ $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)
1477+ } ++ [IntegerEntry("static_KMult", newKMult)])
1478+ }
1479+ }
1480+
1481+
1482+
1483+@Callable(i)
1484+func doRebalancingWithNewTokens (assetIdsStr,assetWeightsStr,baseTokenIdStr) = {
1485+ let newAssetWeightsStrLi = split(assetWeightsStr, ",")
1486+ let prevAssetIdsStrLi = split(tryGetString("static_tokenIds"), ",")
1487+ let newAssetIdsStrLi = split(assetIdsStr, ",")
1488+ let newAssetIds = {
1489+ let $l = newAssetIdsStrLi
1490+ let $s = size($l)
1491+ let $acc0 = nil
1492+ func $f4_1 ($a,$i) = if (($i >= $s))
1493+ then $a
1494+ else addAssetBytesToList($a, $l[$i])
1495+
1496+ func $f4_2 ($a,$i) = if (($i >= $s))
1497+ then $a
1498+ else throw("List size exceeds 10")
1499+
1500+ $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)
1501+ }
1502+ let feeAssetStr = {
1503+ let $l = newAssetIdsStrLi
1504+ let $s = size($l)
1505+ let $acc0 = ""
1506+ func $f5_1 ($a,$i) = if (($i >= $s))
1507+ then $a
1508+ else checkFeeAsset($a, $l[$i])
1509+
1510+ func $f5_2 ($a,$i) = if (($i >= $s))
1511+ then $a
1512+ else throw("List size exceeds 10")
1513+
1514+ $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)
1515+ }
1516+ let addedAssets = split(tryGetString("rebalance_addedAssets"), ",")
1517+ func findAssetPayment (assetId) = valueOrElse(getInteger(("rebalance_attachedPayment_" + getAssetString(assetId))), 0)
1518+
1519+ func addAssetBalanceToLi (li,assetId) = (li ++ [findAssetPayment(assetId)])
1520+
1521+ let attachedBalances = {
1522+ let $l = newAssetIds
1523+ let $s = size($l)
1524+ let $acc0 = nil
1525+ func $f6_1 ($a,$i) = if (($i >= $s))
1526+ then $a
1527+ else addAssetBalanceToLi($a, $l[$i])
1528+
1529+ func $f6_2 ($a,$i) = if (($i >= $s))
1530+ then $a
1531+ else throw("List size exceeds 10")
1532+
1533+ $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)
1534+ }
1535+ if ((i.caller != this))
1536+ then throw(("this call available only for admin, " + toString(i.caller)))
1537+ else {
1538+ let oldKMult = getKMult()
1539+ let oldK = getVirtualPoolTokenAmount()
1540+ func myltiplyAssetsForK (pars,assetId) = {
1541+ func findAssetNum (accum,n) = if ((n == assetId))
1542+ then value(indexOf(newAssetIds, n))
1543+ else accum
1544+
1545+ let currentK = pars
1546+ let assetIdStr = getAssetString(assetId)
1547+ let TokenNum = {
1548+ let $l = newAssetIds
1549+ let $s = size($l)
1550+ let $acc0 = 1
1551+ func $f7_1 ($a,$i) = if (($i >= $s))
1552+ then $a
1553+ else findAssetNum($a, $l[$i])
1554+
1555+ func $f7_2 ($a,$i) = if (($i >= $s))
1556+ then $a
1557+ else throw("List size exceeds 10")
1558+
1559+ $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)
1560+ }
1561+ let weight = parseIntValue(newAssetWeightsStrLi[TokenNum])
1562+ let balanceInState = tryGetInteger((("global_" + assetIdStr) + "_balance"))
1563+ let balanceInPayment = attachedBalances[TokenNum]
1564+ let balance = (balanceInState + balanceInPayment)
1565+ let assetDecimals = if ((assetId == unit))
1566+ then 8
1567+ else value(assetInfo(value(assetId))).decimals
1568+ if ((0 >= balance))
1569+ then throw(("you need to attach all new assets in payment. this asset is missed: " + assetIdStr))
1570+ else fraction(currentK, pow(balance, assetDecimals, weight, AssetsWeightsDecimals, 8, FLOOR), Scale8)
1571+ }
1572+
1573+ let newK = {
1574+ let $l = newAssetIds
1575+ let $s = size($l)
1576+ let $acc0 = PoolTokenScale
1577+ func $f7_1 ($a,$i) = if (($i >= $s))
1578+ then $a
1579+ else myltiplyAssetsForK($a, $l[$i])
1580+
1581+ func $f7_2 ($a,$i) = if (($i >= $s))
1582+ then $a
1583+ else throw("List size exceeds 10")
1584+
1585+ $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)
1586+ }
1587+ let newKMult = fraction(oldKMult, newK, oldK)
1588+ func addTokenDataEntries (accum,assetNum) = {
1589+ let assetIdStr = newAssetIdsStrLi[assetNum]
1590+ let assetId = newAssetIds[assetNum]
1591+ let assetDecimals = if ((assetId == unit))
1592+ then 8
1593+ else value(assetInfo(value(assetId))).decimals
1594+ let newAssetData = if ((indexOf(addedAssets, assetIdStr) != unit))
1595+ then [IntegerEntry((("global_" + assetIdStr) + "_balance"), attachedBalances[assetNum]), IntegerEntry((("static_" + assetIdStr) + "_scale"), pow(10, 0, assetDecimals, 0, 0, DOWN)), IntegerEntry((("static_" + assetIdStr) + "_decimals"), assetDecimals)]
1596+ else nil
1597+ if ((assetNum >= size(newAssetWeightsStrLi)))
1598+ then accum
1599+ else ((accum ++ [IntegerEntry((("static_" + assetIdStr) + "_weight"), value(parseInt(newAssetWeightsStrLi[assetNum])))]) ++ newAssetData)
1600+ }
1601+
1602+ ({
1603+ let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1604+ let $s = size($l)
1605+ let $acc0 = nil
1606+ func $f8_1 ($a,$i) = if (($i >= $s))
1607+ then $a
1608+ else addTokenDataEntries($a, $l[$i])
1609+
1610+ func $f8_2 ($a,$i) = if (($i >= $s))
1611+ then $a
1612+ else throw("List size exceeds 10")
1613+
1614+ $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)
1615+ } ++ [StringEntry("static_tokenIds", assetIdsStr), StringEntry("static_feeToken", feeAssetStr), StringEntry("static_tokenWeights", assetWeightsStr), IntegerEntry("static_tokensAmount", size(newAssetIds)), IntegerEntry("static_KMult", newKMult)])
1616+ }
1617+ }
1618+
1619+
7651620 @Verifier(tx)
766-func verify () = if (isShutdown())
767- then false
768- else if (sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey))
1621+func verify () = if (if ((valueOrElse(getInteger("global_wasPreInited"), 0) == 0))
1622+ then if (sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey))
7691623 then true
7701624 else sigVerify(tx.bodyBytes, tx.proofs[0], masterPubKey)
1625+ else false)
1626+ then true
1627+ else match tx {
1628+ case tx: SetScriptTransaction =>
1629+ let scriptFull = value(tx.script)
1630+ let hash = toBase58String(sha256(scriptFull))
1631+ if (sigVerify(tx.bodyBytes, tx.proofs[0], masterPubKey))
1632+ then (valueOrElse(getInteger(coldMasterAddress, ("approvedScript_" + hash)), 0) > height)
1633+ else false
1634+ case _ =>
1635+ if (sigVerify(tx.bodyBytes, tx.proofs[0], masterPubKey))
1636+ then (valueOrElse(getInteger(coldMasterAddress, ("approvedTx_" + toBase58String(tx.id))), 0) > 0)
1637+ else false
1638+ }
7711639

github/deemru/w8io/786bc32 
173.85 ms