tx · 3s3Gmpeb5JpmeduyopLYdHVo549heXrD5cRd54AHbqht

3M6VzC1ysGT3vKEJqyrz9gS5kWpTb7cG5nu:  -0.05500000 Waves

2025.09.29 04:33 [363747] smart account 3M6VzC1ysGT3vKEJqyrz9gS5kWpTb7cG5nu > SELF 0.00000000 Waves

{ "type": 13, "id": "3s3Gmpeb5JpmeduyopLYdHVo549heXrD5cRd54AHbqht", "fee": 5500000, "feeAssetId": null, "timestamp": 1759109604332, "version": 2, "chainId": 82, "sender": "3M6VzC1ysGT3vKEJqyrz9gS5kWpTb7cG5nu", "senderPublicKey": "14EKuqhhaURrNjUPug5VhQor2xckVUVydkjheQsFQBbH", "proofs": [ "5WQm6psPQcMLHUSs6SkP4YXiEMCEx3pFd1ZAky22TNWhahHxtg9hkjq454s68kYJdaBYnocjxYXwfMFVKW65fTkK" ], "script": "base64:BgJcCAISBAoCCAgSCQoHCAgICAgIARIAEgkKBwgICAgIAQgSAwoBBBIDCgEBEgASAwoBCBIDCgEBEgASAwoBCBIAEgQKAggBEgQKAggBEgUKAwgIARIDCgEIEgMKAQFmAAdWRVJTSU9OAhZQWi0zLjYuMSBQUk9ELXJlZmFjdG9yAAljb25maWdTdHIJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwINY29uZmlnQWRkcmVzcwIjM1BNb0VpYmRMZVdxY1VSUTgzNTFYaGFXd3lhY0RjN0c0ZTUADkNPTkZJR19BRERSRVNTAwkAAAIFCWNvbmZpZ1N0cgIABQR0aGlzCQEHQWRkcmVzcwEJANkEAQUJY29uZmlnU3RyABVBc3NldHNXZWlnaHRzRGVjaW1hbHMABAAFU2NhbGUAkE4ABlNjYWxlOACAwtcvAAlTY2FsZThfQkkJALYCAQUGU2NhbGU4AAdTY2FsZTEyAICglKWNHQAHU2NhbGUxNgCAgIT+pt7hEQAKU2NhbGUxNl9CSQkAtgIBBQdTY2FsZTE2AAhGZWVTY2FsZQCQTgARUG9vbFRva2VuRGVjaW1hbHMACAAOUG9vbFRva2VuU2NhbGUJAGwGAAoAAAURUG9vbFRva2VuRGVjaW1hbHMAAAAABQZIQUxGVVAAEE1JTl9TVEVQU19BTU9VTlQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUOQ09ORklHX0FERFJFU1MCEG1pbl9zdGVwc19hbW91bnQAAQAQTUFYX1NURVBTX0FNT1VOVAkBC3ZhbHVlT3JFbHNlAgkAmggCBQ5DT05GSUdfQUREUkVTUwIQbWF4X3N0ZXBzX2Ftb3VudAD0AwASTUlOX1NURVBTX0lOVEVSVkFMCQELdmFsdWVPckVsc2UCCQCaCAIFDkNPTkZJR19BRERSRVNTAhJtaW5fc3RlcHNfaW50ZXJ2YWwAAQASTUFYX1NURVBTX0lOVEVSVkFMCQELdmFsdWVPckVsc2UCCQCaCAIFDkNPTkZJR19BRERSRVNTAhJtYXhfc3RlcHNfaW50ZXJ2YWwAkE4ACk1JTl9XRUlHSFQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUOQ09ORklHX0FERFJFU1MCCm1pbl93ZWlnaHQAZAAKTUFYX1dFSUdIVAkBC3ZhbHVlT3JFbHNlAgkAmggCBQ5DT05GSUdfQUREUkVTUwIKbWF4X3dlaWdodACsTQENdHJ5R2V0SW50ZWdlcgEDa2V5BAckbWF0Y2gwCQCaCAIFBHRoaXMFA2tleQMJAAECBQckbWF0Y2gwAgNJbnQEAWIFByRtYXRjaDAFAWIAAAEMdHJ5R2V0QmluYXJ5AQNrZXkEByRtYXRjaDAJAJwIAgUEdGhpcwUDa2V5AwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEAWIFByRtYXRjaDAFAWIBAAEMdHJ5R2V0U3RyaW5nAQNrZXkEByRtYXRjaDAJAJ0IAgUEdGhpcwUDa2V5AwkAAQIFByRtYXRjaDACBlN0cmluZwQBYgUHJG1hdGNoMAUBYgIAARN0cnlHZXRTdHJpbmdPclRocm93AQNrZXkEByRtYXRjaDAJAJ0IAgUEdGhpcwUDa2V5AwkAAQIFByRtYXRjaDACBlN0cmluZwQBYgUHJG1hdGNoMAUBYgkAAgEJAKwCAgIdbm8gc3VjaCBrZXkgaW4gZGF0YSBzdG9yYWdlOiAFA2tleQEOZ2V0QXNzZXRTdHJpbmcBB2Fzc2V0SWQEByRtYXRjaDAFB2Fzc2V0SWQDCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQBYgUHJG1hdGNoMAkA2AQBBQFiAgVXQVZFUwENZ2V0QXNzZXRCeXRlcwEKYXNzZXRJZFN0cgMJAAACBQphc3NldElkU3RyAgVXQVZFUwUEdW5pdAkA2QQBBQphc3NldElkU3RyAQ9nZXRUb2tlbkJhbGFuY2UBB2Fzc2V0SWQEByRtYXRjaDAFB2Fzc2V0SWQDCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQBdAUHJG1hdGNoMAkA8AcCBQR0aGlzBQF0CAkA7wcBBQR0aGlzCWF2YWlsYWJsZQETYWRkQXNzZXRCeXRlc1RvTGlzdAIFYWNjdW0EaXRlbQkAzggCBQVhY2N1bQkAzAgCCQENZ2V0QXNzZXRCeXRlcwEFBGl0ZW0FA25pbAEUYWRkQXNzZXRXZWlnaHRUb0xpc3QCBWFjY3VtBGl0ZW0JAM4IAgUFYWNjdW0JAMwIAgkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwkBDmdldEFzc2V0U3RyaW5nAQUEaXRlbQIHX3dlaWdodAUDbmlsARdhZGRBc3NldFdlaWdodFRvU3RyTGlzdAIFYWNjdW0EaXRlbQkAzggCBQVhY2N1bQkAzAgCCQCkAwEJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18FBGl0ZW0CB193ZWlnaHQFA25pbAEWYWRkQXNzZXREZWNpbWFsc1RvTGlzdAIFYWNjdW0EaXRlbQkAzggCBQVhY2N1bQkAzAgCCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdzdGF0aWNfCQEOZ2V0QXNzZXRTdHJpbmcBBQRpdGVtAglfZGVjaW1hbHMFA25pbAETYWRkQXNzZXRTY2FsZVRvTGlzdAIFYWNjdW0EaXRlbQkAzggCBQVhY2N1bQkAzAgCCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdzdGF0aWNfCQEOZ2V0QXNzZXRTdHJpbmcBBQRpdGVtAgZfc2NhbGUFA25pbAEMYWRkSW50VG9MaXN0AgVhY2N1bQRpdGVtCQDOCAIFBWFjY3VtCQDMCAIJAQ1wYXJzZUludFZhbHVlAQUEaXRlbQUDbmlsARFwYXJzdFN0clRvSW50TGlzdAEBcwoBAWYCBWFjY3VtBG5leHQJAM4IAgUFYWNjdW0JAMwIAgkBDXBhcnNlSW50VmFsdWUBBQRuZXh0BQNuaWwKAAIkbAkAtQkCBQFzAgEsCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQFmAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAA51c2RuQXNzZXRJZFN0cgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIOdXNkbkFzc2V0SWRTdHICLERHMnhGa1BkRHdLVW9Ca3pHQWhRdExwU0d6ZlhMaUNZUEV6ZUtIMkFkMjRwABBwdXp6bGVBc3NldElkU3RyCQELdmFsdWVPckVsc2UCCQCdCAIFDkNPTkZJR19BRERSRVNTAhBwdXp6bGVBc3NldElkU3RyAixIRUI4UWF3OXhyV3BXczh0SHNpQVRZR0JXREJ0UDJTN2tjUEFMck11NDNBUwAOdXNkdEFzc2V0SWRTdHIJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCDnVzZHRBc3NldElkU3RyAiwzNE45WWNFRVRMV245M3FZUTY0RXNQMXg4OXRTcnVKVTQ0UnJFTVNYWEVQSgARdXNkdFBwdEFzc2V0SWRTdHIJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCEXVzZHRQcHRBc3NldElkU3RyAiw5d2MzTFhOQTRURUJzWHlLdG9MRTltcmJERDdXTUhYdlhyQ2padmFiTEFzaQAOcm9tZUFzc2V0SWRTdHIJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCDnJvbWVBc3NldElkU3RyAixBUDRDYjV4TFlHSDZaaWdIcmVDWkhvWHBRVFdEa1BzRzJCSHFmRFV4NnRhSgAPd2F2ZXNBc3NldElkU3RyAgVXQVZFUwALdXNkbkFzc2V0SWQJANkEAQUOdXNkbkFzc2V0SWRTdHIADXB1enpsZUFzc2V0SWQJANkEAQUQcHV6emxlQXNzZXRJZFN0cgALdXNkdEFzc2V0SWQJANkEAQUOdXNkdEFzc2V0SWRTdHIADnVzZHRQcHRBc3NldElkCQDZBAEFEXVzZHRQcHRBc3NldElkU3RyAAtyb21lQXNzZXRJZAkA2QQBBQ5yb21lQXNzZXRJZFN0cgAMd2F2ZXNBc3NldElkBQR1bml0ABVzdXBwb3J0ZWRGZWVBc3NldHNTdHIJAMwIAgUOdXNkbkFzc2V0SWRTdHIJAMwIAgUQcHV6emxlQXNzZXRJZFN0cgkAzAgCBQ51c2R0QXNzZXRJZFN0cgkAzAgCBRF1c2R0UHB0QXNzZXRJZFN0cgkAzAgCBQ93YXZlc0Fzc2V0SWRTdHIJAMwIAgUOcm9tZUFzc2V0SWRTdHIFA25pbAARcGFyZW50UG9vbEFkZHJlc3MJAQdBZGRyZXNzAQkA2QQBCQELdmFsdWVPckVsc2UCCQCdCAIFDkNPTkZJR19BRERSRVNTAhFwYXJlbnRQb29sQWRkcmVzcwIjM1BGRGd6dTFVdHN3QWtDTXhxcVFqYlRlSGFYNGNNYWI4S2gADW1hc3RlckFkZHJlc3MJAQdBZGRyZXNzAQkA2QQBCQELdmFsdWVPckVsc2UCCQCdCAIFDkNPTkZJR19BRERSRVNTAg1tYXN0ZXJBZGRyZXNzAiMzUExqd0hjejlORXVhVG82M05aUjlCOW9rUWlLUXhaU2JtZgAMbWFzdGVyUHViS2V5CQDZBAEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCDG1hc3RlclB1YktleQIsMmpUSkdxSFNvcHlqNWQxY2piVWU2ZjJqWHFHTUhFNDEyY3kzdkd3WW9SYlAADW9yYWNsZUFkZHJlc3MJAQdBZGRyZXNzAQkA2QQBCQELdmFsdWVPckVsc2UCCQCdCAIFDkNPTkZJR19BRERSRVNTAg1vcmFjbGVBZGRyZXNzAiMzUDhkMUUxQkxLb0Q1MnkzYlFKMWJEVGQyVEQxZ3BhTG45dAAOc3Rha2luZ0FkZHJlc3MJAQdBZGRyZXNzAQkA2QQBCQELdmFsdWVPckVsc2UCCQCdCAIFDkNPTkZJR19BRERSRVNTAg5zdGFraW5nQWRkcmVzcwIjM1BGVGJ5d3F4dEZmdWtYM0h5VDg4MWc0aVc1SzRRTDNGQVMAC2ZlZXNBZGRyZXNzCQEHQWRkcmVzcwEJANkEAQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwILZmVlc0FkZHJlc3MCIzNQRldBVkttWGpmSFh5ekpiMTJqQ2JoUDRVaGk5dDR1V2lEAA9wb29sc0h1YkFkZHJlc3MJAQdBZGRyZXNzAQkA2QQBCQELdmFsdWVPckVsc2UCCQCdCAIFDkNPTkZJR19BRERSRVNTAg9wb29sc0h1YkFkZHJlc3MCIzNQNVJHWXlDbkVMRjhKVFB4Z1g1NGRCR3p3a1FNS1VKNUg3ABJzaHV0ZG93bkFkZHJlc3NTdHIJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCD3NodXRkb3duQWRkcmVzcwIjM1BFcHY5aFJGV0VFQlUyMldSbkxzdzFiSDRZR3RjVTcyOG8AD2xheWVyMkFkZHJlc3NlcwkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIPbGF5ZXIyQWRkcmVzc2VzAkczUFIxUXZpOW1IVDM1U3dXRWtMU3FxRTJMOHRoaVBMZFZXVSwzUFFvQmZVS0hrSkFlR1dob29MUDdXUzhvdmI1NGF2OUpwMgAKZ292QWRkcmVzcwkBB0FkZHJlc3MBCQDZBAEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCCmdvdkFkZHJlc3MCIzNQNnVybzl4Q3NFOHRlNzhRWmp6cXk3YXE4bmF0U3pkY2VDABFjb2xkTWFzdGVyQWRkcmVzcwkBB0FkZHJlc3MBCQDZBAEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCEWNvbGRNYXN0ZXJBZGRyZXNzAiMzUEs5bmhQZlBiTUJ5Z0I5WmdIVk1IYVFiU29vandyQmZ4agABVAkBDXRyeUdldEludGVnZXIBAhNzdGF0aWNfdG9rZW5zQW1vdW50AAhhc3NldElkcwoAAiRsCQC1CQIJAQx0cnlHZXRTdHJpbmcBAg9zdGF0aWNfdG9rZW5JZHMCASwKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBE2FkZEFzc2V0Qnl0ZXNUb0xpc3QCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoADUFzc2V0c1dlaWdodHMKAAIkbAUIYXNzZXRJZHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjFfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBFGFkZEFzc2V0V2VpZ2h0VG9MaXN0AgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYxXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmMV8yAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAAhEZWNpbWFscwoAAiRsBQhhc3NldElkcwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMl8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEWYWRkQXNzZXREZWNpbWFsc1RvTGlzdAIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMl8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjJfMgIJAQUkZjJfMQIJAQUkZjJfMQIJAQUkZjJfMQIJAQUkZjJfMQIJAQUkZjJfMQIJAQUkZjJfMQIJAQUkZjJfMQIJAQUkZjJfMQIJAQUkZjJfMQIJAQUkZjJfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgAGU2NhbGVzCgACJGwFCGFzc2V0SWRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYzXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARNhZGRBc3NldFNjYWxlVG9MaXN0AgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYzXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmM18yAgkBBSRmM18xAgkBBSRmM18xAgkBBSRmM18xAgkBBSRmM18xAgkBBSRmM18xAgkBBSRmM18xAgkBBSRmM18xAgkBBSRmM18xAgkBBSRmM18xAgkBBSRmM18xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAANGZWUJAQ10cnlHZXRJbnRlZ2VyAQIKc3RhdGljX2ZlZQAMZWFybmVkQXNzZXRzBQhhc3NldElkcwEEX2dldAIHYXNzZXRJZAVwYXJhbQkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgkArAICAgdnbG9iYWxfBQdhc3NldElkAgFfBQVwYXJhbQEPX2dldF9mZWVzRWFybmVkAQdhc3NldElkCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgISZ2xvYmFsX2ZlZXNFYXJuZWRfBQdhc3NldElkARdfZ2V0X2xhc3RDaGVja19pbnRlcmVzdAEHYXNzZXRJZAkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIRZ2xvYmFsX2xhc3RDaGVja18FB2Fzc2V0SWQCCV9pbnRlcmVzdAEQX2dldF9leHRyYUVhcm5lZAEHYXNzZXRJZAkBDXRyeUdldEludGVnZXIBCQCsAgICE2dsb2JhbF9leHRyYUVhcm5lZF8FB2Fzc2V0SWQBFWxvYWRHbG9iYWxUb2tlblBhcmFtcwEHYXNzZXRJZAQHJG1hdGNoMAkAoggBCQCsAgICDWdsb2JhbFBhcmFtc18FB2Fzc2V0SWQDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFwBQckbWF0Y2gwBAZwYXJhbXMJALUJAgUBcAICX18JAJoKCAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFBnBhcmFtcwAACQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUGcGFyYW1zAAEJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQZwYXJhbXMAAgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFBnBhcmFtcwADCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUGcGFyYW1zAAQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQZwYXJhbXMABQkBDXBhcnNlSW50VmFsdWUBCQCRAwIFBnBhcmFtcwAGCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUGcGFyYW1zAAcJAJoKCAkBBF9nZXQCBQdhc3NldElkAgdiYWxhbmNlCQEEX2dldAIFB2Fzc2V0SWQCC2ZhY3RCYWxhbmNlCQEPX2dldF9mZWVzRWFybmVkAQUHYXNzZXRJZAkBF19nZXRfbGFzdENoZWNrX2ludGVyZXN0AQUHYXNzZXRJZAkBEF9nZXRfZXh0cmFFYXJuZWQBBQdhc3NldElkCQEEX2dldAIFB2Fzc2V0SWQCB3NlbGxvZmYJAQRfZ2V0AgUHYXNzZXRJZAITc2VsbG9mZlN0YXJ0QmFsYW5jZQkBBF9nZXQCBQdhc3NldElkAhJzZWxsb2ZmU3RhcnRIZWlnaHQBFXNhdmVHbG9iYWxUb2tlblBhcmFtcwIHYXNzZXRJZAZwYXJhbXMJAQtTdHJpbmdFbnRyeQIJAKwCAgINZ2xvYmFsUGFyYW1zXwUHYXNzZXRJZAkAuQkCCQDMCAIJAKQDAQgFBnBhcmFtcwJfMQkAzAgCCQCkAwEIBQZwYXJhbXMCXzIJAMwIAgkApAMBCAUGcGFyYW1zAl8zCQDMCAIJAKQDAQgFBnBhcmFtcwJfNAkAzAgCCQCkAwEIBQZwYXJhbXMCXzUJAMwIAgkApAMBCAUGcGFyYW1zAl82CQDMCAIJAKQDAQgFBnBhcmFtcwJfNwkAzAgCCQCkAwEIBQZwYXJhbXMCXzgFA25pbAICX18BCmlzU2h1dGRvd24ABA9zaHV0ZG93bkFkZHJlc3MJAKYIAQUSc2h1dGRvd25BZGRyZXNzU3RyAwkAAAIFD3NodXRkb3duQWRkcmVzcwUEdW5pdAcEByRtYXRjaDAJAJsIAgkBBXZhbHVlAQUPc2h1dGRvd25BZGRyZXNzAgtpc19zaHV0ZG93bgMJAAECBQckbWF0Y2gwAgdCb29sZWFuBAF4BQckbWF0Y2gwBQF4BwEOZ2V0RmFjdEJhbGFuY2UBCmFzc2V0SWRTdHIEC2Fzc2V0UGFyYW1zCQEVbG9hZEdsb2JhbFRva2VuUGFyYW1zAQUKYXNzZXRJZFN0cggFC2Fzc2V0UGFyYW1zAl8yARZnZXRDdXJyZW50VG9rZW5CYWxhbmNlAQh0b2tlbk51bQQKdG9rZW5JZFN0cgkBDmdldEFzc2V0U3RyaW5nAQkAkQMCBQhhc3NldElkcwUIdG9rZW5OdW0EC3Rva2VuUGFyYW1zCQEVbG9hZEdsb2JhbFRva2VuUGFyYW1zAQUKdG9rZW5JZFN0cggFC3Rva2VuUGFyYW1zAl8xAQ1zdGFrZUlmTmVlZGVkAgphc3NldElkU3RyBmFtb3VudAQHc3Rha2VUeAMJAQIhPQIJAQx0cnlHZXRTdHJpbmcBCQCsAgICF3N0YXRpY19zdGFraW5nQ29udHJhY3RfBQphc3NldElkU3RyAgAJAPwHBAkBEUBleHRyTmF0aXZlKDEwNjIpAQkBDHRyeUdldFN0cmluZwEJAKwCAgIXc3RhdGljX3N0YWtpbmdDb250cmFjdF8FCmFzc2V0SWRTdHICBXN0YWtlBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQ1nZXRBc3NldEJ5dGVzAQUKYXNzZXRJZFN0cgUGYW1vdW50BQNuaWwFBHVuaXQDCQAAAgUHc3Rha2VUeAUHc3Rha2VUeAYJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BD3Vuc3Rha2VJZk5lZWRlZAIKYXNzZXRJZFN0cgZhbW91bnQECXVuc3Rha2VUeAMJAQIhPQIJAQx0cnlHZXRTdHJpbmcBCQCsAgICF3N0YXRpY19zdGFraW5nQ29udHJhY3RfBQphc3NldElkU3RyAgAJAPwHBAkBEUBleHRyTmF0aXZlKDEwNjIpAQkBDHRyeUdldFN0cmluZwEJAKwCAgIXc3RhdGljX3N0YWtpbmdDb250cmFjdF8FCmFzc2V0SWRTdHICB3Vuc3Rha2UJAMwIAgUGYW1vdW50BQNuaWwFA25pbAUEdW5pdAMJAAACBQl1bnN0YWtlVHgFCXVuc3Rha2VUeAYJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BEWJ1cm5JbmRleElmTmVlZGVkAQZhbW91bnQECmluZGV4SWRTdHIJAQx0cnlHZXRTdHJpbmcBAhZzdGF0aWNfcG9vbFRva2VuX2lkU3RyAwkAAAIFCmluZGV4SWRTdHICAAUDbmlsAwkAAAIJAOwHAQkA2QQBBQppbmRleElkU3RyBQR1bml0BQNuaWwJAMwIAgkBBEJ1cm4CCQDZBAEFCmluZGV4SWRTdHIFBmFtb3VudAUDbmlsARFtaW50SW5kZXhJZk5lZWRlZAEGYW1vdW50BAppbmRleElkU3RyCQEMdHJ5R2V0U3RyaW5nAQIWc3RhdGljX3Bvb2xUb2tlbl9pZFN0cgMJAAACBQppbmRleElkU3RyAgAFA25pbAMJAAACCQDsBwEJANkEAQUKaW5kZXhJZFN0cgUEdW5pdAUDbmlsCQDMCAIJAQdSZWlzc3VlAwkA2QQBBQppbmRleElkU3RyBQZhbW91bnQGBQNuaWwBCGdldEtNdWx0AAQHJG1hdGNoMAkAnwgBAgxzdGF0aWNfS011bHQDCQABAgUHJG1hdGNoMAIDSW50BAF4BQckbWF0Y2gwBQF4BQdTY2FsZTE2ARJzYXZlQ3VycmVudFdlaWdodHMABAphc3NldElkc0xpCQC1CQIJAQx0cnlHZXRTdHJpbmcBAg9zdGF0aWNfdG9rZW5JZHMCASwKAQFzAgVhY2N1bQdhc3NldElkCQDOCAIFBWFjY3VtCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgICFnJlYmFsYW5jZV9zdGFydFdlaWdodF8FB2Fzc2V0SWQJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18FB2Fzc2V0SWQCB193ZWlnaHQFA25pbAoAAiRsBQphc3NldElkc0xpCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQFzAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY0XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNF8yAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKARlnZXRWaXJ0dWFsUG9vbFRva2VuQW1vdW50AAkAawMJAQ10cnlHZXRJbnRlZ2VyAQIXZ2xvYmFsX3Bvb2xUb2tlbl9hbW91bnQJAQhnZXRLTXVsdAAFB1NjYWxlMTYBEGNhbGN1bGF0ZVBJc3N1ZWQCBmFtb3VudAd0b2tlbklkBAdQc3VwcGx5CQEZZ2V0VmlydHVhbFBvb2xUb2tlbkFtb3VudAAEB0JhbGFuY2UJAQ5nZXRGYWN0QmFsYW5jZQEJAQ5nZXRBc3NldFN0cmluZwEFB3Rva2VuSWQEAnQxCQBuBAUGYW1vdW50BQdQc3VwcGx5BQdCYWxhbmNlBQRET1dOBQJ0MQENZ2V0TWluUElzc3VlZAEIcGF5bWVudHMKAQdoYW5kbGVyAgVhY2N1bQdjdXJyZW50AwkAAAIJAQ5nZXRGYWN0QmFsYW5jZQEJAQ5nZXRBc3NldFN0cmluZwEIBQdjdXJyZW50B2Fzc2V0SWQAAAUFYWNjdW0EB1BJc3N1ZWQJARBjYWxjdWxhdGVQSXNzdWVkAggFB2N1cnJlbnQGYW1vdW50CAUHY3VycmVudAdhc3NldElkAwkAAAIFB1BJc3N1ZWQAAAkAAgECJG9uZSBvZiB0aGUgdG9rZW5zIGFtb3VudHMgaXMgdG9vIGxvdwMDCQAAAgUFYWNjdW0AAAYJAGYCBQVhY2N1bQUHUElzc3VlZAUHUElzc3VlZAUFYWNjdW0ECW1pblBJc3NlZAoAAiRsBQhwYXltZW50cwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAAAAoBBSRmNF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEHaGFuZGxlcgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjRfMgIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgUJbWluUElzc2VkARJnZXRQcmljZUZyb21PcmFjbGUBCmFzc2V0SWRTdHIEByRtYXRjaDAJAJoIAgUNb3JhY2xlQWRkcmVzcwkArAICBQphc3NldElkU3RyAgdfdHdhcDVCAwkAAQIFByRtYXRjaDACA0ludAQBeAUHJG1hdGNoMAUBeAAAARFjYWxjdWxhdGVVc2RWYWx1ZQQHYXNzZXRJZAZhbW91bnQIYUJhbGFuY2UPZmVlQXNzZXRCYWxhbmNlBAthc3NldFdlaWdodAkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwkBDmdldEFzc2V0U3RyaW5nAQUHYXNzZXRJZAIHX3dlaWdodAQLZmVlQXNzZXRTdHIJAQx0cnlHZXRTdHJpbmcBAg9zdGF0aWNfZmVlVG9rZW4EDWZlZUFzc2V0U2NhbGUJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAKwCAgkArAICAgdzdGF0aWNfBQtmZWVBc3NldFN0cgIGX3NjYWxlBAtmZWVBc3NldE51bQkBBXZhbHVlAQkAzwgCBQhhc3NldElkcwkBDWdldEFzc2V0Qnl0ZXMBBQtmZWVBc3NldFN0cgQOZmVlQXNzZXRXZWlnaHQJAJEDAgUNQXNzZXRzV2VpZ2h0cwULZmVlQXNzZXROdW0EB19hbW91bnQJALkCAgkAtgIBBQZhbW91bnQFCVNjYWxlOF9CSQQNX2ZlZUFzc2V0RGF0YQkAugICCQC2AgEFD2ZlZUFzc2V0QmFsYW5jZQkAtgIBBQ5mZWVBc3NldFdlaWdodAQKX2Fzc2V0RGF0YQkAvAIDCQC2AgEFCGFCYWxhbmNlBQlTY2FsZThfQkkJALYCAQULYXNzZXRXZWlnaHQEDXZhbEluRmVlQXNzZXQJAKADAQkAvAIDBQdfYW1vdW50BQ1fZmVlQXNzZXREYXRhBQpfYXNzZXREYXRhBA1mZWVBc3NldFByaWNlCQESZ2V0UHJpY2VGcm9tT3JhY2xlAQULZmVlQXNzZXRTdHIJAGsDBQ12YWxJbkZlZUFzc2V0BQ1mZWVBc3NldFByaWNlBQ1mZWVBc3NldFNjYWxlARRjYWxjQXZnQ29uY2VudHJhdGlvbgAKAQFmAgVhY2N1bQRuZXh0BAphc3NldElkU3RyCQEOZ2V0QXNzZXRTdHJpbmcBBQRuZXh0BAZ3ZWlnaHQJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18FCmFzc2V0SWRTdHICB193ZWlnaHQEC2Fzc2V0UGFyYW1zCQEVbG9hZEdsb2JhbFRva2VuUGFyYW1zAQUKYXNzZXRJZFN0cgQQYXNzZXRGYWN0QmFsYW5jZQgFC2Fzc2V0UGFyYW1zAl8yBBBhc3NldFZpcnRCYWxhbmNlCAULYXNzZXRQYXJhbXMCXzEJAJQKAgkAZAIIBQVhY2N1bQJfMQkAawMFEGFzc2V0RmFjdEJhbGFuY2UFBndlaWdodAUQYXNzZXRWaXJ0QmFsYW5jZQkAZAIIBQVhY2N1bQJfMgUGd2VpZ2h0CgACJGwFCGFzc2V0SWRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAkAlAoCAAAAAAoBBSRmNF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEBZgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjRfMgIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgETY2hlY2tUb2tlbnNWYWxpZGl0eQEIcGF5bWVudHMKAQhoYW5kbGVyMQIFYWNjdW0HcGF5bWVudAkAzggCBQVhY2N1bQkAzAgCCAUHcGF5bWVudAdhc3NldElkBQNuaWwEA2lkcwoAAiRsBQhwYXltZW50cwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmNF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEIaGFuZGxlcjECBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjRfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY0XzICCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoDCQAAAgUDaWRzBQNpZHMKAQhoYW5kbGVyMgIFYWNjdW0HYXNzZXRJZAMJAQIhPQIJAM8IAgUDaWRzBQdhc3NldElkBQR1bml0CQBkAgUFYWNjdW0AAQkAAgEJAKwCAgIUYXNzZXQgbm90IGF0dGFjaGVkOiAJAQ5nZXRBc3NldFN0cmluZwEFB2Fzc2V0SWQEBmNoZWNrcwoAAiRsBQhhc3NldElkcwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAAAAoBBSRmNV8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEIaGFuZGxlcjICBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjVfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY1XzICCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoDCQAAAgUGY2hlY2tzBQZjaGVja3MGCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuARNoYW5kbGVQb29sVG9rZW5zQWRkBAdQSXNzdWVkCHBheW1lbnRzC3VzZXJBZGRyZXNzCm5lZWRDaGFuZ2UKARVnZXRUb2tlblBheW1lbnRBbW91bnQBB3Rva2VuSWQKAQdoYW5kbGVyAgVhY2N1bQdwYXltZW50AwkAAAIIBQdwYXltZW50B2Fzc2V0SWQFB3Rva2VuSWQIBQdwYXltZW50BmFtb3VudAUFYWNjdW0KAAIkbAUIcGF5bWVudHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwAAAKAQUkZjRfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBB2hhbmRsZXICBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjRfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY0XzICCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoKARFoYW5kbGVUb2tlbkNoYW5nZQIFYWNjdW0HdG9rZW5JZAQKYXNzZXRJZFN0cgkBDmdldEFzc2V0U3RyaW5nAQUHdG9rZW5JZAQLYXNzZXRQYXJhbXMJARVsb2FkR2xvYmFsVG9rZW5QYXJhbXMBBQphc3NldElkU3RyBA1wYXltZW50QW1vdW50CQEVZ2V0VG9rZW5QYXltZW50QW1vdW50AQUHdG9rZW5JZAQCQmsIBQthc3NldFBhcmFtcwJfMgQHUFN1cHBseQkBGWdldFZpcnR1YWxQb29sVG9rZW5BbW91bnQABA10b2tlbkRlY2ltYWxzCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdzdGF0aWNfBQphc3NldElkU3RyAgZfc2NhbGUEAmExCQC9AgQJALkCAgkAtgIBCQBkAgUHUFN1cHBseQUHUElzc3VlZAkAtgIBBQZTY2FsZTgJALYCAQUNdG9rZW5EZWNpbWFscwkAtgIBBQdQU3VwcGx5BQdDRUlMSU5HBAJEawkAoAMBCQC9AgQJALgCAgUCYTEJALkCAgkAtgIBBQ10b2tlbkRlY2ltYWxzCQC2AgEFBlNjYWxlOAkAtgIBBQJCawkAuQICCQC2AgEFDXRva2VuRGVjaW1hbHMJALYCAQUGU2NhbGU4BQdDRUlMSU5HBAh0b1JldHVybgkAZQIFDXBheW1lbnRBbW91bnQFAkRrBAdzdGFrZVR4CQENc3Rha2VJZk5lZWRlZAIFCmFzc2V0SWRTdHIFAkRrAwkAAAIFB3N0YWtlVHgFB3N0YWtlVHgEAXQDAwUKbmVlZENoYW5nZQkAZgIFCHRvUmV0dXJuAAAHCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMFC3VzZXJBZGRyZXNzBQh0b1JldHVybgUHdG9rZW5JZAUDbmlsBQNuaWwEE3NlbGxvZmZTdGFydEJhbGFuY2UDCQECIT0CCAULYXNzZXRQYXJhbXMCXzgJAGgCCQBpAgUGaGVpZ2h0AGQAZAgFC2Fzc2V0UGFyYW1zAl83CQBrAwgFC2Fzc2V0UGFyYW1zAl83CQBkAgUHUFN1cHBseQUHUElzc3VlZAUHUFN1cHBseQQOYXNzZXRQYXJhbXNVcGQJAJoKCAkAbgQIBQthc3NldFBhcmFtcwJfMQkAZAIFB1BTdXBwbHkFB1BJc3N1ZWQFB1BTdXBwbHkFCEhBTEZFVkVOCQBkAggFC2Fzc2V0UGFyYW1zAl8yBQJEawgFC2Fzc2V0UGFyYW1zAl8zCAULYXNzZXRQYXJhbXMCXzQIBQthc3NldFBhcmFtcwJfNQgFC2Fzc2V0UGFyYW1zAl82BRNzZWxsb2ZmU3RhcnRCYWxhbmNlCAULYXNzZXRQYXJhbXMCXzgJAM4IAgkAzggCBQVhY2N1bQUBdAkAzAgCCQEVc2F2ZUdsb2JhbFRva2VuUGFyYW1zAgUKYXNzZXRJZFN0cgUOYXNzZXRQYXJhbXNVcGQFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgoAAiRsBQhhc3NldElkcwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmNF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQERaGFuZGxlVG9rZW5DaGFuZ2UCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjRfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY0XzICCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoBFmNhbGNNaW50ZWRXaXRoT25lVG9rZW4CD2Fzc2V0QWRkZWRJZFN0cgZhbW91bnQEB1BTdXBwbHkJARlnZXRWaXJ0dWFsUG9vbFRva2VuQW1vdW50AAQLYXNzZXRQYXJhbXMJARVsb2FkR2xvYmFsVG9rZW5QYXJhbXMBBQ9hc3NldEFkZGVkSWRTdHIEEGFzc2V0RmFjdEJhbGFuY2UIBQthc3NldFBhcmFtcwJfMgQQYXNzZXRWaXJ0QmFsYW5jZQgFC2Fzc2V0UGFyYW1zAl8xBAthc3NldFdlaWdodAkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwUPYXNzZXRBZGRlZElkU3RyAgdfd2VpZ2h0BAphc3NldFNjYWxlCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdzdGF0aWNfBQ9hc3NldEFkZGVkSWRTdHICBl9zY2FsZQQNYXNzZXREZWNpbWFscwkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwUPYXNzZXRBZGRlZElkU3RyAglfZGVjaW1hbHMEE1BJc3N1ZWROb011bHRpcGxpZXIJAGsDBQdQU3VwcGx5CQBlAgkAoAMBCQB2BgkAtgIBCQBkAgUKYXNzZXRTY2FsZQkAawMFBmFtb3VudAUKYXNzZXRTY2FsZQUQYXNzZXRWaXJ0QmFsYW5jZQUNYXNzZXREZWNpbWFscwkAtgIBBQthc3NldFdlaWdodAAEAAgFBERPV04FBlNjYWxlOAUGU2NhbGU4BAdhdmdDb25jCQEUY2FsY0F2Z0NvbmNlbnRyYXRpb24ABAdQSXNzdWVkCQBrAwUTUElzc3VlZE5vTXVsdGlwbGllcggFB2F2Z0NvbmMCXzIIBQdhdmdDb25jAl8xBA5hc3NldFBhcmFtc1VwZAkAmgoICQBkAgUQYXNzZXRWaXJ0QmFsYW5jZQUGYW1vdW50CQBkAgUQYXNzZXRGYWN0QmFsYW5jZQUGYW1vdW50CAULYXNzZXRQYXJhbXMCXzMIBQthc3NldFBhcmFtcwJfNAgFC2Fzc2V0UGFyYW1zAl81CAULYXNzZXRQYXJhbXMCXzYIBQthc3NldFBhcmFtcwJfNwgFC2Fzc2V0UGFyYW1zAl84CQCUCgIJAMwIAgkBFXNhdmVHbG9iYWxUb2tlblBhcmFtcwIFD2Fzc2V0QWRkZWRJZFN0cgUOYXNzZXRQYXJhbXNVcGQFA25pbAUHUElzc3VlZAEWY2FsY1JlZGVlbVdpdGhPbmVUb2tlbgINYXNzZXRPdXRJZFN0cglQUmVkZWVtZWQEB1BTdXBwbHkJARlnZXRWaXJ0dWFsUG9vbFRva2VuQW1vdW50AAQLYXNzZXRQYXJhbXMJARVsb2FkR2xvYmFsVG9rZW5QYXJhbXMBBQ1hc3NldE91dElkU3RyBBBhc3NldEZhY3RCYWxhbmNlCAULYXNzZXRQYXJhbXMCXzIEEGFzc2V0VmlydEJhbGFuY2UIBQthc3NldFBhcmFtcwJfMQQLYXNzZXRXZWlnaHQJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18FDWFzc2V0T3V0SWRTdHICB193ZWlnaHQECmFzc2V0U2NhbGUJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18FDWFzc2V0T3V0SWRTdHICBl9zY2FsZQQNYXNzZXREZWNpbWFscwkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwUNYXNzZXRPdXRJZFN0cgIJX2RlY2ltYWxzBBVhbW91bnRPdXROb011bGl0cGxpZXIJAGsDBRBhc3NldFZpcnRCYWxhbmNlCQBlAgUGU2NhbGU4CQCgAwEJAHYGCQC2AgEJAGUCBQphc3NldFNjYWxlCQBrAwUJUFJlZGVlbWVkBQphc3NldFNjYWxlBQdQU3VwcGx5BQ1hc3NldERlY2ltYWxzCQC2AgEJAGsDAJBOAJBOBQthc3NldFdlaWdodAAEAAgFBERPV04FBlNjYWxlOAQHYXZnQ29uYwkBFGNhbGNBdmdDb25jZW50cmF0aW9uAAQJYW1vdW50T3V0CQBrAwUVYW1vdW50T3V0Tm9NdWxpdHBsaWVyCAUHYXZnQ29uYwJfMQgFB2F2Z0NvbmMCXzIDCQBmAgUJYW1vdW50T3V0BRBhc3NldEZhY3RCYWxhbmNlCQACAQI0bm8gYXZhaWxhYmxlIGZhY3QgbGlxdWlkaXR5IHRvIHdpdGhkcmF3IGluIG9uZSB0b2tlbgQOYXNzZXRQYXJhbXNVcGQJAJoKCAkAZQIFEGFzc2V0VmlydEJhbGFuY2UFCWFtb3VudE91dAkAZQIFEGFzc2V0RmFjdEJhbGFuY2UFCWFtb3VudE91dAgFC2Fzc2V0UGFyYW1zAl8zCAULYXNzZXRQYXJhbXMCXzQIBQthc3NldFBhcmFtcwJfNQgFC2Fzc2V0UGFyYW1zAl82CAULYXNzZXRQYXJhbXMCXzcIBQthc3NldFBhcmFtcwJfOAkAlAoCCQDMCAIJARVzYXZlR2xvYmFsVG9rZW5QYXJhbXMCBQ1hc3NldE91dElkU3RyBQ5hc3NldFBhcmFtc1VwZAUDbmlsBQlhbW91bnRPdXQBFmhhbmRsZVBvb2xUb2tlbnNSZWRlZW0CCVBSZWRlZW1lZAt1c2VyQWRkcmVzcwoBEWhhbmRsZVRva2VuUmVkZWVtAgVhY2N1bQd0b2tlbklkBAphc3NldElkU3RyCQEOZ2V0QXNzZXRTdHJpbmcBBQd0b2tlbklkBAthc3NldFBhcmFtcwkBFWxvYWRHbG9iYWxUb2tlblBhcmFtcwEFCmFzc2V0SWRTdHIEAkJrCAULYXNzZXRQYXJhbXMCXzIEB1BTdXBwbHkJARlnZXRWaXJ0dWFsUG9vbFRva2VuQW1vdW50AAQNdG9rZW5EZWNpbWFscwkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwUKYXNzZXRJZFN0cgIGX3NjYWxlBAZwc3VwcGwJAL0CBAkAuQICCQC2AgEJAGUCBQdQU3VwcGx5BQlQUmVkZWVtZWQJALYCAQUGU2NhbGU4CQC2AgEFBlNjYWxlOAkAtgIBBQdQU3VwcGx5BQRET1dOBAZhbW91bnQJAKADAQkAvQIECQC4AgIJALYCAQUHU2NhbGUxNgUGcHN1cHBsCQC2AgEFAkJrCQC2AgEFB1NjYWxlMTYFCEhBTEZFVkVOBAl1bnN0YWtlVHgJAQ91bnN0YWtlSWZOZWVkZWQCBQphc3NldElkU3RyBQZhbW91bnQDCQAAAgUJdW5zdGFrZVR4BQl1bnN0YWtlVHgEE3NlbGxvZmZTdGFydEJhbGFuY2UDCQECIT0CCAULYXNzZXRQYXJhbXMCXzgJAGgCCQBpAgUGaGVpZ2h0AGQAZAgFC2Fzc2V0UGFyYW1zAl83CQBrAwgFC2Fzc2V0UGFyYW1zAl83CQBlAgUHUFN1cHBseQUJUFJlZGVlbWVkBQdQU3VwcGx5BA5hc3NldFBhcmFtc1VwZAkAmgoICQBrAwgFC2Fzc2V0UGFyYW1zAl8xCQBlAgUHUFN1cHBseQUJUFJlZGVlbWVkBQdQU3VwcGx5CQBlAggFC2Fzc2V0UGFyYW1zAl8yBQZhbW91bnQIBQthc3NldFBhcmFtcwJfMwgFC2Fzc2V0UGFyYW1zAl80CAULYXNzZXRQYXJhbXMCXzUIBQthc3NldFBhcmFtcwJfNgUTc2VsbG9mZlN0YXJ0QmFsYW5jZQgFC2Fzc2V0UGFyYW1zAl84CQDOCAIJAM4IAgUFYWNjdW0JAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwULdXNlckFkZHJlc3MFBmFtb3VudAUHdG9rZW5JZAUDbmlsCQDMCAIJARVzYXZlR2xvYmFsVG9rZW5QYXJhbXMCBQphc3NldElkU3RyBQ5hc3NldFBhcmFtc1VwZAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCgACJGwFCGFzc2V0SWRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARFoYW5kbGVUb2tlblJlZGVlbQIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjRfMgIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgESY2FsY3VsYXRlT3V0QW1vdW50BQhBbW91bnRJbgdhc3NldEluCGFzc2V0T3V0CUJhbGFuY2VJbgpCYWxhbmNlT3V0BAdJbmRleEluCQEFdmFsdWUBCQDPCAIFCGFzc2V0SWRzBQdhc3NldEluBAhJbmRleE91dAkBBXZhbHVlAQkAzwgCBQhhc3NldElkcwUIYXNzZXRPdXQDCQAAAgUHSW5kZXhJbgUISW5kZXhPdXQFCEFtb3VudEluCQBuBAUKQmFsYW5jZU91dAkAZQIJAGgCBQZTY2FsZTgFBlNjYWxlOAkAoAMBCQB2BgkAvQIECQC5AgIJALYCAQUJQmFsYW5jZUluCQC2AgEAkE4JALYCAQkAaAIFBlNjYWxlOAUGU2NhbGU4CQC5AgIJALYCAQkAZAIFCUJhbGFuY2VJbgUIQW1vdW50SW4JALYCAQCQTgUGSEFMRlVQABAJALYCAQkAawMJAJEDAgUNQXNzZXRzV2VpZ2h0cwUHSW5kZXhJbgCAoJSljR0JAJEDAgUNQXNzZXRzV2VpZ2h0cwUISW5kZXhPdXQADAAQBQdDRUlMSU5HCQBoAgUGU2NhbGU4BQZTY2FsZTgFCEhBTEZFVkVOAQtjbGFpbVJlc3VsdAEHYWRkcmVzcwQKYWRkcmVzc1N0cgkApQgBBQdhZGRyZXNzBAtpbmRleEFtb3VudAkBDXRyeUdldEludGVnZXIBCQCsAgIFCmFkZHJlc3NTdHICDF9pbmRleFN0YWtlZAQLZmVlQXNzZXRTdHIJAQx0cnlHZXRTdHJpbmcBAg9zdGF0aWNfZmVlVG9rZW4EDmZlZUFzc2V0UGFyYW1zCQEVbG9hZEdsb2JhbFRva2VuUGFyYW1zAQULZmVlQXNzZXRTdHIED2ZlZVRva2VuQmFsYW5jZQgFDmZlZUFzc2V0UGFyYW1zAl8xCgEHaGFuZGxlcgIFYWNjdW0HYXNzZXRJZAQKYXNzZXRJZFN0cgkBDmdldEFzc2V0U3RyaW5nAQUHYXNzZXRJZAQLYXNzZXRQYXJhbXMJARVsb2FkR2xvYmFsVG9rZW5QYXJhbXMBBQphc3NldElkU3RyBBRjdXJyZW50VG9rZW5JbnRlcmVzdAgFC2Fzc2V0UGFyYW1zAl80BAhhQmFsYW5jZQgFC2Fzc2V0UGFyYW1zAl8xBAxyZXdhcmRBbW91bnQJAGsDBQtpbmRleEFtb3VudAkAZQIFFGN1cnJlbnRUb2tlbkludGVyZXN0CQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICCQCsAgIFCmFkZHJlc3NTdHICC19sYXN0Q2hlY2tfBQphc3NldElkU3RyAglfaW50ZXJlc3QFB1NjYWxlMTYECnVuc3Rha2VJbnYJAQ91bnN0YWtlSWZOZWVkZWQCBQphc3NldElkU3RyBQxyZXdhcmRBbW91bnQDCQAAAgUKdW5zdGFrZUludgUKdW5zdGFrZUludgQIdHJhbnNmZXIDCQAAAgUMcmV3YXJkQW1vdW50AAAFA25pbAkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDBQdhZGRyZXNzBQxyZXdhcmRBbW91bnQFB2Fzc2V0SWQFA25pbAkAlAoCCQDOCAIJAM4IAggFBWFjY3VtAl8xBQh0cmFuc2ZlcgkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgIJAKwCAgUKYWRkcmVzc1N0cgILX2xhc3RDaGVja18FCmFzc2V0SWRTdHICCV9pbnRlcmVzdAUUY3VycmVudFRva2VuSW50ZXJlc3QFA25pbAkAZAIIBQVhY2N1bQJfMgkBEWNhbGN1bGF0ZVVzZFZhbHVlBAUHYXNzZXRJZAUMcmV3YXJkQW1vdW50BQhhQmFsYW5jZQUPZmVlVG9rZW5CYWxhbmNlCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBAVhY2N1bQoAAiRsBQxlYXJuZWRBc3NldHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwCQCUCgIFA25pbAAACgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQdoYW5kbGVyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY0XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNF8yAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKCQCUCgIJAM4IAggFBWFjY3VtAl8xCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIFCmFkZHJlc3NTdHICEV9jbGFpbWVkUmV3YXJkVVNECQBkAgkBDXRyeUdldEludGVnZXIBCQCsAgIFCmFkZHJlc3NTdHICEV9jbGFpbWVkUmV3YXJkVVNECAUFYWNjdW0CXzIJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgUKYWRkcmVzc1N0cgIKX2xhc3RDbGFpbQgFCWxhc3RCbG9jawl0aW1lc3RhbXAFA25pbAgFBWFjY3VtAl8yARBpbmRleFN0YWtlUmVzdWx0AgphZGRyZXNzU3RyBmFtb3VudAQCbGkICQELY2xhaW1SZXN1bHQBCQERQGV4dHJOYXRpdmUoMTA2MikBBQphZGRyZXNzU3RyAl8xCQDOCAIFAmxpCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIFCmFkZHJlc3NTdHICDF9pbmRleFN0YWtlZAkAZAIJAQ10cnlHZXRJbnRlZ2VyAQkArAICBQphZGRyZXNzU3RyAgxfaW5kZXhTdGFrZWQFBmFtb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgISZ2xvYmFsX2luZGV4U3Rha2VkCQBkAgkBDXRyeUdldEludGVnZXIBAhJnbG9iYWxfaW5kZXhTdGFrZWQFBmFtb3VudAUDbmlsAQNzdW0CBWFjY3VtAW4JAGQCBQVhY2N1bQkBDXBhcnNlSW50VmFsdWUBBQFuAQ1jaGVja0ZlZUFzc2V0AgVhY2N1bQRuZXh0AwMJAQIhPQIJAM8IAgUVc3VwcG9ydGVkRmVlQXNzZXRzU3RyBQRuZXh0BQR1bml0CQAAAgUFYWNjdW0CAAcFBG5leHQFBWFjY3VtARJjYWxjSW50ZXJlc3RDaGFuZ2UCCmFzc2V0SWRTdHIFbHBGZWUECnRvdGFsSW5kZXgJAQ10cnlHZXRJbnRlZ2VyAQISZ2xvYmFsX2luZGV4U3Rha2VkBA1pbnRlcmVzdERlbHRhCQBrAwUFbHBGZWUFB1NjYWxlMTYFCnRvdGFsSW5kZXgFDWludGVyZXN0RGVsdGEBDnVwZFNlbGxvZmZEYXRhBAphc3NldElkU3RyCGFtb3VudEluB2JhbGFuY2UNc2VsbG9mZlBhcmFtcwQNY3VycmVudFBlcmlvZAkAaAIJAGkCBQZoZWlnaHQAZABkBApwcmV2UGVyaW9kCAUNc2VsbG9mZlBhcmFtcwJfMgQLcHJldlNlbGxvZmYDCQAAAgUNY3VycmVudFBlcmlvZAUKcHJldlBlcmlvZAgFDXNlbGxvZmZQYXJhbXMCXzEAAAQTc2VsbG9mZlN0YXJ0QmFsYW5jZQMJAAACBQ1jdXJyZW50UGVyaW9kBQpwcmV2UGVyaW9kCAUNc2VsbG9mZlBhcmFtcwJfMwUHYmFsYW5jZQQMc2VsbG9mZkRlbHRhCQBrAwUHU2NhbGUxNgUIYW1vdW50SW4FE3NlbGxvZmZTdGFydEJhbGFuY2UECm1heFNlbGxvZmYJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18FCmFzc2V0SWRTdHICC19tYXhTZWxsb2ZmAwMJAGYCCQBkAgULcHJldlNlbGxvZmYFDHNlbGxvZmZEZWx0YQUKbWF4U2VsbG9mZgkBAiE9AgUKbWF4U2VsbG9mZgAABwkAAgEJAKwCAgIjbWF4IHNlbGxvZmYgcmVhY2hlZCBmb3IgdGhpcyBhc3NldCAFCmFzc2V0SWRTdHIEBnN0YXJ0SAMJAAACBQ1jdXJyZW50UGVyaW9kBQpwcmV2UGVyaW9kBQpwcmV2UGVyaW9kBQ1jdXJyZW50UGVyaW9kBAZzdGFydEIDCQAAAgUNY3VycmVudFBlcmlvZAUKcHJldlBlcmlvZAgFDXNlbGxvZmZQYXJhbXMCXzMFE3NlbGxvZmZTdGFydEJhbGFuY2UJAJUKAwkAZAIFC3ByZXZTZWxsb2ZmBQxzZWxsb2ZmRGVsdGEFBnN0YXJ0SAUGc3RhcnRCARJnZXRUbXBSZWJhbGFuY2VJZHMBDW5ld0Fzc2V0SWRzTGkEEWN1cnJlbnRBc3NldElkc0xpCQC1CQIJAQx0cnlHZXRTdHJpbmcBAg9zdGF0aWNfdG9rZW5JZHMCASwEBnJlc3VsdAUNbmV3QXNzZXRJZHNMaQoBAWYCBWFjY3VtB2Fzc2V0SWQDCQAAAgkAzwgCBQZyZXN1bHQFB2Fzc2V0SWQFBHVuaXQJAM4IAgUFYWNjdW0JAMwIAgUHYXNzZXRJZAUDbmlsBQVhY2N1bQoAAiRsBRFjdXJyZW50QXNzZXRJZHNMaQoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFBnJlc3VsdAoBBSRmNF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEBZgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjRfMgIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgERY2hlY2tUb2tlbnNDaGFuZ2UBDW5ld0Fzc2V0SWRzTGkEEWN1cnJlbnRBc3NldElkc0xpCQC1CQIJAQx0cnlHZXRTdHJpbmcBAg9zdGF0aWNfdG9rZW5JZHMCASwKAQNyZW0CBWFjY3VtB2Fzc2V0SWQDCQAAAgkAzwgCBQ1uZXdBc3NldElkc0xpBQdhc3NldElkBQR1bml0CQBkAgUFYWNjdW0AAQUFYWNjdW0KAQNhZGQCBWFjY3VtB2Fzc2V0SWQDCQAAAgkAzwgCBRFjdXJyZW50QXNzZXRJZHNMaQUHYXNzZXRJZAUEdW5pdAkAZAIFBWFjY3VtAAEFBWFjY3VtBAdyZW1vdmVkCgACJGwFEWN1cnJlbnRBc3NldElkc0xpCgACJHMJAJADAQUCJGwKAAUkYWNjMAAACgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQNyZW0CBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjRfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY0XzICCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoEBWFkZGVkCgACJGwFDW5ld0Fzc2V0SWRzTGkKAAIkcwkAkAMBBQIkbAoABSRhY2MwAAAKAQUkZjVfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBA2FkZAIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNV8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjVfMgIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgkAZAIFB3JlbW92ZWQFBWFkZGVkARB2YWxpZGF0ZVBheW1lbnRzAgphc3NldHNMaXN0CHBheW1lbnRzCgEQZ2V0UGF5bWVudEFzc2V0cwIFYWNjdW0EbmV4dAMJAGcCAAAIBQRuZXh0BmFtb3VudAkAAgEJAKwCAgkArAICCQCsAgICG1RvbyBsb3cgcGF5bWVudCBhbW91bnQgZm9yIAkBDmdldEFzc2V0U3RyaW5nAQgFBG5leHQHYXNzZXRJZAICOiAJAKQDAQgFBG5leHQGYW1vdW50CQDOCAIFBWFjY3VtCQDMCAIJAQ5nZXRBc3NldFN0cmluZwEIBQRuZXh0B2Fzc2V0SWQFA25pbAQLcGF5bWVudExpc3QKAAIkbAUIcGF5bWVudHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjRfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBEGdldFBheW1lbnRBc3NldHMCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjRfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY0XzICCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECCQEFJGY0XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoKAQJmMQIFYWNjdW0EbmV4dAMJAAACCQDPCAIFCmFzc2V0c0xpc3QFBG5leHQFBHVuaXQJAAIBCQCsAgIJAKwCAgUEbmV4dAI5IGFzc2V0IGlzIHByZXNlbnQgaW4gcGF5bWVudHMsIGJ1dCBpcyBub3QgaW4gbmV3IGFzc2V0czogCQC5CQIFCmFzc2V0c0xpc3QCASwJAGQCBQVhY2N1bQABCgECZjICBWFjY3VtBG5leHQDCQAAAgkAzwgCBQtwYXltZW50TGlzdAUEbmV4dAUEdW5pdAkAAgEJAKwCAgkArAICBQRuZXh0AjkgYXNzZXQgaXMgcHJlc2VudCBpbiBuZXcgYXNzZXRzLCBidXQgaXMgbm90IGluIHBheW1lbnRzOiAJALkJAgULcGF5bWVudExpc3QCASwJAGQCBQVhY2N1bQABBAJhMQoAAiRsBQtwYXltZW50TGlzdAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAAAAoBBSRmNV8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQECZjECBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjVfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGY1XzICCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECCQEFJGY1XzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoEAmEyCgACJGwFCmFzc2V0c0xpc3QKAAIkcwkAkAMBBQIkbAoABSRhY2MwAAAKAQUkZjZfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBAmYyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY2XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNl8yAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKCQBkAgUCYTEFAmEyAQ92YWxpZGF0ZVdlaWdodHMBB3dlaWdodHMKAQF2AgVhY2N1bQF3BAR3SW50CQETdmFsdWVPckVycm9yTWVzc2FnZQIJALYJAQUBdwkArAICAhVXcm9uZyB3ZWlnaHQgZm9ybWF0OiAFAXcDAwkAZgIFCk1JTl9XRUlHSFQFBHdJbnQGCQBmAgUEd0ludAUKTUFYX1dFSUdIVAkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICAhpXZWlnaHQgc2hvdWxkIGJlIGluIHJhbmdlIAkApAMBBQpNSU5fV0VJR0hUAgMgLSAJAKQDAQUKTUFYX1dFSUdIVAILLCBjdXJyZW50OiAFAXcJAGQCBQVhY2N1bQUEd0ludAoAAiRsBQd3ZWlnaHRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAAACgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQF2AgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY0XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNF8yAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgkBBSRmNF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAQdnZXRQMVAyAgphc3NldElkU3RyDmJhc2VBc3NldElkU3RyBAthc3NldFBhcmFtcwkBFWxvYWRHbG9iYWxUb2tlblBhcmFtcwEFCmFzc2V0SWRTdHIED2Jhc2VBc3NldFBhcmFtcwkBFWxvYWRHbG9iYWxUb2tlblBhcmFtcwEFDmJhc2VBc3NldElkU3RyBAJCMQgFD2Jhc2VBc3NldFBhcmFtcwJfMQQCQjIIBQthc3NldFBhcmFtcwJfMQQCRjEIBQ9iYXNlQXNzZXRQYXJhbXMCXzIEAkYyCAULYXNzZXRQYXJhbXMCXzIEAlMxCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdzdGF0aWNfBQ5iYXNlQXNzZXRJZFN0cgIGX3NjYWxlBAJTMgkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwUKYXNzZXRJZFN0cgIGX3NjYWxlBAJEMQkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwUOYmFzZUFzc2V0SWRTdHICCV9kZWNpbWFscwQCRDIJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18FCmFzc2V0SWRTdHICCV9kZWNpbWFscwQCVzEJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18FDmJhc2VBc3NldElkU3RyAgdfd2VpZ2h0BAJXMgkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwUKYXNzZXRJZFN0cgIHX3dlaWdodAQEVzFXMgkAawMFAlcxAJBOBQJXMgQEVzJXMQkAawMFAlcyAJBOBQJXMQQNcDFfdW53ZWlnaHRlZAkAawMJAGUCBQJCMQUCRjEFAlMxCQBrAwUCQjIJAGwGCQBrAwUCQjEFAlMxCQBlAgUCQjEFAkYxBQJEMQUEVzFXMgAEBQJEMQUHQ0VJTElORwUCUzIEAnAxCQBrAwUNcDFfdW53ZWlnaHRlZAUEVzJXMQCQTgMJAAACBQJCMgUCRjIJAJQKAgUCcDEFBHVuaXQEDXAyX3Vud2VpZ2h0ZWQJAGsDCQBrAwUCQjEJAGwGCQBrAwUCQjIFAlMyCQBlAgUCQjIFAkYyBQJEMgUEVzJXMQAEBQJEMgUFRkxPT1IFAlMyBQJTMgkAZQIFAkIyBQJGMgQCcDIJAGsDBQ1wMl91bndlaWdodGVkBQRXMlcxAJBOCQCUCgIFAnAxBQJwMhEBaQETYWRkVW5kZXJseWluZ1N0YWtlcgINc3Rha2VyQWRkcmVzcwphc3NldElkU3RyAwkBAiE9AgUEdGhpcwgFAWkGY2FsbGVyCQACAQIKYWRtaW4gb25seQkAzAgCCQELU3RyaW5nRW50cnkCCQCsAgICF3N0YXRpY19zdGFraW5nQ29udHJhY3RfBQphc3NldElkU3RyBQ1zdGFrZXJBZGRyZXNzBQNuaWwBaQEHcHJlSW5pdAcLYXNzZXRJZHNTdHIPYXNzZXRXZWlnaHRzU3RyEmFzc2V0TWF4U2VsbG9mZlN0cg5iYXNlVG9rZW5JZFN0cgpwb29sRG9tYWluCXBvb2xPd25lcgNmZWUEEHBvb2xPd25lckFkZHJlc3MJARFAZXh0ck5hdGl2ZSgxMDYyKQEFCXBvb2xPd25lcgQNYXNzZXRJZHNTdHJMaQkAtQkCBQthc3NldElkc1N0cgIBLAQUYXNzZXRNYXhTZWxsb2ZmU3RyTGkJALUJAgUSYXNzZXRNYXhTZWxsb2ZmU3RyAgEsBBFhc3NldFdlaWdodHNTdHJMaQkAtQkCBQ9hc3NldFdlaWdodHNTdHICASwECmFzc2V0SWRzTGkKAAIkbAUNYXNzZXRJZHNTdHJMaQoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmNF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQETYWRkQXNzZXRCeXRlc1RvTGlzdAIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjRfMgIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgQRZmVlQXNzZXRDaG9zZW5TdHIKAAIkbAUNYXNzZXRJZHNTdHJMaQoAAiRzCQCQAwEFAiRsCgAFJGFjYzACAAoBBSRmNV8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQENY2hlY2tGZWVBc3NldAIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNV8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjVfMgIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIJAQUkZjVfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgQLZmVlQXNzZXRTdHIDCQAAAgURZmVlQXNzZXRDaG9zZW5TdHICAAUOYmFzZVRva2VuSWRTdHIFEWZlZUFzc2V0Q2hvc2VuU3RyAwkBCmlzU2h1dGRvd24ACQACAQITY29udHJhY3QgaXMgb24gc3RvcAMJAQIhPQIFBHRoaXMIBQFpBmNhbGxlcgkAAgECCmFkbWluIG9ubHkDCQBmAgkAsQIBBQpwb29sRG9tYWluAA0JAAIBAhV0b28gbGFyZ2UgcG9vbCBkb21haW4DAwkAZgIFA2ZlZQD0AwYJAGYCAAAFA2ZlZQkAAgECKmZlZSB2YWx1ZSBtdXN0IGJlIGJldHdlZW4gMCBhbmQgNTAwICgwLTUlKQMJAQIhPQIJAQ92YWxpZGF0ZVdlaWdodHMBBRFhc3NldFdlaWdodHNTdHJMaQCQTgkAAgEJAKwCAgImd2VpZ2h0cyBzdW0gc2hvdWxkIGJlIDEwMDAwLCBjdXJyZW50OiAJAKQDAQkBD3ZhbGlkYXRlV2VpZ2h0cwEFEWFzc2V0V2VpZ2h0c1N0ckxpCgETYWRkVG9rZW5EYXRhRW50cmllcwIFYWNjdW0IYXNzZXROdW0DCQBnAgUIYXNzZXROdW0JAJADAQUKYXNzZXRJZHNMaQUFYWNjdW0EE2Fzc2V0U3Rha2luZ0FkZHJlc3MKAAFACQD8BwQFD3Bvb2xzSHViQWRkcmVzcwIQdXNlRW1wdHlDb250cmFjdAkAzAgCCQCsAgICB3N0YWtlcl8JAJEDAgUNYXNzZXRJZHNTdHJMaQUIYXNzZXROdW0FA25pbAUDbmlsAwkAAQIFAUACBlN0cmluZwUBQAkAAgEJAKwCAgkAAwEFAUACGyBjb3VsZG4ndCBiZSBjYXN0IHRvIFN0cmluZwMJAAACBRNhc3NldFN0YWtpbmdBZGRyZXNzBRNhc3NldFN0YWtpbmdBZGRyZXNzBA1hc3NldERlY2ltYWxzBAckbWF0Y2gwCQCRAwIFCmFzc2V0SWRzTGkFCGFzc2V0TnVtAwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEAXgFByRtYXRjaDAICQEFdmFsdWUBCQDsBwEFAXgIZGVjaW1hbHMACAkAzggCCQDOCAIFBWFjY3VtCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgIHc3RhdGljXwkAkQMCBQ1hc3NldElkc1N0ckxpBQhhc3NldE51bQIGX3NjYWxlCQBsBgAKAAAFDWFzc2V0RGVjaW1hbHMAAAAABQRET1dOCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgIHc3RhdGljXwkAkQMCBQ1hc3NldElkc1N0ckxpBQhhc3NldE51bQIJX2RlY2ltYWxzBQ1hc3NldERlY2ltYWxzCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgIHc3RhdGljXwkAkQMCBQ1hc3NldElkc1N0ckxpBQhhc3NldE51bQIHX3dlaWdodAkBBXZhbHVlAQkAtgkBCQCRAwIFEWFzc2V0V2VpZ2h0c1N0ckxpBQhhc3NldE51bQkAzAgCCQELU3RyaW5nRW50cnkCCQCsAgICF3N0YXRpY19zdGFraW5nQ29udHJhY3RfCQCRAwIFDWFzc2V0SWRzU3RyTGkFCGFzc2V0TnVtBRNhc3NldFN0YWtpbmdBZGRyZXNzBQNuaWwDCQAAAgkAkQMCBRRhc3NldE1heFNlbGxvZmZTdHJMaQUIYXNzZXROdW0CAAUDbmlsCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgIHc3RhdGljXwkAkQMCBQ1hc3NldElkc1N0ckxpBQhhc3NldE51bQILX21heFNlbGxvZmYJAGgCCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUUYXNzZXRNYXhTZWxsb2ZmU3RyTGkFCGFzc2V0TnVtBQdTY2FsZTEyBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAM4IAgoAAiRsCQDMCAIAAAkAzAgCAAEJAMwIAgACCQDMCAIAAwkAzAgCAAQJAMwIAgAFCQDMCAIABgkAzAgCAAcJAMwIAgAICQDMCAIACQUDbmlsCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGY2XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARNhZGRUb2tlbkRhdGFFbnRyaWVzAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGY2XzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmNl8yAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgkBBSRmNl8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKCQDMCAIJAQtTdHJpbmdFbnRyeQICD3N0YXRpY190b2tlbklkcwULYXNzZXRJZHNTdHIJAMwIAgkBC1N0cmluZ0VudHJ5AgIPc3RhdGljX2ZlZVRva2VuBQtmZWVBc3NldFN0cgkAzAgCCQELU3RyaW5nRW50cnkCAhNzdGF0aWNfdG9rZW5XZWlnaHRzBQ9hc3NldFdlaWdodHNTdHIJAMwIAgkBDEludGVnZXJFbnRyeQICE3N0YXRpY190b2tlbnNBbW91bnQJAJADAQUKYXNzZXRJZHNMaQkAzAgCCQELU3RyaW5nRW50cnkCAhFzdGF0aWNfcG9vbERvbWFpbgUKcG9vbERvbWFpbgkAzAgCCQELU3RyaW5nRW50cnkCAhZzdGF0aWNfcG9vbFRva2VuX2lkU3RyAgAJAMwIAgkBC1N0cmluZ0VudHJ5AgISc3RhdGljX2Jhc2VUb2tlbklkBQ5iYXNlVG9rZW5JZFN0cgkAzAgCCQELU3RyaW5nRW50cnkCAhBzdGF0aWNfcG9vbE93bmVyBQlwb29sT3duZXIJAMwIAgkBDEludGVnZXJFbnRyeQICCnN0YXRpY19mZWUFA2ZlZQkAzAgCCQEMSW50ZWdlckVudHJ5AgIMc3RhdGljX0tNdWx0BQdTY2FsZTE2CQDMCAIJAQxJbnRlZ2VyRW50cnkCAhJnbG9iYWxfaW5kZXhTdGFrZWQAAAkAzAgCCQEMSW50ZWdlckVudHJ5AgIXZ2xvYmFsX3Bvb2xUb2tlbl9hbW91bnQAAAkAzAgCCQEMSW50ZWdlckVudHJ5AgITZ2xvYmFsX3dhc1ByZUluaXRlZAABBQNuaWwBaQEGZGVJbml0AAMJAQppc1NodXRkb3duAAkAAgECE2NvbnRyYWN0IGlzIG9uIHN0b3ADCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAAIBAgphZG1pbiBvbmx5CQDMCAIJAQxJbnRlZ2VyRW50cnkCAhBnbG9iYWxfd2FzSW5pdGVkAAAFA25pbAFpAQRpbml0Bwthc3NldElkc1N0cg9hc3NldFdlaWdodHNTdHISYXNzZXRNYXhTZWxsb2ZmU3RyDmJhc2VUb2tlbklkU3RyCnBvb2xEb21haW4DZmVlDHZCYWxhbmNlc1N0cgQKcHJlSW5pdEludgkA/AcEBQR0aGlzAgdwcmVJbml0CQDMCAIFC2Fzc2V0SWRzU3RyCQDMCAIFD2Fzc2V0V2VpZ2h0c1N0cgkAzAgCBRJhc3NldE1heFNlbGxvZmZTdHIJAMwIAgUOYmFzZVRva2VuSWRTdHIJAMwIAgUKcG9vbERvbWFpbgkAzAgCCQClCAEIBQFpBmNhbGxlcgkAzAgCBQNmZWUFA25pbAUDbmlsAwkAAAIFCnByZUluaXRJbnYFCnByZUluaXRJbnYECXZCYWxhbmNlcwkBEXBhcnN0U3RyVG9JbnRMaXN0AQUMdkJhbGFuY2VzU3RyCgEQZ2V0UGF5bWVudEFtb3VudAEKYXNzZXRJZFN0cgoBB2hhbmRsZXICBWFjY3VtB3BheW1lbnQDCQAAAgkBDmdldEFzc2V0U3RyaW5nAQgFB3BheW1lbnQHYXNzZXRJZAUKYXNzZXRJZFN0cggFB3BheW1lbnQGYW1vdW50BQVhY2N1bQoAAiRsCAUBaQhwYXltZW50cwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAAAAoBBSRmNF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEHaGFuZGxlcgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjRfMgIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgoBC3ByZXBhcmVMaXN0AAoBB2hhbmRsZXICBWFjY3VtB2Fzc2V0SWQECmFzc2V0SWRTdHIJAQ5nZXRBc3NldFN0cmluZwEFB2Fzc2V0SWQEAW4JAQV2YWx1ZQEJAM8IAgUIYXNzZXRJZHMFB2Fzc2V0SWQEDXBheW1lbnRBbW91bnQJARBnZXRQYXltZW50QW1vdW50AQUKYXNzZXRJZFN0cgQLYXNzZXRQYXJhbXMJARVsb2FkR2xvYmFsVG9rZW5QYXJhbXMBBQphc3NldElkU3RyBA5hc3NldFBhcmFtc1VwZAkAmgoICQCRAwIFCXZCYWxhbmNlcwUBbgUNcGF5bWVudEFtb3VudAgFC2Fzc2V0UGFyYW1zAl8zCAULYXNzZXRQYXJhbXMCXzQIBQthc3NldFBhcmFtcwJfNQgFC2Fzc2V0UGFyYW1zAl82CAULYXNzZXRQYXJhbXMCXzcIBQthc3NldFBhcmFtcwJfOAkAzggCBQVhY2N1bQkAzAgCCQEVc2F2ZUdsb2JhbFRva2VuUGFyYW1zAgUKYXNzZXRJZFN0cgUOYXNzZXRQYXJhbXNVcGQFA25pbAoAAiRsBQhhc3NldElkcwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmNF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEHaGFuZGxlcgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjRfMgIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgoBGWNhbGN1bGF0ZVBvb2xUb2tlbnNBbW91bnQBB2Fzc2V0SWQKAQdoYW5kbGVyAgVhY2N1bQdhc3NldElkCgEIaGFuZGxlcjICBWFjY3VtAW4DCQAAAgUBbgUHYXNzZXRJZAkBBXZhbHVlAQkAzwgCBQhhc3NldElkcwUBbgUFYWNjdW0EBVRva2VuCgACJGwFCGFzc2V0SWRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAABCgEFJGY0XzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQhoYW5kbGVyMgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjRfMgIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgkAawMFBWFjY3VtCQBsBgkAkQMCBQl2QmFsYW5jZXMFBVRva2VuCQCRAwIFCERlY2ltYWxzBQVUb2tlbgkAkQMCBQ1Bc3NldHNXZWlnaHRzBQVUb2tlbgUVQXNzZXRzV2VpZ2h0c0RlY2ltYWxzAAgFBUZMT09SBQZTY2FsZTgKAAIkbAUIYXNzZXRJZHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQ5Qb29sVG9rZW5TY2FsZQoBBSRmNF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEHaGFuZGxlcgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjRfMgIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgMJAQppc1NodXRkb3duAAkAAgECE2NvbnRyYWN0IGlzIG9uIHN0b3ADCQAAAgkAkAMBCAUBaQhwYXltZW50cwAACQACAQI5YXQgbGVhc3Qgc29tZSBvZiB0aGUgYXNzZXRzIHNob3VsZCBiZSBwcm92aWRlZCBhcyBwYXltZW50AwkAZgIJAQ10cnlHZXRJbnRlZ2VyAQIQZ2xvYmFsX3dhc0luaXRlZAAACQACAQITcG9vbCBhbHJlYWR5IGluaXRlZAQRaW5pdGlhbFBvb2xUb2tlbnMJARljYWxjdWxhdGVQb29sVG9rZW5zQW1vdW50AQUIYXNzZXRJZHMEDG5vdGlmeUludm9rZQkA/AcEBQ9wb29sc0h1YkFkZHJlc3MCC2FkZFNlbGZQb29sBQNuaWwFA25pbAMJAAACBQxub3RpZnlJbnZva2UFDG5vdGlmeUludm9rZQMJAAACBRFpbml0aWFsUG9vbFRva2VucwAACQACAQIyeW91IG5lZWQgYSBiaWdnZXIgdG9rZW5zIGFtb3VudCB0byBsYXVuY2ggdGhlIHBvb2wJAM4IAgkBC3ByZXBhcmVMaXN0AAkAzAgCCQEMSW50ZWdlckVudHJ5AgIXZ2xvYmFsX3Bvb2xUb2tlbl9hbW91bnQFEWluaXRpYWxQb29sVG9rZW5zCQDMCAIJAQxJbnRlZ2VyRW50cnkCAhBnbG9iYWxfd2FzSW5pdGVkAAEJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkApQgBCAUBaQZjYWxsZXICDF9pbmRleFN0YWtlZAURaW5pdGlhbFBvb2xUb2tlbnMJAMwIAgkBDEludGVnZXJFbnRyeQICEmdsb2JhbF9pbmRleFN0YWtlZAURaW5pdGlhbFBvb2xUb2tlbnMFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ1nZW5lcmF0ZUluZGV4AQpuZWVkQ2hhbmdlAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwUBVAkAAgEJAKwCAgI7eW91IG5lZWQgdG8gYXR0YWNoIGFsbCBwb29sIHRva2Vucy4gYW1vdW50IG9mIHBvb2wgdG9rZW5zOiAJAKQDAQUBVAMJAQEhAQkBE2NoZWNrVG9rZW5zVmFsaWRpdHkBCAUBaQhwYXltZW50cwkAAgECFXdyb25nIGFzc2V0cyBhdHRhY2hlZAQNUElzc3VlZE5vTXVsdAkBDWdldE1pblBJc3N1ZWQBCAUBaQhwYXltZW50cwQGcmVzdWx0CQETaGFuZGxlUG9vbFRva2Vuc0FkZAQFDVBJc3N1ZWROb011bHQIBQFpCHBheW1lbnRzCAUBaQxvcmlnaW5DYWxsZXIFCm5lZWRDaGFuZ2UED1BJc3N1ZWRXaXRoTXVsdAkAbgQFDVBJc3N1ZWROb011bHQFB1NjYWxlMTYJAQhnZXRLTXVsdAAFBERPV04JAJQKAgkAzggCCQDOCAIJAM4IAgUGcmVzdWx0CAkBC2NsYWltUmVzdWx0AQgFAWkGY2FsbGVyAl8xCQERbWludEluZGV4SWZOZWVkZWQBBQ9QSXNzdWVkV2l0aE11bHQJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkApQgBCAUBaQZjYWxsZXICDF9pbmRleFN0YWtlZAkAZAIJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQClCAEIBQFpBmNhbGxlcgIMX2luZGV4U3Rha2VkBQ9QSXNzdWVkV2l0aE11bHQJAMwIAgkBDEludGVnZXJFbnRyeQICEmdsb2JhbF9pbmRleFN0YWtlZAkAZAIJAQ10cnlHZXRJbnRlZ2VyAQISZ2xvYmFsX2luZGV4U3Rha2VkBQ9QSXNzdWVkV2l0aE11bHQJAMwIAgkBDEludGVnZXJFbnRyeQICF2dsb2JhbF9wb29sVG9rZW5fYW1vdW50CQBkAgkBDXRyeUdldEludGVnZXIBAhdnbG9iYWxfcG9vbFRva2VuX2Ftb3VudAUPUElzc3VlZFdpdGhNdWx0BQNuaWwFD1BJc3N1ZWRXaXRoTXVsdAFpAQtyZWRlZW1JbmRleAEPcG9vbFRva2VuQW1vdW50AwkAZgIFD3Bvb2xUb2tlbkFtb3VudAkBDXRyeUdldEludGVnZXIBCQCsAgIJAKUIAQgFAWkGY2FsbGVyAgxfaW5kZXhTdGFrZWQJAAIBAix1c2VyIGRvZXNuJ3QgaGF2ZSB0aGlzIGFtb3VudCBvZiBwb29sIHRva2VucwMJAQppc1NodXRkb3duAAkAAgECE2NvbnRyYWN0IGlzIG9uIHN0b3AEEVBSZWRlZW1lZFdpdGhNdWx0BQ9wb29sVG9rZW5BbW91bnQEE1BSZWRlZW1lZFdpdGhOb011bHQJAG4EBRFQUmVkZWVtZWRXaXRoTXVsdAkBCGdldEtNdWx0AAUHU2NhbGUxNgUERE9XTgQGcmVzdWx0CQEWaGFuZGxlUG9vbFRva2Vuc1JlZGVlbQIFE1BSZWRlZW1lZFdpdGhOb011bHQIBQFpBmNhbGxlcgkAzggCCQDOCAIJAM4IAgUGcmVzdWx0CAkBC2NsYWltUmVzdWx0AQgFAWkGY2FsbGVyAl8xCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKUIAQgFAWkGY2FsbGVyAgxfaW5kZXhTdGFrZWQJAGUCCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkApQgBCAUBaQZjYWxsZXICDF9pbmRleFN0YWtlZAURUFJlZGVlbWVkV2l0aE11bHQJAMwIAgkBDEludGVnZXJFbnRyeQICEmdsb2JhbF9pbmRleFN0YWtlZAkAZQIJAQ10cnlHZXRJbnRlZ2VyAQISZ2xvYmFsX2luZGV4U3Rha2VkBRFQUmVkZWVtZWRXaXRoTXVsdAkAzAgCCQEMSW50ZWdlckVudHJ5AgIXZ2xvYmFsX3Bvb2xUb2tlbl9hbW91bnQJAGUCCQENdHJ5R2V0SW50ZWdlcgECF2dsb2JhbF9wb29sVG9rZW5fYW1vdW50BRFQUmVkZWVtZWRXaXRoTXVsdAUDbmlsCQERYnVybkluZGV4SWZOZWVkZWQBBQ9wb29sVG9rZW5BbW91bnQBaQEKc3Rha2VJbmRleAAECmFkZHJlc3NTdHIJAKUIAQgFAWkMb3JpZ2luQ2FsbGVyBANwbXQJAJEDAggFAWkIcGF5bWVudHMAAAMJAQIhPQIJAQV2YWx1ZQEIBQNwbXQHYXNzZXRJZAkA2QQBCQEMdHJ5R2V0U3RyaW5nAQIWc3RhdGljX3Bvb2xUb2tlbl9pZFN0cgkAAgECFHdyb25nIGFzc2V0IGF0dGFjaGVkCQEQaW5kZXhTdGFrZVJlc3VsdAIFCmFkZHJlc3NTdHIIBQNwbXQGYW1vdW50AWkBDXN0YWtlSW5kZXhGb3IBCmFkZHJlc3NTdHIEA3BtdAkAkQMCCAUBaQhwYXltZW50cwAAAwkBAiE9AgkBBXZhbHVlAQgFA3BtdAdhc3NldElkCQDZBAEJAQx0cnlHZXRTdHJpbmcBAhZzdGF0aWNfcG9vbFRva2VuX2lkU3RyCQACAQIUd3JvbmcgYXNzZXQgYXR0YWNoZWQJARBpbmRleFN0YWtlUmVzdWx0AgUKYWRkcmVzc1N0cggFA3BtdAZhbW91bnQBaQEMdW5zdGFrZUluZGV4AQtpbmRleEFtb3VudAoBCmlzc3VlSW5kZXgABAVpc3N1ZQkAwwgHCQCsAgICA1BSIAkBDHRyeUdldFN0cmluZwECEXN0YXRpY19wb29sRG9tYWluAhJQdXp6bGUgUmFuZ2UgSW5kZXgJAQ10cnlHZXRJbnRlZ2VyAQIXZ2xvYmFsX3Bvb2xUb2tlbl9hbW91bnQFEVBvb2xUb2tlbkRlY2ltYWxzBgUEdW5pdAAABA5wb29sVG9rZW5JZFN0cgkA2AQBCQC4CAEFBWlzc3VlCQCUCgIJAMwIAgUFaXNzdWUJAMwIAgkBC1N0cmluZ0VudHJ5AgIWc3RhdGljX3Bvb2xUb2tlbl9pZFN0cgUOcG9vbFRva2VuSWRTdHIFA25pbAUOcG9vbFRva2VuSWRTdHIEDSR0MDQwNDA4NDA1NzQDCQAAAgkBDHRyeUdldFN0cmluZwECFnN0YXRpY19wb29sVG9rZW5faWRTdHICAAkBCmlzc3VlSW5kZXgACQCUCgIFA25pbAkBDHRyeUdldFN0cmluZwECFnN0YXRpY19wb29sVG9rZW5faWRTdHIEFHBvb2xUb2tlbklzc3VlUmVzdWx0CAUNJHQwNDA0MDg0MDU3NAJfMQQOcG9vbFRva2VuSWRTdHIIBQ0kdDA0MDQwODQwNTc0Al8yBAtwb29sVG9rZW5JZAkA2QQBBQ5wb29sVG9rZW5JZFN0cgQKYWRkcmVzc1N0cgkApQgBCAUBaQZjYWxsZXIEDmluZGV4QXZhaWxhYmxlCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgUKYWRkcmVzc1N0cgIMX2luZGV4U3Rha2VkAwkBCmlzU2h1dGRvd24ACQACAQITY29udHJhY3QgaXMgb24gc3RvcAMJAGYCBQtpbmRleEFtb3VudAUOaW5kZXhBdmFpbGFibGUJAAIBAiV5b3UgZG9uJ3QgaGF2ZSBpbmRleCB0b2tlbnMgYXZhaWxhYmxlAwkBCmlzU2h1dGRvd24ACQACAQITY29udHJhY3QgaXMgb24gc3RvcAkAzggCCQDOCAIFFHBvb2xUb2tlbklzc3VlUmVzdWx0CAkBC2NsYWltUmVzdWx0AQkBEUBleHRyTmF0aXZlKDEwNjIpAQUKYWRkcmVzc1N0cgJfMQkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICBQphZGRyZXNzU3RyAgxfaW5kZXhTdGFrZWQJAGUCBQ5pbmRleEF2YWlsYWJsZQULaW5kZXhBbW91bnQJAMwIAgkBDEludGVnZXJFbnRyeQICEmdsb2JhbF9pbmRleFN0YWtlZAkAZQIJAQ10cnlHZXRJbnRlZ2VyAQISZ2xvYmFsX2luZGV4U3Rha2VkBQtpbmRleEFtb3VudAkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCAUBaQZjYWxsZXIFC2luZGV4QW1vdW50BQtwb29sVG9rZW5JZAUDbmlsAWkBEWNsYWltSW5kZXhSZXdhcmRzAAMJAQppc1NodXRkb3duAAkAAgECE2NvbnRyYWN0IGlzIG9uIHN0b3AJAQtjbGFpbVJlc3VsdAEIBQFpBmNhbGxlcgFpAQ1ldmFsdWF0ZUNsYWltAQR1c2VyCQCUCgIFA25pbAgJAQtjbGFpbVJlc3VsdAEJARFAZXh0ck5hdGl2ZSgxMDYyKQEFBHVzZXICXzIBaQETYWRkSW50ZXJlc3RFeHRlcm5hbAAEB2Fzc2V0SWQICQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAAHYXNzZXRJZAQKYXNzZXRJZFN0cgkBDmdldEFzc2V0U3RyaW5nAQUHYXNzZXRJZAQGYW1vdW50CAkAkQMCCAUBaQhwYXltZW50cwAABmFtb3VudAQHc3Rha2VUeAkBDXN0YWtlSWZOZWVkZWQCBQphc3NldElkU3RyBQZhbW91bnQDCQAAAgUHc3Rha2VUeAUHc3Rha2VUeAMJAAACCQDPCAIFCGFzc2V0SWRzBQdhc3NldElkBQR1bml0CQACAQIweW91IGNhbiBvbmx5IGFkZCBpbnRlcmVzdCBmb3IgYXNzZXRzIGluIHRoZSBwb29sBAZwYXJhbXMJARVsb2FkR2xvYmFsVG9rZW5QYXJhbXMBBQphc3NldElkU3RyBA1pbnRlcmVzdERlbHRhCQESY2FsY0ludGVyZXN0Q2hhbmdlAgUKYXNzZXRJZFN0cgUGYW1vdW50BAl1cGRQYXJhbXMJAJoKCAgFBnBhcmFtcwJfMQgFBnBhcmFtcwJfMggFBnBhcmFtcwJfMwkAZAIIBQZwYXJhbXMCXzQFDWludGVyZXN0RGVsdGEJAGQCCAUGcGFyYW1zAl81BQZhbW91bnQIBQZwYXJhbXMCXzYIBQZwYXJhbXMCXzcIBQZwYXJhbXMCXzgJAMwIAgkBFXNhdmVHbG9iYWxUb2tlblBhcmFtcwIFCmFzc2V0SWRTdHIFCXVwZFBhcmFtcwUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBFG5vdGlmeVN0YWtpbmdQYXltZW50Agphc3NldElkU3RyBmFtb3VudAQHYXNzZXRJZAkBDWdldEFzc2V0Qnl0ZXMBBQphc3NldElkU3RyAwkAAAIJAM8IAgUIYXNzZXRJZHMFB2Fzc2V0SWQFBHVuaXQJAAIBAjB5b3UgY2FuIG9ubHkgYWRkIGludGVyZXN0IGZvciBhc3NldHMgaW4gdGhlIHBvb2wDCQECIT0CCQEMdHJ5R2V0U3RyaW5nAQkArAICAhdzdGF0aWNfc3Rha2luZ0NvbnRyYWN0XwUKYXNzZXRJZFN0cgkApQgBCAUBaQZjYWxsZXIJAAIBAiZjYW4gb25seSBiZSBpbnZva2VkIGJ5IHN0YWtlciBjb250cmFjdAQGcGFyYW1zCQEVbG9hZEdsb2JhbFRva2VuUGFyYW1zAQUKYXNzZXRJZFN0cgQNaW50ZXJlc3REZWx0YQkBEmNhbGNJbnRlcmVzdENoYW5nZQIFCmFzc2V0SWRTdHIFBmFtb3VudAQJdXBkUGFyYW1zCQCaCggIBQZwYXJhbXMCXzEIBQZwYXJhbXMCXzIIBQZwYXJhbXMCXzMJAGQCCAUGcGFyYW1zAl80BQ1pbnRlcmVzdERlbHRhCQBkAggFBnBhcmFtcwJfNQUGYW1vdW50CAUGcGFyYW1zAl82CAUGcGFyYW1zAl83CAUGcGFyYW1zAl84CQDMCAIJARVzYXZlR2xvYmFsVG9rZW5QYXJhbXMCBQphc3NldElkU3RyBQl1cGRQYXJhbXMFA25pbAFpAQRzd2FwAghhc3NldE91dAdtaW5pbXVtBANwbXQDCQAAAgkAkAMBCAUBaQhwYXltZW50cwABCQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAAJAAIBAiFwbGVhc2UgYXR0YWNoIGV4YWN0bHkgb25lIHBheW1lbnQECEFtb3VudEluCQEFdmFsdWUBCAkAkQMCCAUBaQhwYXltZW50cwAABmFtb3VudAQHQXNzZXRJbggFA3BtdAdhc3NldElkBAhBc3NldE91dAkBDWdldEFzc2V0Qnl0ZXMBBQhhc3NldE91dAQHYXNzZXRJbgkBDmdldEFzc2V0U3RyaW5nAQUHQXNzZXRJbgQHc2NhbGVJbgkAaQIFBlNjYWxlOAkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwUHYXNzZXRJbgIGX3NjYWxlBAhzY2FsZU91dAkAaQIFBlNjYWxlOAkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwUIYXNzZXRPdXQCBl9zY2FsZQQNYXNzZXRJblBhcmFtcwkBFWxvYWRHbG9iYWxUb2tlblBhcmFtcwEJAQ5nZXRBc3NldFN0cmluZwEFB0Fzc2V0SW4EDmFzc2V0T3V0UGFyYW1zCQEVbG9hZEdsb2JhbFRva2VuUGFyYW1zAQUIYXNzZXRPdXQEDkFzc2V0SW5CYWxhbmNlCAUNYXNzZXRJblBhcmFtcwJfMQQSQXNzZXRJbkZhY3RCYWxhbmNlCAUNYXNzZXRJblBhcmFtcwJfMgQRYXNzZXRJbkZlZXNFYXJuZWQIBQ1hc3NldEluUGFyYW1zAl8zBBhhc3NldEluTGFzdENoZWNrSW50ZXJlc3QIBQ1hc3NldEluUGFyYW1zAl80BA9Bc3NldE91dEJhbGFuY2UIBQ5hc3NldE91dFBhcmFtcwJfMQQTYXNzZXRPdXRGYWN0QmFsYW5jZQgFDmFzc2V0T3V0UGFyYW1zAl8yBBRBc3NldEluQmFsYW5jZVNjYWxlZAkAaAIFDkFzc2V0SW5CYWxhbmNlBQdzY2FsZUluBBVBc3NldE91dEJhbGFuY2VTY2FsZWQJAGgCBQ9Bc3NldE91dEJhbGFuY2UFCHNjYWxlT3V0BAtmZWVBbW91bnRJbgkAawMFCEFtb3VudEluBQNGZWUFCEZlZVNjYWxlBA1jbGVhbkFtb3VudEluCQBlAgUIQW1vdW50SW4FC2ZlZUFtb3VudEluBBNjbGVhbkFtb3VudEluU2NhbGVkCQBoAgUNY2xlYW5BbW91bnRJbgUHc2NhbGVJbgQKQW1vdW50T3V0MQkBEmNhbGN1bGF0ZU91dEFtb3VudAUFE2NsZWFuQW1vdW50SW5TY2FsZWQFB0Fzc2V0SW4FCEFzc2V0T3V0BRRBc3NldEluQmFsYW5jZVNjYWxlZAUVQXNzZXRPdXRCYWxhbmNlU2NhbGVkBAlBbW91bnRPdXQJAGsDBQpBbW91bnRPdXQxAAEFCHNjYWxlT3V0BBBBc3NldE91dEJhbGFuY2UyCQBlAgUPQXNzZXRPdXRCYWxhbmNlBQlBbW91bnRPdXQED0Fzc2V0SW5CYWxhbmNlMgkAZAIFDkFzc2V0SW5CYWxhbmNlBQ1jbGVhbkFtb3VudEluAwkAZgIFB21pbmltdW0FCUFtb3VudE91dAkAAgECKWFtb3VudCB0byByZWNpZXZlIGlzIGxvd2VyIHRoYW4gZ2l2ZW4gb25lAwkAAAIFCEFzc2V0T3V0BQdBc3NldEluCQACAQIYdGhpcyBzd2FwIGlzIG5vdCBhbGxvd2VkAwkAZgIAAAkAZQIFE2Fzc2V0T3V0RmFjdEJhbGFuY2UFCUFtb3VudE91dAkAAgECG2NvbnRyYWN0IGlzIG91dCBvZiByZXNlcnZlcwMJAQppc1NodXRkb3duAAkAAgECE2NvbnRyYWN0IGlzIG9uIHN0b3ADCQELdmFsdWVPckVsc2UCCQCbCAIFD3Bvb2xzSHViQWRkcmVzcwkArAICAhJnbG9iYWxfc2h1dGRvd25Jbl8FB2Fzc2V0SW4HCQACAQIbdG9rZW4gSU4gdHJhZGVzIGFyZSBzdG9wcGVkAwkBC3ZhbHVlT3JFbHNlAgkAmwgCBQ9wb29sc0h1YkFkZHJlc3MJAKwCAgITZ2xvYmFsX3NodXRkb3duT3V0XwUIYXNzZXRPdXQHCQACAQIcdG9rZW4gT1VUIHRyYWRlcyBhcmUgc3RvcHBlZAQLcHJvdG9jb2xGZWUJAGsDBQtmZWVBbW91bnRJbgAFAAoEBWxwRmVlCQBlAgULZmVlQW1vdW50SW4FC3Byb3RvY29sRmVlBA1pbnRlcmVzdERlbHRhCQESY2FsY0ludGVyZXN0Q2hhbmdlAgUHYXNzZXRJbgUFbHBGZWUEB3N0YWtlVHgJAQ1zdGFrZUlmTmVlZGVkAgUHYXNzZXRJbgkAZAIFDWNsZWFuQW1vdW50SW4FBWxwRmVlAwkAAAIFB3N0YWtlVHgFB3N0YWtlVHgECXVuc3Rha2VUeAkBD3Vuc3Rha2VJZk5lZWRlZAIFCGFzc2V0T3V0BQlBbW91bnRPdXQDCQAAAgUJdW5zdGFrZVR4BQl1bnN0YWtlVHgEDG5ld0JhbGFuY2VJbgUPQXNzZXRJbkJhbGFuY2UyBA1uZXdCYWxhbmNlT3V0BRBBc3NldE91dEJhbGFuY2UyBBJhc3NldEluU2VsbG9mZkRhdGEJAQ51cGRTZWxsb2ZmRGF0YQQFB2Fzc2V0SW4FDWNsZWFuQW1vdW50SW4FDkFzc2V0SW5CYWxhbmNlCQCVCgMIBQ1hc3NldEluUGFyYW1zAl82CAUNYXNzZXRJblBhcmFtcwJfNwgFDWFzc2V0SW5QYXJhbXMCXzgEE2Fzc2V0T3V0U2VsbG9mZkRhdGEJAQ51cGRTZWxsb2ZmRGF0YQQFCGFzc2V0T3V0CQEBLQEFCUFtb3VudE91dAUPQXNzZXRPdXRCYWxhbmNlCQCVCgMIBQ5hc3NldE91dFBhcmFtcwJfNggFDmFzc2V0T3V0UGFyYW1zAl83CAUOYXNzZXRPdXRQYXJhbXMCXzgEEmFzc2V0SW5GaW5hbFBhcmFtcwkAmgoIBQxuZXdCYWxhbmNlSW4JAGQCBRJBc3NldEluRmFjdEJhbGFuY2UFDWNsZWFuQW1vdW50SW4JAGQCBRFhc3NldEluRmVlc0Vhcm5lZAUFbHBGZWUJAGQCBRhhc3NldEluTGFzdENoZWNrSW50ZXJlc3QFDWludGVyZXN0RGVsdGEIBQ1hc3NldEluUGFyYW1zAl81CAUSYXNzZXRJblNlbGxvZmZEYXRhAl8xCAUSYXNzZXRJblNlbGxvZmZEYXRhAl8yCAUSYXNzZXRJblNlbGxvZmZEYXRhAl8zBBNhc3NldE91dEZpbmFsUGFyYW1zCQCaCggFDW5ld0JhbGFuY2VPdXQJAGUCBRNhc3NldE91dEZhY3RCYWxhbmNlBQlBbW91bnRPdXQIBQ5hc3NldE91dFBhcmFtcwJfMwgFDmFzc2V0T3V0UGFyYW1zAl80CAUOYXNzZXRPdXRQYXJhbXMCXzUIBRNhc3NldE91dFNlbGxvZmZEYXRhAl8xCAUTYXNzZXRPdXRTZWxsb2ZmRGF0YQJfMggFE2Fzc2V0T3V0U2VsbG9mZkRhdGECXzMEDWFzc2V0SW5DaGFuZ2UJARVzYXZlR2xvYmFsVG9rZW5QYXJhbXMCBQdhc3NldEluBRJhc3NldEluRmluYWxQYXJhbXMEDmFzc2V0T3V0Q2hhbmdlCQEVc2F2ZUdsb2JhbFRva2VuUGFyYW1zAgUIYXNzZXRPdXQFE2Fzc2V0T3V0RmluYWxQYXJhbXMEC2ZlZUFzc2V0U3RyCQEMdHJ5R2V0U3RyaW5nAQIPc3RhdGljX2ZlZVRva2VuBA5mZWVBc3NldFBhcmFtcwkBFWxvYWRHbG9iYWxUb2tlblBhcmFtcwEFC2ZlZUFzc2V0U3RyBA9mZWVUb2tlbkJhbGFuY2UIBQ5mZWVBc3NldFBhcmFtcwJfMQQPdm9sdW1lVXNkVXBkYXRlCQERY2FsY3VsYXRlVXNkVmFsdWUEBQdBc3NldEluBQhBbW91bnRJbgUOQXNzZXRJbkJhbGFuY2UFD2ZlZVRva2VuQmFsYW5jZQkAlAoCCQDMCAIFDWFzc2V0SW5DaGFuZ2UJAMwIAgUOYXNzZXRPdXRDaGFuZ2UJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwgFAWkGY2FsbGVyBQlBbW91bnRPdXQFCEFzc2V0T3V0CQDMCAIJAQxJbnRlZ2VyRW50cnkCAhFnbG9iYWxfdm9sdW1lX3VzZAkAZAIJAQ10cnlHZXRJbnRlZ2VyAQIRZ2xvYmFsX3ZvbHVtZV91c2QFD3ZvbHVtZVVzZFVwZGF0ZQkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDBQtmZWVzQWRkcmVzcwULcHJvdG9jb2xGZWUJAQ1nZXRBc3NldEJ5dGVzAQUHYXNzZXRJbgUDbmlsBQlBbW91bnRPdXQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEMc3dhcFJlYWRPbmx5Awdhc3NldEluCGFzc2V0T3V0CEFtb3VudEluBAdBc3NldEluCQENZ2V0QXNzZXRCeXRlcwEFB2Fzc2V0SW4ECEFzc2V0T3V0CQENZ2V0QXNzZXRCeXRlcwEFCGFzc2V0T3V0BAdzY2FsZUluCQBpAgUGU2NhbGU4CQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdzdGF0aWNfBQdhc3NldEluAgZfc2NhbGUECHNjYWxlT3V0CQBpAgUGU2NhbGU4CQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdzdGF0aWNfBQhhc3NldE91dAIGX3NjYWxlBA5mZWVBc3NldE91dFN0cgkBDHRyeUdldFN0cmluZwECD3N0YXRpY19mZWVUb2tlbgQLZmVlQXNzZXRPdXQDCQAAAgUOZmVlQXNzZXRPdXRTdHICAAULdXNkbkFzc2V0SWQJAQ1nZXRBc3NldEJ5dGVzAQUOZmVlQXNzZXRPdXRTdHIEDWFzc2V0SW5QYXJhbXMJARVsb2FkR2xvYmFsVG9rZW5QYXJhbXMBCQEOZ2V0QXNzZXRTdHJpbmcBBQdBc3NldEluBA5hc3NldE91dFBhcmFtcwkBFWxvYWRHbG9iYWxUb2tlblBhcmFtcwEFCGFzc2V0T3V0BA5Bc3NldEluQmFsYW5jZQgFDWFzc2V0SW5QYXJhbXMCXzEEEkFzc2V0SW5GYWN0QmFsYW5jZQgFDWFzc2V0SW5QYXJhbXMCXzIEEWFzc2V0SW5GZWVzRWFybmVkCAUNYXNzZXRJblBhcmFtcwJfMwQYYXNzZXRJbkxhc3RDaGVja0ludGVyZXN0CAUNYXNzZXRJblBhcmFtcwJfNAQPQXNzZXRPdXRCYWxhbmNlCAUOYXNzZXRPdXRQYXJhbXMCXzEEE2Fzc2V0T3V0RmFjdEJhbGFuY2UIBQ5hc3NldE91dFBhcmFtcwJfMgQUQXNzZXRJbkJhbGFuY2VTY2FsZWQJAGgCBQ5Bc3NldEluQmFsYW5jZQUHc2NhbGVJbgQVQXNzZXRPdXRCYWxhbmNlU2NhbGVkCQBoAgUPQXNzZXRPdXRCYWxhbmNlBQhzY2FsZU91dAQLZmVlQW1vdW50SW4JAGsDBQhBbW91bnRJbgUDRmVlBQhGZWVTY2FsZQQNY2xlYW5BbW91bnRJbgkAZQIFCEFtb3VudEluBQtmZWVBbW91bnRJbgQTY2xlYW5BbW91bnRJblNjYWxlZAkAaAIFDWNsZWFuQW1vdW50SW4FB3NjYWxlSW4ECkFtb3VudE91dDEJARJjYWxjdWxhdGVPdXRBbW91bnQFBRNjbGVhbkFtb3VudEluU2NhbGVkBQdBc3NldEluBQhBc3NldE91dAUUQXNzZXRJbkJhbGFuY2VTY2FsZWQFFUFzc2V0T3V0QmFsYW5jZVNjYWxlZAQJQW1vdW50T3V0CQBrAwUKQW1vdW50T3V0MQABBQhzY2FsZU91dAQQQXNzZXRPdXRCYWxhbmNlMgkAZQIFD0Fzc2V0T3V0QmFsYW5jZQUJQW1vdW50T3V0BA9Bc3NldEluQmFsYW5jZTIJAGQCBQ5Bc3NldEluQmFsYW5jZQUNY2xlYW5BbW91bnRJbgMJAAACBQhBc3NldE91dAUHQXNzZXRJbgkAAgECGHRoaXMgc3dhcCBpcyBub3QgYWxsb3dlZAMJAGYCAAAJAGUCCAUOYXNzZXRPdXRQYXJhbXMCXzIFCUFtb3VudE91dAkAAgECG2NvbnRyYWN0IGlzIG91dCBvZiByZXNlcnZlcwMJAQppc1NodXRkb3duAAkAAgECE2NvbnRyYWN0IGlzIG9uIHN0b3AJAJQKAgUDbmlsBQlBbW91bnRPdXQBaQERdHJhbnNmZXJPd25lcnNoaXABD25ld093bmVyQWRkcmVzcwMJAQIhPQIJAKUIAQgFAWkGY2FsbGVyCQEMdHJ5R2V0U3RyaW5nAQIQc3RhdGljX3Bvb2xPd25lcgkAAgECJ3RoaXMgY2FsbCBhdmFpbGFibGUgb25seSBmb3IgcG9vbCBvd25lcgkAzAgCCQELU3RyaW5nRW50cnkCAhBzdGF0aWNfcG9vbE93bmVyBQ9uZXdPd25lckFkZHJlc3MFA25pbAFpAQZzZXRGZWUBBm5ld0ZlZQMJAQIhPQIJAKUIAQgFAWkGY2FsbGVyCQEMdHJ5R2V0U3RyaW5nAQIQc3RhdGljX3Bvb2xPd25lcgkAAgECJ3RoaXMgY2FsbCBhdmFpbGFibGUgb25seSBmb3IgcG9vbCBvd25lcgkAzAgCCQEMSW50ZWdlckVudHJ5AgIKc3RhdGljX2ZlZQUGbmV3RmVlBQNuaWwBAnR4AQZ2ZXJpZnkACQD0AwMIBQJ0eAlib2R5Qnl0ZXMJAJEDAggFAnR4BnByb29mcwAABQxtYXN0ZXJQdWJLZXmSQK2p", "height": 363747, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: BUcchNnomoftgCqjrqWAhbA7Qht2ENSkf8u7woKAvUwS Next: none Diff:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let VERSION = "PZ-3.6.0 PROD"
4+let VERSION = "PZ-3.6.1 PROD-refactor"
55
66 let configStr = valueOrElse(getString(this, "configAddress"), "3PMoEibdLeWqcURQ8351XhaWwyacDc7G4e5")
77
1515
1616 let Scale8 = 100000000
1717
18+let Scale8_BI = toBigInt(Scale8)
19+
1820 let Scale12 = 1000000000000
1921
2022 let Scale16 = 10000000000000000
23+
24+let Scale16_BI = toBigInt(Scale16)
2125
2226 let FeeScale = 10000
2327
8892 case _ =>
8993 wavesBalance(this).available
9094 }
91-
92-
93-func getFactBalance (assetIdStr) = tryGetInteger((("global_" + assetIdStr) + "_factBalance"))
9495
9596
9697 func addAssetBytesToList (accum,item) = (accum ++ [getAssetBytes(item)])
243244
244245 let earnedAssets = assetIds
245246
247+func _get (assetId,param) = tryGetInteger(((("global_" + assetId) + "_") + param))
248+
249+
250+func _get_feesEarned (assetId) = tryGetInteger(("global_feesEarned_" + assetId))
251+
252+
253+func _get_lastCheck_interest (assetId) = tryGetInteger((("global_lastCheck_" + assetId) + "_interest"))
254+
255+
256+func _get_extraEarned (assetId) = tryGetInteger(("global_extraEarned_" + assetId))
257+
258+
259+func loadGlobalTokenParams (assetId) = match getString(("globalParams_" + assetId)) {
260+ case p: String =>
261+ let params = split(p, "__")
262+ $Tuple8(parseIntValue(params[0]), parseIntValue(params[1]), parseIntValue(params[2]), parseIntValue(params[3]), parseIntValue(params[4]), parseIntValue(params[5]), parseIntValue(params[6]), parseIntValue(params[7]))
263+ case _ =>
264+ $Tuple8(_get(assetId, "balance"), _get(assetId, "factBalance"), _get_feesEarned(assetId), _get_lastCheck_interest(assetId), _get_extraEarned(assetId), _get(assetId, "selloff"), _get(assetId, "selloffStartBalance"), _get(assetId, "selloffStartHeight"))
265+}
266+
267+
268+func saveGlobalTokenParams (assetId,params) = StringEntry(("globalParams_" + assetId), makeString([toString(params._1), toString(params._2), toString(params._3), toString(params._4), toString(params._5), toString(params._6), toString(params._7), toString(params._8)], "__"))
269+
270+
246271 func isShutdown () = {
247272 let shutdownAddress = addressFromString(shutdownAddressStr)
248273 if ((shutdownAddress == unit))
256281 }
257282
258283
284+func getFactBalance (assetIdStr) = {
285+ let assetParams = loadGlobalTokenParams(assetIdStr)
286+ assetParams._2
287+ }
288+
289+
259290 func getCurrentTokenBalance (tokenNum) = {
260291 let tokenIdStr = getAssetString(assetIds[tokenNum])
261- tryGetInteger((("global_" + tokenIdStr) + "_balance"))
292+ let tokenParams = loadGlobalTokenParams(tokenIdStr)
293+ tokenParams._1
262294 }
263295
264296
380412 }
381413
382414
383-func calculateUsdValue (assetId,amount,aBalance) = {
415+func calculateUsdValue (assetId,amount,aBalance,feeAssetBalance) = {
384416 let assetWeight = tryGetInteger((("static_" + getAssetString(assetId)) + "_weight"))
385417 let feeAssetStr = tryGetString("static_feeToken")
386418 let feeAssetScale = getIntegerValue(this, (("static_" + feeAssetStr) + "_scale"))
387419 let feeAssetNum = value(indexOf(assetIds, getAssetBytes(feeAssetStr)))
388420 let feeAssetWeight = AssetsWeights[feeAssetNum]
389- let feeAssetBalance = tryGetInteger((("global_" + feeAssetStr) + "_balance"))
390- let valInFeeAsset = fraction(amount, (feeAssetBalance / feeAssetWeight), (aBalance / assetWeight))
421+ let _amount = (toBigInt(amount) * Scale8_BI)
422+ let _feeAssetData = (toBigInt(feeAssetBalance) / toBigInt(feeAssetWeight))
423+ let _assetData = fraction(toBigInt(aBalance), Scale8_BI, toBigInt(assetWeight))
424+ let valInFeeAsset = toInt(fraction(_amount, _feeAssetData, _assetData))
391425 let feeAssetPrice = getPriceFromOracle(feeAssetStr)
392426 fraction(valInFeeAsset, feeAssetPrice, feeAssetScale)
393427 }
397431 func f (accum,next) = {
398432 let assetIdStr = getAssetString(next)
399433 let weight = tryGetInteger((("static_" + assetIdStr) + "_weight"))
400- let assetFactBalance = tryGetInteger((("global_" + assetIdStr) + "_factBalance"))
401- let assetVirtBalance = tryGetInteger((("global_" + assetIdStr) + "_balance"))
434+ let assetParams = loadGlobalTokenParams(assetIdStr)
435+ let assetFactBalance = assetParams._2
436+ let assetVirtBalance = assetParams._1
402437 $Tuple2((accum._1 + fraction(assetFactBalance, weight, assetVirtBalance)), (accum._2 + weight))
403438 }
404439
484519
485520 func handleTokenChange (accum,tokenId) = {
486521 let assetIdStr = getAssetString(tokenId)
522+ let assetParams = loadGlobalTokenParams(assetIdStr)
487523 let paymentAmount = getTokenPaymentAmount(tokenId)
488- let Bk = getFactBalance(assetIdStr)
524+ let Bk = assetParams._2
489525 let PSupply = getVirtualPoolTokenAmount()
490526 let tokenDecimals = tryGetInteger((("static_" + assetIdStr) + "_scale"))
491527 let a1 = fraction((toBigInt((PSupply + PIssued)) * toBigInt(Scale8)), toBigInt(tokenDecimals), toBigInt(PSupply), CEILING)
499535 else false)
500536 then [ScriptTransfer(userAddress, toReturn, tokenId)]
501537 else nil
502- (((accum ++ t) ++ [IntegerEntry((("global_" + assetIdStr) + "_factBalance"), (tryGetInteger((("global_" + assetIdStr) + "_factBalance")) + Dk)), IntegerEntry((("global_" + assetIdStr) + "_balance"), fraction(tryGetInteger((("global_" + assetIdStr) + "_balance")), (PSupply + PIssued), PSupply))]) ++ (if ((tryGetInteger((("global_" + assetIdStr) + "_selloffStartHeight")) != ((height / 100) * 100)))
503- then nil
504- else [IntegerEntry((("global_" + assetIdStr) + "_selloffStartBalance"), fraction(tryGetInteger((("global_" + assetIdStr) + "_selloffStartBalance")), (PSupply + PIssued), PSupply))]))
538+ let selloffStartBalance = if ((assetParams._8 != ((height / 100) * 100)))
539+ then assetParams._7
540+ else fraction(assetParams._7, (PSupply + PIssued), PSupply)
541+ let assetParamsUpd = $Tuple8(fraction(assetParams._1, (PSupply + PIssued), PSupply, HALFEVEN), (assetParams._2 + Dk), assetParams._3, assetParams._4, assetParams._5, assetParams._6, selloffStartBalance, assetParams._8)
542+ ((accum ++ t) ++ [saveGlobalTokenParams(assetIdStr, assetParamsUpd)])
505543 }
506544 else throw("Strict value is not equal to itself.")
507545 }
523561
524562 func calcMintedWithOneToken (assetAddedIdStr,amount) = {
525563 let PSupply = getVirtualPoolTokenAmount()
526- let assetFactBalance = tryGetInteger((("global_" + assetAddedIdStr) + "_factBalance"))
527- let assetVirtBalance = tryGetInteger((("global_" + assetAddedIdStr) + "_balance"))
564+ let assetParams = loadGlobalTokenParams(assetAddedIdStr)
565+ let assetFactBalance = assetParams._2
566+ let assetVirtBalance = assetParams._1
528567 let assetWeight = tryGetInteger((("static_" + assetAddedIdStr) + "_weight"))
529568 let assetScale = tryGetInteger((("static_" + assetAddedIdStr) + "_scale"))
530569 let assetDecimals = tryGetInteger((("static_" + assetAddedIdStr) + "_decimals"))
531570 let PIssuedNoMultiplier = fraction(PSupply, (toInt(pow(toBigInt((assetScale + fraction(amount, assetScale, assetVirtBalance))), assetDecimals, toBigInt(assetWeight), 4, 8, DOWN)) - Scale8), Scale8)
532571 let avgConc = calcAvgConcentration()
533572 let PIssued = fraction(PIssuedNoMultiplier, avgConc._2, avgConc._1)
534- $Tuple2([IntegerEntry((("global_" + assetAddedIdStr) + "_factBalance"), (assetFactBalance + amount)), IntegerEntry((("global_" + assetAddedIdStr) + "_balance"), (assetVirtBalance + amount))], PIssued)
573+ let assetParamsUpd = $Tuple8((assetVirtBalance + amount), (assetFactBalance + amount), assetParams._3, assetParams._4, assetParams._5, assetParams._6, assetParams._7, assetParams._8)
574+ $Tuple2([saveGlobalTokenParams(assetAddedIdStr, assetParamsUpd)], PIssued)
535575 }
536576
537577
538578 func calcRedeemWithOneToken (assetOutIdStr,PRedeemed) = {
539579 let PSupply = getVirtualPoolTokenAmount()
540- let assetFactBalance = tryGetInteger((("global_" + assetOutIdStr) + "_factBalance"))
541- let assetVirtBalance = tryGetInteger((("global_" + assetOutIdStr) + "_balance"))
580+ let assetParams = loadGlobalTokenParams(assetOutIdStr)
581+ let assetFactBalance = assetParams._2
582+ let assetVirtBalance = assetParams._1
542583 let assetWeight = tryGetInteger((("static_" + assetOutIdStr) + "_weight"))
543584 let assetScale = tryGetInteger((("static_" + assetOutIdStr) + "_scale"))
544585 let assetDecimals = tryGetInteger((("static_" + assetOutIdStr) + "_decimals"))
547588 let amountOut = fraction(amountOutNoMulitplier, avgConc._1, avgConc._2)
548589 if ((amountOut > assetFactBalance))
549590 then throw("no available fact liquidity to withdraw in one token")
550- else $Tuple2([IntegerEntry((("global_" + assetOutIdStr) + "_factBalance"), (assetFactBalance - amountOut)), IntegerEntry((("global_" + assetOutIdStr) + "_balance"), (assetVirtBalance - amountOut))], amountOut)
591+ else {
592+ let assetParamsUpd = $Tuple8((assetVirtBalance - amountOut), (assetFactBalance - amountOut), assetParams._3, assetParams._4, assetParams._5, assetParams._6, assetParams._7, assetParams._8)
593+ $Tuple2([saveGlobalTokenParams(assetOutIdStr, assetParamsUpd)], amountOut)
594+ }
551595 }
552596
553597
554598 func handlePoolTokensRedeem (PRedeemed,userAddress) = {
555599 func handleTokenRedeem (accum,tokenId) = {
556600 let assetIdStr = getAssetString(tokenId)
557- let Bk = getFactBalance(assetIdStr)
601+ let assetParams = loadGlobalTokenParams(assetIdStr)
602+ let Bk = assetParams._2
558603 let PSupply = getVirtualPoolTokenAmount()
559604 let tokenDecimals = tryGetInteger((("static_" + assetIdStr) + "_scale"))
560605 let psuppl = fraction((toBigInt((PSupply - PRedeemed)) * toBigInt(Scale8)), toBigInt(Scale8), toBigInt(PSupply), DOWN)
561- let amount = toInt(fraction((toBigInt(Scale16) - psuppl), toBigInt(Bk), toBigInt(Scale16), CEILING))
606+ let amount = toInt(fraction((toBigInt(Scale16) - psuppl), toBigInt(Bk), toBigInt(Scale16), HALFEVEN))
562607 let unstakeTx = unstakeIfNeeded(assetIdStr, amount)
563608 if ((unstakeTx == unstakeTx))
564- then ((accum ++ [IntegerEntry((("global_" + assetIdStr) + "_factBalance"), (tryGetInteger((("global_" + assetIdStr) + "_factBalance")) - amount)), IntegerEntry((("global_" + assetIdStr) + "_balance"), fraction(tryGetInteger((("global_" + assetIdStr) + "_balance")), (PSupply - PRedeemed), PSupply)), ScriptTransfer(userAddress, amount, tokenId)]) ++ (if ((tryGetInteger((("global_" + assetIdStr) + "_selloffStartHeight")) != ((height / 100) * 100)))
565- then nil
566- else [IntegerEntry((("global_" + assetIdStr) + "_selloffStartBalance"), fraction(tryGetInteger((("global_" + assetIdStr) + "_selloffStartBalance")), (PSupply - PRedeemed), PSupply))]))
609+ then {
610+ let selloffStartBalance = if ((assetParams._8 != ((height / 100) * 100)))
611+ then assetParams._7
612+ else fraction(assetParams._7, (PSupply - PRedeemed), PSupply)
613+ let assetParamsUpd = $Tuple8(fraction(assetParams._1, (PSupply - PRedeemed), PSupply), (assetParams._2 - amount), assetParams._3, assetParams._4, assetParams._5, assetParams._6, selloffStartBalance, assetParams._8)
614+ ((accum ++ [ScriptTransfer(userAddress, amount, tokenId)]) ++ [saveGlobalTokenParams(assetIdStr, assetParamsUpd)])
615+ }
567616 else throw("Strict value is not equal to itself.")
568617 }
569618
594643 func claimResult (address) = {
595644 let addressStr = toString(address)
596645 let indexAmount = tryGetInteger((addressStr + "_indexStaked"))
646+ let feeAssetStr = tryGetString("static_feeToken")
647+ let feeAssetParams = loadGlobalTokenParams(feeAssetStr)
648+ let feeTokenBalance = feeAssetParams._1
597649 func handler (accum,assetId) = {
598650 let assetIdStr = getAssetString(assetId)
599- let currentTokenInterest = tryGetInteger((("global_lastCheck_" + assetIdStr) + "_interest"))
600- let aBalance = tryGetInteger((("global_" + getAssetString(assetId)) + "_balance"))
651+ let assetParams = loadGlobalTokenParams(assetIdStr)
652+ let currentTokenInterest = assetParams._4
653+ let aBalance = assetParams._1
601654 let rewardAmount = fraction(indexAmount, (currentTokenInterest - tryGetInteger((((addressStr + "_lastCheck_") + assetIdStr) + "_interest"))), Scale16)
602655 let unstakeInv = unstakeIfNeeded(assetIdStr, rewardAmount)
603656 if ((unstakeInv == unstakeInv))
605658 let transfer = if ((rewardAmount == 0))
606659 then nil
607660 else [ScriptTransfer(address, rewardAmount, assetId)]
608- $Tuple2(((accum._1 ++ transfer) ++ [IntegerEntry((((addressStr + "_lastCheck_") + assetIdStr) + "_interest"), currentTokenInterest)]), (accum._2 + calculateUsdValue(assetId, rewardAmount, aBalance)))
661+ $Tuple2(((accum._1 ++ transfer) ++ [IntegerEntry((((addressStr + "_lastCheck_") + assetIdStr) + "_interest"), currentTokenInterest)]), (accum._2 + calculateUsdValue(assetId, rewardAmount, aBalance, feeTokenBalance)))
609662 }
610663 else throw("Strict value is not equal to itself.")
611664 }
647700 func calcInterestChange (assetIdStr,lpFee) = {
648701 let totalIndex = tryGetInteger("global_indexStaked")
649702 let interestDelta = fraction(lpFee, Scale16, totalIndex)
650- IntegerEntry((("global_lastCheck_" + assetIdStr) + "_interest"), (tryGetInteger((("global_lastCheck_" + assetIdStr) + "_interest")) + interestDelta))
703+ interestDelta
651704 }
652705
653706
654-func updSelloffData (assetIdStr,amountIn) = {
707+func updSelloffData (assetIdStr,amountIn,balance,selloffParams) = {
655708 let currentPeriod = ((height / 100) * 100)
656- let prevPeriod = tryGetInteger((("global_" + assetIdStr) + "_selloffStartHeight"))
709+ let prevPeriod = selloffParams._2
657710 let prevSelloff = if ((currentPeriod == prevPeriod))
658- then tryGetInteger((("global_" + assetIdStr) + "_selloff"))
711+ then selloffParams._1
659712 else 0
660713 let selloffStartBalance = if ((currentPeriod == prevPeriod))
661- then tryGetInteger((("global_" + assetIdStr) + "_selloffStartBalance"))
662- else tryGetInteger((("global_" + assetIdStr) + "_balance"))
714+ then selloffParams._3
715+ else balance
663716 let selloffDelta = fraction(Scale16, amountIn, selloffStartBalance)
664717 let maxSelloff = tryGetInteger((("static_" + assetIdStr) + "_maxSelloff"))
665718 if (if (((prevSelloff + selloffDelta) > maxSelloff))
666719 then (maxSelloff != 0)
667720 else false)
668721 then throw(("max selloff reached for this asset " + assetIdStr))
669- else ([IntegerEntry((("global_" + assetIdStr) + "_selloff"), (prevSelloff + selloffDelta))] ++ (if ((currentPeriod == prevPeriod))
670- then nil
671- else [IntegerEntry((("global_" + assetIdStr) + "_selloffStartHeight"), currentPeriod), IntegerEntry((("global_" + assetIdStr) + "_selloffStartBalance"), selloffStartBalance)]))
722+ else {
723+ let startH = if ((currentPeriod == prevPeriod))
724+ then prevPeriod
725+ else currentPeriod
726+ let startB = if ((currentPeriod == prevPeriod))
727+ then selloffParams._3
728+ else selloffStartBalance
729+ $Tuple3((prevSelloff + selloffDelta), startH, startB)
730+ }
672731 }
673732
674733
802861 then true
803862 else (wInt > MAX_WEIGHT))
804863 then throw(((((("Weight should be in range " + toString(MIN_WEIGHT)) + " - ") + toString(MAX_WEIGHT)) + ", current: ") + w))
805- else accum
864+ else (accum + wInt)
806865 }
807866
808867 let $l = weights
821880
822881
823882 func getP1P2 (assetIdStr,baseAssetIdStr) = {
824- let B1 = tryGetInteger((("global_" + baseAssetIdStr) + "_balance"))
825- let B2 = tryGetInteger((("global_" + assetIdStr) + "_balance"))
826- let F1 = getFactBalance(baseAssetIdStr)
827- let F2 = getFactBalance(assetIdStr)
883+ let assetParams = loadGlobalTokenParams(assetIdStr)
884+ let baseAssetParams = loadGlobalTokenParams(baseAssetIdStr)
885+ let B1 = baseAssetParams._1
886+ let B2 = assetParams._1
887+ let F1 = baseAssetParams._2
888+ let F2 = assetParams._2
828889 let S1 = tryGetInteger((("static_" + baseAssetIdStr) + "_scale"))
829890 let S2 = tryGetInteger((("static_" + assetIdStr) + "_scale"))
830891 let D1 = tryGetInteger((("static_" + baseAssetIdStr) + "_decimals"))
857918 let poolOwnerAddress = addressFromStringValue(poolOwner)
858919 let assetIdsStrLi = split(assetIdsStr, ",")
859920 let assetMaxSelloffStrLi = split(assetMaxSelloffStr, ",")
921+ let assetWeightsStrLi = split(assetWeightsStr, ",")
860922 let assetIdsLi = {
861923 let $l = assetIdsStrLi
862924 let $s = size($l)
898960 then true
899961 else (0 > fee))
900962 then throw("fee value must be between 0 and 500 (0-5%)")
901- else {
902- let assetWeightsStrLi = split(assetWeightsStr, ",")
903- func addTokenDataEntries (accum,assetNum) = if ((assetNum >= size(assetIdsLi)))
904- then accum
905- else {
906- let assetStakingAddress = {
907- let @ = invoke(poolsHubAddress, "useEmptyContract", [("staker_" + assetIdsStrLi[assetNum])], nil)
908- if ($isInstanceOf(@, "String"))
909- then @
910- else throw(($getType(@) + " couldn't be cast to String"))
963+ else if ((validateWeights(assetWeightsStrLi) != 10000))
964+ then throw(("weights sum should be 10000, current: " + toString(validateWeights(assetWeightsStrLi))))
965+ else {
966+ func addTokenDataEntries (accum,assetNum) = if ((assetNum >= size(assetIdsLi)))
967+ then accum
968+ else {
969+ let assetStakingAddress = {
970+ let @ = invoke(poolsHubAddress, "useEmptyContract", [("staker_" + assetIdsStrLi[assetNum])], nil)
971+ if ($isInstanceOf(@, "String"))
972+ then @
973+ else throw(($getType(@) + " couldn't be cast to String"))
974+ }
975+ if ((assetStakingAddress == assetStakingAddress))
976+ then {
977+ let assetDecimals = match assetIdsLi[assetNum] {
978+ case x: ByteVector =>
979+ value(assetInfo(x)).decimals
980+ case _ =>
981+ 8
982+ }
983+ ((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]))), StringEntry(("static_stakingContract_" + assetIdsStrLi[assetNum]), assetStakingAddress)]) ++ (if ((assetMaxSelloffStrLi[assetNum] == ""))
984+ then nil
985+ else [IntegerEntry((("static_" + assetIdsStrLi[assetNum]) + "_maxSelloff"), (parseIntValue(assetMaxSelloffStrLi[assetNum]) * Scale12))]))
986+ }
987+ else throw("Strict value is not equal to itself.")
911988 }
912- if ((assetStakingAddress == assetStakingAddress))
913- then {
914- let assetDecimals = match assetIdsLi[assetNum] {
915- case x: ByteVector =>
916- value(assetInfo(x)).decimals
917- case _ =>
918- 8
919- }
920- ((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]))), StringEntry(("static_stakingContract_" + assetIdsStrLi[assetNum]), assetStakingAddress)]) ++ (if ((assetMaxSelloffStrLi[assetNum] == ""))
921- then nil
922- else [IntegerEntry((("static_" + assetIdsStrLi[assetNum]) + "_maxSelloff"), (parseIntValue(assetMaxSelloffStrLi[assetNum]) * Scale12))]))
923- }
924- else throw("Strict value is not equal to itself.")
925- }
926989
927- ({
928- let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
929- let $s = size($l)
930- let $acc0 = nil
931- func $f6_1 ($a,$i) = if (($i >= $s))
932- then $a
933- else addTokenDataEntries($a, $l[$i])
990+ ({
991+ let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
992+ let $s = size($l)
993+ let $acc0 = nil
994+ func $f6_1 ($a,$i) = if (($i >= $s))
995+ then $a
996+ else addTokenDataEntries($a, $l[$i])
934997
935- func $f6_2 ($a,$i) = if (($i >= $s))
936- then $a
937- else throw("List size exceeds 10")
998+ func $f6_2 ($a,$i) = if (($i >= $s))
999+ then $a
1000+ else throw("List size exceeds 10")
9381001
939- $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)
940- } ++ [StringEntry("static_tokenIds", assetIdsStr), StringEntry("static_feeToken", feeAssetStr), StringEntry("static_tokenWeights", assetWeightsStr), IntegerEntry("static_tokensAmount", size(assetIdsLi)), StringEntry("static_poolDomain", poolDomain), StringEntry("static_poolToken_idStr", ""), StringEntry("static_baseTokenId", baseTokenIdStr), StringEntry("static_poolOwner", poolOwner), IntegerEntry("static_fee", fee), IntegerEntry("static_KMult", Scale16), IntegerEntry("global_indexStaked", 0), IntegerEntry("global_poolToken_amount", 0), IntegerEntry("global_wasPreInited", 1)])
941- }
1002+ $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)
1003+ } ++ [StringEntry("static_tokenIds", assetIdsStr), StringEntry("static_feeToken", feeAssetStr), StringEntry("static_tokenWeights", assetWeightsStr), IntegerEntry("static_tokensAmount", size(assetIdsLi)), StringEntry("static_poolDomain", poolDomain), StringEntry("static_poolToken_idStr", ""), StringEntry("static_baseTokenId", baseTokenIdStr), StringEntry("static_poolOwner", poolOwner), IntegerEntry("static_fee", fee), IntegerEntry("static_KMult", Scale16), IntegerEntry("global_indexStaked", 0), IntegerEntry("global_poolToken_amount", 0), IntegerEntry("global_wasPreInited", 1)])
1004+ }
9421005 }
9431006
9441007
9581021 if ((preInitInv == preInitInv))
9591022 then {
9601023 let vBalances = parstStrToIntList(vBalancesStr)
961- func prepareList () = {
962- func handler (accum,assetId) = {
963- let n = value(indexOf(assetIds, assetId))
964- (accum ++ [IntegerEntry((("global_" + getAssetString(assetId)) + "_balance"), vBalances[n]), IntegerEntry((("global_lastCheck_" + getAssetString(assetId)) + "_interest"), 0)])
965- }
1024+ func getPaymentAmount (assetIdStr) = {
1025+ func handler (accum,payment) = if ((getAssetString(payment.assetId) == assetIdStr))
1026+ then payment.amount
1027+ else accum
9661028
967- let $l = assetIds
1029+ let $l = i.payments
9681030 let $s = size($l)
969- let $acc0 = nil
1031+ let $acc0 = 0
9701032 func $f4_1 ($a,$i) = if (($i >= $s))
9711033 then $a
9721034 else handler($a, $l[$i])
9781040 $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)
9791041 }
9801042
981- func prepareList2 () = {
982- func handler1 (accum,payment) = {
983- let stakeTx = stakeIfNeeded(getAssetString(payment.assetId), payment.amount)
984- if ((stakeTx == stakeTx))
985- then (accum ++ [IntegerEntry((("global_" + getAssetString(payment.assetId)) + "_factBalance"), payment.amount)])
986- else throw("Strict value is not equal to itself.")
1043+ func prepareList () = {
1044+ func handler (accum,assetId) = {
1045+ let assetIdStr = getAssetString(assetId)
1046+ let n = value(indexOf(assetIds, assetId))
1047+ let paymentAmount = getPaymentAmount(assetIdStr)
1048+ let assetParams = loadGlobalTokenParams(assetIdStr)
1049+ let assetParamsUpd = $Tuple8(vBalances[n], paymentAmount, assetParams._3, assetParams._4, assetParams._5, assetParams._6, assetParams._7, assetParams._8)
1050+ (accum ++ [saveGlobalTokenParams(assetIdStr, assetParamsUpd)])
9871051 }
9881052
989- let $l = i.payments
1053+ let $l = assetIds
9901054 let $s = size($l)
9911055 let $acc0 = nil
9921056 func $f4_1 ($a,$i) = if (($i >= $s))
9931057 then $a
994- else handler1($a, $l[$i])
1058+ else handler($a, $l[$i])
9951059
9961060 func $f4_2 ($a,$i) = if (($i >= $s))
9971061 then $a
10491113 if ((notifyInvoke == notifyInvoke))
10501114 then if ((initialPoolTokens == 0))
10511115 then throw("you need a bigger tokens amount to launch the pool")
1052- else ((prepareList() ++ prepareList2()) ++ [IntegerEntry("global_poolToken_amount", initialPoolTokens), IntegerEntry("global_wasInited", 1), IntegerEntry((toString(i.caller) + "_indexStaked"), initialPoolTokens), IntegerEntry("global_indexStaked", initialPoolTokens)])
1116+ else (prepareList() ++ [IntegerEntry("global_poolToken_amount", initialPoolTokens), IntegerEntry("global_wasInited", 1), IntegerEntry((toString(i.caller) + "_indexStaked"), initialPoolTokens), IntegerEntry("global_indexStaked", initialPoolTokens)])
10531117 else throw("Strict value is not equal to itself.")
10541118 }
10551119 }
11151179 $Tuple2([issue, StringEntry("static_poolToken_idStr", poolTokenIdStr)], poolTokenIdStr)
11161180 }
11171181
1118- let $t03722937395 = if ((tryGetString("static_poolToken_idStr") == ""))
1182+ let $t04040840574 = if ((tryGetString("static_poolToken_idStr") == ""))
11191183 then issueIndex()
11201184 else $Tuple2(nil, tryGetString("static_poolToken_idStr"))
1121- let poolTokenIssueResult = $t03722937395._1
1122- let poolTokenIdStr = $t03722937395._2
1185+ let poolTokenIssueResult = $t04040840574._1
1186+ let poolTokenIdStr = $t04040840574._2
11231187 let poolTokenId = fromBase58String(poolTokenIdStr)
11241188 let addressStr = toString(i.caller)
11251189 let indexAvailable = tryGetInteger((addressStr + "_indexStaked"))
11551219 if ((stakeTx == stakeTx))
11561220 then if ((indexOf(assetIds, assetId) == unit))
11571221 then throw("you can only add interest for assets in the pool")
1158- else [calcInterestChange(assetIdStr, amount), IntegerEntry(("global_extraEarned_" + assetIdStr), (tryGetInteger(("global_extraEarned_" + assetIdStr)) + amount))]
1222+ else {
1223+ let params = loadGlobalTokenParams(assetIdStr)
1224+ let interestDelta = calcInterestChange(assetIdStr, amount)
1225+ let updParams = $Tuple8(params._1, params._2, params._3, (params._4 + interestDelta), (params._5 + amount), params._6, params._7, params._8)
1226+[saveGlobalTokenParams(assetIdStr, updParams)]
1227+ }
11591228 else throw("Strict value is not equal to itself.")
11601229 }
11611230
11681237 then throw("you can only add interest for assets in the pool")
11691238 else if ((tryGetString(("static_stakingContract_" + assetIdStr)) != toString(i.caller)))
11701239 then throw("can only be invoked by staker contract")
1171- else [calcInterestChange(assetIdStr, amount), IntegerEntry(("global_extraEarned_" + assetIdStr), (tryGetInteger(("global_extraEarned_" + assetIdStr)) + amount))]
1240+ else {
1241+ let params = loadGlobalTokenParams(assetIdStr)
1242+ let interestDelta = calcInterestChange(assetIdStr, amount)
1243+ let updParams = $Tuple8(params._1, params._2, params._3, (params._4 + interestDelta), (params._5 + amount), params._6, params._7, params._8)
1244+[saveGlobalTokenParams(assetIdStr, updParams)]
1245+ }
11721246 }
11731247
11741248
11841258 let assetIn = getAssetString(AssetIn)
11851259 let scaleIn = (Scale8 / tryGetInteger((("static_" + assetIn) + "_scale")))
11861260 let scaleOut = (Scale8 / tryGetInteger((("static_" + assetOut) + "_scale")))
1187- let AssetInBalance = tryGetInteger((("global_" + getAssetString(AssetIn)) + "_balance"))
1188- let AssetOutBalance = tryGetInteger((("global_" + assetOut) + "_balance"))
1261+ let assetInParams = loadGlobalTokenParams(getAssetString(AssetIn))
1262+ let assetOutParams = loadGlobalTokenParams(assetOut)
1263+ let AssetInBalance = assetInParams._1
1264+ let AssetInFactBalance = assetInParams._2
1265+ let assetInFeesEarned = assetInParams._3
1266+ let assetInLastCheckInterest = assetInParams._4
1267+ let AssetOutBalance = assetOutParams._1
1268+ let assetOutFactBalance = assetOutParams._2
11891269 let AssetInBalanceScaled = (AssetInBalance * scaleIn)
11901270 let AssetOutBalanceScaled = (AssetOutBalance * scaleOut)
11911271 let feeAmountIn = fraction(AmountIn, Fee, FeeScale)
11991279 then throw("amount to recieve is lower than given one")
12001280 else if ((AssetOut == AssetIn))
12011281 then throw("this swap is not allowed")
1202- else if ((0 > (getFactBalance(assetOut) - AmountOut)))
1282+ else if ((0 > (assetOutFactBalance - AmountOut)))
12031283 then throw("contract is out of reserves")
12041284 else if (isShutdown())
12051285 then throw("contract is on stop")
12101290 else {
12111291 let protocolFee = fraction(feeAmountIn, 5, 10)
12121292 let lpFee = (feeAmountIn - protocolFee)
1213- let interestChange = calcInterestChange(assetIn, lpFee)
1214- let statsChange = IntegerEntry(("global_feesEarned_" + assetIn), (tryGetInteger(("global_feesEarned_" + assetIn)) + lpFee))
1293+ let interestDelta = calcInterestChange(assetIn, lpFee)
12151294 let stakeTx = stakeIfNeeded(assetIn, (cleanAmountIn + lpFee))
12161295 if ((stakeTx == stakeTx))
12171296 then {
12201299 then {
12211300 let newBalanceIn = AssetInBalance2
12221301 let newBalanceOut = AssetOutBalance2
1223- let assetInChange = IntegerEntry((("global_" + getAssetString(AssetIn)) + "_balance"), newBalanceIn)
1224- let assetOutChange = IntegerEntry((("global_" + assetOut) + "_balance"), newBalanceOut)
1225- let assetInFactChange = IntegerEntry((("global_" + getAssetString(AssetIn)) + "_factBalance"), (tryGetInteger((("global_" + getAssetString(AssetIn)) + "_factBalance")) + cleanAmountIn))
1226- let assetOutFactChange = IntegerEntry((("global_" + assetOut) + "_factBalance"), (tryGetInteger((("global_" + assetOut) + "_factBalance")) - AmountOut))
1227- let volumeUsdUpdate = calculateUsdValue(AssetIn, AmountIn, AssetInBalance)
1228- $Tuple2((([assetOutChange, assetInChange, assetInFactChange, assetOutFactChange, ScriptTransfer(i.caller, AmountOut, AssetOut), IntegerEntry("global_volume_usd", (tryGetInteger("global_volume_usd") + volumeUsdUpdate)), ScriptTransfer(feesAddress, protocolFee, getAssetBytes(assetIn)), interestChange, statsChange] ++ updSelloffData(assetIn, cleanAmountIn)) ++ updSelloffData(assetOut, -(AmountOut))), AmountOut)
1302+ let assetInSelloffData = updSelloffData(assetIn, cleanAmountIn, AssetInBalance, $Tuple3(assetInParams._6, assetInParams._7, assetInParams._8))
1303+ let assetOutSelloffData = updSelloffData(assetOut, -(AmountOut), AssetOutBalance, $Tuple3(assetOutParams._6, assetOutParams._7, assetOutParams._8))
1304+ let assetInFinalParams = $Tuple8(newBalanceIn, (AssetInFactBalance + cleanAmountIn), (assetInFeesEarned + lpFee), (assetInLastCheckInterest + interestDelta), assetInParams._5, assetInSelloffData._1, assetInSelloffData._2, assetInSelloffData._3)
1305+ let assetOutFinalParams = $Tuple8(newBalanceOut, (assetOutFactBalance - AmountOut), assetOutParams._3, assetOutParams._4, assetOutParams._5, assetOutSelloffData._1, assetOutSelloffData._2, assetOutSelloffData._3)
1306+ let assetInChange = saveGlobalTokenParams(assetIn, assetInFinalParams)
1307+ let assetOutChange = saveGlobalTokenParams(assetOut, assetOutFinalParams)
1308+ let feeAssetStr = tryGetString("static_feeToken")
1309+ let feeAssetParams = loadGlobalTokenParams(feeAssetStr)
1310+ let feeTokenBalance = feeAssetParams._1
1311+ let volumeUsdUpdate = calculateUsdValue(AssetIn, AmountIn, AssetInBalance, feeTokenBalance)
1312+ $Tuple2([assetInChange, assetOutChange, ScriptTransfer(i.caller, AmountOut, AssetOut), IntegerEntry("global_volume_usd", (tryGetInteger("global_volume_usd") + volumeUsdUpdate)), ScriptTransfer(feesAddress, protocolFee, getAssetBytes(assetIn))], AmountOut)
12291313 }
12301314 else throw("Strict value is not equal to itself.")
12311315 }
12451329 let feeAssetOut = if ((feeAssetOutStr == ""))
12461330 then usdnAssetId
12471331 else getAssetBytes(feeAssetOutStr)
1248- let AssetInBalance = tryGetInteger((("global_" + getAssetString(AssetIn)) + "_balance"))
1249- let AssetOutBalance = tryGetInteger((("global_" + assetOut) + "_balance"))
1332+ let assetInParams = loadGlobalTokenParams(getAssetString(AssetIn))
1333+ let assetOutParams = loadGlobalTokenParams(assetOut)
1334+ let AssetInBalance = assetInParams._1
1335+ let AssetInFactBalance = assetInParams._2
1336+ let assetInFeesEarned = assetInParams._3
1337+ let assetInLastCheckInterest = assetInParams._4
1338+ let AssetOutBalance = assetOutParams._1
1339+ let assetOutFactBalance = assetOutParams._2
12501340 let AssetInBalanceScaled = (AssetInBalance * scaleIn)
12511341 let AssetOutBalanceScaled = (AssetOutBalance * scaleOut)
12521342 let feeAmountIn = fraction(AmountIn, Fee, FeeScale)
12561346 let AmountOut = fraction(AmountOut1, 1, scaleOut)
12571347 let AssetOutBalance2 = (AssetOutBalance - AmountOut)
12581348 let AssetInBalance2 = (AssetInBalance + cleanAmountIn)
1259- let feeAssetOutBalance = if ((feeAssetOut == AssetIn))
1260- then AssetInBalance2
1261- else if ((feeAssetOut == AssetOut))
1262- then AssetOutBalance2
1263- else tryGetInteger((("global_" + getAssetString(feeAssetOut)) + "_balance"))
1264- let feeAmountOut = calculateOutAmount(feeAmountIn, AssetIn, feeAssetOut, AssetInBalance, feeAssetOutBalance)
12651349 if ((AssetOut == AssetIn))
12661350 then throw("this swap is not allowed")
1267- else if ((0 > (getFactBalance(assetOut) - AmountOut)))
1351+ else if ((0 > (assetOutParams._2 - AmountOut)))
12681352 then throw("contract is out of reserves")
12691353 else if (isShutdown())
12701354 then throw("contract is on stop")
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let VERSION = "PZ-3.6.0 PROD"
4+let VERSION = "PZ-3.6.1 PROD-refactor"
55
66 let configStr = valueOrElse(getString(this, "configAddress"), "3PMoEibdLeWqcURQ8351XhaWwyacDc7G4e5")
77
88 let CONFIG_ADDRESS = if ((configStr == ""))
99 then this
1010 else Address(fromBase58String(configStr))
1111
1212 let AssetsWeightsDecimals = 4
1313
1414 let Scale = 10000
1515
1616 let Scale8 = 100000000
1717
18+let Scale8_BI = toBigInt(Scale8)
19+
1820 let Scale12 = 1000000000000
1921
2022 let Scale16 = 10000000000000000
23+
24+let Scale16_BI = toBigInt(Scale16)
2125
2226 let FeeScale = 10000
2327
2428 let PoolTokenDecimals = 8
2529
2630 let PoolTokenScale = pow(10, 0, PoolTokenDecimals, 0, 0, HALFUP)
2731
2832 let MIN_STEPS_AMOUNT = valueOrElse(getInteger(CONFIG_ADDRESS, "min_steps_amount"), 1)
2933
3034 let MAX_STEPS_AMOUNT = valueOrElse(getInteger(CONFIG_ADDRESS, "max_steps_amount"), 500)
3135
3236 let MIN_STEPS_INTERVAL = valueOrElse(getInteger(CONFIG_ADDRESS, "min_steps_interval"), 1)
3337
3438 let MAX_STEPS_INTERVAL = valueOrElse(getInteger(CONFIG_ADDRESS, "max_steps_interval"), 10000)
3539
3640 let MIN_WEIGHT = valueOrElse(getInteger(CONFIG_ADDRESS, "min_weight"), 100)
3741
3842 let MAX_WEIGHT = valueOrElse(getInteger(CONFIG_ADDRESS, "max_weight"), 9900)
3943
4044 func tryGetInteger (key) = match getInteger(this, key) {
4145 case b: Int =>
4246 b
4347 case _ =>
4448 0
4549 }
4650
4751
4852 func tryGetBinary (key) = match getBinary(this, key) {
4953 case b: ByteVector =>
5054 b
5155 case _ =>
5256 base58''
5357 }
5458
5559
5660 func tryGetString (key) = match getString(this, key) {
5761 case b: String =>
5862 b
5963 case _ =>
6064 ""
6165 }
6266
6367
6468 func tryGetStringOrThrow (key) = match getString(this, key) {
6569 case b: String =>
6670 b
6771 case _ =>
6872 throw(("no such key in data storage: " + key))
6973 }
7074
7175
7276 func getAssetString (assetId) = match assetId {
7377 case b: ByteVector =>
7478 toBase58String(b)
7579 case _ =>
7680 "WAVES"
7781 }
7882
7983
8084 func getAssetBytes (assetIdStr) = if ((assetIdStr == "WAVES"))
8185 then unit
8286 else fromBase58String(assetIdStr)
8387
8488
8589 func getTokenBalance (assetId) = match assetId {
8690 case t: ByteVector =>
8791 assetBalance(this, t)
8892 case _ =>
8993 wavesBalance(this).available
9094 }
91-
92-
93-func getFactBalance (assetIdStr) = tryGetInteger((("global_" + assetIdStr) + "_factBalance"))
9495
9596
9697 func addAssetBytesToList (accum,item) = (accum ++ [getAssetBytes(item)])
9798
9899
99100 func addAssetWeightToList (accum,item) = (accum ++ [tryGetInteger((("static_" + getAssetString(item)) + "_weight"))])
100101
101102
102103 func addAssetWeightToStrList (accum,item) = (accum ++ [toString(tryGetInteger((("static_" + item) + "_weight")))])
103104
104105
105106 func addAssetDecimalsToList (accum,item) = (accum ++ [tryGetInteger((("static_" + getAssetString(item)) + "_decimals"))])
106107
107108
108109 func addAssetScaleToList (accum,item) = (accum ++ [tryGetInteger((("static_" + getAssetString(item)) + "_scale"))])
109110
110111
111112 func addIntToList (accum,item) = (accum ++ [parseIntValue(item)])
112113
113114
114115 func parstStrToIntList (s) = {
115116 func f (accum,next) = (accum ++ [parseIntValue(next)])
116117
117118 let $l = split(s, ",")
118119 let $s = size($l)
119120 let $acc0 = nil
120121 func $f0_1 ($a,$i) = if (($i >= $s))
121122 then $a
122123 else f($a, $l[$i])
123124
124125 func $f0_2 ($a,$i) = if (($i >= $s))
125126 then $a
126127 else throw("List size exceeds 10")
127128
128129 $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)
129130 }
130131
131132
132133 let usdnAssetIdStr = valueOrElse(getString(CONFIG_ADDRESS, "usdnAssetIdStr"), "DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p")
133134
134135 let puzzleAssetIdStr = valueOrElse(getString(CONFIG_ADDRESS, "puzzleAssetIdStr"), "HEB8Qaw9xrWpWs8tHsiATYGBWDBtP2S7kcPALrMu43AS")
135136
136137 let usdtAssetIdStr = valueOrElse(getString(CONFIG_ADDRESS, "usdtAssetIdStr"), "34N9YcEETLWn93qYQ64EsP1x89tSruJU44RrEMSXXEPJ")
137138
138139 let usdtPptAssetIdStr = valueOrElse(getString(CONFIG_ADDRESS, "usdtPptAssetIdStr"), "9wc3LXNA4TEBsXyKtoLE9mrbDD7WMHXvXrCjZvabLAsi")
139140
140141 let romeAssetIdStr = valueOrElse(getString(CONFIG_ADDRESS, "romeAssetIdStr"), "AP4Cb5xLYGH6ZigHreCZHoXpQTWDkPsG2BHqfDUx6taJ")
141142
142143 let wavesAssetIdStr = "WAVES"
143144
144145 let usdnAssetId = fromBase58String(usdnAssetIdStr)
145146
146147 let puzzleAssetId = fromBase58String(puzzleAssetIdStr)
147148
148149 let usdtAssetId = fromBase58String(usdtAssetIdStr)
149150
150151 let usdtPptAssetId = fromBase58String(usdtPptAssetIdStr)
151152
152153 let romeAssetId = fromBase58String(romeAssetIdStr)
153154
154155 let wavesAssetId = unit
155156
156157 let supportedFeeAssetsStr = [usdnAssetIdStr, puzzleAssetIdStr, usdtAssetIdStr, usdtPptAssetIdStr, wavesAssetIdStr, romeAssetIdStr]
157158
158159 let parentPoolAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "parentPoolAddress"), "3PFDgzu1UtswAkCMxqqQjbTeHaX4cMab8Kh")))
159160
160161 let masterAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "masterAddress"), "3PLjwHcz9NEuaTo63NZR9B9okQiKQxZSbmf")))
161162
162163 let masterPubKey = fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "masterPubKey"), "2jTJGqHSopyj5d1cjbUe6f2jXqGMHE412cy3vGwYoRbP"))
163164
164165 let oracleAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "oracleAddress"), "3P8d1E1BLKoD52y3bQJ1bDTd2TD1gpaLn9t")))
165166
166167 let stakingAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "stakingAddress"), "3PFTbywqxtFfukX3HyT881g4iW5K4QL3FAS")))
167168
168169 let feesAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "feesAddress"), "3PFWAVKmXjfHXyzJb12jCbhP4Uhi9t4uWiD")))
169170
170171 let poolsHubAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "poolsHubAddress"), "3P5RGYyCnELF8JTPxgX54dBGzwkQMKUJ5H7")))
171172
172173 let shutdownAddressStr = valueOrElse(getString(CONFIG_ADDRESS, "shutdownAddress"), "3PEpv9hRFWEEBU22WRnLsw1bH4YGtcU728o")
173174
174175 let layer2Addresses = valueOrElse(getString(CONFIG_ADDRESS, "layer2Addresses"), "3PR1Qvi9mHT35SwWEkLSqqE2L8thiPLdVWU,3PQoBfUKHkJAeGWhooLP7WS8ovb54av9Jp2")
175176
176177 let govAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "govAddress"), "3P6uro9xCsE8te78QZjzqy7aq8natSzdceC")))
177178
178179 let coldMasterAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "coldMasterAddress"), "3PK9nhPfPbMBygB9ZgHVMHaQbSoojwrBfxj")))
179180
180181 let T = tryGetInteger("static_tokensAmount")
181182
182183 let assetIds = {
183184 let $l = split(tryGetString("static_tokenIds"), ",")
184185 let $s = size($l)
185186 let $acc0 = nil
186187 func $f0_1 ($a,$i) = if (($i >= $s))
187188 then $a
188189 else addAssetBytesToList($a, $l[$i])
189190
190191 func $f0_2 ($a,$i) = if (($i >= $s))
191192 then $a
192193 else throw("List size exceeds 10")
193194
194195 $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)
195196 }
196197
197198 let AssetsWeights = {
198199 let $l = assetIds
199200 let $s = size($l)
200201 let $acc0 = nil
201202 func $f1_1 ($a,$i) = if (($i >= $s))
202203 then $a
203204 else addAssetWeightToList($a, $l[$i])
204205
205206 func $f1_2 ($a,$i) = if (($i >= $s))
206207 then $a
207208 else throw("List size exceeds 10")
208209
209210 $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)
210211 }
211212
212213 let Decimals = {
213214 let $l = assetIds
214215 let $s = size($l)
215216 let $acc0 = nil
216217 func $f2_1 ($a,$i) = if (($i >= $s))
217218 then $a
218219 else addAssetDecimalsToList($a, $l[$i])
219220
220221 func $f2_2 ($a,$i) = if (($i >= $s))
221222 then $a
222223 else throw("List size exceeds 10")
223224
224225 $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)
225226 }
226227
227228 let Scales = {
228229 let $l = assetIds
229230 let $s = size($l)
230231 let $acc0 = nil
231232 func $f3_1 ($a,$i) = if (($i >= $s))
232233 then $a
233234 else addAssetScaleToList($a, $l[$i])
234235
235236 func $f3_2 ($a,$i) = if (($i >= $s))
236237 then $a
237238 else throw("List size exceeds 10")
238239
239240 $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)
240241 }
241242
242243 let Fee = tryGetInteger("static_fee")
243244
244245 let earnedAssets = assetIds
245246
247+func _get (assetId,param) = tryGetInteger(((("global_" + assetId) + "_") + param))
248+
249+
250+func _get_feesEarned (assetId) = tryGetInteger(("global_feesEarned_" + assetId))
251+
252+
253+func _get_lastCheck_interest (assetId) = tryGetInteger((("global_lastCheck_" + assetId) + "_interest"))
254+
255+
256+func _get_extraEarned (assetId) = tryGetInteger(("global_extraEarned_" + assetId))
257+
258+
259+func loadGlobalTokenParams (assetId) = match getString(("globalParams_" + assetId)) {
260+ case p: String =>
261+ let params = split(p, "__")
262+ $Tuple8(parseIntValue(params[0]), parseIntValue(params[1]), parseIntValue(params[2]), parseIntValue(params[3]), parseIntValue(params[4]), parseIntValue(params[5]), parseIntValue(params[6]), parseIntValue(params[7]))
263+ case _ =>
264+ $Tuple8(_get(assetId, "balance"), _get(assetId, "factBalance"), _get_feesEarned(assetId), _get_lastCheck_interest(assetId), _get_extraEarned(assetId), _get(assetId, "selloff"), _get(assetId, "selloffStartBalance"), _get(assetId, "selloffStartHeight"))
265+}
266+
267+
268+func saveGlobalTokenParams (assetId,params) = StringEntry(("globalParams_" + assetId), makeString([toString(params._1), toString(params._2), toString(params._3), toString(params._4), toString(params._5), toString(params._6), toString(params._7), toString(params._8)], "__"))
269+
270+
246271 func isShutdown () = {
247272 let shutdownAddress = addressFromString(shutdownAddressStr)
248273 if ((shutdownAddress == unit))
249274 then false
250275 else match getBoolean(value(shutdownAddress), "is_shutdown") {
251276 case x: Boolean =>
252277 x
253278 case _ =>
254279 false
255280 }
256281 }
257282
258283
284+func getFactBalance (assetIdStr) = {
285+ let assetParams = loadGlobalTokenParams(assetIdStr)
286+ assetParams._2
287+ }
288+
289+
259290 func getCurrentTokenBalance (tokenNum) = {
260291 let tokenIdStr = getAssetString(assetIds[tokenNum])
261- tryGetInteger((("global_" + tokenIdStr) + "_balance"))
292+ let tokenParams = loadGlobalTokenParams(tokenIdStr)
293+ tokenParams._1
262294 }
263295
264296
265297 func stakeIfNeeded (assetIdStr,amount) = {
266298 let stakeTx = if ((tryGetString(("static_stakingContract_" + assetIdStr)) != ""))
267299 then invoke(addressFromStringValue(tryGetString(("static_stakingContract_" + assetIdStr))), "stake", nil, [AttachedPayment(getAssetBytes(assetIdStr), amount)])
268300 else unit
269301 if ((stakeTx == stakeTx))
270302 then true
271303 else throw("Strict value is not equal to itself.")
272304 }
273305
274306
275307 func unstakeIfNeeded (assetIdStr,amount) = {
276308 let unstakeTx = if ((tryGetString(("static_stakingContract_" + assetIdStr)) != ""))
277309 then invoke(addressFromStringValue(tryGetString(("static_stakingContract_" + assetIdStr))), "unstake", [amount], nil)
278310 else unit
279311 if ((unstakeTx == unstakeTx))
280312 then true
281313 else throw("Strict value is not equal to itself.")
282314 }
283315
284316
285317 func burnIndexIfNeeded (amount) = {
286318 let indexIdStr = tryGetString("static_poolToken_idStr")
287319 if ((indexIdStr == ""))
288320 then nil
289321 else if ((assetInfo(fromBase58String(indexIdStr)) == unit))
290322 then nil
291323 else [Burn(fromBase58String(indexIdStr), amount)]
292324 }
293325
294326
295327 func mintIndexIfNeeded (amount) = {
296328 let indexIdStr = tryGetString("static_poolToken_idStr")
297329 if ((indexIdStr == ""))
298330 then nil
299331 else if ((assetInfo(fromBase58String(indexIdStr)) == unit))
300332 then nil
301333 else [Reissue(fromBase58String(indexIdStr), amount, true)]
302334 }
303335
304336
305337 func getKMult () = match getInteger("static_KMult") {
306338 case x: Int =>
307339 x
308340 case _ =>
309341 Scale16
310342 }
311343
312344
313345 func saveCurrentWeights () = {
314346 let assetIdsLi = split(tryGetString("static_tokenIds"), ",")
315347 func s (accum,assetId) = (accum ++ [IntegerEntry(("rebalance_startWeight_" + assetId), tryGetInteger((("static_" + assetId) + "_weight")))])
316348
317349 let $l = assetIdsLi
318350 let $s = size($l)
319351 let $acc0 = nil
320352 func $f4_1 ($a,$i) = if (($i >= $s))
321353 then $a
322354 else s($a, $l[$i])
323355
324356 func $f4_2 ($a,$i) = if (($i >= $s))
325357 then $a
326358 else throw("List size exceeds 10")
327359
328360 $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)
329361 }
330362
331363
332364 func getVirtualPoolTokenAmount () = fraction(tryGetInteger("global_poolToken_amount"), getKMult(), Scale16)
333365
334366
335367 func calculatePIssued (amount,tokenId) = {
336368 let Psupply = getVirtualPoolTokenAmount()
337369 let Balance = getFactBalance(getAssetString(tokenId))
338370 let t1 = fraction(amount, Psupply, Balance, DOWN)
339371 t1
340372 }
341373
342374
343375 func getMinPIssued (payments) = {
344376 func handler (accum,current) = if ((getFactBalance(getAssetString(current.assetId)) == 0))
345377 then accum
346378 else {
347379 let PIssued = calculatePIssued(current.amount, current.assetId)
348380 if ((PIssued == 0))
349381 then throw("one of the tokens amounts is too low")
350382 else if (if ((accum == 0))
351383 then true
352384 else (accum > PIssued))
353385 then PIssued
354386 else accum
355387 }
356388
357389 let minPIssed = {
358390 let $l = payments
359391 let $s = size($l)
360392 let $acc0 = 0
361393 func $f4_1 ($a,$i) = if (($i >= $s))
362394 then $a
363395 else handler($a, $l[$i])
364396
365397 func $f4_2 ($a,$i) = if (($i >= $s))
366398 then $a
367399 else throw("List size exceeds 10")
368400
369401 $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)
370402 }
371403 minPIssed
372404 }
373405
374406
375407 func getPriceFromOracle (assetIdStr) = match getInteger(oracleAddress, (assetIdStr + "_twap5B")) {
376408 case x: Int =>
377409 x
378410 case _ =>
379411 0
380412 }
381413
382414
383-func calculateUsdValue (assetId,amount,aBalance) = {
415+func calculateUsdValue (assetId,amount,aBalance,feeAssetBalance) = {
384416 let assetWeight = tryGetInteger((("static_" + getAssetString(assetId)) + "_weight"))
385417 let feeAssetStr = tryGetString("static_feeToken")
386418 let feeAssetScale = getIntegerValue(this, (("static_" + feeAssetStr) + "_scale"))
387419 let feeAssetNum = value(indexOf(assetIds, getAssetBytes(feeAssetStr)))
388420 let feeAssetWeight = AssetsWeights[feeAssetNum]
389- let feeAssetBalance = tryGetInteger((("global_" + feeAssetStr) + "_balance"))
390- let valInFeeAsset = fraction(amount, (feeAssetBalance / feeAssetWeight), (aBalance / assetWeight))
421+ let _amount = (toBigInt(amount) * Scale8_BI)
422+ let _feeAssetData = (toBigInt(feeAssetBalance) / toBigInt(feeAssetWeight))
423+ let _assetData = fraction(toBigInt(aBalance), Scale8_BI, toBigInt(assetWeight))
424+ let valInFeeAsset = toInt(fraction(_amount, _feeAssetData, _assetData))
391425 let feeAssetPrice = getPriceFromOracle(feeAssetStr)
392426 fraction(valInFeeAsset, feeAssetPrice, feeAssetScale)
393427 }
394428
395429
396430 func calcAvgConcentration () = {
397431 func f (accum,next) = {
398432 let assetIdStr = getAssetString(next)
399433 let weight = tryGetInteger((("static_" + assetIdStr) + "_weight"))
400- let assetFactBalance = tryGetInteger((("global_" + assetIdStr) + "_factBalance"))
401- let assetVirtBalance = tryGetInteger((("global_" + assetIdStr) + "_balance"))
434+ let assetParams = loadGlobalTokenParams(assetIdStr)
435+ let assetFactBalance = assetParams._2
436+ let assetVirtBalance = assetParams._1
402437 $Tuple2((accum._1 + fraction(assetFactBalance, weight, assetVirtBalance)), (accum._2 + weight))
403438 }
404439
405440 let $l = assetIds
406441 let $s = size($l)
407442 let $acc0 = $Tuple2(0, 0)
408443 func $f4_1 ($a,$i) = if (($i >= $s))
409444 then $a
410445 else f($a, $l[$i])
411446
412447 func $f4_2 ($a,$i) = if (($i >= $s))
413448 then $a
414449 else throw("List size exceeds 10")
415450
416451 $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)
417452 }
418453
419454
420455 func checkTokensValidity (payments) = {
421456 func handler1 (accum,payment) = (accum ++ [payment.assetId])
422457
423458 let ids = {
424459 let $l = payments
425460 let $s = size($l)
426461 let $acc0 = nil
427462 func $f4_1 ($a,$i) = if (($i >= $s))
428463 then $a
429464 else handler1($a, $l[$i])
430465
431466 func $f4_2 ($a,$i) = if (($i >= $s))
432467 then $a
433468 else throw("List size exceeds 10")
434469
435470 $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)
436471 }
437472 if ((ids == ids))
438473 then {
439474 func handler2 (accum,assetId) = if ((indexOf(ids, assetId) != unit))
440475 then (accum + 1)
441476 else throw(("asset not attached: " + getAssetString(assetId)))
442477
443478 let checks = {
444479 let $l = assetIds
445480 let $s = size($l)
446481 let $acc0 = 0
447482 func $f5_1 ($a,$i) = if (($i >= $s))
448483 then $a
449484 else handler2($a, $l[$i])
450485
451486 func $f5_2 ($a,$i) = if (($i >= $s))
452487 then $a
453488 else throw("List size exceeds 10")
454489
455490 $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)
456491 }
457492 if ((checks == checks))
458493 then true
459494 else throw("Strict value is not equal to itself.")
460495 }
461496 else throw("Strict value is not equal to itself.")
462497 }
463498
464499
465500 func handlePoolTokensAdd (PIssued,payments,userAddress,needChange) = {
466501 func getTokenPaymentAmount (tokenId) = {
467502 func handler (accum,payment) = if ((payment.assetId == tokenId))
468503 then payment.amount
469504 else accum
470505
471506 let $l = payments
472507 let $s = size($l)
473508 let $acc0 = 0
474509 func $f4_1 ($a,$i) = if (($i >= $s))
475510 then $a
476511 else handler($a, $l[$i])
477512
478513 func $f4_2 ($a,$i) = if (($i >= $s))
479514 then $a
480515 else throw("List size exceeds 10")
481516
482517 $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)
483518 }
484519
485520 func handleTokenChange (accum,tokenId) = {
486521 let assetIdStr = getAssetString(tokenId)
522+ let assetParams = loadGlobalTokenParams(assetIdStr)
487523 let paymentAmount = getTokenPaymentAmount(tokenId)
488- let Bk = getFactBalance(assetIdStr)
524+ let Bk = assetParams._2
489525 let PSupply = getVirtualPoolTokenAmount()
490526 let tokenDecimals = tryGetInteger((("static_" + assetIdStr) + "_scale"))
491527 let a1 = fraction((toBigInt((PSupply + PIssued)) * toBigInt(Scale8)), toBigInt(tokenDecimals), toBigInt(PSupply), CEILING)
492528 let Dk = toInt(fraction((a1 - (toBigInt(tokenDecimals) * toBigInt(Scale8))), toBigInt(Bk), (toBigInt(tokenDecimals) * toBigInt(Scale8)), CEILING))
493529 let toReturn = (paymentAmount - Dk)
494530 let stakeTx = stakeIfNeeded(assetIdStr, Dk)
495531 if ((stakeTx == stakeTx))
496532 then {
497533 let t = if (if (needChange)
498534 then (toReturn > 0)
499535 else false)
500536 then [ScriptTransfer(userAddress, toReturn, tokenId)]
501537 else nil
502- (((accum ++ t) ++ [IntegerEntry((("global_" + assetIdStr) + "_factBalance"), (tryGetInteger((("global_" + assetIdStr) + "_factBalance")) + Dk)), IntegerEntry((("global_" + assetIdStr) + "_balance"), fraction(tryGetInteger((("global_" + assetIdStr) + "_balance")), (PSupply + PIssued), PSupply))]) ++ (if ((tryGetInteger((("global_" + assetIdStr) + "_selloffStartHeight")) != ((height / 100) * 100)))
503- then nil
504- else [IntegerEntry((("global_" + assetIdStr) + "_selloffStartBalance"), fraction(tryGetInteger((("global_" + assetIdStr) + "_selloffStartBalance")), (PSupply + PIssued), PSupply))]))
538+ let selloffStartBalance = if ((assetParams._8 != ((height / 100) * 100)))
539+ then assetParams._7
540+ else fraction(assetParams._7, (PSupply + PIssued), PSupply)
541+ let assetParamsUpd = $Tuple8(fraction(assetParams._1, (PSupply + PIssued), PSupply, HALFEVEN), (assetParams._2 + Dk), assetParams._3, assetParams._4, assetParams._5, assetParams._6, selloffStartBalance, assetParams._8)
542+ ((accum ++ t) ++ [saveGlobalTokenParams(assetIdStr, assetParamsUpd)])
505543 }
506544 else throw("Strict value is not equal to itself.")
507545 }
508546
509547 let $l = assetIds
510548 let $s = size($l)
511549 let $acc0 = nil
512550 func $f4_1 ($a,$i) = if (($i >= $s))
513551 then $a
514552 else handleTokenChange($a, $l[$i])
515553
516554 func $f4_2 ($a,$i) = if (($i >= $s))
517555 then $a
518556 else throw("List size exceeds 10")
519557
520558 $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)
521559 }
522560
523561
524562 func calcMintedWithOneToken (assetAddedIdStr,amount) = {
525563 let PSupply = getVirtualPoolTokenAmount()
526- let assetFactBalance = tryGetInteger((("global_" + assetAddedIdStr) + "_factBalance"))
527- let assetVirtBalance = tryGetInteger((("global_" + assetAddedIdStr) + "_balance"))
564+ let assetParams = loadGlobalTokenParams(assetAddedIdStr)
565+ let assetFactBalance = assetParams._2
566+ let assetVirtBalance = assetParams._1
528567 let assetWeight = tryGetInteger((("static_" + assetAddedIdStr) + "_weight"))
529568 let assetScale = tryGetInteger((("static_" + assetAddedIdStr) + "_scale"))
530569 let assetDecimals = tryGetInteger((("static_" + assetAddedIdStr) + "_decimals"))
531570 let PIssuedNoMultiplier = fraction(PSupply, (toInt(pow(toBigInt((assetScale + fraction(amount, assetScale, assetVirtBalance))), assetDecimals, toBigInt(assetWeight), 4, 8, DOWN)) - Scale8), Scale8)
532571 let avgConc = calcAvgConcentration()
533572 let PIssued = fraction(PIssuedNoMultiplier, avgConc._2, avgConc._1)
534- $Tuple2([IntegerEntry((("global_" + assetAddedIdStr) + "_factBalance"), (assetFactBalance + amount)), IntegerEntry((("global_" + assetAddedIdStr) + "_balance"), (assetVirtBalance + amount))], PIssued)
573+ let assetParamsUpd = $Tuple8((assetVirtBalance + amount), (assetFactBalance + amount), assetParams._3, assetParams._4, assetParams._5, assetParams._6, assetParams._7, assetParams._8)
574+ $Tuple2([saveGlobalTokenParams(assetAddedIdStr, assetParamsUpd)], PIssued)
535575 }
536576
537577
538578 func calcRedeemWithOneToken (assetOutIdStr,PRedeemed) = {
539579 let PSupply = getVirtualPoolTokenAmount()
540- let assetFactBalance = tryGetInteger((("global_" + assetOutIdStr) + "_factBalance"))
541- let assetVirtBalance = tryGetInteger((("global_" + assetOutIdStr) + "_balance"))
580+ let assetParams = loadGlobalTokenParams(assetOutIdStr)
581+ let assetFactBalance = assetParams._2
582+ let assetVirtBalance = assetParams._1
542583 let assetWeight = tryGetInteger((("static_" + assetOutIdStr) + "_weight"))
543584 let assetScale = tryGetInteger((("static_" + assetOutIdStr) + "_scale"))
544585 let assetDecimals = tryGetInteger((("static_" + assetOutIdStr) + "_decimals"))
545586 let amountOutNoMulitplier = fraction(assetVirtBalance, (Scale8 - toInt(pow(toBigInt((assetScale - fraction(PRedeemed, assetScale, PSupply))), assetDecimals, toBigInt(fraction(10000, 10000, assetWeight)), 4, 8, DOWN))), Scale8)
546587 let avgConc = calcAvgConcentration()
547588 let amountOut = fraction(amountOutNoMulitplier, avgConc._1, avgConc._2)
548589 if ((amountOut > assetFactBalance))
549590 then throw("no available fact liquidity to withdraw in one token")
550- else $Tuple2([IntegerEntry((("global_" + assetOutIdStr) + "_factBalance"), (assetFactBalance - amountOut)), IntegerEntry((("global_" + assetOutIdStr) + "_balance"), (assetVirtBalance - amountOut))], amountOut)
591+ else {
592+ let assetParamsUpd = $Tuple8((assetVirtBalance - amountOut), (assetFactBalance - amountOut), assetParams._3, assetParams._4, assetParams._5, assetParams._6, assetParams._7, assetParams._8)
593+ $Tuple2([saveGlobalTokenParams(assetOutIdStr, assetParamsUpd)], amountOut)
594+ }
551595 }
552596
553597
554598 func handlePoolTokensRedeem (PRedeemed,userAddress) = {
555599 func handleTokenRedeem (accum,tokenId) = {
556600 let assetIdStr = getAssetString(tokenId)
557- let Bk = getFactBalance(assetIdStr)
601+ let assetParams = loadGlobalTokenParams(assetIdStr)
602+ let Bk = assetParams._2
558603 let PSupply = getVirtualPoolTokenAmount()
559604 let tokenDecimals = tryGetInteger((("static_" + assetIdStr) + "_scale"))
560605 let psuppl = fraction((toBigInt((PSupply - PRedeemed)) * toBigInt(Scale8)), toBigInt(Scale8), toBigInt(PSupply), DOWN)
561- let amount = toInt(fraction((toBigInt(Scale16) - psuppl), toBigInt(Bk), toBigInt(Scale16), CEILING))
606+ let amount = toInt(fraction((toBigInt(Scale16) - psuppl), toBigInt(Bk), toBigInt(Scale16), HALFEVEN))
562607 let unstakeTx = unstakeIfNeeded(assetIdStr, amount)
563608 if ((unstakeTx == unstakeTx))
564- then ((accum ++ [IntegerEntry((("global_" + assetIdStr) + "_factBalance"), (tryGetInteger((("global_" + assetIdStr) + "_factBalance")) - amount)), IntegerEntry((("global_" + assetIdStr) + "_balance"), fraction(tryGetInteger((("global_" + assetIdStr) + "_balance")), (PSupply - PRedeemed), PSupply)), ScriptTransfer(userAddress, amount, tokenId)]) ++ (if ((tryGetInteger((("global_" + assetIdStr) + "_selloffStartHeight")) != ((height / 100) * 100)))
565- then nil
566- else [IntegerEntry((("global_" + assetIdStr) + "_selloffStartBalance"), fraction(tryGetInteger((("global_" + assetIdStr) + "_selloffStartBalance")), (PSupply - PRedeemed), PSupply))]))
609+ then {
610+ let selloffStartBalance = if ((assetParams._8 != ((height / 100) * 100)))
611+ then assetParams._7
612+ else fraction(assetParams._7, (PSupply - PRedeemed), PSupply)
613+ let assetParamsUpd = $Tuple8(fraction(assetParams._1, (PSupply - PRedeemed), PSupply), (assetParams._2 - amount), assetParams._3, assetParams._4, assetParams._5, assetParams._6, selloffStartBalance, assetParams._8)
614+ ((accum ++ [ScriptTransfer(userAddress, amount, tokenId)]) ++ [saveGlobalTokenParams(assetIdStr, assetParamsUpd)])
615+ }
567616 else throw("Strict value is not equal to itself.")
568617 }
569618
570619 let $l = assetIds
571620 let $s = size($l)
572621 let $acc0 = nil
573622 func $f4_1 ($a,$i) = if (($i >= $s))
574623 then $a
575624 else handleTokenRedeem($a, $l[$i])
576625
577626 func $f4_2 ($a,$i) = if (($i >= $s))
578627 then $a
579628 else throw("List size exceeds 10")
580629
581630 $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)
582631 }
583632
584633
585634 func calculateOutAmount (AmountIn,assetIn,assetOut,BalanceIn,BalanceOut) = {
586635 let IndexIn = value(indexOf(assetIds, assetIn))
587636 let IndexOut = value(indexOf(assetIds, assetOut))
588637 if ((IndexIn == IndexOut))
589638 then AmountIn
590639 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)
591640 }
592641
593642
594643 func claimResult (address) = {
595644 let addressStr = toString(address)
596645 let indexAmount = tryGetInteger((addressStr + "_indexStaked"))
646+ let feeAssetStr = tryGetString("static_feeToken")
647+ let feeAssetParams = loadGlobalTokenParams(feeAssetStr)
648+ let feeTokenBalance = feeAssetParams._1
597649 func handler (accum,assetId) = {
598650 let assetIdStr = getAssetString(assetId)
599- let currentTokenInterest = tryGetInteger((("global_lastCheck_" + assetIdStr) + "_interest"))
600- let aBalance = tryGetInteger((("global_" + getAssetString(assetId)) + "_balance"))
651+ let assetParams = loadGlobalTokenParams(assetIdStr)
652+ let currentTokenInterest = assetParams._4
653+ let aBalance = assetParams._1
601654 let rewardAmount = fraction(indexAmount, (currentTokenInterest - tryGetInteger((((addressStr + "_lastCheck_") + assetIdStr) + "_interest"))), Scale16)
602655 let unstakeInv = unstakeIfNeeded(assetIdStr, rewardAmount)
603656 if ((unstakeInv == unstakeInv))
604657 then {
605658 let transfer = if ((rewardAmount == 0))
606659 then nil
607660 else [ScriptTransfer(address, rewardAmount, assetId)]
608- $Tuple2(((accum._1 ++ transfer) ++ [IntegerEntry((((addressStr + "_lastCheck_") + assetIdStr) + "_interest"), currentTokenInterest)]), (accum._2 + calculateUsdValue(assetId, rewardAmount, aBalance)))
661+ $Tuple2(((accum._1 ++ transfer) ++ [IntegerEntry((((addressStr + "_lastCheck_") + assetIdStr) + "_interest"), currentTokenInterest)]), (accum._2 + calculateUsdValue(assetId, rewardAmount, aBalance, feeTokenBalance)))
609662 }
610663 else throw("Strict value is not equal to itself.")
611664 }
612665
613666 let accum = {
614667 let $l = earnedAssets
615668 let $s = size($l)
616669 let $acc0 = $Tuple2(nil, 0)
617670 func $f4_1 ($a,$i) = if (($i >= $s))
618671 then $a
619672 else handler($a, $l[$i])
620673
621674 func $f4_2 ($a,$i) = if (($i >= $s))
622675 then $a
623676 else throw("List size exceeds 10")
624677
625678 $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)
626679 }
627680 $Tuple2((accum._1 ++ [IntegerEntry((addressStr + "_claimedRewardUSD"), (tryGetInteger((addressStr + "_claimedRewardUSD")) + accum._2)), IntegerEntry((addressStr + "_lastClaim"), lastBlock.timestamp)]), accum._2)
628681 }
629682
630683
631684 func indexStakeResult (addressStr,amount) = {
632685 let li = claimResult(addressFromStringValue(addressStr))._1
633686 (li ++ [IntegerEntry((addressStr + "_indexStaked"), (tryGetInteger((addressStr + "_indexStaked")) + amount)), IntegerEntry("global_indexStaked", (tryGetInteger("global_indexStaked") + amount))])
634687 }
635688
636689
637690 func sum (accum,n) = (accum + parseIntValue(n))
638691
639692
640693 func checkFeeAsset (accum,next) = if (if ((indexOf(supportedFeeAssetsStr, next) != unit))
641694 then (accum == "")
642695 else false)
643696 then next
644697 else accum
645698
646699
647700 func calcInterestChange (assetIdStr,lpFee) = {
648701 let totalIndex = tryGetInteger("global_indexStaked")
649702 let interestDelta = fraction(lpFee, Scale16, totalIndex)
650- IntegerEntry((("global_lastCheck_" + assetIdStr) + "_interest"), (tryGetInteger((("global_lastCheck_" + assetIdStr) + "_interest")) + interestDelta))
703+ interestDelta
651704 }
652705
653706
654-func updSelloffData (assetIdStr,amountIn) = {
707+func updSelloffData (assetIdStr,amountIn,balance,selloffParams) = {
655708 let currentPeriod = ((height / 100) * 100)
656- let prevPeriod = tryGetInteger((("global_" + assetIdStr) + "_selloffStartHeight"))
709+ let prevPeriod = selloffParams._2
657710 let prevSelloff = if ((currentPeriod == prevPeriod))
658- then tryGetInteger((("global_" + assetIdStr) + "_selloff"))
711+ then selloffParams._1
659712 else 0
660713 let selloffStartBalance = if ((currentPeriod == prevPeriod))
661- then tryGetInteger((("global_" + assetIdStr) + "_selloffStartBalance"))
662- else tryGetInteger((("global_" + assetIdStr) + "_balance"))
714+ then selloffParams._3
715+ else balance
663716 let selloffDelta = fraction(Scale16, amountIn, selloffStartBalance)
664717 let maxSelloff = tryGetInteger((("static_" + assetIdStr) + "_maxSelloff"))
665718 if (if (((prevSelloff + selloffDelta) > maxSelloff))
666719 then (maxSelloff != 0)
667720 else false)
668721 then throw(("max selloff reached for this asset " + assetIdStr))
669- else ([IntegerEntry((("global_" + assetIdStr) + "_selloff"), (prevSelloff + selloffDelta))] ++ (if ((currentPeriod == prevPeriod))
670- then nil
671- else [IntegerEntry((("global_" + assetIdStr) + "_selloffStartHeight"), currentPeriod), IntegerEntry((("global_" + assetIdStr) + "_selloffStartBalance"), selloffStartBalance)]))
722+ else {
723+ let startH = if ((currentPeriod == prevPeriod))
724+ then prevPeriod
725+ else currentPeriod
726+ let startB = if ((currentPeriod == prevPeriod))
727+ then selloffParams._3
728+ else selloffStartBalance
729+ $Tuple3((prevSelloff + selloffDelta), startH, startB)
730+ }
672731 }
673732
674733
675734 func getTmpRebalanceIds (newAssetIdsLi) = {
676735 let currentAssetIdsLi = split(tryGetString("static_tokenIds"), ",")
677736 let result = newAssetIdsLi
678737 func f (accum,assetId) = if ((indexOf(result, assetId) == unit))
679738 then (accum ++ [assetId])
680739 else accum
681740
682741 let $l = currentAssetIdsLi
683742 let $s = size($l)
684743 let $acc0 = result
685744 func $f4_1 ($a,$i) = if (($i >= $s))
686745 then $a
687746 else f($a, $l[$i])
688747
689748 func $f4_2 ($a,$i) = if (($i >= $s))
690749 then $a
691750 else throw("List size exceeds 10")
692751
693752 $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)
694753 }
695754
696755
697756 func checkTokensChange (newAssetIdsLi) = {
698757 let currentAssetIdsLi = split(tryGetString("static_tokenIds"), ",")
699758 func rem (accum,assetId) = if ((indexOf(newAssetIdsLi, assetId) == unit))
700759 then (accum + 1)
701760 else accum
702761
703762 func add (accum,assetId) = if ((indexOf(currentAssetIdsLi, assetId) == unit))
704763 then (accum + 1)
705764 else accum
706765
707766 let removed = {
708767 let $l = currentAssetIdsLi
709768 let $s = size($l)
710769 let $acc0 = 0
711770 func $f4_1 ($a,$i) = if (($i >= $s))
712771 then $a
713772 else rem($a, $l[$i])
714773
715774 func $f4_2 ($a,$i) = if (($i >= $s))
716775 then $a
717776 else throw("List size exceeds 10")
718777
719778 $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)
720779 }
721780 let added = {
722781 let $l = newAssetIdsLi
723782 let $s = size($l)
724783 let $acc0 = 0
725784 func $f5_1 ($a,$i) = if (($i >= $s))
726785 then $a
727786 else add($a, $l[$i])
728787
729788 func $f5_2 ($a,$i) = if (($i >= $s))
730789 then $a
731790 else throw("List size exceeds 10")
732791
733792 $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)
734793 }
735794 (removed + added)
736795 }
737796
738797
739798 func validatePayments (assetsList,payments) = {
740799 func getPaymentAssets (accum,next) = if ((0 >= next.amount))
741800 then throw(((("Too low payment amount for " + getAssetString(next.assetId)) + ": ") + toString(next.amount)))
742801 else (accum ++ [getAssetString(next.assetId)])
743802
744803 let paymentList = {
745804 let $l = payments
746805 let $s = size($l)
747806 let $acc0 = nil
748807 func $f4_1 ($a,$i) = if (($i >= $s))
749808 then $a
750809 else getPaymentAssets($a, $l[$i])
751810
752811 func $f4_2 ($a,$i) = if (($i >= $s))
753812 then $a
754813 else throw("List size exceeds 10")
755814
756815 $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)
757816 }
758817 func f1 (accum,next) = if ((indexOf(assetsList, next) == unit))
759818 then throw(((next + " asset is present in payments, but is not in new assets: ") + makeString(assetsList, ",")))
760819 else (accum + 1)
761820
762821 func f2 (accum,next) = if ((indexOf(paymentList, next) == unit))
763822 then throw(((next + " asset is present in new assets, but is not in payments: ") + makeString(paymentList, ",")))
764823 else (accum + 1)
765824
766825 let a1 = {
767826 let $l = paymentList
768827 let $s = size($l)
769828 let $acc0 = 0
770829 func $f5_1 ($a,$i) = if (($i >= $s))
771830 then $a
772831 else f1($a, $l[$i])
773832
774833 func $f5_2 ($a,$i) = if (($i >= $s))
775834 then $a
776835 else throw("List size exceeds 10")
777836
778837 $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)
779838 }
780839 let a2 = {
781840 let $l = assetsList
782841 let $s = size($l)
783842 let $acc0 = 0
784843 func $f6_1 ($a,$i) = if (($i >= $s))
785844 then $a
786845 else f2($a, $l[$i])
787846
788847 func $f6_2 ($a,$i) = if (($i >= $s))
789848 then $a
790849 else throw("List size exceeds 10")
791850
792851 $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)
793852 }
794853 (a1 + a2)
795854 }
796855
797856
798857 func validateWeights (weights) = {
799858 func v (accum,w) = {
800859 let wInt = valueOrErrorMessage(parseInt(w), ("Wrong weight format: " + w))
801860 if (if ((MIN_WEIGHT > wInt))
802861 then true
803862 else (wInt > MAX_WEIGHT))
804863 then throw(((((("Weight should be in range " + toString(MIN_WEIGHT)) + " - ") + toString(MAX_WEIGHT)) + ", current: ") + w))
805- else accum
864+ else (accum + wInt)
806865 }
807866
808867 let $l = weights
809868 let $s = size($l)
810869 let $acc0 = 0
811870 func $f4_1 ($a,$i) = if (($i >= $s))
812871 then $a
813872 else v($a, $l[$i])
814873
815874 func $f4_2 ($a,$i) = if (($i >= $s))
816875 then $a
817876 else throw("List size exceeds 10")
818877
819878 $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)
820879 }
821880
822881
823882 func getP1P2 (assetIdStr,baseAssetIdStr) = {
824- let B1 = tryGetInteger((("global_" + baseAssetIdStr) + "_balance"))
825- let B2 = tryGetInteger((("global_" + assetIdStr) + "_balance"))
826- let F1 = getFactBalance(baseAssetIdStr)
827- let F2 = getFactBalance(assetIdStr)
883+ let assetParams = loadGlobalTokenParams(assetIdStr)
884+ let baseAssetParams = loadGlobalTokenParams(baseAssetIdStr)
885+ let B1 = baseAssetParams._1
886+ let B2 = assetParams._1
887+ let F1 = baseAssetParams._2
888+ let F2 = assetParams._2
828889 let S1 = tryGetInteger((("static_" + baseAssetIdStr) + "_scale"))
829890 let S2 = tryGetInteger((("static_" + assetIdStr) + "_scale"))
830891 let D1 = tryGetInteger((("static_" + baseAssetIdStr) + "_decimals"))
831892 let D2 = tryGetInteger((("static_" + assetIdStr) + "_decimals"))
832893 let W1 = tryGetInteger((("static_" + baseAssetIdStr) + "_weight"))
833894 let W2 = tryGetInteger((("static_" + assetIdStr) + "_weight"))
834895 let W1W2 = fraction(W1, 10000, W2)
835896 let W2W1 = fraction(W2, 10000, W1)
836897 let p1_unweighted = fraction((B1 - F1), S1, fraction(B2, pow(fraction(B1, S1, (B1 - F1)), D1, W1W2, 4, D1, CEILING), S2))
837898 let p1 = fraction(p1_unweighted, W2W1, 10000)
838899 if ((B2 == F2))
839900 then $Tuple2(p1, unit)
840901 else {
841902 let p2_unweighted = fraction(fraction(B1, pow(fraction(B2, S2, (B2 - F2)), D2, W2W1, 4, D2, FLOOR), S2), S2, (B2 - F2))
842903 let p2 = fraction(p2_unweighted, W2W1, 10000)
843904 $Tuple2(p1, p2)
844905 }
845906 }
846907
847908
848909 @Callable(i)
849910 func addUnderlyingStaker (stakerAddress,assetIdStr) = if ((this != i.caller))
850911 then throw("admin only")
851912 else [StringEntry(("static_stakingContract_" + assetIdStr), stakerAddress)]
852913
853914
854915
855916 @Callable(i)
856917 func preInit (assetIdsStr,assetWeightsStr,assetMaxSelloffStr,baseTokenIdStr,poolDomain,poolOwner,fee) = {
857918 let poolOwnerAddress = addressFromStringValue(poolOwner)
858919 let assetIdsStrLi = split(assetIdsStr, ",")
859920 let assetMaxSelloffStrLi = split(assetMaxSelloffStr, ",")
921+ let assetWeightsStrLi = split(assetWeightsStr, ",")
860922 let assetIdsLi = {
861923 let $l = assetIdsStrLi
862924 let $s = size($l)
863925 let $acc0 = nil
864926 func $f4_1 ($a,$i) = if (($i >= $s))
865927 then $a
866928 else addAssetBytesToList($a, $l[$i])
867929
868930 func $f4_2 ($a,$i) = if (($i >= $s))
869931 then $a
870932 else throw("List size exceeds 10")
871933
872934 $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)
873935 }
874936 let feeAssetChosenStr = {
875937 let $l = assetIdsStrLi
876938 let $s = size($l)
877939 let $acc0 = ""
878940 func $f5_1 ($a,$i) = if (($i >= $s))
879941 then $a
880942 else checkFeeAsset($a, $l[$i])
881943
882944 func $f5_2 ($a,$i) = if (($i >= $s))
883945 then $a
884946 else throw("List size exceeds 10")
885947
886948 $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)
887949 }
888950 let feeAssetStr = if ((feeAssetChosenStr == ""))
889951 then baseTokenIdStr
890952 else feeAssetChosenStr
891953 if (isShutdown())
892954 then throw("contract is on stop")
893955 else if ((this != i.caller))
894956 then throw("admin only")
895957 else if ((size(poolDomain) > 13))
896958 then throw("too large pool domain")
897959 else if (if ((fee > 500))
898960 then true
899961 else (0 > fee))
900962 then throw("fee value must be between 0 and 500 (0-5%)")
901- else {
902- let assetWeightsStrLi = split(assetWeightsStr, ",")
903- func addTokenDataEntries (accum,assetNum) = if ((assetNum >= size(assetIdsLi)))
904- then accum
905- else {
906- let assetStakingAddress = {
907- let @ = invoke(poolsHubAddress, "useEmptyContract", [("staker_" + assetIdsStrLi[assetNum])], nil)
908- if ($isInstanceOf(@, "String"))
909- then @
910- else throw(($getType(@) + " couldn't be cast to String"))
963+ else if ((validateWeights(assetWeightsStrLi) != 10000))
964+ then throw(("weights sum should be 10000, current: " + toString(validateWeights(assetWeightsStrLi))))
965+ else {
966+ func addTokenDataEntries (accum,assetNum) = if ((assetNum >= size(assetIdsLi)))
967+ then accum
968+ else {
969+ let assetStakingAddress = {
970+ let @ = invoke(poolsHubAddress, "useEmptyContract", [("staker_" + assetIdsStrLi[assetNum])], nil)
971+ if ($isInstanceOf(@, "String"))
972+ then @
973+ else throw(($getType(@) + " couldn't be cast to String"))
974+ }
975+ if ((assetStakingAddress == assetStakingAddress))
976+ then {
977+ let assetDecimals = match assetIdsLi[assetNum] {
978+ case x: ByteVector =>
979+ value(assetInfo(x)).decimals
980+ case _ =>
981+ 8
982+ }
983+ ((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]))), StringEntry(("static_stakingContract_" + assetIdsStrLi[assetNum]), assetStakingAddress)]) ++ (if ((assetMaxSelloffStrLi[assetNum] == ""))
984+ then nil
985+ else [IntegerEntry((("static_" + assetIdsStrLi[assetNum]) + "_maxSelloff"), (parseIntValue(assetMaxSelloffStrLi[assetNum]) * Scale12))]))
986+ }
987+ else throw("Strict value is not equal to itself.")
911988 }
912- if ((assetStakingAddress == assetStakingAddress))
913- then {
914- let assetDecimals = match assetIdsLi[assetNum] {
915- case x: ByteVector =>
916- value(assetInfo(x)).decimals
917- case _ =>
918- 8
919- }
920- ((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]))), StringEntry(("static_stakingContract_" + assetIdsStrLi[assetNum]), assetStakingAddress)]) ++ (if ((assetMaxSelloffStrLi[assetNum] == ""))
921- then nil
922- else [IntegerEntry((("static_" + assetIdsStrLi[assetNum]) + "_maxSelloff"), (parseIntValue(assetMaxSelloffStrLi[assetNum]) * Scale12))]))
923- }
924- else throw("Strict value is not equal to itself.")
925- }
926989
927- ({
928- let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
929- let $s = size($l)
930- let $acc0 = nil
931- func $f6_1 ($a,$i) = if (($i >= $s))
932- then $a
933- else addTokenDataEntries($a, $l[$i])
990+ ({
991+ let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
992+ let $s = size($l)
993+ let $acc0 = nil
994+ func $f6_1 ($a,$i) = if (($i >= $s))
995+ then $a
996+ else addTokenDataEntries($a, $l[$i])
934997
935- func $f6_2 ($a,$i) = if (($i >= $s))
936- then $a
937- else throw("List size exceeds 10")
998+ func $f6_2 ($a,$i) = if (($i >= $s))
999+ then $a
1000+ else throw("List size exceeds 10")
9381001
939- $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)
940- } ++ [StringEntry("static_tokenIds", assetIdsStr), StringEntry("static_feeToken", feeAssetStr), StringEntry("static_tokenWeights", assetWeightsStr), IntegerEntry("static_tokensAmount", size(assetIdsLi)), StringEntry("static_poolDomain", poolDomain), StringEntry("static_poolToken_idStr", ""), StringEntry("static_baseTokenId", baseTokenIdStr), StringEntry("static_poolOwner", poolOwner), IntegerEntry("static_fee", fee), IntegerEntry("static_KMult", Scale16), IntegerEntry("global_indexStaked", 0), IntegerEntry("global_poolToken_amount", 0), IntegerEntry("global_wasPreInited", 1)])
941- }
1002+ $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)
1003+ } ++ [StringEntry("static_tokenIds", assetIdsStr), StringEntry("static_feeToken", feeAssetStr), StringEntry("static_tokenWeights", assetWeightsStr), IntegerEntry("static_tokensAmount", size(assetIdsLi)), StringEntry("static_poolDomain", poolDomain), StringEntry("static_poolToken_idStr", ""), StringEntry("static_baseTokenId", baseTokenIdStr), StringEntry("static_poolOwner", poolOwner), IntegerEntry("static_fee", fee), IntegerEntry("static_KMult", Scale16), IntegerEntry("global_indexStaked", 0), IntegerEntry("global_poolToken_amount", 0), IntegerEntry("global_wasPreInited", 1)])
1004+ }
9421005 }
9431006
9441007
9451008
9461009 @Callable(i)
9471010 func deInit () = if (isShutdown())
9481011 then throw("contract is on stop")
9491012 else if ((i.caller != this))
9501013 then throw("admin only")
9511014 else [IntegerEntry("global_wasInited", 0)]
9521015
9531016
9541017
9551018 @Callable(i)
9561019 func init (assetIdsStr,assetWeightsStr,assetMaxSelloffStr,baseTokenIdStr,poolDomain,fee,vBalancesStr) = {
9571020 let preInitInv = invoke(this, "preInit", [assetIdsStr, assetWeightsStr, assetMaxSelloffStr, baseTokenIdStr, poolDomain, toString(i.caller), fee], nil)
9581021 if ((preInitInv == preInitInv))
9591022 then {
9601023 let vBalances = parstStrToIntList(vBalancesStr)
961- func prepareList () = {
962- func handler (accum,assetId) = {
963- let n = value(indexOf(assetIds, assetId))
964- (accum ++ [IntegerEntry((("global_" + getAssetString(assetId)) + "_balance"), vBalances[n]), IntegerEntry((("global_lastCheck_" + getAssetString(assetId)) + "_interest"), 0)])
965- }
1024+ func getPaymentAmount (assetIdStr) = {
1025+ func handler (accum,payment) = if ((getAssetString(payment.assetId) == assetIdStr))
1026+ then payment.amount
1027+ else accum
9661028
967- let $l = assetIds
1029+ let $l = i.payments
9681030 let $s = size($l)
969- let $acc0 = nil
1031+ let $acc0 = 0
9701032 func $f4_1 ($a,$i) = if (($i >= $s))
9711033 then $a
9721034 else handler($a, $l[$i])
9731035
9741036 func $f4_2 ($a,$i) = if (($i >= $s))
9751037 then $a
9761038 else throw("List size exceeds 10")
9771039
9781040 $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)
9791041 }
9801042
981- func prepareList2 () = {
982- func handler1 (accum,payment) = {
983- let stakeTx = stakeIfNeeded(getAssetString(payment.assetId), payment.amount)
984- if ((stakeTx == stakeTx))
985- then (accum ++ [IntegerEntry((("global_" + getAssetString(payment.assetId)) + "_factBalance"), payment.amount)])
986- else throw("Strict value is not equal to itself.")
1043+ func prepareList () = {
1044+ func handler (accum,assetId) = {
1045+ let assetIdStr = getAssetString(assetId)
1046+ let n = value(indexOf(assetIds, assetId))
1047+ let paymentAmount = getPaymentAmount(assetIdStr)
1048+ let assetParams = loadGlobalTokenParams(assetIdStr)
1049+ let assetParamsUpd = $Tuple8(vBalances[n], paymentAmount, assetParams._3, assetParams._4, assetParams._5, assetParams._6, assetParams._7, assetParams._8)
1050+ (accum ++ [saveGlobalTokenParams(assetIdStr, assetParamsUpd)])
9871051 }
9881052
989- let $l = i.payments
1053+ let $l = assetIds
9901054 let $s = size($l)
9911055 let $acc0 = nil
9921056 func $f4_1 ($a,$i) = if (($i >= $s))
9931057 then $a
994- else handler1($a, $l[$i])
1058+ else handler($a, $l[$i])
9951059
9961060 func $f4_2 ($a,$i) = if (($i >= $s))
9971061 then $a
9981062 else throw("List size exceeds 10")
9991063
10001064 $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)
10011065 }
10021066
10031067 func calculatePoolTokensAmount (assetId) = {
10041068 func handler (accum,assetId) = {
10051069 func handler2 (accum,n) = if ((n == assetId))
10061070 then value(indexOf(assetIds, n))
10071071 else accum
10081072
10091073 let Token = {
10101074 let $l = assetIds
10111075 let $s = size($l)
10121076 let $acc0 = 1
10131077 func $f4_1 ($a,$i) = if (($i >= $s))
10141078 then $a
10151079 else handler2($a, $l[$i])
10161080
10171081 func $f4_2 ($a,$i) = if (($i >= $s))
10181082 then $a
10191083 else throw("List size exceeds 10")
10201084
10211085 $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)
10221086 }
10231087 fraction(accum, pow(vBalances[Token], Decimals[Token], AssetsWeights[Token], AssetsWeightsDecimals, 8, FLOOR), Scale8)
10241088 }
10251089
10261090 let $l = assetIds
10271091 let $s = size($l)
10281092 let $acc0 = PoolTokenScale
10291093 func $f4_1 ($a,$i) = if (($i >= $s))
10301094 then $a
10311095 else handler($a, $l[$i])
10321096
10331097 func $f4_2 ($a,$i) = if (($i >= $s))
10341098 then $a
10351099 else throw("List size exceeds 10")
10361100
10371101 $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)
10381102 }
10391103
10401104 if (isShutdown())
10411105 then throw("contract is on stop")
10421106 else if ((size(i.payments) == 0))
10431107 then throw("at least some of the assets should be provided as payment")
10441108 else if ((tryGetInteger("global_wasInited") > 0))
10451109 then throw("pool already inited")
10461110 else {
10471111 let initialPoolTokens = calculatePoolTokensAmount(assetIds)
10481112 let notifyInvoke = invoke(poolsHubAddress, "addSelfPool", nil, nil)
10491113 if ((notifyInvoke == notifyInvoke))
10501114 then if ((initialPoolTokens == 0))
10511115 then throw("you need a bigger tokens amount to launch the pool")
1052- else ((prepareList() ++ prepareList2()) ++ [IntegerEntry("global_poolToken_amount", initialPoolTokens), IntegerEntry("global_wasInited", 1), IntegerEntry((toString(i.caller) + "_indexStaked"), initialPoolTokens), IntegerEntry("global_indexStaked", initialPoolTokens)])
1116+ else (prepareList() ++ [IntegerEntry("global_poolToken_amount", initialPoolTokens), IntegerEntry("global_wasInited", 1), IntegerEntry((toString(i.caller) + "_indexStaked"), initialPoolTokens), IntegerEntry("global_indexStaked", initialPoolTokens)])
10531117 else throw("Strict value is not equal to itself.")
10541118 }
10551119 }
10561120 else throw("Strict value is not equal to itself.")
10571121 }
10581122
10591123
10601124
10611125 @Callable(i)
10621126 func generateIndex (needChange) = if ((size(i.payments) != T))
10631127 then throw(("you need to attach all pool tokens. amount of pool tokens: " + toString(T)))
10641128 else if (!(checkTokensValidity(i.payments)))
10651129 then throw("wrong assets attached")
10661130 else {
10671131 let PIssuedNoMult = getMinPIssued(i.payments)
10681132 let result = handlePoolTokensAdd(PIssuedNoMult, i.payments, i.originCaller, needChange)
10691133 let PIssuedWithMult = fraction(PIssuedNoMult, Scale16, getKMult(), DOWN)
10701134 $Tuple2((((result ++ claimResult(i.caller)._1) ++ mintIndexIfNeeded(PIssuedWithMult)) ++ [IntegerEntry((toString(i.caller) + "_indexStaked"), (tryGetInteger((toString(i.caller) + "_indexStaked")) + PIssuedWithMult)), IntegerEntry("global_indexStaked", (tryGetInteger("global_indexStaked") + PIssuedWithMult)), IntegerEntry("global_poolToken_amount", (tryGetInteger("global_poolToken_amount") + PIssuedWithMult))]), PIssuedWithMult)
10711135 }
10721136
10731137
10741138
10751139 @Callable(i)
10761140 func redeemIndex (poolTokenAmount) = if ((poolTokenAmount > tryGetInteger((toString(i.caller) + "_indexStaked"))))
10771141 then throw("user doesn't have this amount of pool tokens")
10781142 else if (isShutdown())
10791143 then throw("contract is on stop")
10801144 else {
10811145 let PRedeemedWithMult = poolTokenAmount
10821146 let PRedeemedWithNoMult = fraction(PRedeemedWithMult, getKMult(), Scale16, DOWN)
10831147 let result = handlePoolTokensRedeem(PRedeemedWithNoMult, i.caller)
10841148 (((result ++ claimResult(i.caller)._1) ++ [IntegerEntry((toString(i.caller) + "_indexStaked"), (tryGetInteger((toString(i.caller) + "_indexStaked")) - PRedeemedWithMult)), IntegerEntry("global_indexStaked", (tryGetInteger("global_indexStaked") - PRedeemedWithMult)), IntegerEntry("global_poolToken_amount", (tryGetInteger("global_poolToken_amount") - PRedeemedWithMult))]) ++ burnIndexIfNeeded(poolTokenAmount))
10851149 }
10861150
10871151
10881152
10891153 @Callable(i)
10901154 func stakeIndex () = {
10911155 let addressStr = toString(i.originCaller)
10921156 let pmt = i.payments[0]
10931157 if ((value(pmt.assetId) != fromBase58String(tryGetString("static_poolToken_idStr"))))
10941158 then throw("wrong asset attached")
10951159 else indexStakeResult(addressStr, pmt.amount)
10961160 }
10971161
10981162
10991163
11001164 @Callable(i)
11011165 func stakeIndexFor (addressStr) = {
11021166 let pmt = i.payments[0]
11031167 if ((value(pmt.assetId) != fromBase58String(tryGetString("static_poolToken_idStr"))))
11041168 then throw("wrong asset attached")
11051169 else indexStakeResult(addressStr, pmt.amount)
11061170 }
11071171
11081172
11091173
11101174 @Callable(i)
11111175 func unstakeIndex (indexAmount) = {
11121176 func issueIndex () = {
11131177 let issue = Issue(("PR " + tryGetString("static_poolDomain")), "Puzzle Range Index", tryGetInteger("global_poolToken_amount"), PoolTokenDecimals, true, unit, 0)
11141178 let poolTokenIdStr = toBase58String(calculateAssetId(issue))
11151179 $Tuple2([issue, StringEntry("static_poolToken_idStr", poolTokenIdStr)], poolTokenIdStr)
11161180 }
11171181
1118- let $t03722937395 = if ((tryGetString("static_poolToken_idStr") == ""))
1182+ let $t04040840574 = if ((tryGetString("static_poolToken_idStr") == ""))
11191183 then issueIndex()
11201184 else $Tuple2(nil, tryGetString("static_poolToken_idStr"))
1121- let poolTokenIssueResult = $t03722937395._1
1122- let poolTokenIdStr = $t03722937395._2
1185+ let poolTokenIssueResult = $t04040840574._1
1186+ let poolTokenIdStr = $t04040840574._2
11231187 let poolTokenId = fromBase58String(poolTokenIdStr)
11241188 let addressStr = toString(i.caller)
11251189 let indexAvailable = tryGetInteger((addressStr + "_indexStaked"))
11261190 if (isShutdown())
11271191 then throw("contract is on stop")
11281192 else if ((indexAmount > indexAvailable))
11291193 then throw("you don't have index tokens available")
11301194 else if (isShutdown())
11311195 then throw("contract is on stop")
11321196 else ((poolTokenIssueResult ++ claimResult(addressFromStringValue(addressStr))._1) ++ [IntegerEntry((addressStr + "_indexStaked"), (indexAvailable - indexAmount)), IntegerEntry("global_indexStaked", (tryGetInteger("global_indexStaked") - indexAmount)), ScriptTransfer(i.caller, indexAmount, poolTokenId)])
11331197 }
11341198
11351199
11361200
11371201 @Callable(i)
11381202 func claimIndexRewards () = if (isShutdown())
11391203 then throw("contract is on stop")
11401204 else claimResult(i.caller)
11411205
11421206
11431207
11441208 @Callable(i)
11451209 func evaluateClaim (user) = $Tuple2(nil, claimResult(addressFromStringValue(user))._2)
11461210
11471211
11481212
11491213 @Callable(i)
11501214 func addInterestExternal () = {
11511215 let assetId = value(i.payments[0]).assetId
11521216 let assetIdStr = getAssetString(assetId)
11531217 let amount = i.payments[0].amount
11541218 let stakeTx = stakeIfNeeded(assetIdStr, amount)
11551219 if ((stakeTx == stakeTx))
11561220 then if ((indexOf(assetIds, assetId) == unit))
11571221 then throw("you can only add interest for assets in the pool")
1158- else [calcInterestChange(assetIdStr, amount), IntegerEntry(("global_extraEarned_" + assetIdStr), (tryGetInteger(("global_extraEarned_" + assetIdStr)) + amount))]
1222+ else {
1223+ let params = loadGlobalTokenParams(assetIdStr)
1224+ let interestDelta = calcInterestChange(assetIdStr, amount)
1225+ let updParams = $Tuple8(params._1, params._2, params._3, (params._4 + interestDelta), (params._5 + amount), params._6, params._7, params._8)
1226+[saveGlobalTokenParams(assetIdStr, updParams)]
1227+ }
11591228 else throw("Strict value is not equal to itself.")
11601229 }
11611230
11621231
11631232
11641233 @Callable(i)
11651234 func notifyStakingPayment (assetIdStr,amount) = {
11661235 let assetId = getAssetBytes(assetIdStr)
11671236 if ((indexOf(assetIds, assetId) == unit))
11681237 then throw("you can only add interest for assets in the pool")
11691238 else if ((tryGetString(("static_stakingContract_" + assetIdStr)) != toString(i.caller)))
11701239 then throw("can only be invoked by staker contract")
1171- else [calcInterestChange(assetIdStr, amount), IntegerEntry(("global_extraEarned_" + assetIdStr), (tryGetInteger(("global_extraEarned_" + assetIdStr)) + amount))]
1240+ else {
1241+ let params = loadGlobalTokenParams(assetIdStr)
1242+ let interestDelta = calcInterestChange(assetIdStr, amount)
1243+ let updParams = $Tuple8(params._1, params._2, params._3, (params._4 + interestDelta), (params._5 + amount), params._6, params._7, params._8)
1244+[saveGlobalTokenParams(assetIdStr, updParams)]
1245+ }
11721246 }
11731247
11741248
11751249
11761250 @Callable(i)
11771251 func swap (assetOut,minimum) = {
11781252 let pmt = if ((size(i.payments) == 1))
11791253 then value(i.payments[0])
11801254 else throw("please attach exactly one payment")
11811255 let AmountIn = value(i.payments[0].amount)
11821256 let AssetIn = pmt.assetId
11831257 let AssetOut = getAssetBytes(assetOut)
11841258 let assetIn = getAssetString(AssetIn)
11851259 let scaleIn = (Scale8 / tryGetInteger((("static_" + assetIn) + "_scale")))
11861260 let scaleOut = (Scale8 / tryGetInteger((("static_" + assetOut) + "_scale")))
1187- let AssetInBalance = tryGetInteger((("global_" + getAssetString(AssetIn)) + "_balance"))
1188- let AssetOutBalance = tryGetInteger((("global_" + assetOut) + "_balance"))
1261+ let assetInParams = loadGlobalTokenParams(getAssetString(AssetIn))
1262+ let assetOutParams = loadGlobalTokenParams(assetOut)
1263+ let AssetInBalance = assetInParams._1
1264+ let AssetInFactBalance = assetInParams._2
1265+ let assetInFeesEarned = assetInParams._3
1266+ let assetInLastCheckInterest = assetInParams._4
1267+ let AssetOutBalance = assetOutParams._1
1268+ let assetOutFactBalance = assetOutParams._2
11891269 let AssetInBalanceScaled = (AssetInBalance * scaleIn)
11901270 let AssetOutBalanceScaled = (AssetOutBalance * scaleOut)
11911271 let feeAmountIn = fraction(AmountIn, Fee, FeeScale)
11921272 let cleanAmountIn = (AmountIn - feeAmountIn)
11931273 let cleanAmountInScaled = (cleanAmountIn * scaleIn)
11941274 let AmountOut1 = calculateOutAmount(cleanAmountInScaled, AssetIn, AssetOut, AssetInBalanceScaled, AssetOutBalanceScaled)
11951275 let AmountOut = fraction(AmountOut1, 1, scaleOut)
11961276 let AssetOutBalance2 = (AssetOutBalance - AmountOut)
11971277 let AssetInBalance2 = (AssetInBalance + cleanAmountIn)
11981278 if ((minimum > AmountOut))
11991279 then throw("amount to recieve is lower than given one")
12001280 else if ((AssetOut == AssetIn))
12011281 then throw("this swap is not allowed")
1202- else if ((0 > (getFactBalance(assetOut) - AmountOut)))
1282+ else if ((0 > (assetOutFactBalance - AmountOut)))
12031283 then throw("contract is out of reserves")
12041284 else if (isShutdown())
12051285 then throw("contract is on stop")
12061286 else if (valueOrElse(getBoolean(poolsHubAddress, ("global_shutdownIn_" + assetIn)), false))
12071287 then throw("token IN trades are stopped")
12081288 else if (valueOrElse(getBoolean(poolsHubAddress, ("global_shutdownOut_" + assetOut)), false))
12091289 then throw("token OUT trades are stopped")
12101290 else {
12111291 let protocolFee = fraction(feeAmountIn, 5, 10)
12121292 let lpFee = (feeAmountIn - protocolFee)
1213- let interestChange = calcInterestChange(assetIn, lpFee)
1214- let statsChange = IntegerEntry(("global_feesEarned_" + assetIn), (tryGetInteger(("global_feesEarned_" + assetIn)) + lpFee))
1293+ let interestDelta = calcInterestChange(assetIn, lpFee)
12151294 let stakeTx = stakeIfNeeded(assetIn, (cleanAmountIn + lpFee))
12161295 if ((stakeTx == stakeTx))
12171296 then {
12181297 let unstakeTx = unstakeIfNeeded(assetOut, AmountOut)
12191298 if ((unstakeTx == unstakeTx))
12201299 then {
12211300 let newBalanceIn = AssetInBalance2
12221301 let newBalanceOut = AssetOutBalance2
1223- let assetInChange = IntegerEntry((("global_" + getAssetString(AssetIn)) + "_balance"), newBalanceIn)
1224- let assetOutChange = IntegerEntry((("global_" + assetOut) + "_balance"), newBalanceOut)
1225- let assetInFactChange = IntegerEntry((("global_" + getAssetString(AssetIn)) + "_factBalance"), (tryGetInteger((("global_" + getAssetString(AssetIn)) + "_factBalance")) + cleanAmountIn))
1226- let assetOutFactChange = IntegerEntry((("global_" + assetOut) + "_factBalance"), (tryGetInteger((("global_" + assetOut) + "_factBalance")) - AmountOut))
1227- let volumeUsdUpdate = calculateUsdValue(AssetIn, AmountIn, AssetInBalance)
1228- $Tuple2((([assetOutChange, assetInChange, assetInFactChange, assetOutFactChange, ScriptTransfer(i.caller, AmountOut, AssetOut), IntegerEntry("global_volume_usd", (tryGetInteger("global_volume_usd") + volumeUsdUpdate)), ScriptTransfer(feesAddress, protocolFee, getAssetBytes(assetIn)), interestChange, statsChange] ++ updSelloffData(assetIn, cleanAmountIn)) ++ updSelloffData(assetOut, -(AmountOut))), AmountOut)
1302+ let assetInSelloffData = updSelloffData(assetIn, cleanAmountIn, AssetInBalance, $Tuple3(assetInParams._6, assetInParams._7, assetInParams._8))
1303+ let assetOutSelloffData = updSelloffData(assetOut, -(AmountOut), AssetOutBalance, $Tuple3(assetOutParams._6, assetOutParams._7, assetOutParams._8))
1304+ let assetInFinalParams = $Tuple8(newBalanceIn, (AssetInFactBalance + cleanAmountIn), (assetInFeesEarned + lpFee), (assetInLastCheckInterest + interestDelta), assetInParams._5, assetInSelloffData._1, assetInSelloffData._2, assetInSelloffData._3)
1305+ let assetOutFinalParams = $Tuple8(newBalanceOut, (assetOutFactBalance - AmountOut), assetOutParams._3, assetOutParams._4, assetOutParams._5, assetOutSelloffData._1, assetOutSelloffData._2, assetOutSelloffData._3)
1306+ let assetInChange = saveGlobalTokenParams(assetIn, assetInFinalParams)
1307+ let assetOutChange = saveGlobalTokenParams(assetOut, assetOutFinalParams)
1308+ let feeAssetStr = tryGetString("static_feeToken")
1309+ let feeAssetParams = loadGlobalTokenParams(feeAssetStr)
1310+ let feeTokenBalance = feeAssetParams._1
1311+ let volumeUsdUpdate = calculateUsdValue(AssetIn, AmountIn, AssetInBalance, feeTokenBalance)
1312+ $Tuple2([assetInChange, assetOutChange, ScriptTransfer(i.caller, AmountOut, AssetOut), IntegerEntry("global_volume_usd", (tryGetInteger("global_volume_usd") + volumeUsdUpdate)), ScriptTransfer(feesAddress, protocolFee, getAssetBytes(assetIn))], AmountOut)
12291313 }
12301314 else throw("Strict value is not equal to itself.")
12311315 }
12321316 else throw("Strict value is not equal to itself.")
12331317 }
12341318 }
12351319
12361320
12371321
12381322 @Callable(i)
12391323 func swapReadOnly (assetIn,assetOut,AmountIn) = {
12401324 let AssetIn = getAssetBytes(assetIn)
12411325 let AssetOut = getAssetBytes(assetOut)
12421326 let scaleIn = (Scale8 / tryGetInteger((("static_" + assetIn) + "_scale")))
12431327 let scaleOut = (Scale8 / tryGetInteger((("static_" + assetOut) + "_scale")))
12441328 let feeAssetOutStr = tryGetString("static_feeToken")
12451329 let feeAssetOut = if ((feeAssetOutStr == ""))
12461330 then usdnAssetId
12471331 else getAssetBytes(feeAssetOutStr)
1248- let AssetInBalance = tryGetInteger((("global_" + getAssetString(AssetIn)) + "_balance"))
1249- let AssetOutBalance = tryGetInteger((("global_" + assetOut) + "_balance"))
1332+ let assetInParams = loadGlobalTokenParams(getAssetString(AssetIn))
1333+ let assetOutParams = loadGlobalTokenParams(assetOut)
1334+ let AssetInBalance = assetInParams._1
1335+ let AssetInFactBalance = assetInParams._2
1336+ let assetInFeesEarned = assetInParams._3
1337+ let assetInLastCheckInterest = assetInParams._4
1338+ let AssetOutBalance = assetOutParams._1
1339+ let assetOutFactBalance = assetOutParams._2
12501340 let AssetInBalanceScaled = (AssetInBalance * scaleIn)
12511341 let AssetOutBalanceScaled = (AssetOutBalance * scaleOut)
12521342 let feeAmountIn = fraction(AmountIn, Fee, FeeScale)
12531343 let cleanAmountIn = (AmountIn - feeAmountIn)
12541344 let cleanAmountInScaled = (cleanAmountIn * scaleIn)
12551345 let AmountOut1 = calculateOutAmount(cleanAmountInScaled, AssetIn, AssetOut, AssetInBalanceScaled, AssetOutBalanceScaled)
12561346 let AmountOut = fraction(AmountOut1, 1, scaleOut)
12571347 let AssetOutBalance2 = (AssetOutBalance - AmountOut)
12581348 let AssetInBalance2 = (AssetInBalance + cleanAmountIn)
1259- let feeAssetOutBalance = if ((feeAssetOut == AssetIn))
1260- then AssetInBalance2
1261- else if ((feeAssetOut == AssetOut))
1262- then AssetOutBalance2
1263- else tryGetInteger((("global_" + getAssetString(feeAssetOut)) + "_balance"))
1264- let feeAmountOut = calculateOutAmount(feeAmountIn, AssetIn, feeAssetOut, AssetInBalance, feeAssetOutBalance)
12651349 if ((AssetOut == AssetIn))
12661350 then throw("this swap is not allowed")
1267- else if ((0 > (getFactBalance(assetOut) - AmountOut)))
1351+ else if ((0 > (assetOutParams._2 - AmountOut)))
12681352 then throw("contract is out of reserves")
12691353 else if (isShutdown())
12701354 then throw("contract is on stop")
12711355 else $Tuple2(nil, AmountOut)
12721356 }
12731357
12741358
12751359
12761360 @Callable(i)
12771361 func transferOwnership (newOwnerAddress) = if ((toString(i.caller) != tryGetString("static_poolOwner")))
12781362 then throw("this call available only for pool owner")
12791363 else [StringEntry("static_poolOwner", newOwnerAddress)]
12801364
12811365
12821366
12831367 @Callable(i)
12841368 func setFee (newFee) = if ((toString(i.caller) != tryGetString("static_poolOwner")))
12851369 then throw("this call available only for pool owner")
12861370 else [IntegerEntry("static_fee", newFee)]
12871371
12881372
12891373 @Verifier(tx)
12901374 func verify () = sigVerify(tx.bodyBytes, tx.proofs[0], masterPubKey)
12911375

github/deemru/w8io
153.80 ms