tx · 6ucPTMS69LQoCnwyCG8G9DRAYQ37cSkBrZowPyWP43mK

3N4yRVN6agjvhtb5rw4XssVddBh6vHv8Yee:  -0.02100000 Waves

2024.10.28 18:18 [3346897] smart account 3N4yRVN6agjvhtb5rw4XssVddBh6vHv8Yee > SELF 0.00000000 Waves

{ "type": 13, "id": "6ucPTMS69LQoCnwyCG8G9DRAYQ37cSkBrZowPyWP43mK", "fee": 2100000, "feeAssetId": null, "timestamp": 1730128789969, "version": 2, "chainId": 84, "sender": "3N4yRVN6agjvhtb5rw4XssVddBh6vHv8Yee", "senderPublicKey": "FfJBDiVR6hARyAJorY2iWNpzUzmAQnvRmTNzVBYEjVrN", "proofs": [ "45HhriaCPZkYPNCwmL7SU5dK2zSZFYu9syfyn7eKGMbDLcJUkQSrPaCBpxBtdG4bexK3LDA39qGesMcdy4z75N1m" ], "script": "base64:BgItCAISBwoFCAgICAESBwoFCAgICAESABIDCgEIEgQKAggBEgUKAwgIARIDCgEIRwAHVkVSU0lPTgIIUE0tMC43LjAACWNvbmZpZ1N0cgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzAg1jb25maWdBZGRyZXNzAiMzTjkxZTd3SGlWN1FhZERzeDNSVUpReHgxZXRxY0FLcmZIagAOQ09ORklHX0FERFJFU1MDCQAAAgUJY29uZmlnU3RyAgAFBHRoaXMJAQdBZGRyZXNzAQkA2QQBBQljb25maWdTdHIAFUFzc2V0c1dlaWdodHNEZWNpbWFscwAEAAVTY2FsZQCQTgAGU2NhbGU4AIDC1y8AB1NjYWxlMTYAgICE/qbe4REACEZlZVNjYWxlAJBOABFQb29sVG9rZW5EZWNpbWFscwAIAA5Qb29sVG9rZW5TY2FsZQkAbAYACgAABRFQb29sVG9rZW5EZWNpbWFscwAAAAAFBkhBTEZVUAAQTUlOX1NURVBTX0FNT1VOVAkBC3ZhbHVlT3JFbHNlAgkAmggCBQ5DT05GSUdfQUREUkVTUwIQbWluX3N0ZXBzX2Ftb3VudAABABBNQVhfU1RFUFNfQU1PVU5UCQELdmFsdWVPckVsc2UCCQCaCAIFDkNPTkZJR19BRERSRVNTAhBtYXhfc3RlcHNfYW1vdW50APQDABJNSU5fU1RFUFNfSU5URVJWQUwJAQt2YWx1ZU9yRWxzZQIJAJoIAgUOQ09ORklHX0FERFJFU1MCEm1pbl9zdGVwc19pbnRlcnZhbAABABJNQVhfU1RFUFNfSU5URVJWQUwJAQt2YWx1ZU9yRWxzZQIJAJoIAgUOQ09ORklHX0FERFJFU1MCEm1heF9zdGVwc19pbnRlcnZhbACQTgAKTUlOX1dFSUdIVAkBC3ZhbHVlT3JFbHNlAgkAmggCBQ5DT05GSUdfQUREUkVTUwIKbWluX3dlaWdodABkAApNQVhfV0VJR0hUCQELdmFsdWVPckVsc2UCCQCaCAIFDkNPTkZJR19BRERSRVNTAgptYXhfd2VpZ2h0AKxNAQ10cnlHZXRJbnRlZ2VyAQNrZXkEByRtYXRjaDAJAJoIAgUEdGhpcwUDa2V5AwkAAQIFByRtYXRjaDACA0ludAQBYgUHJG1hdGNoMAUBYgAAAQx0cnlHZXRCaW5hcnkBA2tleQQHJG1hdGNoMAkAnAgCBQR0aGlzBQNrZXkDCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQBYgUHJG1hdGNoMAUBYgEAAQx0cnlHZXRTdHJpbmcBA2tleQQHJG1hdGNoMAkAnQgCBQR0aGlzBQNrZXkDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFiBQckbWF0Y2gwBQFiAgABE3RyeUdldFN0cmluZ09yVGhyb3cBA2tleQQHJG1hdGNoMAkAnQgCBQR0aGlzBQNrZXkDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFiBQckbWF0Y2gwBQFiCQACAQkArAICAh1ubyBzdWNoIGtleSBpbiBkYXRhIHN0b3JhZ2U6IAUDa2V5AQ5nZXRBc3NldFN0cmluZwEHYXNzZXRJZAQHJG1hdGNoMAUHYXNzZXRJZAMJAAECBQckbWF0Y2gwAgpCeXRlVmVjdG9yBAFiBQckbWF0Y2gwCQDYBAEFAWICBVdBVkVTAQ1nZXRBc3NldEJ5dGVzAQphc3NldElkU3RyAwkAAAIFCmFzc2V0SWRTdHICBVdBVkVTBQR1bml0CQDZBAEFCmFzc2V0SWRTdHIBD2dldFRva2VuQmFsYW5jZQEHYXNzZXRJZAQHJG1hdGNoMAUHYXNzZXRJZAMJAAECBQckbWF0Y2gwAgpCeXRlVmVjdG9yBAF0BQckbWF0Y2gwCQDwBwIFBHRoaXMFAXQICQDvBwEFBHRoaXMJYXZhaWxhYmxlARNhZGRBc3NldEJ5dGVzVG9MaXN0AgVhY2N1bQRpdGVtCQDOCAIFBWFjY3VtCQDMCAIJAQ1nZXRBc3NldEJ5dGVzAQUEaXRlbQUDbmlsARRhZGRBc3NldFdlaWdodFRvTGlzdAIFYWNjdW0EaXRlbQkAzggCBQVhY2N1bQkAzAgCCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdzdGF0aWNfCQEOZ2V0QXNzZXRTdHJpbmcBBQRpdGVtAgdfd2VpZ2h0BQNuaWwBF2FkZEFzc2V0V2VpZ2h0VG9TdHJMaXN0AgVhY2N1bQRpdGVtCQDOCAIFBWFjY3VtCQDMCAIJAKQDAQkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwUEaXRlbQIHX3dlaWdodAUDbmlsARZhZGRBc3NldERlY2ltYWxzVG9MaXN0AgVhY2N1bQRpdGVtCQDOCAIFBWFjY3VtCQDMCAIJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18JAQ5nZXRBc3NldFN0cmluZwEFBGl0ZW0CCV9kZWNpbWFscwUDbmlsARNhZGRBc3NldFNjYWxlVG9MaXN0AgVhY2N1bQRpdGVtCQDOCAIFBWFjY3VtCQDMCAIJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18JAQ5nZXRBc3NldFN0cmluZwEFBGl0ZW0CBl9zY2FsZQUDbmlsAQxhZGRJbnRUb0xpc3QCBWFjY3VtBGl0ZW0JAM4IAgUFYWNjdW0JAMwIAgkBDXBhcnNlSW50VmFsdWUBBQRpdGVtBQNuaWwADnVzZG5Bc3NldElkU3RyCQELdmFsdWVPckVsc2UCCQCdCAIFDkNPTkZJR19BRERSRVNTAg51c2RuQXNzZXRJZFN0cgIsREcyeEZrUGREd0tVb0JrekdBaFF0THBTR3pmWExpQ1lQRXplS0gyQWQyNHAAEHB1enpsZUFzc2V0SWRTdHIJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCEHB1enpsZUFzc2V0SWRTdHICLEhFQjhRYXc5eHJXcFdzOHRIc2lBVFlHQldEQnRQMlM3a2NQQUxyTXU0M0FTAA51c2R0QXNzZXRJZFN0cgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIOdXNkdEFzc2V0SWRTdHICLDM0TjlZY0VFVExXbjkzcVlRNjRFc1AxeDg5dFNydUpVNDRSckVNU1hYRVBKABF1c2R0UHB0QXNzZXRJZFN0cgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIRdXNkdFBwdEFzc2V0SWRTdHICLDl3YzNMWE5BNFRFQnNYeUt0b0xFOW1yYkREN1dNSFh2WHJDalp2YWJMQXNpAA5yb21lQXNzZXRJZFN0cgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIOcm9tZUFzc2V0SWRTdHICLEFQNENiNXhMWUdINlppZ0hyZUNaSG9YcFFUV0RrUHNHMkJIcWZEVXg2dGFKAA93YXZlc0Fzc2V0SWRTdHICBVdBVkVTAAt1c2RuQXNzZXRJZAkA2QQBBQ51c2RuQXNzZXRJZFN0cgANcHV6emxlQXNzZXRJZAkA2QQBBRBwdXp6bGVBc3NldElkU3RyAAt1c2R0QXNzZXRJZAkA2QQBBQ51c2R0QXNzZXRJZFN0cgAOdXNkdFBwdEFzc2V0SWQJANkEAQURdXNkdFBwdEFzc2V0SWRTdHIAC3JvbWVBc3NldElkCQDZBAEFDnJvbWVBc3NldElkU3RyAAx3YXZlc0Fzc2V0SWQFBHVuaXQAFXN1cHBvcnRlZEZlZUFzc2V0c1N0cgkAzAgCBQ51c2RuQXNzZXRJZFN0cgkAzAgCBRBwdXp6bGVBc3NldElkU3RyCQDMCAIFDnVzZHRBc3NldElkU3RyCQDMCAIFEXVzZHRQcHRBc3NldElkU3RyCQDMCAIFD3dhdmVzQXNzZXRJZFN0cgkAzAgCBQ5yb21lQXNzZXRJZFN0cgUDbmlsAA1vcmFjbGVBZGRyZXNzCQEHQWRkcmVzcwEJANkEAQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwINb3JhY2xlQWRkcmVzcwIjM045MWU3d0hpVjdRYWREc3gzUlVKUXh4MWV0cWNBS3JmSGoAC2ZlZXNBZGRyZXNzCQEHQWRkcmVzcwEJANkEAQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwILZmVlc0FkZHJlc3MCIzNOOTFlN3dIaVY3UWFkRHN4M1JVSlF4eDFldHFjQUtyZkhqABJzaHV0ZG93bkFkZHJlc3NTdHIJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCD3NodXRkb3duQWRkcmVzcwIjM045MWU3d0hpVjdRYWREc3gzUlVKUXh4MWV0cWNBS3JmSGoAD2xheWVyMkFkZHJlc3NlcwkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIPbGF5ZXIyQWRkcmVzc2VzAiMzTjkxZTd3SGlWN1FhZERzeDNSVUpReHgxZXRxY0FLcmZIagARY29sZE1hc3RlckFkZHJlc3MJAQdBZGRyZXNzAQkA2QQBCQELdmFsdWVPckVsc2UCCQCdCAIFDkNPTkZJR19BRERSRVNTAhFjb2xkTWFzdGVyQWRkcmVzcwIjM045MWU3d0hpVjdRYWREc3gzUlVKUXh4MWV0cWNBS3JmSGoAEWNhbGN1bGF0b3JBY2NvdW50CQEHQWRkcmVzcwEJANkEAQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQ5DT05GSUdfQUREUkVTUwIOZmFjdG9yeUFkZHJlc3MCIzNOMXl0QVV5aHRpZzlYNkYyaEhIczFqYnpZeHI0N1lwOEZyAA5mYWN0b3J5QWNjb3VudAkBB0FkZHJlc3MBCQDZBAEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCDmZhY3RvcnlBZGRyZXNzAiMzTXNnemJ0Umc4TkVrYlRjSEJ5d3R3VGRDZTlCUnhNUW81VAAMbWFzdGVyUHViS2V5CQDZBAEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOQ09ORklHX0FERFJFU1MCDG1hc3RlclB1YktleQIsNHo4Q0tTWVFCS2t6eDdQQmI1dUJQMVlQYTZZQUhSTlRBcFcxc1FWSFQ1ZVUAAVQJAQ10cnlHZXRJbnRlZ2VyAQITc3RhdGljX3Rva2Vuc0Ftb3VudAAIYXNzZXRJZHMKAAIkbAkAtQkCCQEMdHJ5R2V0U3RyaW5nAQIPc3RhdGljX3Rva2VuSWRzAgEsCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARNhZGRBc3NldEJ5dGVzVG9MaXN0AgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAA1Bc3NldHNXZWlnaHRzCgACJGwFCGFzc2V0SWRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYxXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARRhZGRBc3NldFdlaWdodFRvTGlzdAIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMV8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjFfMgIJAQUkZjFfMQIJAQUkZjFfMQIJAQUkZjFfMQIJAQUkZjFfMQIJAQUkZjFfMQIJAQUkZjFfMQIJAQUkZjFfMQIJAQUkZjFfMQIJAQUkZjFfMQIJAQUkZjFfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgAIRGVjaW1hbHMKAAIkbAUIYXNzZXRJZHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjJfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBFmFkZEFzc2V0RGVjaW1hbHNUb0xpc3QCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjJfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGYyXzICCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECCQEFJGYyXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoABlNjYWxlcwoAAiRsBQhhc3NldElkcwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmM18xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQETYWRkQXNzZXRTY2FsZVRvTGlzdAIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmM18yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjNfMgIJAQUkZjNfMQIJAQUkZjNfMQIJAQUkZjNfMQIJAQUkZjNfMQIJAQUkZjNfMQIJAQUkZjNfMQIJAQUkZjNfMQIJAQUkZjNfMQIJAQUkZjNfMQIJAQUkZjNfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgADRmVlCQENdHJ5R2V0SW50ZWdlcgECCnN0YXRpY19mZWUADGVhcm5lZEFzc2V0cwUIYXNzZXRJZHMBDWdldFBvb2xTdGF0dXMABAZwb29sSWQJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUOZmFjdG9yeUFjY291bnQJAKwCAgIGcG9vbF9fCQClCAEFBHRoaXMCAAQGc3RhdHVzCQELdmFsdWVPckVsc2UCCQCaCAIFDmZhY3RvcnlBY2NvdW50CQCsAgICBnBvb2xfXwUGcG9vbElkAAIFBnN0YXR1cwEKZ2V0U2V0dGluZwEDa2V5CQERQGV4dHJOYXRpdmUoMTA1MCkCBQ5mYWN0b3J5QWNjb3VudAkArAICAgdzZXR1cF9fBQNrZXkAFEluaXRhbFdhdmVzTGlxdWlkaXR5CQEKZ2V0U2V0dGluZwECEHZpcnR1YWxMaXF1aWRpdHkAC0NyZWF0aW9uRmVlCQEKZ2V0U2V0dGluZwECC2NyZWF0aW9uRmVlAAtDdXJ2ZVRhcmdldAkBCmdldFNldHRpbmcBAgtjdXJ2ZVRhcmdldAEKaXNTaHV0ZG93bgAED3NodXRkb3duQWRkcmVzcwkApggBBRJzaHV0ZG93bkFkZHJlc3NTdHIDCQAAAgUPc2h1dGRvd25BZGRyZXNzBQR1bml0BwQHJG1hdGNoMAkAmwgCCQEFdmFsdWUBBQ9zaHV0ZG93bkFkZHJlc3MCC2lzX3NodXRkb3duAwkAAQIFByRtYXRjaDACB0Jvb2xlYW4EAXgFByRtYXRjaDAFAXgHARJnZXRQcmljZUZyb21PcmFjbGUBCmFzc2V0SWRTdHIEByRtYXRjaDAJAJoIAgUNb3JhY2xlQWRkcmVzcwkArAICBQphc3NldElkU3RyAgdfdHdhcDVCAwkAAQIFByRtYXRjaDACA0ludAQBeAUHJG1hdGNoMAUBeADAhD0BEWNhbGN1bGF0ZVVzZFZhbHVlAwdhc3NldElkBmFtb3VudAhhQmFsYW5jZQQLYXNzZXRXZWlnaHQJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB3N0YXRpY18JAQ5nZXRBc3NldFN0cmluZwEFB2Fzc2V0SWQCB193ZWlnaHQEC2ZlZUFzc2V0U3RyCQEMdHJ5R2V0U3RyaW5nAQIPc3RhdGljX2ZlZVRva2VuBA1mZWVBc3NldFNjYWxlCQERQGV4dHJOYXRpdmUoMTA1MCkCBQR0aGlzCQCsAgIJAKwCAgIHc3RhdGljXwULZmVlQXNzZXRTdHICBl9zY2FsZQQLZmVlQXNzZXROdW0JAQV2YWx1ZQEJAM8IAgUIYXNzZXRJZHMJAQ1nZXRBc3NldEJ5dGVzAQULZmVlQXNzZXRTdHIEDmZlZUFzc2V0V2VpZ2h0CQCRAwIFDUFzc2V0c1dlaWdodHMFC2ZlZUFzc2V0TnVtBA9mZWVBc3NldEJhbGFuY2UJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB2dsb2JhbF8FC2ZlZUFzc2V0U3RyAghfYmFsYW5jZQQNdmFsSW5GZWVBc3NldAkAawMFBmFtb3VudAkAaQIFD2ZlZUFzc2V0QmFsYW5jZQUOZmVlQXNzZXRXZWlnaHQJAGkCBQhhQmFsYW5jZQULYXNzZXRXZWlnaHQEDWZlZUFzc2V0UHJpY2UJARJnZXRQcmljZUZyb21PcmFjbGUBBQtmZWVBc3NldFN0cgkAawMFDXZhbEluRmVlQXNzZXQFDWZlZUFzc2V0UHJpY2UFDWZlZUFzc2V0U2NhbGUBEmNhbGN1bGF0ZU91dEFtb3VudAUIQW1vdW50SW4HYXNzZXRJbghhc3NldE91dAlCYWxhbmNlSW4KQmFsYW5jZU91dAQHSW5kZXhJbgkBBXZhbHVlAQkAzwgCBQhhc3NldElkcwUHYXNzZXRJbgQISW5kZXhPdXQJAQV2YWx1ZQEJAM8IAgUIYXNzZXRJZHMFCGFzc2V0T3V0AwkAAAIFB0luZGV4SW4FCEluZGV4T3V0BQhBbW91bnRJbgkAbgQFCkJhbGFuY2VPdXQJAGUCCQBoAgUGU2NhbGU4BQZTY2FsZTgJAKADAQkAdgYJAL0CBAkAuQICCQC2AgEFCUJhbGFuY2VJbgkAtgIBAJBOCQC2AgEJAGgCBQZTY2FsZTgFBlNjYWxlOAkAuQICCQC2AgEJAGQCBQlCYWxhbmNlSW4FCEFtb3VudEluCQC2AgEAkE4FBkhBTEZVUAAQCQC2AgEJAGsDCQCRAwIFDUFzc2V0c1dlaWdodHMFB0luZGV4SW4AgKCUpY0dCQCRAwIFDUFzc2V0c1dlaWdodHMFCEluZGV4T3V0AAwAEAUHQ0VJTElORwkAaAIFBlNjYWxlOAUGU2NhbGU4BQhIQUxGRVZFTgEdY2FsY3VsYXRlQ3VycmVudEFzc2V0SW50ZXJlc3QEB2Fzc2V0SWQKYXNzZXRJZFN0cghhQmFsYW5jZRZ0b2tlbkVhcm5pbmdzTGFzdENoZWNrBAt0b3RhbFN0YWtlZAkBDXRyeUdldEludGVnZXIBAhJnbG9iYWxfaW5kZXhTdGFrZWQEFXRva2VuQmFsYW5jZUxhc3RDaGVjawUWdG9rZW5FYXJuaW5nc0xhc3RDaGVjawQTY3VycmVudEJhbGFuY2VEZWx0YQkAZQIJAQ9nZXRUb2tlbkJhbGFuY2UBBQdhc3NldElkBQhhQmFsYW5jZQQUY3VycmVudFRva2VuRWFybmluZ3MDCQBmAgUTY3VycmVudEJhbGFuY2VEZWx0YQUVdG9rZW5CYWxhbmNlTGFzdENoZWNrBRNjdXJyZW50QmFsYW5jZURlbHRhBRV0b2tlbkJhbGFuY2VMYXN0Q2hlY2sEC25ld0Vhcm5pbmdzCQBlAgUUY3VycmVudFRva2VuRWFybmluZ3MFFXRva2VuQmFsYW5jZUxhc3RDaGVjawQLbmV3SW50ZXJlc3QDCQAAAgULdG90YWxTdGFrZWQAAAAACQBrAwULbmV3RWFybmluZ3MFBlNjYWxlOAULdG90YWxTdGFrZWQEEWxhc3RDaGVja0ludGVyZXN0CQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAhFnbG9iYWxfbGFzdENoZWNrXwUKYXNzZXRJZFN0cgIJX2ludGVyZXN0CQBkAgURbGFzdENoZWNrSW50ZXJlc3QFC25ld0ludGVyZXN0AQtjbGFpbVJlc3VsdAEHYWRkcmVzcwQKYWRkcmVzc1N0cgkApQgBBQdhZGRyZXNzBAxwdXp6bGVBbW91bnQJAQ10cnlHZXRJbnRlZ2VyAQkArAICBQphZGRyZXNzU3RyAgxfaW5kZXhTdGFrZWQKAQdoYW5kbGVyAgVhY2N1bQdhc3NldElkBAphc3NldElkU3RyCQEOZ2V0QXNzZXRTdHJpbmcBBQdhc3NldElkBAhhQmFsYW5jZQkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHZ2xvYmFsXwkBDmdldEFzc2V0U3RyaW5nAQUHYXNzZXRJZAIIX2JhbGFuY2UEFnRva2VuRWFybmluZ3NMYXN0Q2hlY2sJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICEWdsb2JhbF9sYXN0Q2hlY2tfBQphc3NldElkU3RyAglfZWFybmluZ3MEFGN1cnJlbnRUb2tlbkludGVyZXN0CQEdY2FsY3VsYXRlQ3VycmVudEFzc2V0SW50ZXJlc3QEBQdhc3NldElkBQphc3NldElkU3RyBQhhQmFsYW5jZQUWdG9rZW5FYXJuaW5nc0xhc3RDaGVjawQUY3VycmVudFRva2VuRWFybmluZ3MJAJYDAQkAzAgCBRZ0b2tlbkVhcm5pbmdzTGFzdENoZWNrCQDMCAIJAGUCCQEPZ2V0VG9rZW5CYWxhbmNlAQUHYXNzZXRJZAUIYUJhbGFuY2UFA25pbAQMcmV3YXJkQW1vdW50CQBrAwUMcHV6emxlQW1vdW50CQBlAgUUY3VycmVudFRva2VuSW50ZXJlc3QJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgIJAKwCAgUKYWRkcmVzc1N0cgILX2xhc3RDaGVja18FCmFzc2V0SWRTdHICCV9pbnRlcmVzdAUGU2NhbGU4BAh0cmFuc2ZlcgMJAAACBQxyZXdhcmRBbW91bnQAAAUDbmlsCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMFB2FkZHJlc3MFDHJld2FyZEFtb3VudAUHYXNzZXRJZAUDbmlsCQCUCgIJAM4IAgkAzggCCAUFYWNjdW0CXzEFCHRyYW5zZmVyCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgIRZ2xvYmFsX2xhc3RDaGVja18FCmFzc2V0SWRTdHICCV9lYXJuaW5ncwkAZQIFFGN1cnJlbnRUb2tlbkVhcm5pbmdzBQxyZXdhcmRBbW91bnQJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICAhFnbG9iYWxfbGFzdENoZWNrXwUKYXNzZXRJZFN0cgIJX2ludGVyZXN0BRRjdXJyZW50VG9rZW5JbnRlcmVzdAkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgIJAKwCAgUKYWRkcmVzc1N0cgILX2xhc3RDaGVja18FCmFzc2V0SWRTdHICCV9pbnRlcmVzdAUUY3VycmVudFRva2VuSW50ZXJlc3QFA25pbAkAZAIIBQVhY2N1bQJfMgkBEWNhbGN1bGF0ZVVzZFZhbHVlAwUHYXNzZXRJZAUMcmV3YXJkQW1vdW50BQhhQmFsYW5jZQQFYWNjdW0KAAIkbAUMZWFybmVkQXNzZXRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAkAlAoCBQNuaWwAAAoBBSRmNF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEHaGFuZGxlcgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmNF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjRfMgIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIJAQUkZjRfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgkAlAoCCQDOCAIIBQVhY2N1bQJfMQkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICBQphZGRyZXNzU3RyAhFfY2xhaW1lZFJld2FyZFVTRAkAZAIJAQ10cnlHZXRJbnRlZ2VyAQkArAICBQphZGRyZXNzU3RyAhFfY2xhaW1lZFJld2FyZFVTRAgFBWFjY3VtAl8yCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIFCmFkZHJlc3NTdHICCl9sYXN0Q2xhaW0IBQlsYXN0QmxvY2sJdGltZXN0YW1wBQNuaWwIBQVhY2N1bQJfMgEDc3VtAgVhY2N1bQFuCQBkAgUFYWNjdW0JAQ1wYXJzZUludFZhbHVlAQUBbgENY2hlY2tGZWVBc3NldAIFYWNjdW0EbmV4dAMDCQECIT0CCQDPCAIFFXN1cHBvcnRlZEZlZUFzc2V0c1N0cgUEbmV4dAUEdW5pdAkAAAIFBWFjY3VtAgAHBQRuZXh0BQVhY2N1bQEMc3dhcEludGVybmFsBQdhc3NldEluCGFzc2V0T3V0CGFtb3VudEluB21pbmltdW0UcmVjZWlwaWVudEFkZHJlc3NTdHIECEFtb3VudEluBQhhbW91bnRJbgQHQXNzZXRJbgkBDWdldEFzc2V0Qnl0ZXMBBQdhc3NldEluBAhBc3NldE91dAkBDWdldEFzc2V0Qnl0ZXMBBQhhc3NldE91dAQHc2NhbGVJbgkAaQIFBlNjYWxlOAkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwUHYXNzZXRJbgIGX3NjYWxlBAhzY2FsZU91dAkAaQIFBlNjYWxlOAkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHc3RhdGljXwUIYXNzZXRPdXQCBl9zY2FsZQQOZmVlQXNzZXRPdXRTdHIJAQx0cnlHZXRTdHJpbmcBAg9zdGF0aWNfZmVlVG9rZW4EC2ZlZUFzc2V0T3V0AwkAAAIFDmZlZUFzc2V0T3V0U3RyAgAFDHdhdmVzQXNzZXRJZAkBDWdldEFzc2V0Qnl0ZXMBBQ5mZWVBc3NldE91dFN0cgQOQXNzZXRJbkJhbGFuY2UJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB2dsb2JhbF8JAQ5nZXRBc3NldFN0cmluZwEFB0Fzc2V0SW4CCF9iYWxhbmNlBA9Bc3NldE91dEJhbGFuY2UJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICB2dsb2JhbF8FCGFzc2V0T3V0AghfYmFsYW5jZQQUQXNzZXRJbkJhbGFuY2VTY2FsZWQJAGgCBQ5Bc3NldEluQmFsYW5jZQUHc2NhbGVJbgQVQXNzZXRPdXRCYWxhbmNlU2NhbGVkCQBoAgUPQXNzZXRPdXRCYWxhbmNlBQhzY2FsZU91dAQLZmVlQW1vdW50SW4JAGsDBQhBbW91bnRJbgUDRmVlBQhGZWVTY2FsZQQNY2xlYW5BbW91bnRJbgkAZQIFCEFtb3VudEluBQtmZWVBbW91bnRJbgQTY2xlYW5BbW91bnRJblNjYWxlZAkAaAIFDWNsZWFuQW1vdW50SW4FB3NjYWxlSW4ECkFtb3VudE91dDEJARJjYWxjdWxhdGVPdXRBbW91bnQFBRNjbGVhbkFtb3VudEluU2NhbGVkBQdBc3NldEluBQhBc3NldE91dAUUQXNzZXRJbkJhbGFuY2VTY2FsZWQFFUFzc2V0T3V0QmFsYW5jZVNjYWxlZAQJQW1vdW50T3V0CQBrAwUKQW1vdW50T3V0MQABBQhzY2FsZU91dAQQQXNzZXRPdXRCYWxhbmNlMgkAZQIFD0Fzc2V0T3V0QmFsYW5jZQUJQW1vdW50T3V0BA9Bc3NldEluQmFsYW5jZTIJAGQCBQ5Bc3NldEluQmFsYW5jZQUNY2xlYW5BbW91bnRJbgQSZmVlQXNzZXRPdXRCYWxhbmNlAwkAAAIFC2ZlZUFzc2V0T3V0BQdBc3NldEluBQ9Bc3NldEluQmFsYW5jZTIDCQAAAgULZmVlQXNzZXRPdXQFCEFzc2V0T3V0BRBBc3NldE91dEJhbGFuY2UyCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdnbG9iYWxfCQEOZ2V0QXNzZXRTdHJpbmcBBQtmZWVBc3NldE91dAIIX2JhbGFuY2UEDGZlZUFtb3VudE91dAkBEmNhbGN1bGF0ZU91dEFtb3VudAUFC2ZlZUFtb3VudEluBQdBc3NldEluBQtmZWVBc3NldE91dAUOQXNzZXRJbkJhbGFuY2UFEmZlZUFzc2V0T3V0QmFsYW5jZQMJAGYCBQdtaW5pbXVtBQlBbW91bnRPdXQJAAIBAilhbW91bnQgdG8gcmVjaWV2ZSBpcyBsb3dlciB0aGFuIGdpdmVuIG9uZQMJAAACBQhBc3NldE91dAUHQXNzZXRJbgkAAgECGHRoaXMgc3dhcCBpcyBub3QgYWxsb3dlZAMJAGYCAAAJAGUCBQ9Bc3NldE91dEJhbGFuY2UFCUFtb3VudE91dAkAAgECG2NvbnRyYWN0IGlzIG91dCBvZiByZXNlcnZlcwMJAQppc1NodXRkb3duAAkAAgECE2NvbnRyYWN0IGlzIG9uIHN0b3AECmNyZWF0b3JGZWUJAGsDBQxmZWVBbW91bnRPdXQAAQAKBAtwcm90b2NvbEZlZQkAawMFDGZlZUFtb3VudE91dAAEAAoEDG5ld0JhbGFuY2VJbgUPQXNzZXRJbkJhbGFuY2UyBA1uZXdCYWxhbmNlT3V0CQBlAgUQQXNzZXRPdXRCYWxhbmNlMgMJAAACBQhBc3NldE91dAULZmVlQXNzZXRPdXQFDGZlZUFtb3VudE91dAAABBJuZXdCYWxhbmNlRmVlQXNzZXQDAwkBAiE9AgULZmVlQXNzZXRPdXQFB0Fzc2V0SW4JAQIhPQIFC2ZlZUFzc2V0T3V0BQhBc3NldE91dAcJAGUCBRJmZWVBc3NldE91dEJhbGFuY2UFDGZlZUFtb3VudE91dAUEdW5pdAQNYXNzZXRJbkNoYW5nZQkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICAgdnbG9iYWxfCQEOZ2V0QXNzZXRTdHJpbmcBBQdBc3NldEluAghfYmFsYW5jZQUMbmV3QmFsYW5jZUluBA5hc3NldE91dENoYW5nZQkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICAgdnbG9iYWxfBQhhc3NldE91dAIIX2JhbGFuY2UFDW5ld0JhbGFuY2VPdXQEEWZlZUFzc2V0T3V0Q2hhbmdlAwkBAiE9AgUSbmV3QmFsYW5jZUZlZUFzc2V0BQR1bml0CQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgICB2dsb2JhbF8JAQ5nZXRBc3NldFN0cmluZwEFC2ZlZUFzc2V0T3V0AghfYmFsYW5jZQkBBXZhbHVlAQUSbmV3QmFsYW5jZUZlZUFzc2V0CQELU3RyaW5nRW50cnkCAgVoZWxsbwIFd29ybGQED3ZvbHVtZVVzZFVwZGF0ZQkBEWNhbGN1bGF0ZVVzZFZhbHVlAwUHQXNzZXRJbgUIQW1vdW50SW4FDkFzc2V0SW5CYWxhbmNlCQCUCgIJAMwIAgUOYXNzZXRPdXRDaGFuZ2UJAMwIAgUNYXNzZXRJbkNoYW5nZQkAzAgCBRFmZWVBc3NldE91dENoYW5nZQkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCQERQGV4dHJOYXRpdmUoMTA2MikBBRRyZWNlaXBpZW50QWRkcmVzc1N0cgUJQW1vdW50T3V0BQhBc3NldE91dAkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCQERQGV4dHJOYXRpdmUoMTA2MikBCQEMdHJ5R2V0U3RyaW5nAQIQc3RhdGljX3Bvb2xPd25lcgUKY3JlYXRvckZlZQULZmVlQXNzZXRPdXQJAMwIAgkBDEludGVnZXJFbnRyeQICFGdsb2JhbF9lYXJuZWRCeU93bmVyCQBkAgkBDXRyeUdldEludGVnZXIBAhRnbG9iYWxfZWFybmVkQnlPd25lcgUKY3JlYXRvckZlZQkAzAgCCQEMSW50ZWdlckVudHJ5AgIRZ2xvYmFsX3ZvbHVtZV91c2QJAGQCCQENdHJ5R2V0SW50ZWdlcgECEWdsb2JhbF92b2x1bWVfdXNkBQ92b2x1bWVVc2RVcGRhdGUJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwULZmVlc0FkZHJlc3MFC3Byb3Rv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dW0JAJADAQUKYXNzZXRJZHNMaQUFYWNjdW0EDWFzc2V0RGVjaW1hbHMACAkAzggCBQVhY2N1bQkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgICB3N0YXRpY18JAJEDAgUNYXNzZXRJZHNTdHJMaQUIYXNzZXROdW0CBl9zY2FsZQkAbAYACgAABQ1hc3NldERlY2ltYWxzAAAAAAUERE9XTgkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgICB3N0YXRpY18JAJEDAgUNYXNzZXRJZHNTdHJMaQUIYXNzZXROdW0CCV9kZWNpbWFscwUNYXNzZXREZWNpbWFscwkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgICB3N0YXRpY18JAJEDAgUNYXNzZXRJZHNTdHJMaQUIYXNzZXROdW0CB193ZWlnaHQJAQV2YWx1ZQEJALYJAQkAkQMCBRFhc3NldFdlaWdodHNTdHJMaQUIYXNzZXROdW0FA25pbAQRaW5pdGlhbFBvb2xUb2tlbnMJARljYWxjdWxhdGVQb29sVG9rZW5zQW1vdW50AQgFAWkIcGF5bWVudHMDCQECIT0CBQ9hc3NldFdlaWdodHNTdW0AkE4JAAIBAitzdW0gb2YgdG9rZW4gd2VpZ2h0cyBtdXN0IGJlIGVxdWFsIHRvIDEwMDAwAwkAAAIFEWluaXRpYWxQb29sVG9rZW5zAAAJAAIBAjJ5b3UgbmVlZCBhIGJpZ2dlciB0b2tlbnMgYW1vdW50IHRvIGxhdW5jaCB0aGUgcG9vbAQOcG9vbFRva2VuSXNzdWUJAMMIBwkArAICAgNQWiAFCnBvb2xEb21haW4CHVB1enpsZSBTd2FwOiBwb29sIGluZGV4IHRva2VuBRFpbml0aWFsUG9vbFRva2VucwURUG9vbFRva2VuRGVjaW1hbHMGBQR1bml0AAAEC3Bvb2xUb2tlbklkCQC4CAEFDnBvb2xUb2tlbklzc3VlCQCUCgIJAM4IAgkAzggCCQDOCAIKAAIkbAkAzAgCAAAJAMwIAgABCQDMCAIAAgkAzAgCAAMJAMwIAgAECQDMCAIABQkAzAgCAAYJAMwIAgAHCQDMCAIACAkAzAgCAAkFA25pbAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmN18xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQETYWRkVG9rZW5EYXRhRW50cmllcwIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmN18yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjdfMgIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIJAQUkZjdfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgkAzAgCBQRtZW1lCQDMCAIJAQtTdHJpbmdFbnRyeQICD3N0YXRpY190b2tlbklkcwULYXNzZXRJZHNTdHIJAMwIAgkBC1N0cmluZ0VudHJ5AgIPc3RhdGljX2ZlZVRva2VuBQtmZWVBc3NldFN0cgkAzAgCCQELU3RyaW5nRW50cnkCAhNzdGF0aWNfdG9rZW5XZWlnaHRzBQ9hc3NldFdlaWdodHNTdHIJAMwIAgkBDEludGVnZXJFbnRyeQICE3N0YXRpY190b2tlbnNBbW91bnQJAJADAQUKYXNzZXRJZHNMaQkAzAgCCQELU3RyaW5nRW50cnkCAhFzdGF0aWNfcG9vbERvbWFpbgUKcG9vbERvbWFpbgkAzAgCCQELU3RyaW5nRW50cnkCAhJzdGF0aWNfYmFzZVRva2VuSWQFDmJhc2VUb2tlbklkU3RyCQDMCAIJAQtTdHJpbmdFbnRyeQICEHN0YXRpY19wb29sT3duZXIFCXBvb2xPd25lcgkAzAgCCQEMSW50ZWdlckVudHJ5AgIKc3RhdGljX2ZlZQUDZmVlCQDMCAIJAQxJbnRlZ2VyRW50cnkCAgxzdGF0aWNfS011bHQFB1NjYWxlMTYJAMwIAgkBDEludGVnZXJFbnRyeQICE2dsb2JhbF93YXNQcmVJbml0ZWQAAQUDbmlsCQDMCAIJAQxJbnRlZ2VyRW50cnkCAhRnbG9iYWxfV0FWRVNfYmFsYW5jZQUUSW5pdGFsV2F2ZXNMaXF1aWRpdHkJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICAgdnbG9iYWxfBQltZW1lSWRTdHICCF9iYWxhbmNlBQ10b2tlblF1YW50aXR5BQNuaWwJAMwIAgUOcG9vbFRva2VuSXNzdWUJAMwIAgkBDEludGVnZXJFbnRyeQICF2dsb2JhbF9wb29sVG9rZW5fYW1vdW50BRFpbml0aWFsUG9vbFRva2VucwkAzAgCCQEMSW50ZWdlckVudHJ5AgIQZ2xvYmFsX3dhc0luaXRlZAABCQDMCAIJAQtCaW5hcnlFbnRyeQICE2dsb2JhbF9wb29sVG9rZW5faWQFC3Bvb2xUb2tlbklkCQDMCAIJAQtTdHJpbmdFbnRyeQICFnN0YXRpY19wb29sVG9rZW5faWRTdHIJAQ5nZXRBc3NldFN0cmluZwEFC3Bvb2xUb2tlbklkCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKUIAQgFAWkGY2FsbGVyAgxfaW5kZXhTdGFrZWQFEWluaXRpYWxQb29sVG9rZW5zCQDMCAIJAQxJbnRlZ2VyRW50cnkCAhJnbG9iYWxfaW5kZXhTdGFrZWQFEWluaXRpYWxQb29sVG9rZW5zBQNuaWwFCW1lbWVJZFN0cgFpAQRpbml0BQpwb29sRG9tYWluCXBvb2xPd25lcgl0b2tlbk5hbWUJdG9rZW5EZXNjDXRva2VuUXVhbnRpdHkDCQECIT0CCAUBaQZjYWxsZXIFDmZhY3RvcnlBY2NvdW50CQACAQIKYWRtaW4gb25seQQEaW52MQkA/AcEBQR0aGlzAghpbml0UG9vbAkAzAgCBQpwb29sRG9tYWluCQDMCAIFCXBvb2xPd25lcgkAzAgCBQl0b2tlbk5hbWUJAMwIAgUJdG9rZW5EZXNjCQDMCAIFDXRva2VuUXVhbnRpdHkFA25pbAUDbmlsAwkAAAIFBGludjEFBGludjEECW1lbWVJZFN0cgoAAUAFBGludjEDCQABAgUBQAIGU3RyaW5nBQFACQACAQkArAICCQADAQUBQAIbIGNvdWxkbid0IGJlIGNhc3QgdG8gU3RyaW5nCAkBDHN3YXBJbnRlcm5hbAUCBVdBVkVTBQltZW1lSWRTdHIJAGUCCAkAkQMCCAUBaQhwYXltZW50cwAABmFtb3VudAULQ3JlYXRpb25GZWUAAAkApQgBCAUBaQZjYWxsZXICXzEJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQERY2xhaW1JbmRleFJld2FyZHMAAwkBCmlzU2h1dGRvd24ACQACAQITY29udHJhY3QgaXMgb24gc3RvcAkBC2NsYWltUmVzdWx0AQgFAWkGY2FsbGVyAWkBDWV2YWx1YXRlQ2xhaW0BBHVzZXIJAJQKAgUDbmlsCAkBC2NsYWltUmVzdWx0AQkBEUBleHRyTmF0aXZlKDEwNjIpAQUEdXNlcgJfMgFpAQRzd2FwAghhc3NldE91dAdtaW5pbXVtBAZzdGF0dXMJAQ1nZXRQb29sU3RhdHVzAAMJAGYCAAIFBnN0YXR1cwQDcG10AwkAAAIJAJADAQgFAWkIcGF5bWVudHMAAQkBBXZhbHVlAQkAkQMCCAUBaQhwYXltZW50cwAACQACAQIhcGxlYXNlIGF0dGFjaCBleGFjdGx5IG9uZSBwYXltZW50BAhBbW91bnRJbgkBBXZhbHVlAQgJAJEDAggFAWkIcGF5bWVudHMAAAZhbW91bnQEB0Fzc2V0SW4ICQCRAwIIBQFpCHBheW1lbnRzAAAHYXNzZXRJZAQDcmVzCQEMc3dhcEludGVybmFsBQkBDmdldEFzc2V0U3RyaW5nAQUHQXNzZXRJbgUIYXNzZXRPdXQFCEFtb3VudEluBQdtaW5pbXVtCQClCAEIBQFpBmNhbGxlcgMJAGYCCQERQGV4dHJOYXRpdmUoMTA1NSkBAhRnbG9iYWxfV0FWRVNfYmFsYW5jZQULQ3VydmVUYXJnZXQECW5vdGlmeUludgkA/AcEBQ5mYWN0b3J5QWNjb3VudAISbm90aWZ5U3RhdHVzVXBkYXRlCQDMCAIAAgUDbmlsBQNuaWwDCQAAAgUJbm90aWZ5SW52BQlub3RpZnlJbnYFA3JlcwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDcmVzCQACAQI+cG9vbCBpcyBzdG9wcGVkOiBtb3N0IHByb2JhYmx5IGl0IHJlYWNoZWQgdGhlIHRhcmdldCBsaXF1aWRpdHkBaQEMc3dhcFJlYWRPbmx5Awdhc3NldEluCGFzc2V0T3V0CEFtb3VudEluBAdBc3NldEluCQENZ2V0QXNzZXRCeXRlcwEFB2Fzc2V0SW4ECEFzc2V0T3V0CQENZ2V0QXNzZXRCeXRlcwEFCGFzc2V0T3V0BAdzY2FsZUluCQBpAgUGU2NhbGU4CQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdzdGF0aWNfBQdhc3NldEluAgZfc2NhbGUECHNjYWxlT3V0CQBpAgUGU2NhbGU4CQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdzdGF0aWNfBQhhc3NldE91dAIGX3NjYWxlBA5mZWVBc3NldE91dFN0cgkBDHRyeUdldFN0cmluZwECD3N0YXRpY19mZWVUb2tlbgQLZmVlQXNzZXRPdXQDCQAAAgUOZmVlQXNzZXRPdXRTdHICAAULdXNkbkFzc2V0SWQJAQ1nZXRBc3NldEJ5dGVzAQUOZmVlQXNzZXRPdXRTdHIEDkFzc2V0SW5CYWxhbmNlCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdnbG9iYWxfCQEOZ2V0QXNzZXRTdHJpbmcBBQdBc3NldEluAghfYmFsYW5jZQQPQXNzZXRPdXRCYWxhbmNlCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgdnbG9iYWxfBQhhc3NldE91dAIIX2JhbGFuY2UEFEFzc2V0SW5CYWxhbmNlU2NhbGVkCQBoAgUOQXNzZXRJbkJhbGFuY2UFB3NjYWxlSW4EFUFzc2V0T3V0QmFsYW5jZVNjYWxlZAkAaAIFD0Fzc2V0T3V0QmFsYW5jZQUIc2NhbGVPdXQEC2ZlZUFtb3VudEluCQBrAwUIQW1vdW50SW4FA0ZlZQUIRmVlU2NhbGUEDWNsZWFuQW1vdW50SW4JAGUCBQhBbW91bnRJbgULZmVlQW1vdW50SW4EE2NsZWFuQW1vdW50SW5TY2FsZWQJAGgCBQ1jbGVhbkFtb3VudEluBQdzY2FsZUluBApBbW91bnRPdXQxCQESY2FsY3VsYXRlT3V0QW1vdW50BQUTY2xlYW5BbW91bnRJblNjYWxlZAUHQXNzZXRJbgUIQXNzZXRPdXQFFEFzc2V0SW5CYWxhbmNlU2NhbGVkBRVBc3NldE91dEJhbGFuY2VTY2FsZWQECUFtb3VudE91dAkAawMFCkFtb3VudE91dDEAAQUIc2NhbGVPdXQEEEFzc2V0T3V0QmFsYW5jZTIJAGUCBQ9Bc3NldE91dEJhbGFuY2UFCUFtb3VudE91dAQPQXNzZXRJbkJhbGFuY2UyCQBkAgUOQXNzZXRJbkJhbGFuY2UFDWNsZWFuQW1vdW50SW4EEmZlZUFzc2V0T3V0QmFsYW5jZQMJAAACBQtmZWVBc3NldE91dAUHQXNzZXRJbgUPQXNzZXRJbkJhbGFuY2UyAwkAAAIFC2ZlZUFzc2V0T3V0BQhBc3NldE91dAUQQXNzZXRPdXRCYWxhbmNlMgkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIHZ2xvYmFsXwkBDmdldEFzc2V0U3RyaW5nAQULZmVlQXNzZXRPdXQCCF9iYWxhbmNlBAxmZWVBbW91bnRPdXQJARJjYWxjdWxhdGVPdXRBbW91bnQFBQtmZWVBbW91bnRJbgUHQXNzZXRJbgULZmVlQXNzZXRPdXQFDkFzc2V0SW5CYWxhbmNlBRJmZWVBc3NldE91dEJhbGFuY2UDCQAAAgUIQXNzZXRPdXQFB0Fzc2V0SW4JAAIBAhh0aGlzIHN3YXAgaXMgbm90IGFsbG93ZWQDCQBmAgAACQBlAgUPQXNzZXRPdXRCYWxhbmNlBQlBbW91bnRPdXQJAAIBAhtjb250cmFjdCBpcyBvdXQgb2YgcmVzZXJ2ZXMDCQEKaXNTaHV0ZG93bgAJAAIBAhNjb250cmFjdCBpcyBvbiBzdG9wCQCUCgIFA25pbAUJQW1vdW50T3V0AWkBEXRyYW5zZmVyT3duZXJzaGlwAQ9uZXdPd25lckFkZHJlc3MDCQECIT0CCQClCAEIBQFpBmNhbGxlcgkBDHRyeUdldFN0cmluZwECEHN0YXRpY19wb29sT3duZXIJAAIBAid0aGlzIGNhbGwgYXZhaWxhYmxlIG9ubHkgZm9yIHBvb2wgb3duZXIJAMwIAgkBC1N0cmluZ0VudHJ5AgIQc3RhdGljX3Bvb2xPd25lcgUPbmV3T3duZXJBZGRyZXNzBQNuaWwAkFzlgg==", "height": 3346897, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: none Next: none Full:
OldNewDifferences
1-# no script
1+{-# STDLIB_VERSION 6 #-}
2+{-# SCRIPT_TYPE ACCOUNT #-}
3+{-# CONTENT_TYPE DAPP #-}
4+let VERSION = "PM-0.7.0"
5+
6+let configStr = valueOrElse(getString(this, "configAddress"), "3N91e7wHiV7QadDsx3RUJQxx1etqcAKrfHj")
7+
8+let CONFIG_ADDRESS = if ((configStr == ""))
9+ then this
10+ else Address(fromBase58String(configStr))
11+
12+let AssetsWeightsDecimals = 4
13+
14+let Scale = 10000
15+
16+let Scale8 = 100000000
17+
18+let Scale16 = 10000000000000000
19+
20+let FeeScale = 10000
21+
22+let PoolTokenDecimals = 8
23+
24+let PoolTokenScale = pow(10, 0, PoolTokenDecimals, 0, 0, HALFUP)
25+
26+let MIN_STEPS_AMOUNT = valueOrElse(getInteger(CONFIG_ADDRESS, "min_steps_amount"), 1)
27+
28+let MAX_STEPS_AMOUNT = valueOrElse(getInteger(CONFIG_ADDRESS, "max_steps_amount"), 500)
29+
30+let MIN_STEPS_INTERVAL = valueOrElse(getInteger(CONFIG_ADDRESS, "min_steps_interval"), 1)
31+
32+let MAX_STEPS_INTERVAL = valueOrElse(getInteger(CONFIG_ADDRESS, "max_steps_interval"), 10000)
33+
34+let MIN_WEIGHT = valueOrElse(getInteger(CONFIG_ADDRESS, "min_weight"), 100)
35+
36+let MAX_WEIGHT = valueOrElse(getInteger(CONFIG_ADDRESS, "max_weight"), 9900)
37+
38+func tryGetInteger (key) = match getInteger(this, key) {
39+ case b: Int =>
40+ b
41+ case _ =>
42+ 0
43+}
44+
45+
46+func tryGetBinary (key) = match getBinary(this, key) {
47+ case b: ByteVector =>
48+ b
49+ case _ =>
50+ base58''
51+}
52+
53+
54+func tryGetString (key) = match getString(this, key) {
55+ case b: String =>
56+ b
57+ case _ =>
58+ ""
59+}
60+
61+
62+func tryGetStringOrThrow (key) = match getString(this, key) {
63+ case b: String =>
64+ b
65+ case _ =>
66+ throw(("no such key in data storage: " + key))
67+}
68+
69+
70+func getAssetString (assetId) = match assetId {
71+ case b: ByteVector =>
72+ toBase58String(b)
73+ case _ =>
74+ "WAVES"
75+}
76+
77+
78+func getAssetBytes (assetIdStr) = if ((assetIdStr == "WAVES"))
79+ then unit
80+ else fromBase58String(assetIdStr)
81+
82+
83+func getTokenBalance (assetId) = match assetId {
84+ case t: ByteVector =>
85+ assetBalance(this, t)
86+ case _ =>
87+ wavesBalance(this).available
88+}
89+
90+
91+func addAssetBytesToList (accum,item) = (accum ++ [getAssetBytes(item)])
92+
93+
94+func addAssetWeightToList (accum,item) = (accum ++ [tryGetInteger((("static_" + getAssetString(item)) + "_weight"))])
95+
96+
97+func addAssetWeightToStrList (accum,item) = (accum ++ [toString(tryGetInteger((("static_" + item) + "_weight")))])
98+
99+
100+func addAssetDecimalsToList (accum,item) = (accum ++ [tryGetInteger((("static_" + getAssetString(item)) + "_decimals"))])
101+
102+
103+func addAssetScaleToList (accum,item) = (accum ++ [tryGetInteger((("static_" + getAssetString(item)) + "_scale"))])
104+
105+
106+func addIntToList (accum,item) = (accum ++ [parseIntValue(item)])
107+
108+
109+let usdnAssetIdStr = valueOrElse(getString(CONFIG_ADDRESS, "usdnAssetIdStr"), "DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p")
110+
111+let puzzleAssetIdStr = valueOrElse(getString(CONFIG_ADDRESS, "puzzleAssetIdStr"), "HEB8Qaw9xrWpWs8tHsiATYGBWDBtP2S7kcPALrMu43AS")
112+
113+let usdtAssetIdStr = valueOrElse(getString(CONFIG_ADDRESS, "usdtAssetIdStr"), "34N9YcEETLWn93qYQ64EsP1x89tSruJU44RrEMSXXEPJ")
114+
115+let usdtPptAssetIdStr = valueOrElse(getString(CONFIG_ADDRESS, "usdtPptAssetIdStr"), "9wc3LXNA4TEBsXyKtoLE9mrbDD7WMHXvXrCjZvabLAsi")
116+
117+let romeAssetIdStr = valueOrElse(getString(CONFIG_ADDRESS, "romeAssetIdStr"), "AP4Cb5xLYGH6ZigHreCZHoXpQTWDkPsG2BHqfDUx6taJ")
118+
119+let wavesAssetIdStr = "WAVES"
120+
121+let usdnAssetId = fromBase58String(usdnAssetIdStr)
122+
123+let puzzleAssetId = fromBase58String(puzzleAssetIdStr)
124+
125+let usdtAssetId = fromBase58String(usdtAssetIdStr)
126+
127+let usdtPptAssetId = fromBase58String(usdtPptAssetIdStr)
128+
129+let romeAssetId = fromBase58String(romeAssetIdStr)
130+
131+let wavesAssetId = unit
132+
133+let supportedFeeAssetsStr = [usdnAssetIdStr, puzzleAssetIdStr, usdtAssetIdStr, usdtPptAssetIdStr, wavesAssetIdStr, romeAssetIdStr]
134+
135+let oracleAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "oracleAddress"), "3N91e7wHiV7QadDsx3RUJQxx1etqcAKrfHj")))
136+
137+let feesAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "feesAddress"), "3N91e7wHiV7QadDsx3RUJQxx1etqcAKrfHj")))
138+
139+let shutdownAddressStr = valueOrElse(getString(CONFIG_ADDRESS, "shutdownAddress"), "3N91e7wHiV7QadDsx3RUJQxx1etqcAKrfHj")
140+
141+let layer2Addresses = valueOrElse(getString(CONFIG_ADDRESS, "layer2Addresses"), "3N91e7wHiV7QadDsx3RUJQxx1etqcAKrfHj")
142+
143+let coldMasterAddress = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "coldMasterAddress"), "3N91e7wHiV7QadDsx3RUJQxx1etqcAKrfHj")))
144+
145+let calculatorAccount = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "factoryAddress"), "3N1ytAUyhtig9X6F2hHHs1jbzYxr47Yp8Fr")))
146+
147+let factoryAccount = Address(fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "factoryAddress"), "3MsgzbtRg8NEkbTcHBywtwTdCe9BRxMQo5T")))
148+
149+let masterPubKey = fromBase58String(valueOrElse(getString(CONFIG_ADDRESS, "masterPubKey"), "4z8CKSYQBKkzx7PBb5uBP1YPa6YAHRNTApW1sQVHT5eU"))
150+
151+let T = tryGetInteger("static_tokensAmount")
152+
153+let assetIds = {
154+ let $l = split(tryGetString("static_tokenIds"), ",")
155+ let $s = size($l)
156+ let $acc0 = nil
157+ func $f0_1 ($a,$i) = if (($i >= $s))
158+ then $a
159+ else addAssetBytesToList($a, $l[$i])
160+
161+ func $f0_2 ($a,$i) = if (($i >= $s))
162+ then $a
163+ else throw("List size exceeds 10")
164+
165+ $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)
166+ }
167+
168+let AssetsWeights = {
169+ let $l = assetIds
170+ let $s = size($l)
171+ let $acc0 = nil
172+ func $f1_1 ($a,$i) = if (($i >= $s))
173+ then $a
174+ else addAssetWeightToList($a, $l[$i])
175+
176+ func $f1_2 ($a,$i) = if (($i >= $s))
177+ then $a
178+ else throw("List size exceeds 10")
179+
180+ $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)
181+ }
182+
183+let Decimals = {
184+ let $l = assetIds
185+ let $s = size($l)
186+ let $acc0 = nil
187+ func $f2_1 ($a,$i) = if (($i >= $s))
188+ then $a
189+ else addAssetDecimalsToList($a, $l[$i])
190+
191+ func $f2_2 ($a,$i) = if (($i >= $s))
192+ then $a
193+ else throw("List size exceeds 10")
194+
195+ $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)
196+ }
197+
198+let Scales = {
199+ let $l = assetIds
200+ let $s = size($l)
201+ let $acc0 = nil
202+ func $f3_1 ($a,$i) = if (($i >= $s))
203+ then $a
204+ else addAssetScaleToList($a, $l[$i])
205+
206+ func $f3_2 ($a,$i) = if (($i >= $s))
207+ then $a
208+ else throw("List size exceeds 10")
209+
210+ $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)
211+ }
212+
213+let Fee = tryGetInteger("static_fee")
214+
215+let earnedAssets = assetIds
216+
217+func getPoolStatus () = {
218+ let poolId = valueOrElse(getString(factoryAccount, ("pool__" + toString(this))), "")
219+ let status = valueOrElse(getInteger(factoryAccount, ("pool__" + poolId)), 2)
220+ status
221+ }
222+
223+
224+func getSetting (key) = getIntegerValue(factoryAccount, ("setup__" + key))
225+
226+
227+let InitalWavesLiquidity = getSetting("virtualLiquidity")
228+
229+let CreationFee = getSetting("creationFee")
230+
231+let CurveTarget = getSetting("curveTarget")
232+
233+func isShutdown () = {
234+ let shutdownAddress = addressFromString(shutdownAddressStr)
235+ if ((shutdownAddress == unit))
236+ then false
237+ else match getBoolean(value(shutdownAddress), "is_shutdown") {
238+ case x: Boolean =>
239+ x
240+ case _ =>
241+ false
242+ }
243+ }
244+
245+
246+func getPriceFromOracle (assetIdStr) = match getInteger(oracleAddress, (assetIdStr + "_twap5B")) {
247+ case x: Int =>
248+ x
249+ case _ =>
250+ 1000000
251+}
252+
253+
254+func calculateUsdValue (assetId,amount,aBalance) = {
255+ let assetWeight = tryGetInteger((("static_" + getAssetString(assetId)) + "_weight"))
256+ let feeAssetStr = tryGetString("static_feeToken")
257+ let feeAssetScale = getIntegerValue(this, (("static_" + feeAssetStr) + "_scale"))
258+ let feeAssetNum = value(indexOf(assetIds, getAssetBytes(feeAssetStr)))
259+ let feeAssetWeight = AssetsWeights[feeAssetNum]
260+ let feeAssetBalance = tryGetInteger((("global_" + feeAssetStr) + "_balance"))
261+ let valInFeeAsset = fraction(amount, (feeAssetBalance / feeAssetWeight), (aBalance / assetWeight))
262+ let feeAssetPrice = getPriceFromOracle(feeAssetStr)
263+ fraction(valInFeeAsset, feeAssetPrice, feeAssetScale)
264+ }
265+
266+
267+func calculateOutAmount (AmountIn,assetIn,assetOut,BalanceIn,BalanceOut) = {
268+ let IndexIn = value(indexOf(assetIds, assetIn))
269+ let IndexOut = value(indexOf(assetIds, assetOut))
270+ if ((IndexIn == IndexOut))
271+ then AmountIn
272+ 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)
273+ }
274+
275+
276+func calculateCurrentAssetInterest (assetId,assetIdStr,aBalance,tokenEarningsLastCheck) = {
277+ let totalStaked = tryGetInteger("global_indexStaked")
278+ let tokenBalanceLastCheck = tokenEarningsLastCheck
279+ let currentBalanceDelta = (getTokenBalance(assetId) - aBalance)
280+ let currentTokenEarnings = if ((currentBalanceDelta > tokenBalanceLastCheck))
281+ then currentBalanceDelta
282+ else tokenBalanceLastCheck
283+ let newEarnings = (currentTokenEarnings - tokenBalanceLastCheck)
284+ let newInterest = if ((totalStaked == 0))
285+ then 0
286+ else fraction(newEarnings, Scale8, totalStaked)
287+ let lastCheckInterest = tryGetInteger((("global_lastCheck_" + assetIdStr) + "_interest"))
288+ (lastCheckInterest + newInterest)
289+ }
290+
291+
292+func claimResult (address) = {
293+ let addressStr = toString(address)
294+ let puzzleAmount = tryGetInteger((addressStr + "_indexStaked"))
295+ func handler (accum,assetId) = {
296+ let assetIdStr = getAssetString(assetId)
297+ let aBalance = tryGetInteger((("global_" + getAssetString(assetId)) + "_balance"))
298+ let tokenEarningsLastCheck = tryGetInteger((("global_lastCheck_" + assetIdStr) + "_earnings"))
299+ let currentTokenInterest = calculateCurrentAssetInterest(assetId, assetIdStr, aBalance, tokenEarningsLastCheck)
300+ let currentTokenEarnings = max([tokenEarningsLastCheck, (getTokenBalance(assetId) - aBalance)])
301+ let rewardAmount = fraction(puzzleAmount, (currentTokenInterest - tryGetInteger((((addressStr + "_lastCheck_") + assetIdStr) + "_interest"))), Scale8)
302+ let transfer = if ((rewardAmount == 0))
303+ then nil
304+ else [ScriptTransfer(address, rewardAmount, assetId)]
305+ $Tuple2(((accum._1 ++ transfer) ++ [IntegerEntry((("global_lastCheck_" + assetIdStr) + "_earnings"), (currentTokenEarnings - rewardAmount)), IntegerEntry((("global_lastCheck_" + assetIdStr) + "_interest"), currentTokenInterest), IntegerEntry((((addressStr + "_lastCheck_") + assetIdStr) + "_interest"), currentTokenInterest)]), (accum._2 + calculateUsdValue(assetId, rewardAmount, aBalance)))
306+ }
307+
308+ let accum = {
309+ let $l = earnedAssets
310+ let $s = size($l)
311+ let $acc0 = $Tuple2(nil, 0)
312+ func $f4_1 ($a,$i) = if (($i >= $s))
313+ then $a
314+ else handler($a, $l[$i])
315+
316+ func $f4_2 ($a,$i) = if (($i >= $s))
317+ then $a
318+ else throw("List size exceeds 10")
319+
320+ $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)
321+ }
322+ $Tuple2((accum._1 ++ [IntegerEntry((addressStr + "_claimedRewardUSD"), (tryGetInteger((addressStr + "_claimedRewardUSD")) + accum._2)), IntegerEntry((addressStr + "_lastClaim"), lastBlock.timestamp)]), accum._2)
323+ }
324+
325+
326+func sum (accum,n) = (accum + parseIntValue(n))
327+
328+
329+func checkFeeAsset (accum,next) = if (if ((indexOf(supportedFeeAssetsStr, next) != unit))
330+ then (accum == "")
331+ else false)
332+ then next
333+ else accum
334+
335+
336+func swapInternal (assetIn,assetOut,amountIn,minimum,receipientAddressStr) = {
337+ let AmountIn = amountIn
338+ let AssetIn = getAssetBytes(assetIn)
339+ let AssetOut = getAssetBytes(assetOut)
340+ let scaleIn = (Scale8 / tryGetInteger((("static_" + assetIn) + "_scale")))
341+ let scaleOut = (Scale8 / tryGetInteger((("static_" + assetOut) + "_scale")))
342+ let feeAssetOutStr = tryGetString("static_feeToken")
343+ let feeAssetOut = if ((feeAssetOutStr == ""))
344+ then wavesAssetId
345+ else getAssetBytes(feeAssetOutStr)
346+ let AssetInBalance = tryGetInteger((("global_" + getAssetString(AssetIn)) + "_balance"))
347+ let AssetOutBalance = tryGetInteger((("global_" + assetOut) + "_balance"))
348+ let AssetInBalanceScaled = (AssetInBalance * scaleIn)
349+ let AssetOutBalanceScaled = (AssetOutBalance * scaleOut)
350+ let feeAmountIn = fraction(AmountIn, Fee, FeeScale)
351+ let cleanAmountIn = (AmountIn - feeAmountIn)
352+ let cleanAmountInScaled = (cleanAmountIn * scaleIn)
353+ let AmountOut1 = calculateOutAmount(cleanAmountInScaled, AssetIn, AssetOut, AssetInBalanceScaled, AssetOutBalanceScaled)
354+ let AmountOut = fraction(AmountOut1, 1, scaleOut)
355+ let AssetOutBalance2 = (AssetOutBalance - AmountOut)
356+ let AssetInBalance2 = (AssetInBalance + cleanAmountIn)
357+ let feeAssetOutBalance = if ((feeAssetOut == AssetIn))
358+ then AssetInBalance2
359+ else if ((feeAssetOut == AssetOut))
360+ then AssetOutBalance2
361+ else tryGetInteger((("global_" + getAssetString(feeAssetOut)) + "_balance"))
362+ let feeAmountOut = calculateOutAmount(feeAmountIn, AssetIn, feeAssetOut, AssetInBalance, feeAssetOutBalance)
363+ if ((minimum > AmountOut))
364+ then throw("amount to recieve is lower than given one")
365+ else if ((AssetOut == AssetIn))
366+ then throw("this swap is not allowed")
367+ else if ((0 > (AssetOutBalance - AmountOut)))
368+ then throw("contract is out of reserves")
369+ else if (isShutdown())
370+ then throw("contract is on stop")
371+ else {
372+ let creatorFee = fraction(feeAmountOut, 1, 10)
373+ let protocolFee = fraction(feeAmountOut, 4, 10)
374+ let newBalanceIn = AssetInBalance2
375+ let newBalanceOut = (AssetOutBalance2 - (if ((AssetOut == feeAssetOut))
376+ then feeAmountOut
377+ else 0))
378+ let newBalanceFeeAsset = if (if ((feeAssetOut != AssetIn))
379+ then (feeAssetOut != AssetOut)
380+ else false)
381+ then (feeAssetOutBalance - feeAmountOut)
382+ else unit
383+ let assetInChange = IntegerEntry((("global_" + getAssetString(AssetIn)) + "_balance"), newBalanceIn)
384+ let assetOutChange = IntegerEntry((("global_" + assetOut) + "_balance"), newBalanceOut)
385+ let feeAssetOutChange = if ((newBalanceFeeAsset != unit))
386+ then IntegerEntry((("global_" + getAssetString(feeAssetOut)) + "_balance"), value(newBalanceFeeAsset))
387+ else StringEntry("hello", "world")
388+ let volumeUsdUpdate = calculateUsdValue(AssetIn, AmountIn, AssetInBalance)
389+ $Tuple2([assetOutChange, assetInChange, feeAssetOutChange, ScriptTransfer(addressFromStringValue(receipientAddressStr), AmountOut, AssetOut), ScriptTransfer(addressFromStringValue(tryGetString("static_poolOwner")), creatorFee, feeAssetOut), IntegerEntry("global_earnedByOwner", (tryGetInteger("global_earnedByOwner") + creatorFee)), IntegerEntry("global_volume_usd", (tryGetInteger("global_volume_usd") + volumeUsdUpdate)), ScriptTransfer(feesAddress, protocolFee, feeAssetOut)], AmountOut)
390+ }
391+ }
392+
393+
394+@Callable(i)
395+func initPool (poolDomain,poolOwner,tokenName,tokenDesc,tokenQuantity) = {
396+ func calculatePoolTokensAmount (payments) = {
397+ func handler (accum,pmt) = {
398+ let assetId = pmt.assetId
399+ func handler2 (accum,n) = if ((n == assetId))
400+ then value(indexOf(assetIds, n))
401+ else accum
402+
403+ let Token = {
404+ let $l = assetIds
405+ let $s = size($l)
406+ let $acc0 = 1
407+ func $f4_1 ($a,$i) = if (($i >= $s))
408+ then $a
409+ else handler2($a, $l[$i])
410+
411+ func $f4_2 ($a,$i) = if (($i >= $s))
412+ then $a
413+ else throw("List size exceeds 10")
414+
415+ $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)
416+ }
417+ fraction(accum, pow(pmt.amount, Decimals[Token], AssetsWeights[Token], AssetsWeightsDecimals, 8, FLOOR), Scale8)
418+ }
419+
420+ let $l = payments
421+ let $s = size($l)
422+ let $acc0 = PoolTokenScale
423+ func $f4_1 ($a,$i) = if (($i >= $s))
424+ then $a
425+ else handler($a, $l[$i])
426+
427+ func $f4_2 ($a,$i) = if (($i >= $s))
428+ then $a
429+ else throw("List size exceeds 10")
430+
431+ $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)
432+ }
433+
434+ let meme = Issue(tokenName, tokenDesc, tokenQuantity, 8, false)
435+ let memeId = calculateAssetId(meme)
436+ let memeIdStr = getAssetString(memeId)
437+ let assetWeightsStr = "5000,5000"
438+ let baseTokenIdStr = "WAVES"
439+ let poolOwnerAddress = Address(fromBase58String(poolOwner))
440+ let assetIdsStr = ("WAVES," + memeIdStr)
441+ let assetIdsStrLi = split(assetIdsStr, ",")
442+ let assetIdsLi = {
443+ let $l = assetIdsStrLi
444+ let $s = size($l)
445+ let $acc0 = nil
446+ func $f4_1 ($a,$i) = if (($i >= $s))
447+ then $a
448+ else addAssetBytesToList($a, $l[$i])
449+
450+ func $f4_2 ($a,$i) = if (($i >= $s))
451+ then $a
452+ else throw("List size exceeds 10")
453+
454+ $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)
455+ }
456+ let fee = 100
457+ let feeAssetStr = {
458+ let $l = assetIdsStrLi
459+ let $s = size($l)
460+ let $acc0 = ""
461+ func $f5_1 ($a,$i) = if (($i >= $s))
462+ then $a
463+ else checkFeeAsset($a, $l[$i])
464+
465+ func $f5_2 ($a,$i) = if (($i >= $s))
466+ then $a
467+ else throw("List size exceeds 10")
468+
469+ $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)
470+ }
471+ let pmt = i.payments[0]
472+ let amount = pmt.amount
473+ let pmtAsset = if ((pmt.assetId == unit))
474+ then "WAVES"
475+ else throw("you have to attach some WAVES")
476+ if ((this != this))
477+ then throw("self-invoke only")
478+ else if ((feeAssetStr == ""))
479+ then throw("pool must have one of the supported fee assets in the composition")
480+ else if ((size(poolDomain) > 13))
481+ then throw("too large pool domain")
482+ else if (if ((fee > 500))
483+ then true
484+ else (0 > fee))
485+ then throw("fee value must be between 50 and 500 (0.5-5%)")
486+ else if (isShutdown())
487+ then throw("contract is on stop")
488+ else {
489+ let assetWeightsStrLi = split(assetWeightsStr, ",")
490+ let assetWeightsSum = {
491+ let $l = assetWeightsStrLi
492+ let $s = size($l)
493+ let $acc0 = 0
494+ func $f6_1 ($a,$i) = if (($i >= $s))
495+ then $a
496+ else sum($a, $l[$i])
497+
498+ func $f6_2 ($a,$i) = if (($i >= $s))
499+ then $a
500+ else throw("List size exceeds 10")
501+
502+ $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)
503+ }
504+ func addTokenDataEntries (accum,assetNum) = if ((assetNum >= size(assetIdsLi)))
505+ then accum
506+ else {
507+ let assetDecimals = 8
508+ (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])))])
509+ }
510+
511+ let initialPoolTokens = calculatePoolTokensAmount(i.payments)
512+ if ((assetWeightsSum != 10000))
513+ then throw("sum of token weights must be equal to 10000")
514+ else if ((initialPoolTokens == 0))
515+ then throw("you need a bigger tokens amount to launch the pool")
516+ else {
517+ let poolTokenIssue = Issue(("PZ " + poolDomain), "Puzzle Swap: pool index token", initialPoolTokens, PoolTokenDecimals, true, unit, 0)
518+ let poolTokenId = calculateAssetId(poolTokenIssue)
519+ $Tuple2(((({
520+ let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
521+ let $s = size($l)
522+ let $acc0 = nil
523+ func $f7_1 ($a,$i) = if (($i >= $s))
524+ then $a
525+ else addTokenDataEntries($a, $l[$i])
526+
527+ func $f7_2 ($a,$i) = if (($i >= $s))
528+ then $a
529+ else throw("List size exceeds 10")
530+
531+ $f7_2($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($f7_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
532+ } ++ [meme, StringEntry("static_tokenIds", assetIdsStr), StringEntry("static_feeToken", feeAssetStr), StringEntry("static_tokenWeights", assetWeightsStr), IntegerEntry("static_tokensAmount", size(assetIdsLi)), StringEntry("static_poolDomain", poolDomain), StringEntry("static_baseTokenId", baseTokenIdStr), StringEntry("static_poolOwner", poolOwner), IntegerEntry("static_fee", fee), IntegerEntry("static_KMult", Scale16), IntegerEntry("global_wasPreInited", 1)]) ++ [IntegerEntry("global_WAVES_balance", InitalWavesLiquidity), IntegerEntry((("global_" + memeIdStr) + "_balance"), tokenQuantity)]) ++ [poolTokenIssue, IntegerEntry("global_poolToken_amount", initialPoolTokens), IntegerEntry("global_wasInited", 1), BinaryEntry("global_poolToken_id", poolTokenId), StringEntry("static_poolToken_idStr", getAssetString(poolTokenId)), IntegerEntry((toString(i.caller) + "_indexStaked"), initialPoolTokens), IntegerEntry("global_indexStaked", initialPoolTokens)]), memeIdStr)
533+ }
534+ }
535+ }
536+
537+
538+
539+@Callable(i)
540+func init (poolDomain,poolOwner,tokenName,tokenDesc,tokenQuantity) = if ((i.caller != factoryAccount))
541+ then throw("admin only")
542+ else {
543+ let inv1 = invoke(this, "initPool", [poolDomain, poolOwner, tokenName, tokenDesc, tokenQuantity], nil)
544+ if ((inv1 == inv1))
545+ then {
546+ let memeIdStr = {
547+ let @ = inv1
548+ if ($isInstanceOf(@, "String"))
549+ then @
550+ else throw(($getType(@) + " couldn't be cast to String"))
551+ }
552+ swapInternal("WAVES", memeIdStr, (i.payments[0].amount - CreationFee), 0, toString(i.caller))._1
553+ }
554+ else throw("Strict value is not equal to itself.")
555+ }
556+
557+
558+
559+@Callable(i)
560+func claimIndexRewards () = if (isShutdown())
561+ then throw("contract is on stop")
562+ else claimResult(i.caller)
563+
564+
565+
566+@Callable(i)
567+func evaluateClaim (user) = $Tuple2(nil, claimResult(addressFromStringValue(user))._2)
568+
569+
570+
571+@Callable(i)
572+func swap (assetOut,minimum) = {
573+ let status = getPoolStatus()
574+ if ((2 > status))
575+ then {
576+ let pmt = if ((size(i.payments) == 1))
577+ then value(i.payments[0])
578+ else throw("please attach exactly one payment")
579+ let AmountIn = value(i.payments[0].amount)
580+ let AssetIn = i.payments[0].assetId
581+ let res = swapInternal(getAssetString(AssetIn), assetOut, AmountIn, minimum, toString(i.caller))
582+ if ((getIntegerValue("global_WAVES_balance") > CurveTarget))
583+ then {
584+ let notifyInv = invoke(factoryAccount, "notifyStatusUpdate", [2], nil)
585+ if ((notifyInv == notifyInv))
586+ then res
587+ else throw("Strict value is not equal to itself.")
588+ }
589+ else res
590+ }
591+ else throw("pool is stopped: most probably it reached the target liquidity")
592+ }
593+
594+
595+
596+@Callable(i)
597+func swapReadOnly (assetIn,assetOut,AmountIn) = {
598+ let AssetIn = getAssetBytes(assetIn)
599+ let AssetOut = getAssetBytes(assetOut)
600+ let scaleIn = (Scale8 / tryGetInteger((("static_" + assetIn) + "_scale")))
601+ let scaleOut = (Scale8 / tryGetInteger((("static_" + assetOut) + "_scale")))
602+ let feeAssetOutStr = tryGetString("static_feeToken")
603+ let feeAssetOut = if ((feeAssetOutStr == ""))
604+ then usdnAssetId
605+ else getAssetBytes(feeAssetOutStr)
606+ let AssetInBalance = tryGetInteger((("global_" + getAssetString(AssetIn)) + "_balance"))
607+ let AssetOutBalance = tryGetInteger((("global_" + assetOut) + "_balance"))
608+ let AssetInBalanceScaled = (AssetInBalance * scaleIn)
609+ let AssetOutBalanceScaled = (AssetOutBalance * scaleOut)
610+ let feeAmountIn = fraction(AmountIn, Fee, FeeScale)
611+ let cleanAmountIn = (AmountIn - feeAmountIn)
612+ let cleanAmountInScaled = (cleanAmountIn * scaleIn)
613+ let AmountOut1 = calculateOutAmount(cleanAmountInScaled, AssetIn, AssetOut, AssetInBalanceScaled, AssetOutBalanceScaled)
614+ let AmountOut = fraction(AmountOut1, 1, scaleOut)
615+ let AssetOutBalance2 = (AssetOutBalance - AmountOut)
616+ let AssetInBalance2 = (AssetInBalance + cleanAmountIn)
617+ let feeAssetOutBalance = if ((feeAssetOut == AssetIn))
618+ then AssetInBalance2
619+ else if ((feeAssetOut == AssetOut))
620+ then AssetOutBalance2
621+ else tryGetInteger((("global_" + getAssetString(feeAssetOut)) + "_balance"))
622+ let feeAmountOut = calculateOutAmount(feeAmountIn, AssetIn, feeAssetOut, AssetInBalance, feeAssetOutBalance)
623+ if ((AssetOut == AssetIn))
624+ then throw("this swap is not allowed")
625+ else if ((0 > (AssetOutBalance - AmountOut)))
626+ then throw("contract is out of reserves")
627+ else if (isShutdown())
628+ then throw("contract is on stop")
629+ else $Tuple2(nil, AmountOut)
630+ }
631+
632+
633+
634+@Callable(i)
635+func transferOwnership (newOwnerAddress) = if ((toString(i.caller) != tryGetString("static_poolOwner")))
636+ then throw("this call available only for pool owner")
637+ else [StringEntry("static_poolOwner", newOwnerAddress)]
638+
639+

github/deemru/w8io/fabc49c 
27.67 ms