tx · HfrtsyoqcdEVaFxU5r5WYqxKStbNaMKKcXtUkx3P5Yxf

3NAg2HDvKz7gwrNc2wnUxdK74NydBFUXTYP:  -0.03300000 Waves

2024.11.21 12:49 [3381050] smart account 3NAg2HDvKz7gwrNc2wnUxdK74NydBFUXTYP > SELF 0.00000000 Waves

{ "type": 13, "id": "HfrtsyoqcdEVaFxU5r5WYqxKStbNaMKKcXtUkx3P5Yxf", "fee": 3300000, "feeAssetId": null, "timestamp": 1732182366091, "version": 2, "chainId": 84, "sender": "3NAg2HDvKz7gwrNc2wnUxdK74NydBFUXTYP", "senderPublicKey": "BEbZF8zo7WjaQFZFFuPs7hqSLEgGwjwQFGg4tSidf9C3", "proofs": [ "5NfG7vsi81GVynKckDuiGUz9WWFjf169tv4GbzN44gj3aYNuDgZBZUGrVmiBxDsSSKs7NBw8k8acfvn3mnaripvL" ], "script": "base64:BwJuCAISCAoGCAgICAgIEggKBggICAgICBIJCgcICAgICAgIEgUKAwgICBIDCgEIEgwKCggICAgICAgICAgSBgoECAgICBIFCgMBCAgSBQoDAQgIEgMKAQESAwoBCBIDCgEIEgASABIDCgEIEgMKAQhwAAlTRVBBUkFUT1ICAl9fAAxLRVlfTVVMVElTSUcCCE1VTFRJU0lHAApLRVlfU1RBVFVTAgZTVEFUVVMACEtFWV9JTklUAgRJTklUAApLRVlfUEFVU0VEAgZQQVVTRUQACktFWV9QQVVTRVICBlBBVVNFUgAMS0VZX0VYRUNVVE9SAghFWEVDVVRPUgATS0VZX0NBTExFUl9DT05UUkFDVAIPQ0FMTEVSX0NPTlRSQUNUAA9LRVlfV0FWRVNfVkFVTFQCC1dBVkVTX1ZBVUxUABNLRVlfQUNDT1VOVF9TVE9SQUdFAg9BQ0NPVU5UX1NUT1JBR0UACUtFWV9DSEFJTgIFQ0hBSU4AEktFWV9BU1NFVF9DVVJSRU5DWQIOQVNTRVRfQ1VSUkVOQ1kAEktFWV9BU1NFVF9SRVNFUlZFUwIOQVNTRVRfUkVTRVJWRVMAGUtFWV9BU1NFVF9SRVNFUlZFU19MT0NLRUQCFUFTU0VUX1JFU0VSVkVTX0xPQ0tFRAAYS0VZX1VTRVJfTE9DS0VEX0NVUlJFTkNZAhRVU0VSX0xPQ0tFRF9DVVJSRU5DWQAVS0VZX0NVUlJFTkNZX1JFU0VSVkVTAhFDVVJSRU5DWV9SRVNFUlZFUwAbS0VZX1JFUVVFU1RfV0lUSERSQVdBTF9TSVpFAhdSRVFVRVNUX1dJVEhEUkFXQUxfU0laRQAWS0VZX1JFUVVFU1RfV0lUSERSQVdBTAISUkVRVUVTVF9XSVRIRFJBV0FMACJLRVlfUkVRVUVTVF9XSVRIRFJBV0FMX0JMT0NLX0RFTEFZAh5SRVFVRVNUX1dJVEhEUkFXQUxfQkxPQ0tfREVMQVkADUtFWV9TRVFVRU5DRVICCVNFUVVFTkNFUgATS0VZX1dJVEhEUkFXQUxfSEFTSAIPV0lUSERSQVdBTF9IQVNIABFLRVlfVkFVTFRfQURBUFRFUgINVkFVTFRfQURBUFRFUgAWS0VZX1JFV0FSRF9ESVNUUklCVVRPUgISUkVXQVJEX0RJU1RSSUJVVE9SABlLRVlfUkVMQVlFUl9GRUVfUkVDSVBJRU5UAhVSRUxBWUVSX0ZFRV9SRUNJUElFTlQADEZVTkNfREVQT1NJVAIHZGVwb3NpdAAVRlVOQ19HRVRfVVNFUl9CQUxBTkNFAg5nZXRVc2VyQmFsYW5jZQAWRlVOQ19JTlRFUk5BTF9UUkFOU0ZFUgIQaW50ZXJuYWxUcmFuc2ZlcgANRlVOQ19XSVRIRFJBVwIId2l0aGRyYXcAG0ZVTkNfREVQT1NJVF9TVEFLSU5HX1JFV0FSRAIUZGVwb3NpdFN0YWtpbmdSZXdhcmQAFlJFUVVFU1RfU1RBVFVTX0NSRUFURUQAAAATUkVRVUVTVF9TVEFUVVNfRE9ORQABABdSRVFVRVNUX1NUQVRVU19SRUpFQ1RFRAACAAVXQVZFUwIFV0FWRVMAC1NQT1RfV0FMTEVUAgRTUE9UAAdNQVhfSU5UAP//////////fwALWkVST19CSUdJTlQJALYCAQAAAApPTkVfQklHSU5UCQC2AgEAAQAHT05FX0RBWQCAuJkpAA5BTEdfVFlQRV9XQVZFUwABAAxBTEdfVFlQRV9FVk0AAgAURVZNX1NJR05BVFVSRV9QUkVGSVgBHBlFdGhlcmV1bSBTaWduZWQgTWVzc2FnZToKMzIBEF92YWxpZGF0ZUFkZHJlc3MCCGFkZHJlc3NfBGVycl8EByRtYXRjaDAJAKYIAQUIYWRkcmVzc18DCQABAgUHJG1hdGNoMAIHQWRkcmVzcwQBYQUHJG1hdGNoMAYJAAIBBQRlcnJfAQxfdmFsaWRhdGVJbnQEBHZhbF8ObG93ZXJCb3VuZGFyeV8OdXBwZXJCb3VuZGFyeV8EZXJyXwMDCQBmAgUObG93ZXJCb3VuZGFyeV8FBHZhbF8GCQBmAgUEdmFsXwUOdXBwZXJCb3VuZGFyeV8JAAIBBQRlcnJfBgEPX3ZhbGlkYXRlQmlnSW50AwR2YWxfDmxvd2VyQm91bmRhcnlfBGVycl8DCQC/AgIFDmxvd2VyQm91bmRhcnlfBQR2YWxfCQACAQUEZXJyXwYBEV92YWxpZGF0ZUJpZ0ludF8yBAR2YWxfDmxvd2VyQm91bmRhcnlfDnVwcGVyQm91bmRhcnlfBGVycl8DAwkAvwICBQ5sb3dlckJvdW5kYXJ5XwUEdmFsXwYJAL8CAgUEdmFsXwUOdXBwZXJCb3VuZGFyeV8JAAIBBQRlcnJfBgEPX3ZhbGlkYXRlU3RyaW5nAgR2YWxfBGVycl8DAwkAZwIAAAkAsQIBBQR2YWxfBgkBCGNvbnRhaW5zAgUEdmFsXwUJU0VQQVJBVE9SCQACAQUEZXJyXwYBFF92YWxpZGF0ZVN0cmluZ0VxdWFsAwV2YWwxXwV2YWwyXwRlcnJfAwkBAiE9AgUFdmFsMV8FBXZhbDJfCQACAQUEZXJyXwYBCV9sb2FkSW5pdAAEByRtYXRjaDAJAKAIAQUIS0VZX0lOSVQDCQABAgUHJG1hdGNoMAIHQm9vbGVhbgQBYQUHJG1hdGNoMAUBYQcBCV9zYXZlSW5pdAEHaXNJbml0XwkAzAgCCQEMQm9vbGVhbkVudHJ5AgUIS0VZX0lOSVQFB2lzSW5pdF8FA25pbAEKX2xvYWRQYXVzZQAEByRtYXRjaDAJAKAIAQUKS0VZX1BBVVNFRAMJAAECBQckbWF0Y2gwAgdCb29sZWFuBAFhBQckbWF0Y2gwBQFhBwEKX3NhdmVQYXVzZQEJaXNQYXVzZWRfCQDMCAIJAQxCb29sZWFuRW50cnkCBQpLRVlfUEFVU0VEBQlpc1BhdXNlZF8FA25pbAELX2xvYWRQYXVzZXIABAckbWF0Y2gwCQCiCAEFCktFWV9QQVVTRVIDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFhBQckbWF0Y2gwCQERQGV4dHJOYXRpdmUoMTA2MikBBQFhCQEHQWRkcmVzcwEBAAELX3NhdmVQYXVzZXIBB3BhdXNlcl8JAMwIAgkBC1N0cmluZ0VudHJ5AgUKS0VZX1BBVVNFUgkApQgBBQdwYXVzZXJfBQNuaWwBDV9sb2FkTXVsdGlzaWcABAckbWF0Y2gwCQCiCAEFDEtFWV9NVUxUSVNJRwMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAWEFByRtYXRjaDAJARFAZXh0ck5hdGl2ZSgxMDYyKQEFAWEJAQdBZGRyZXNzAQEAAQ1fc2F2ZU11bHRpc2lnAQltdWx0aXNpZ18JAMwIAgkBC1N0cmluZ0VudHJ5AgUMS0VZX01VTFRJU0lHCQClCAEFCW11bHRpc2lnXwUDbmlsARNfbG9hZENhbGxlckNvbnRyYWN0AQhjaGFpbklkXwQHJG1hdGNoMAkAoggBCQC5CQIJAMwIAgUTS0VZX0NBTExFUl9DT05UUkFDVAkAzAgCCQCkAwEFCGNoYWluSWRfBQNuaWwFCVNFUEFSQVRPUgMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAWEFByRtYXRjaDAFAWECAAETX3NhdmVDYWxsZXJDb250cmFjdAIIY2hhaW5JZF8PY2FsbGVyQ29udHJhY3RfCQDMCAIJAQtTdHJpbmdFbnRyeQIJALkJAgkAzAgCBRNLRVlfQ0FMTEVSX0NPTlRSQUNUCQDMCAIJAKQDAQUIY2hhaW5JZF8FA25pbAUJU0VQQVJBVE9SBQ9jYWxsZXJDb250cmFjdF8FA25pbAENX2xvYWRFeGVjdXRvcgAEByRtYXRjaDAJAKIIAQUMS0VZX0VYRUNVVE9SAwkAAQIFByRtYXRjaDACBlN0cmluZwQBYQUHJG1hdGNoMAkBEUBleHRyTmF0aXZlKDEwNjIpAQUBYQkBB0FkZHJlc3MBAQABDV9zYXZlRXhlY3V0b3IBCWV4ZWN1dG9yXwkAzAgCCQELU3RyaW5nRW50cnkCBQxLRVlfRVhFQ1VUT1IJAKUIAQUJZXhlY3V0b3JfBQNuaWwBE19sb2FkQWNjb3VudFN0b3JhZ2UABAckbWF0Y2gwCQCiCAEFE0tFWV9BQ0NPVU5UX1NUT1JBR0UDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFhBQckbWF0Y2gwCQERQGV4dHJOYXRpdmUoMTA2MikBBQFhCQEHQWRkcmVzcwEBAAETX3NhdmVBY2NvdW50U3RvcmFnZQEPYWNjb3VudFN0b3JhZ2VfCQDMCAIJAQtTdHJpbmdFbnRyeQIFE0tFWV9BQ0NPVU5UX1NUT1JBR0UJAKUIAQUPYWNjb3VudFN0b3JhZ2VfBQNuaWwBD19sb2FkV2F2ZXNWYXVsdAAEByRtYXRjaDAJAKIIAQUPS0VZX1dBVkVTX1ZBVUxUAwkAAQIFByRtYXRjaDACBlN0cmluZwQBYQUHJG1hdGNoMAkBEUBleHRyTmF0aXZlKDEwNjIpAQUBYQkBB0FkZHJlc3MBAQABD19zYXZlV2F2ZXNWYXVsdAELd2F2ZXNWYXVsdF8JAMwIAgkBC1N0cmluZ0VudHJ5AgUPS0VZX1dBVkVTX1ZBVUxUCQClCAEFC3dhdmVzVmF1bHRfBQNuaWwBCl9sb2FkQ2hhaW4BCGNoYWluSWRfBAckbWF0Y2gwCQCiCAEJALkJAgkAzAgCBQlLRVlfQ0hBSU4JAMwIAgkApAMBBQhjaGFpbklkXwUDbmlsBQlTRVBBUkFUT1IDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFhBQckbWF0Y2gwBQFhAgABCl9zYXZlQ2hhaW4CCGNoYWluSWRfBW5hbWVfCQDMCAIJAQtTdHJpbmdFbnRyeQIJALkJAgkAzAgCBQlLRVlfQ0hBSU4JAMwIAgkApAMBBQhjaGFpbklkXwUDbmlsBQlTRVBBUkFUT1IFBW5hbWVfBQNuaWwBEl9sb2FkQXNzZXRDdXJyZW5jeQIIY2hhaW5JZF8GYXNzZXRfBAckbWF0Y2gwCQCiCAEJALkJAgkAzAgCBRJLRVlfQVNTRVRfQ1VSUkVOQ1kJAMwIAgkApAMBBQhjaGFpbklkXwkAzAgCBQZhc3NldF8FA25pbAUJU0VQQVJBVE9SAwkAAQIFByRtYXRjaDACBlN0cmluZwQBYQUHJG1hdGNoMAUBYQIAARJfc2F2ZUFzc2V0Q3VycmVuY3kDCGNoYWluSWRfBmFzc2V0XwljdXJyZW5jeV8JAMwIAgkBC1N0cmluZ0VudHJ5AgkAuQkCCQDMCAIFEktFWV9BU1NFVF9DVVJSRU5DWQkAzAgCCQCkAwEFCGNoYWluSWRfCQDMCAIFBmFzc2V0XwUDbmlsBQlTRVBBUkFUT1IFCWN1cnJlbmN5XwUDbmlsARJfbG9hZEFzc2V0UmVzZXJ2ZXMCCGNoYWluSWRfBmFzc2V0XwQHJG1hdGNoMAkAoggBCQC5CQIJAMwIAgUSS0VZX0FTU0VUX1JFU0VSVkVTCQDMCAIJAKQDAQUIY2hhaW5JZF8JAMwIAgUGYXNzZXRfBQNuaWwFCVNFUEFSQVRPUgMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAWEFByRtYXRjaDAJAKcDAQUBYQULWkVST19CSUdJTlQBEl9zYXZlQXNzZXRSZXNlcnZlcwMIY2hhaW5JZF8GYXNzZXRfCXJlc2VydmVzXwkAzAgCCQELU3RyaW5nRW50cnkCCQC5CQIJAMwIAgUSS0VZX0FTU0VUX1JFU0VSVkVTCQDMCAIJAKQDAQUIY2hhaW5JZF8JAMwIAgUGYXNzZXRfBQNuaWwFCVNFUEFSQVRPUgkApgMBBQlyZXNlcnZlc18FA25pbAEYX2xvYWRBc3NldFJlc2VydmVzTG9ja2VkAghjaGFpbklkXwZhc3NldF8EByRtYXRjaDAJAKIIAQkAuQkCCQDMCAIFGUtFWV9BU1NFVF9SRVNFUlZFU19MT0NLRUQJAMwIAgkApAMBBQhjaGFpbklkXwkAzAgCBQZhc3NldF8FA25pbAUJU0VQQVJBVE9SAwkAAQIFByRtYXRjaDACBlN0cmluZwQBYQUHJG1hdGNoMAkApwMBBQFhBQtaRVJPX0JJR0lOVAEYX3NhdmVBc3NldFJlc2VydmVzTG9ja2VkAwhjaGFpbklkXwZhc3NldF8JcmVzZXJ2ZXNfCQDMCAIJAQtTdHJpbmdFbnRyeQIJALkJAgkAzAgCBRlLRVlfQVNTRVRfUkVTRVJWRVNfTE9DS0VECQDMCAIJAKQDAQUIY2hhaW5JZF8JAMwIAgUGYXNzZXRfBQNuaWwFCVNFUEFSQVRPUgkApgMBBQlyZXNlcnZlc18FA25pbAEXX2xvYWRVc2VyTG9ja2VkQ3VycmVuY3kCCWN1cnJlbmN5XwV1c2VyXwQHJG1hdGNoMAkAoggBCQC5CQIJAMwIAgUYS0VZX1VTRVJfTE9DS0VEX0NVUlJFTkNZCQDMCAIFCWN1cnJlbmN5XwkAzAgCBQV1c2VyXwUDbmlsBQlTRVBBUkFUT1IDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFhBQckbWF0Y2gwCQCnAwEFAWEFC1pFUk9fQklHSU5UARdfc2F2ZVVzZXJMb2NrZWRDdXJyZW5jeQMJY3VycmVuY3lfBXVzZXJfB2Ftb3VudF8JAMwIAgkBC1N0cmluZ0VudHJ5AgkAuQkCCQDMCAIFGEtFWV9VU0VSX0xPQ0tFRF9DVVJSRU5DWQkAzAgCBQljdXJyZW5jeV8JAMwIAgUFdXNlcl8FA25pbAUJU0VQQVJBVE9SCQCmAwEFB2Ftb3VudF8FA25pbAEVX2xvYWRDdXJyZW5jeVJlc2VydmVzAQljdXJyZW5jeV8EByRtYXRjaDAJAKIIAQkAuQkCCQDMCAIFFUtFWV9DVVJSRU5DWV9SRVNFUlZFUwkAzAgCBQljdXJyZW5jeV8FA25pbAUJU0VQQVJBVE9SAwkAAQIFByRtYXRjaDACBlN0cmluZwQBYQUHJG1hdGNoMAkApwMBBQFhBQtaRVJPX0JJR0lOVAEVX3NhdmVDdXJyZW5jeVJlc2VydmVzAgljdXJyZW5jeV8JcmVzZXJ2ZXNfCQDMCAIJAQtTdHJpbmdFbnRyeQIJALkJAgkAzAgCBRVLRVlfQ1VSUkVOQ1lfUkVTRVJWRVMJAMwIAgUJY3VycmVuY3lfBQNuaWwFCVNFUEFSQVRPUgkApgMBBQlyZXNlcnZlc18FA25pbAEaX2xvYWRSZXF1ZXN0V2l0aGRyYXdhbFNpemUABAckbWF0Y2gwCQCfCAEFG0tFWV9SRVFVRVNUX1dJVEhEUkFXQUxfU0laRQMJAAECBQckbWF0Y2gwAgNJbnQEAWEFByRtYXRjaDAFAWEAAAEaX3NhdmVSZXF1ZXN0V2l0aGRyYXdhbFNpemUBBHZhbF8JAMwIAgkBDEludGVnZXJFbnRyeQIFG0tFWV9SRVFVRVNUX1dJVEhEUkFXQUxfU0laRQUEdmFsXwUDbmlsARZfbG9hZFJlcXVlc3RXaXRoZHJhd2FsAQZpbmRleF8EByRtYXRjaDAJAKIIAQkAuQkCCQDMCAIFFktFWV9SRVFVRVNUX1dJVEhEUkFXQUwJAMwIAgkApAMBBQZpbmRleF8FA25pbAUJU0VQQVJBVE9SAwkAAQIFByRtYXRjaDACBlN0cmluZwQBYQUHJG1hdGNoMAQGc3RydWN0CQC1CQIFAWEFCVNFUEFSQVRPUgkAmgoICQCRAwIFBnN0cnVjdAAACQCRAwIFBnN0cnVjdAABCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUGc3RydWN0AAIJAJEDAgUGc3RydWN0AAMJAKcDAQkAkQMCBQZzdHJ1Y3QABAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFBnN0cnVjdAAFCQCRAwIFBnN0cnVjdAAGCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUGc3RydWN0AAcJAJoKCAIAAgAAAAIABQtaRVJPX0JJR0lOVAAAAgAFFlJFUVVFU1RfU1RBVFVTX0NSRUFURUQBFl9zYXZlUmVxdWVzdFdpdGhkcmF3YWwCBmluZGV4XwhyZXF1ZXN0XwkAzAgCCQELU3RyaW5nRW50cnkCCQC5CQIJAMwIAgUWS0VZX1JFUVVFU1RfV0lUSERSQVdBTAkAzAgCCQCkAwEFBmluZGV4XwUDbmlsBQlTRVBBUkFUT1IJALkJAgkAzAgCCAUIcmVxdWVzdF8CXzEJAMwIAggFCHJlcXVlc3RfAl8yCQDMCAIJAKQDAQgFCHJlcXVlc3RfAl8zCQDMCAIIBQhyZXF1ZXN0XwJfNAkAzAgCCQCmAwEIBQhyZXF1ZXN0XwJfNQkAzAgCCQCkAwEIBQhyZXF1ZXN0XwJfNgkAzAgCCAUIcmVxdWVzdF8CXzcJAMwIAgkApAMBCAUIcmVxdWVzdF8CXzgFA25pbAUJU0VQQVJBVE9SBQNuaWwBIF9sb2FkUmVxdWVzdFdpdGhkcmF3YWxCbG9ja0RlbGF5AAQHJG1hdGNoMAkAnwgBBSJLRVlfUkVRVUVTVF9XSVRIRFJBV0FMX0JMT0NLX0RFTEFZAwkAAQIFByRtYXRjaDACA0ludAQBYQUHJG1hdGNoMAUBYQAAASBfc2F2ZVJlcXVlc3RXaXRoZHJhd2FsQmxvY2tEZWxheQEGZGVsYXlfCQDMCAIJAQxJbnRlZ2VyRW50cnkCBSJLRVlfUkVRVUVTVF9XSVRIRFJBV0FMX0JMT0NLX0RFTEFZBQZkZWxheV8FA25pbAEOX2xvYWRTZXF1ZW5jZXIABAckbWF0Y2gwCQCiCAEFDUtFWV9TRVFVRU5DRVIDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFhBQckbWF0Y2gwCQERQGV4dHJOYXRpdmUoMTA2MikBBQFhCQEHQWRkcmVzcwEBAAEOX3NhdmVTZXF1ZW5jZXIBCnNlcXVlbmNlcl8JAMwIAgkBC1N0cmluZ0VudHJ5AgUNS0VZX1NFUVVFTkNFUgkApQgBBQpzZXF1ZW5jZXJfBQNuaWwBE19sb2FkV2l0aGRyYXdhbEhhc2gBD3dpdGhkcmF3YWxIYXNoXwQHJG1hdGNoMAkAoggBCQC5CQIJAMwIAgUTS0VZX1dJVEhEUkFXQUxfSEFTSAkAzAgCCQDYBAEFD3dpdGhkcmF3YWxIYXNoXwUDbmlsBQlTRVBBUkFUT1IDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFhBQckbWF0Y2gwBQFhAgABE19zYXZlV2l0aGRyYXdhbEhhc2gCD3dpdGhkcmF3YWxIYXNoXwV0eElkXwkAzAgCCQELU3RyaW5nRW50cnkCCQC5CQIJAMwIAgUTS0VZX1dJVEhEUkFXQUxfSEFTSAkAzAgCCQDYBAEFD3dpdGhkcmF3YWxIYXNoXwUDbmlsBQlTRVBBUkFUT1IFBXR4SWRfBQNuaWwBEV9sb2FkVmF1bHRBZGFwdGVyAAQHJG1hdGNoMAkAoggBBRFLRVlfVkFVTFRfQURBUFRFUgMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAWEFByRtYXRjaDAJARFAZXh0ck5hdGl2ZSgxMDYyKQEFAWEJAQdBZGRyZXNzAQEAARFfc2F2ZVZhdWx0QWRhcHRlcgENdmF1bHRBZGFwdGVyXwkAzAgCCQELU3RyaW5nRW50cnkCBRFLRVlfVkFVTFRfQURBUFRFUgkApQgBBQ12YXVsdEFkYXB0ZXJfBQNuaWwBFl9sb2FkUmV3YXJkRGlzdHJpYnV0b3IABAckbWF0Y2gwCQCiCAEFFktFWV9SRVdBUkRfRElTVFJJQlVUT1IDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFhBQckbWF0Y2gwBQFhAgABFl9zYXZlUmV3YXJkRGlzdHJpYnV0b3IBDGRpc3RyaWJ1dG9yXwkAzAgCCQELU3RyaW5nRW50cnkCBRZLRVlfUkVXQVJEX0RJU1RSSUJVVE9SBQxkaXN0cmlidXRvcl8FA25pbAEYX2xvYWRSZWxheWVyRmVlUmVjaXBpZW50AAQHJG1hdGNoMAkAoggBBRlLRVlfUkVMQVlFUl9GRUVfUkVDSVBJRU5UAwkAAQIFByRtYXRjaDACBlN0cmluZwQBYQUHJG1hdGNoMAUBYQIAARhfc2F2ZVJlbGF5ZXJGZWVSZWNpcGllbnQBFHJlbGF5ZXJGZWVSZWNpcGllbnRfCQDMCAIJAQtTdHJpbmdFbnRyeQIFGUtFWV9SRUxBWUVSX0ZFRV9SRUNJUElFTlQFFHJlbGF5ZXJGZWVSZWNpcGllbnRfBQNuaWwBEV9vbmx5VGhpc0NvbnRyYWN0AQdjYWxsZXJfAwkBAiE9AgUHY2FsbGVyXwUEdGhpcwkAAgECGV9vbmx5VGhpc0NvbnRyYWN0OiByZXZlcnQGARBfd2hlbk11bHRpc2lnU2V0AAMJAAACCQENX2xvYWRNdWx0aXNpZwAJAQdBZGRyZXNzAQEACQACAQIYX3doZW5NdWx0aXNpZ1NldDogcmV2ZXJ0BgETX3doZW5Ob3RJbml0aWFsaXplZAADCQEJX2xvYWRJbml0AAkAAgECG193aGVuTm90SW5pdGlhbGl6ZWQ6IHJldmVydAYBEF93aGVuSW5pdGlhbGl6ZWQAAwkBASEBCQEJX2xvYWRJbml0AAkAAgECGF93aGVuSW5pdGlhbGl6ZWQ6IHJldmVydAYBDl93aGVuTm90UGF1c2VkAAMJAQpfbG9hZFBhdXNlAAkAAgECFl93aGVuTm90UGF1c2VkOiByZXZlcnQGAQtfd2hlblBhdXNlZAADCQEBIQEJAQpfbG9hZFBhdXNlAAkAAgECE193aGVuUGF1c2VkOiByZXZlcnQGAQtfb25seVBhdXNlcgEHY2FsbGVyXwMJAQIhPQIFB2NhbGxlcl8JAQtfbG9hZFBhdXNlcgAJAAIBAhNfb25seVBhdXNlcjogcmV2ZXJ0BgERX3ZhbGlkYXRlRXhlY3V0b3ICBHZhbF8EZXJyXwMJAQIhPQIFBHZhbF8JAQ1fbG9hZEV4ZWN1dG9yAAkAAgEFBGVycl8GARdfdmFsaWRhdGVDYWxsZXJDb250cmFjdAMIY2hhaW5JZF8PY2FsbGVyQ29udHJhY3RfBGVycl8DCQECIT0CCQETX2xvYWRDYWxsZXJDb250cmFjdAEFCGNoYWluSWRfBQ9jYWxsZXJDb250cmFjdF8JAAIBBQRlcnJfBgEMX2NoYWluRXhpc3RzAghjaGFpbklkXwRlcnJfAwkAZwIAAAkAsQIBCQEKX2xvYWRDaGFpbgEFCGNoYWluSWRfCQACAQUEZXJyXwYBDl9jaGFpbk5vdEV4aXN0AghjaGFpbklkXwRlcnJfAwkAZgIJALECAQkBCl9sb2FkQ2hhaW4BBQhjaGFpbklkXwAACQACAQUEZXJyXwYBFF9hc3NldEN1cnJlbmN5RXhpc3RzAwhjaGFpbklkXwZhc3NldF8EZXJyXwMJAGcCAAAJALECAQkBEl9sb2FkQXNzZXRDdXJyZW5jeQIFCGNoYWluSWRfBQZhc3NldF8JAAIBBQRlcnJfBgEWX2Fzc2V0Q3VycmVuY3lOb3RFeGlzdAMIY2hhaW5JZF8GYXNzZXRfBGVycl8DCQBmAgkAsQIBCQESX2xvYWRBc3NldEN1cnJlbmN5AgUIY2hhaW5JZF8FBmFzc2V0XwAACQACAQUEZXJyXwYBE192YWxpZGF0ZVdhdmVzVmF1bHQCBmNhbGxlcgRlcnJfAwkBAiE9AgkBD19sb2FkV2F2ZXNWYXVsdAAFBmNhbGxlcgkAAgEFBGVycl8GARFfcmVxdWVzdElzQ3JlYXRlZAIHc3RhdHVzXwRlcnJfAwkBAiE9AgUHc3RhdHVzXwUWUkVRVUVTVF9TVEFUVVNfQ1JFQVRFRAkAAgEFBGVycl8GARJfdmFsaWRhdGVTZXF1ZW5jZXICBmNhbGxlcgRlcnJfAwkBAiE9AgkBDl9sb2FkU2VxdWVuY2VyAAUGY2FsbGVyCQACAQUEZXJyXwYBHF9jaGVja1dpdGhkcmF3YWxIYXNoTm90RXhpc3QCD3dpdGhkcmF3YWxIYXNoXwRlcnJfAwkAZgIJALECAQkBE19sb2FkV2l0aGRyYXdhbEhhc2gBBQ93aXRoZHJhd2FsSGFzaF8AAAkAAgEFBGVycl8GARhfdmFsaWRhdGVTaWduYXR1cmVGb3JtYXQDCnNpZ25hdHVyZV8EYWxnXwRlcnJfAwkAAAIFBGFsZ18FDkFMR19UWVBFX1dBVkVTAwkBAiE9AgkAyAEBBQpzaWduYXR1cmVfAEAJAAIBBQRlcnJfBgMJAAACBQRhbGdfBQxBTEdfVFlQRV9FVk0DCQECIT0CCQDIAQEFCnNpZ25hdHVyZV8AQQkAAgEFBGVycl8GCQACAQkArAICBQRlcnJfAgk6IGludiBhbGcBD192YWxpZGF0ZVdlYjNJZAMHd2ViM0lkXwRhbGdfBGVycl8DCQAAAgUEYWxnXwUOQUxHX1RZUEVfV0FWRVMDCQECIT0CCQDIAQEFB3dlYjNJZF8AIAkAAgEFBGVycl8GAwkAAAIFBGFsZ18FDEFMR19UWVBFX0VWTQMJAQIhPQIJAMgBAQUHd2ViM0lkXwAUCQACAQUEZXJyXwYJAAIBCQCsAgIFBGVycl8CCTogaW52IGFsZwEcX3ZhbGlkYXRlV2l0aGRyYXdhbFNpZ25hdHVyZQUPd2l0aGRyYXdhbEhhc2hfCnNpZ25hdHVyZV8Hd2ViM0lkXwRhbGdfBGVycl8EBnJlc3VsdAMJAAACBQRhbGdfBQ5BTEdfVFlQRV9XQVZFUwkA9AMDBQ93aXRoZHJhd2FsSGFzaF8FCnNpZ25hdHVyZV8FB3dlYjNJZF8DCQAAAgUEYWxnXwUMQUxHX1RZUEVfRVZNBA5oYXNoV2l0aFByZWZpeAkAjBUBCQDLAQIFFEVWTV9TSUdOQVRVUkVfUFJFRklYBQ93aXRoZHJhd2FsSGFzaF8JAAACCQDMAQIJAIwVAQkAhAcCBQ5oYXNoV2l0aFByZWZpeAUKc2lnbmF0dXJlXwAUBQd3ZWIzSWRfCQACAQkArAICBQRlcnJfAgk6IGludiBhbGcDCQEBIQEFBnJlc3VsdAkAAgEFBGVycl8GAR1fdmFsaWRhdGVXZWIzSWRNYXRjaGVzQWRkcmVzcwQHd2ViM0lkXwVmcm9tXwRhbGdfBGVycl8EB2FkZHJlc3MDCQAAAgUEYWxnXwUOQUxHX1RZUEVfV0FWRVMJAKUIAQkApwgBBQd3ZWIzSWRfAwkAAAIFBGFsZ18FDEFMR19UWVBFX0VWTQkArAICAgIweAkA3AQBBQd3ZWIzSWRfCQACAQkArAICBQRlcnJfAgk6IGludiBhbGcDCQECIT0CBQdhZGRyZXNzBQVmcm9tXwkAAgEFBGVycl8GEAFpAQRpbml0BglleGVjdXRvcl8HcGF1c2VyXw9hY2NvdW50U3RvcmFnZV8Ld2F2ZXNWYXVsdF8Kc2VxdWVuY2VyXw12YXVsdEFkYXB0ZXJfBANlcnIDAwMDAwMDAwkBEV9vbmx5VGhpc0NvbnRyYWN0AQgFAWkGY2FsbGVyCQETX3doZW5Ob3RJbml0aWFsaXplZAAHCQEQX3doZW5NdWx0aXNpZ1NldAAHCQEQX3ZhbGlkYXRlQWRkcmVzcwIFCWV4ZWN1dG9yXwIWaW5pdDogaW52YWxpZCBleGVjdXRvcgcJARBfdmFsaWRhdGVBZGRyZXNzAgUHcGF1c2VyXwIUaW5pdDogaW52YWxpZCBwYXVzZXIHCQEQX3ZhbGlkYXRlQWRkcmVzcwIFD2FjY291bnRTdG9yYWdlXwIcaW5pdDogaW52YWxpZCBhY2NvdW50U3RvcmFnZQcJARBfdmFsaWRhdGVBZGRyZXNzAgULd2F2ZXNWYXVsdF8CGGluaXQ6IGludmFsaWQgd2F2ZXNWYXVsdAcJARBfdmFsaWRhdGVBZGRyZXNzAgUKc2VxdWVuY2VyXwIXaW5pdDogaW52YWxpZCBzZXF1ZW5jZXIHCQEQX3ZhbGlkYXRlQWRkcmVzcwIFDXZhdWx0QWRhcHRlcl8CGmluaXQ6IGludmFsaWQgdmF1bHRBZGFwdGVyBwMJAAACBQNlcnIFA2VycgkAlAoCCQDOCAIJAM4IAgkAzggCCQDOCAIJAM4IAgkAzggCCQEJX3NhdmVJbml0AQYJAQ1fc2F2ZUV4ZWN1dG9yAQkBEUBleHRyTmF0aXZlKDEwNjIpAQUJZXhlY3V0b3JfCQELX3NhdmVQYXVzZXIBCQERQGV4dHJOYXRpdmUoMTA2MikBBQdwYXVzZXJfCQETX3NhdmVBY2NvdW50U3RvcmFnZQEJARFAZXh0ck5hdGl2ZSgxMDYyKQEFD2FjY291bnRTdG9yYWdlXwkBD19zYXZlV2F2ZXNWYXVsdAEJARFAZXh0ck5hdGl2ZSgxMDYyKQEFC3dhdmVzVmF1bHRfCQEOX3NhdmVTZXF1ZW5jZXIBCQERQGV4dHJOYXRpdmUoMTA2MikBBQpzZXF1ZW5jZXJfCQERX3NhdmVWYXVsdEFkYXB0ZXIBCQERQGV4dHJOYXRpdmUoMTA2MikBBQ12YXVsdEFkYXB0ZXJfBQR1bml0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBB2RlcG9zaXQGD2NhbGxlckNvbnRyYWN0XwVmcm9tXwN0b18IY2hhaW5JZF8GYXNzZXRfB2Ftb3VudF8EB2NoYWluSWQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAtgkBBQhjaGFpbklkXwIYZGVwb3NpdDogY2hhaW5JZCBub3QgaW50BAZhbW91bnQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAqAMBBQdhbW91bnRfAhdkZXBvc2l0OiBhbW91bnQgbm90IGludAQDZXJyAwMDAwMDCQEQX3doZW5Jbml0aWFsaXplZAAJAQ5fd2hlbk5vdFBhdXNlZAAHCQEMX2NoYWluRXhpc3RzAgUHY2hhaW5JZAIYZGVwb3NpdDogaW52YWxpZCBjaGFpbklkBwkBD192YWxpZGF0ZVN0cmluZwIFBWZyb21fAhVkZXBvc2l0OiBpbnZhbGlkIGZyb20HCQEPX3ZhbGlkYXRlU3RyaW5nAgUDdG9fAhNkZXBvc2l0OiBpbnZhbGlkIHRvBwkBFF9hc3NldEN1cnJlbmN5RXhpc3RzAwUHY2hhaW5JZAUGYXNzZXRfAhZkZXBvc2l0OiBpbnZhbGlkIGFzc2V0BwkBD192YWxpZGF0ZUJpZ0ludAMFBmFtb3VudAULWkVST19CSUdJTlQCF2RlcG9zaXQ6IGludmFsaWQgYW1vdW50BwMJAAACBQNlcnIFA2VycgQEZXJyMQMJAAACCQEKX2xvYWRDaGFpbgEFB2NoYWluSWQFBVdBVkVTCQETX3ZhbGlkYXRlV2F2ZXNWYXVsdAIIBQFpBmNhbGxlcgIcZGVwb3NpdDogaW52YWxpZCB3YXZlcyB2YXVsdAMJARFfdmFsaWRhdGVFeGVjdXRvcgIIBQFpBmNhbGxlcgIZZGVwb3NpdDogaW52YWxpZCBleGVjdXRvcgkBF192YWxpZGF0ZUNhbGxlckNvbnRyYWN0AwUHY2hhaW5JZAUPY2FsbGVyQ29udHJhY3RfAiBkZXBvc2l0OiBpbnZhbGlkIGNhbGxlciBjb250cmFjdAcDCQAAAgUEZXJyMQUEZXJyMQQQbmV3QXNzZXRSZXNlcnZlcwkAtwICCQESX2xvYWRBc3NldFJlc2VydmVzAgUHY2hhaW5JZAUGYXNzZXRfBQZhbW91bnQECGN1cnJlbmN5CQESX2xvYWRBc3NldEN1cnJlbmN5AgUHY2hhaW5JZAUGYXNzZXRfBBNuZXdDdXJyZW5jeVJlc2VydmVzCQC3AgIJARVfbG9hZEN1cnJlbmN5UmVzZXJ2ZXMBBQhjdXJyZW5jeQUGYW1vdW50BAppbnZvY2F0aW9uCQD8BwQJARNfbG9hZEFjY291bnRTdG9yYWdlAAUMRlVOQ19ERVBPU0lUCQDMCAIFA3RvXwkAzAgCBQhjdXJyZW5jeQkAzAgCBQdhbW91bnRfBQNuaWwFA25pbAMJAAACBQppbnZvY2F0aW9uBQppbnZvY2F0aW9uCQCUCgIJAM4IAgkBEl9zYXZlQXNzZXRSZXNlcnZlcwMFB2NoYWluSWQFBmFzc2V0XwUQbmV3QXNzZXRSZXNlcnZlcwkBFV9zYXZlQ3VycmVuY3lSZXNlcnZlcwIFCGN1cnJlbmN5BRNuZXdDdXJyZW5jeVJlc2VydmVzBQR1bml0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBEXJlcXVlc3RXaXRoZHJhd2FsBw9jYWxsZXJDb250cmFjdF8FZnJvbV8DdG9fDGZyb21DaGFpbklkXwp0b0NoYWluSWRfBmFzc2V0XwdhbW91bnRfBAtmcm9tQ2hhaW5JZAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEFDGZyb21DaGFpbklkXwImcmVxdWVzdFdpdGhkcmF3YWw6IGZyb21DaGFpbklkIG5vdCBpbnQECXRvQ2hhaW5JZAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEFCnRvQ2hhaW5JZF8CJHJlcXVlc3RXaXRoZHJhd2FsOiB0b0NoYWluSWQgbm90IGludAQGYW1vdW50CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKgDAQUHYW1vdW50XwIhcmVxdWVzdFdpdGhkcmF3YWw6IGFtb3VudCBub3QgaW50BANlcnIDAwMDAwMJARBfd2hlbkluaXRpYWxpemVkAAkBDF9jaGFpbkV4aXN0cwIFC2Zyb21DaGFpbklkAiZyZXF1ZXN0V2l0aGRyYXdhbDogaW52YWxpZCBmcm9tQ2hhaW5JZAcJAQxfY2hhaW5FeGlzdHMCBQl0b0NoYWluSWQCJHJlcXVlc3RXaXRoZHJhd2FsOiBpbnZhbGlkIHRvQ2hhaW5JZAcJAQ9fdmFsaWRhdGVTdHJpbmcCBQVmcm9tXwIfcmVxdWVzdFdpdGhkcmF3YWw6IGludmFsaWQgZnJvbQcJAQ9fdmFsaWRhdGVTdHJpbmcCBQN0b18CHXJlcXVlc3RXaXRoZHJhd2FsOiBpbnZhbGlkIHRvBwkBFF9hc3NldEN1cnJlbmN5RXhpc3RzAwUJdG9DaGFpbklkBQZhc3NldF8CIHJlcXVlc3RXaXRoZHJhd2FsOiBpbnZhbGlkIGFzc2V0BwkBD192YWxpZGF0ZUJpZ0ludAMFBmFtb3VudAULWkVST19CSUdJTlQCIXJlcXVlc3RXaXRoZHJhd2FsOiBpbnZhbGlkIGFtb3VudAcDCQAAAgUDZXJyBQNlcnIEBGVycjEDCQAAAgkBCl9sb2FkQ2hhaW4BBQtmcm9tQ2hhaW5JZAUFV0FWRVMJARNfdmFsaWRhdGVXYXZlc1ZhdWx0AggFAWkGY2FsbGVyAiZyZXF1ZXN0V2l0aGRyYXdhbDogaW52YWxpZCB3YXZlcyB2YXVsdAMJARFfdmFsaWRhdGVFeGVjdXRvcgIIBQFpBmNhbGxlcgIjcmVxdWVzdFdpdGhkcmF3YWw6IGludmFsaWQgZXhlY3V0b3IJARdfdmFsaWRhdGVDYWxsZXJDb250cmFjdAMFC2Zyb21DaGFpbklkBQ9jYWxsZXJDb250cmFjdF8CKnJlcXVlc3RXaXRoZHJhd2FsOiBpbnZhbGlkIGNhbGxlciBjb250cmFjdAcDCQAAAgUEZXJyMQUEZXJyMQQIY3VycmVuY3kJARJfbG9hZEFzc2V0Q3VycmVuY3kCBQl0b0NoYWluSWQFBmFzc2V0XwQQYXZhaWxhYmxlQmFsYW5jZQQHJG1hdGNoMAkA/AcECQETX2xvYWRBY2NvdW50U3RvcmFnZQAFFUZVTkNfR0VUX1VTRVJfQkFMQU5DRQkAzAgCBQVmcm9tXwkAzAgCBQtTUE9UX1dBTExFVAkAzAgCBQhjdXJyZW5jeQUDbmlsBQNuaWwDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFhBQckbWF0Y2gwCQCnAwEFAWEJAAIBAjxyZXF1ZXN0V2l0aGRyYXdhbDogY2FuJ3QgdGFrZSBhdmFpbGFibGUgYmFsYW5jZSBmcm9tIHN0b3JhZ2UDCQAAAgUQYXZhaWxhYmxlQmFsYW5jZQUQYXZhaWxhYmxlQmFsYW5jZQQObG9ja2VkUmVzZXJ2ZXMJARhfbG9hZEFzc2V0UmVzZXJ2ZXNMb2NrZWQCBQl0b0NoYWluSWQFBmFzc2V0XwQSdXNlckxvY2tlZEN1cnJlbmN5CQEXX2xvYWRVc2VyTG9ja2VkQ3VycmVuY3kCBQhjdXJyZW5jeQUFZnJvbV8EDSR0MDE5Mjk1MTk3NTADAwkAwAICCQC4AgIFEGF2YWlsYWJsZUJhbGFuY2UFEnVzZXJMb2NrZWRDdXJyZW5jeQUGYW1vdW50CQDAAgIJALgCAgkBEl9sb2FkQXNzZXRSZXNlcnZlcwIFCXRvQ2hhaW5JZAUGYXNzZXRfBQ5sb2NrZWRSZXNlcnZlcwUGYW1vdW50BwkAlAoCBRZSRVFVRVNUX1NUQVRVU19DUkVBVEVECQDOCAIJARhfc2F2ZUFzc2V0UmVzZXJ2ZXNMb2NrZWQDBQl0b0NoYWluSWQFBmFzc2V0XwkAtwICBQ5sb2NrZWRSZXNlcnZlcwUGYW1vdW50CQEXX3NhdmVVc2VyTG9ja2VkQ3VycmVuY3kDBQhjdXJyZW5jeQUFZnJvbV8JALcCAgUGYW1vdW50BRJ1c2VyTG9ja2VkQ3VycmVuY3kJAJQKAgUXUkVRVUVTVF9TVEFUVVNfUkVKRUNURUQFA25pbAQNcmVxdWVzdFN0YXR1cwgFDSR0MDE5Mjk1MTk3NTACXzEED3Jlc2VydmVzQWN0aW9ucwgFDSR0MDE5Mjk1MTk3NTACXzIEFXJlcXVlc3RXaXRoZHJhd2FsU2l6ZQkBGl9sb2FkUmVxdWVzdFdpdGhkcmF3YWxTaXplAAQRcmVxdWVzdFdpdGhkcmF3YWwJAJoKCAUFZnJvbV8FA3RvXwUJdG9DaGFpbklkBQZhc3NldF8FBmFtb3VudAUGaGVpZ2h0CQDYBAEIBQFpDXRyYW5zYWN0aW9uSWQFDXJlcXVlc3RTdGF0dXMJAJQKAgkAzggCCQDOCAIJARZfc2F2ZVJlcXVlc3RXaXRoZHJhd2FsAgUVcmVxdWVzdFdpdGhkcmF3YWxTaXplBRFyZXF1ZXN0V2l0aGRyYXdhbAkBGl9zYXZlUmVxdWVzdFdpdGhkcmF3YWxTaXplAQkAZAIFFXJlcXVlc3RXaXRoZHJhd2FsU2l6ZQABBQ9yZXNlcnZlc0FjdGlvbnMFFXJlcXVlc3RXaXRoZHJhd2FsU2l6ZQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARFleGVjdXRlV2l0aGRyYXdhbAMPY2FsbGVyQ29udHJhY3RfCGNoYWluSWRfFHJlcXVlc3RXaXRoZHJhd2FsSWRfBAdjaGFpbklkCQETdmFsdWVPckVycm9yTWVzc2FnZQIJALYJAQUIY2hhaW5JZF8CImV4ZWN1dGVXaXRoZHJhd2FsOiBjaGFpbklkIG5vdCBpbnQEE3JlcXVlc3RXaXRoZHJhd2FsSWQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAtgkBBRRyZXF1ZXN0V2l0aGRyYXdhbElkXwIuZXhlY3V0ZVdpdGhkcmF3YWw6IHJlcXVlc3RXaXRoZHJhd2FsSWQgbm90IGludAQVcmVxdWVzdFdpdGhkcmF3YWxTaXplCQEaX2xvYWRSZXF1ZXN0V2l0aGRyYXdhbFNpemUABANlcnIDAwkBEF93aGVuSW5pdGlhbGl6ZWQACQEMX2NoYWluRXhpc3RzAgUHY2hhaW5JZAIiZXhlY3V0ZVdpdGhkcmF3YWw6IGludmFsaWQgY2hhaW5JZAcJAQxfdmFsaWRhdGVJbnQEBRNyZXF1ZXN0V2l0aGRyYXdhbElkAAAJAGUCBRVyZXF1ZXN0V2l0aGRyYXdhbFNpemUAAQIuZXhlY3V0ZVdpdGhkcmF3YWw6IGludmFsaWQgcmVxdWVzdFdpdGhkcmF3YWxJZAcDCQAAAgUDZXJyBQNlcnIEBGVycjEDCQAAAgkBCl9sb2FkQ2hhaW4BBQdjaGFpbklkBQVXQVZFUwkBE192YWxpZGF0ZVdhdmVzVmF1bHQCCAUBaQZjYWxsZXICJmV4ZWN1dGVXaXRoZHJhd2FsOiBpbnZhbGlkIHdhdmVzIHZhdWx0AwkBEV92YWxpZGF0ZUV4ZWN1dG9yAggFAWkGY2FsbGVyAiNleGVjdXRlV2l0aGRyYXdhbDogaW52YWxpZCBleGVjdXRvcgkBF192YWxpZGF0ZUNhbGxlckNvbnRyYWN0AwUHY2hhaW5JZAUPY2FsbGVyQ29udHJhY3RfAipleGVjdXRlV2l0aGRyYXdhbDogaW52YWxpZCBjYWxsZXIgY29udHJhY3QHAwkAAAIFBGVycjEFBGVycjEEB3JlcXVlc3QJARZfbG9hZFJlcXVlc3RXaXRoZHJhd2FsAQUTcmVxdWVzdFdpdGhkcmF3YWxJZAQLcmVxdWVzdEZyb20IBQdyZXF1ZXN0Al8xBAlyZXF1ZXN0VG8IBQdyZXF1ZXN0Al8yBBByZXF1ZXN0VG9DaGFpbklkCAUHcmVxdWVzdAJfMwQMcmVxdWVzdEFzc2V0CAUHcmVxdWVzdAJfNAQNcmVxdWVzdEFtb3VudAgFB3JlcXVlc3QCXzUEDXJlcXVlc3RIZWlnaHQIBQdyZXF1ZXN0Al82BA1yZXF1ZXN0U3RhdHVzCAUHcmVxdWVzdAJfOAQQbmV3QXNzZXRSZXNlcnZlcwkAuAICCQESX2xvYWRBc3NldFJlc2VydmVzAgUQcmVxdWVzdFRvQ2hhaW5JZAUMcmVxdWVzdEFzc2V0BQ1yZXF1ZXN0QW1vdW50BBZuZXdBc3NldFJlc2VydmVzTG9ja2VkCQC4AgIJARhfbG9hZEFzc2V0UmVzZXJ2ZXNMb2NrZWQCBRByZXF1ZXN0VG9DaGFpbklkBQxyZXF1ZXN0QXNzZXQFDXJlcXVlc3RBbW91bnQECGN1cnJlbmN5CQESX2xvYWRBc3NldEN1cnJlbmN5AgUQcmVxdWVzdFRvQ2hhaW5JZAUMcmVxdWVzdEFzc2V0BBNuZXdDdXJyZW5jeVJlc2VydmVzCQC4AgIJARVfbG9hZEN1cnJlbmN5UmVzZXJ2ZXMBBQhjdXJyZW5jeQUNcmVxdWVzdEFtb3VudAQVbmV3VXNlckxvY2tlZEN1cnJlbmN5CQC4AgIJARdfbG9hZFVzZXJMb2NrZWRDdXJyZW5jeQIFCGN1cnJlbmN5BQtyZXF1ZXN0RnJvbQUNcmVxdWVzdEFtb3VudAQEZXJyMgMDAwMDCQEPX3ZhbGlkYXRlQmlnSW50AwUQbmV3QXNzZXRSZXNlcnZlcwULWkVST19CSUdJTlQCLGV4ZWN1dGVXaXRoZHJhd2FsOiBuZWdhdGl2ZSBuZXdBc3NldFJlc2VydmVzCQEPX3ZhbGlkYXRlQmlnSW50AwUWbmV3QXNzZXRSZXNlcnZlc0xvY2tlZAULWkVST19CSUdJTlQCMmV4ZWN1dGVXaXRoZHJhd2FsOiBuZWdhdGl2ZSBuZXdBc3NldFJlc2VydmVzTG9ja2VkBwkBD192YWxpZGF0ZUJpZ0ludAMFE25ld0N1cnJlbmN5UmVzZXJ2ZXMFC1pFUk9fQklHSU5UAi9leGVjdXRlV2l0aGRyYXdhbDogbmVnYXRpdmUgbmV3Q3VycmVuY3lSZXNlcnZlcwcJAQ9fdmFsaWRhdGVCaWdJbnQDBRVuZXdVc2VyTG9ja2VkQ3VycmVuY3kFC1pFUk9fQklHSU5UAjFleGVjdXRlV2l0aGRyYXdhbDogbmVnYXRpdmUgbmV3VXNlckxvY2tlZEN1cnJlbmN5BwkBDF92YWxpZGF0ZUludAQJAGUCBQZoZWlnaHQFDXJlcXVlc3RIZWlnaHQJASBfbG9hZFJlcXVlc3RXaXRoZHJhd2FsQmxvY2tEZWxheQAFB01BWF9JTlQCJ2V4ZWN1dGVXaXRoZHJhd2FsOiB0b28gZWFybHkgdG8gZXhlY3V0ZQcJARFfcmVxdWVzdElzQ3JlYXRlZAIFDXJlcXVlc3RTdGF0dXMCJmV4ZWN1dGVXaXRoZHJhd2FsOiByZXF1ZXN0IGlzIHJlc29sdmVkBwMJAAACBQRlcnIyBQRlcnIyBBFzdG9yYWdlSW52b2NhdGlvbgkA/AcECQETX2xvYWRBY2NvdW50U3RvcmFnZQAFDUZVTkNfV0lUSERSQVcJAMwIAgULcmVxdWVzdEZyb20JAMwIAgUIY3VycmVuY3kJAMwIAgkApgMBBQ1yZXF1ZXN0QW1vdW50BQNuaWwFA25pbAMJAAACBRFzdG9yYWdlSW52b2NhdGlvbgURc3RvcmFnZUludm9jYXRpb24EEndpdGhkcmF3SW52b2NhdGlvbgMJAAACCQEKX2xvYWRDaGFpbgEFEHJlcXVlc3RUb0NoYWluSWQFBVdBVkVTCQD8BwQJAQ9fbG9hZFdhdmVzVmF1bHQABQ1GVU5DX1dJVEhEUkFXCQDMCAIFCXJlcXVlc3RUbwkAzAgCBQxyZXF1ZXN0QXNzZXQJAMwIAgkApgMBBQ1yZXF1ZXN0QW1vdW50BQNuaWwFA25pbAkA/AcECQERX2xvYWRWYXVsdEFkYXB0ZXIABQ1GVU5DX1dJVEhEUkFXCQDMCAIFEHJlcXVlc3RUb0NoYWluSWQJAMwIAgUMcmVxdWVzdEFzc2V0CQDMCAIJAKYDAQUNcmVxdWVzdEFtb3VudAkAzAgCBQlyZXF1ZXN0VG8FA25pbAUDbmlsAwkAAAIFEndpdGhkcmF3SW52b2NhdGlvbgUSd2l0aGRyYXdJbnZvY2F0aW9uBA5yZXF1ZXN0VXBkYXRlZAkAmgoICAUHcmVxdWVzdAJfMQgFB3JlcXVlc3QCXzIIBQdyZXF1ZXN0Al8zCAUHcmVxdWVzdAJfNAgFB3JlcXVlc3QCXzUIBQdyZXF1ZXN0Al82CAUHcmVxdWVzdAJfNwUTUkVRVUVTVF9TVEFUVVNfRE9ORQkAlAoCCQDOCAIJAM4IAgkAzggCCQDOCAIJARJfc2F2ZUFzc2V0UmVzZXJ2ZXMDBRByZXF1ZXN0VG9DaGFpbklkBQxyZXF1ZXN0QXNzZXQFEG5ld0Fzc2V0UmVzZXJ2ZXMJARhfc2F2ZUFzc2V0UmVzZXJ2ZXNMb2NrZWQDBRByZXF1ZXN0VG9DaGFpbklkBQxyZXF1ZXN0QXNzZXQFFm5ld0Fzc2V0UmVzZXJ2ZXNMb2NrZWQJARVfc2F2ZUN1cnJlbmN5UmVzZXJ2ZXMCBQhjdXJyZW5jeQUTbmV3Q3VycmVuY3lSZXNlcnZlcwkBF19zYXZlVXNlckxvY2tlZEN1cnJlbmN5AwUIY3VycmVuY3kFC3JlcXVlc3RGcm9tBRVuZXdVc2VyTG9ja2VkQ3VycmVuY3kJARZfc2F2ZVJlcXVlc3RXaXRoZHJhd2FsAgUTcmVxdWVzdFdpdGhkcmF3YWxJZAUOcmVxdWVzdFVwZGF0ZWQFBHVuaXQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEQcmVqZWN0V2l0aGRyYXdhbAEUcmVxdWVzdFdpdGhkcmF3YWxJZF8EE3JlcXVlc3RXaXRoZHJhd2FsSWQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAtgkBBRRyZXF1ZXN0V2l0aGRyYXdhbElkXwItcmVqZWN0V2l0aGRyYXdhbDogcmVxdWVzdFdpdGhkcmF3YWxJZCBub3QgaW50BBVyZXF1ZXN0V2l0aGRyYXdhbFNpemUJARpfbG9hZFJlcXVlc3RXaXRoZHJhd2FsU2l6ZQAEA2VycgMDCQEQX3doZW5Jbml0aWFsaXplZAAJARJfdmFsaWRhdGVTZXF1ZW5jZXICCAUBaQZjYWxsZXICI3JlamVjdFdpdGhkcmF3YWw6IGludmFsaWQgc2VxdWVuY2VyBwkBDF92YWxpZGF0ZUludAQFE3JlcXVlc3RXaXRoZHJhd2FsSWQAAAkAZQIFFXJlcXVlc3RXaXRoZHJhd2FsU2l6ZQABAi1yZWplY3RXaXRoZHJhd2FsOiBpbnZhbGlkIHJlcXVlc3RXaXRoZHJhd2FsSWQHAwkAAAIFA2VycgUDZXJyBAdyZXF1ZXN0CQEWX2xvYWRSZXF1ZXN0V2l0aGRyYXdhbAEFE3JlcXVlc3RXaXRoZHJhd2FsSWQEC3JlcXVlc3RGcm9tCAUHcmVxdWVzdAJfMQQJcmVxdWVzdFRvCAUHcmVxdWVzdAJfMgQQcmVxdWVzdFRvQ2hhaW5JZAgFB3JlcXVlc3QCXzMEDHJlcXVlc3RBc3NldAgFB3JlcXVlc3QCXzQEDXJlcXVlc3RBbW91bnQIBQdyZXF1ZXN0Al81BA1yZXF1ZXN0SGVpZ2h0CAUHcmVxdWVzdAJfNgQNcmVxdWVzdFN0YXR1cwgFB3JlcXVlc3QCXzgECGN1cnJlbmN5CQESX2xvYWRBc3NldEN1cnJlbmN5AgUQcmVxdWVzdFRvQ2hhaW5JZAUMcmVxdWVzdEFzc2V0BBZuZXdBc3NldFJlc2VydmVzTG9ja2VkCQC4AgIJARhfbG9hZEFzc2V0UmVzZXJ2ZXNMb2NrZWQCBRByZXF1ZXN0VG9DaGFpbklkBQxyZXF1ZXN0QXNzZXQFDXJlcXVlc3RBbW91bnQEFW5ld1VzZXJMb2NrZWRDdXJyZW5jeQkAuAICCQEXX2xvYWRVc2VyTG9ja2VkQ3VycmVuY3kCBQhjdXJyZW5jeQULcmVxdWVzdEZyb20FDXJlcXVlc3RBbW91bnQEBGVycjEDAwkBD192YWxpZGF0ZUJpZ0ludAMFFm5ld0Fzc2V0UmVzZXJ2ZXNMb2NrZWQFC1pFUk9fQklHSU5UAjFyZWplY3RXaXRoZHJhd2FsOiBuZWdhdGl2ZSBuZXdBc3NldFJlc2VydmVzTG9ja2VkCQEPX3ZhbGlkYXRlQmlnSW50AwUVbmV3VXNlckxvY2tlZEN1cnJlbmN5BQtaRVJPX0JJR0lOVAIwcmVqZWN0V2l0aGRyYXdhbDogbmVnYXRpdmUgbmV3VXNlckxvY2tlZEN1cnJlbmN5BwkBEV9yZXF1ZXN0SXNDcmVhdGVkAgUNcmVxdWVzdFN0YXR1cwIlcmVqZWN0V2l0aGRyYXdhbDogcmVxdWVzdCBpcyByZXNvbHZlZAcDCQAAAgUEZXJyMQUEZXJyMQQQYXZhaWxhYmxlQmFsYW5jZQQHJG1hdGNoMAkA/AcECQETX2xvYWRBY2NvdW50U3RvcmFnZQAFFUZVTkNfR0VUX1VTRVJfQkFMQU5DRQkAzAgCBQtyZXF1ZXN0RnJvbQkAzAgCBQtTUE9UX1dBTExFVAkAzAgCBQhjdXJyZW5jeQUDbmlsBQNuaWwDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFhBQckbWF0Y2gwCQCnAwEFAWEJAAIBAjtyZWplY3RXaXRoZHJhd2FsOiBjYW4ndCB0YWtlIGF2YWlsYWJsZSBiYWxhbmNlIGZyb20gc3RvcmFnZQMJAAACBRBhdmFpbGFibGVCYWxhbmNlBRBhdmFpbGFibGVCYWxhbmNlAwkAvwICBQ1yZXF1ZXN0QW1vdW50BRBhdmFpbGFibGVCYWxhbmNlBA5yZXF1ZXN0VXBkYXRlZAkAmgoICAUHcmVxdWVzdAJfMQgFB3JlcXVlc3QCXzIIBQdyZXF1ZXN0Al8zCAUHcmVxdWVzdAJfNAgFB3JlcXVlc3QCXzUIBQdyZXF1ZXN0Al82CAUHcmVxdWVzdAJfNwUXUkVRVUVTVF9TVEFUVVNfUkVKRUNURUQJAJQKAgkAzggCCQDOCAIJARhfc2F2ZUFzc2V0UmVzZXJ2ZXNMb2NrZWQDBRByZXF1ZXN0VG9DaGFpbklkBQxyZXF1ZXN0QXNzZXQFFm5ld0Fzc2V0UmVzZXJ2ZXNMb2NrZWQJARdfc2F2ZVVzZXJMb2NrZWRDdXJyZW5jeQMFCGN1cnJlbmN5BQtyZXF1ZXN0RnJvbQUVbmV3VXNlckxvY2tlZEN1cnJlbmN5CQEWX3NhdmVSZXF1ZXN0V2l0aGRyYXdhbAIFE3JlcXVlc3RXaXRoZHJhd2FsSWQFDnJlcXVlc3RVcGRhdGVkBgkAlAoCBQNuaWwHCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCHdpdGhkcmF3CgVmcm9tXwN0b18KdG9DaGFpbklkXwZhc3NldF8HYW1vdW50XwtyZWxheWVyRmVlXwp0aW1lc3RhbXBfB3dlYjNJZF8EYWxnXwpzaWduYXR1cmVfBAl0b0NoYWluSWQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAtgkBBQp0b0NoYWluSWRfAht3aXRoZHJhdzogdG9DaGFpbklkIG5vdCBpbnQEBmFtb3VudAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCoAwEFB2Ftb3VudF8CGHdpdGhkcmF3OiBhbW91bnQgbm90IGludAQKcmVsYXllckZlZQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCoAwEFC3JlbGF5ZXJGZWVfAhx3aXRoZHJhdzogcmVsYXllckZlZSBub3QgaW50BAl0aW1lc3RhbXAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAtgkBBQp0aW1lc3RhbXBfAht3aXRoZHJhdzogdGltZXN0YW1wIG5vdCBpbnQEA2FsZwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEFBGFsZ18CFXdpdGhkcmF3OiBhbGcgbm90IGludAQGd2ViM0lkCQDZBAEFB3dlYjNJZF8ECXNpZ25hdHVyZQkA2QQBBQpzaWduYXR1cmVfBANlcnIDAwMDAwMDAwMDAwkBEF93aGVuSW5pdGlhbGl6ZWQACQESX3ZhbGlkYXRlU2VxdWVuY2VyAggFAWkGY2FsbGVyAht3aXRoZHJhdzogaW52YWxpZCBzZXF1ZW5jZXIHCQEPX3ZhbGlkYXRlU3RyaW5nAgUFZnJvbV8CFndpdGhkcmF3OiBpbnZhbGlkIGZyb20HCQEPX3ZhbGlkYXRlU3RyaW5nAgUDdG9fAhR3aXRoZHJhdzogaW52YWxpZCB0bwcJAQxfY2hhaW5FeGlzdHMCBQl0b0NoYWluSWQCG3dpdGhkcmF3OiBpbnZhbGlkIHRvQ2hhaW5JZAcJARRfYXNzZXRDdXJyZW5jeUV4aXN0cwMFCXRvQ2hhaW5JZAUGYXNzZXRfAhd3aXRoZHJhdzogaW52YWxpZCBhc3NldAcJAQ9fdmFsaWRhdGVCaWdJbnQDBQZhbW91bnQFC1pFUk9fQklHSU5UAhh3aXRoZHJhdzogaW52YWxpZCBhbW91bnQHCQERX3ZhbGlkYXRlQmlnSW50XzIEBQpyZWxheWVyRmVlBQtaRVJPX0JJR0lOVAUGYW1vdW50Ahx3aXRoZHJhdzogaW52YWxpZCByZWxheWVyRmVlBwkBDF92YWxpZGF0ZUludAQJAGQCBQl0aW1lc3RhbXAFB09ORV9EQVkIBQlsYXN0QmxvY2sJdGltZXN0YW1wBQdNQVhfSU5UAht3aXRoZHJhdzogaW52YWxpZCB0aW1lc3RhbXAHCQEPX3ZhbGlkYXRlV2ViM0lkAwUGd2ViM0lkBQNhbGcCFHdpdGhkcmF3OiBpbnYgd2ViM0lkBwkBGF92YWxpZGF0ZVNpZ25hdHVyZUZvcm1hdAMFCXNpZ25hdHVyZQUDYWxnAhh3aXRoZHJhdzogaW52IHNpZyBmb3JtYXQHCQEdX3ZhbGlkYXRlV2ViM0lkTWF0Y2hlc0FkZHJlc3MEBQZ3ZWIzSWQFBWZyb21fBQNhbGcCGXdpdGhkcmF3OiB3ZWIzSWQgbWlzbWF0Y2gHAwkAAAIFA2VycgUDZXJyBA93aXRoZHJhd2FsQnl0ZXMJAMsBAgkAywECCQDLAQIJAMsBAgkAywECCQDLAQIJAMsBAgkAywECCQDLAQIJAMsBAgkAywECCQCaAwEJALECAQUFZnJvbV8JAJsDAQUFZnJvbV8JAJoDAQkAsQIBBQN0b18JAJsDAQUDdG9fCQCaAwEFCXRvQ2hhaW5JZAkAmgMBCQCxAgEFBmFzc2V0XwkAmwMBBQZhc3NldF8JAJ0DAQUGYW1vdW50CQCdAwEFCnJlbGF5ZXJGZWUJAJoDAQUJdGltZXN0YW1wBQZ3ZWIzSWQJAJoDAQUDYWxnBA53aXRoZHJhd2FsSGFzaAkAjBUBBQ93aXRoZHJhd2FsQnl0ZXMECGN1cnJlbmN5CQESX2xvYWRBc3NldEN1cnJlbmN5AgUJdG9DaGFpbklkBQZhc3NldF8EEGF2YWlsYWJsZUJhbGFuY2UEByRtYXRjaDAJAPwHBAkBE19sb2FkQWNjb3VudFN0b3JhZ2UABRVGVU5DX0dFVF9VU0VSX0JBTEFOQ0UJAMwIAgUFZnJvbV8JAMwIAgULU1BPVF9XQUxMRVQJAMwIAgUIY3VycmVuY3kFA25pbAUDbmlsAwkAAQIFByRtYXRjaDACBlN0cmluZwQBYQUHJG1hdGNoMAkApwMBBQFhCQACAQIzd2l0aGRyYXc6IGNhbid0IHRha2UgYXZhaWxhYmxlIGJhbGFuY2UgZnJvbSBzdG9yYWdlAwkAAAIFEGF2YWlsYWJsZUJhbGFuY2UFEGF2YWlsYWJsZUJhbGFuY2UEDWFzc2V0UmVzZXJ2ZXMJARJfbG9hZEFzc2V0UmVzZXJ2ZXMCBQl0b0NoYWluSWQFBmFzc2V0XwQObG9ja2VkUmVzZXJ2ZXMJARhfbG9hZEFzc2V0UmVzZXJ2ZXNMb2NrZWQCBQl0b0NoYWluSWQFBmFzc2V0XwQMYW1vdW50VG9TZW5kCQC4AgIFBmFtb3VudAUKcmVsYXllckZlZQQPYW1vdW50VG9TZW5kU3RyCQCmAwEFDGFtb3VudFRvU2VuZAQEZXJyMQMDAwkBHF92YWxpZGF0ZVdpdGhkcmF3YWxTaWduYXR1cmUFBQ53aXRoZHJhd2FsSGFzaAUJc2lnbmF0dXJlBQZ3ZWIzSWQFA2FsZwIVd2l0aGRyYXc6IGludmFsaWQgc2lnCQEcX2NoZWNrV2l0aGRyYXdhbEhhc2hOb3RFeGlzdAIFDndpdGhkcmF3YWxIYXNoAhp3aXRoZHJhdzogYWxyZWFkeSBleGVjdXRlZAcJAQ9fdmFsaWRhdGVCaWdJbnQDBRBhdmFpbGFibGVCYWxhbmNlBQxhbW91bnRUb1NlbmQCHndpdGhkcmF3OiBpbnN1ZmZpY2llbnQgYmFsYW5jZQcJAQ9fdmFsaWRhdGVCaWdJbnQDCQC4AgIFDWFzc2V0UmVzZXJ2ZXMFDmxvY2tlZFJlc2VydmVzBQxhbW91bnRUb1NlbmQCH3dpdGhkcmF3OiBpbnN1ZmZpY2llbnQgcmVzZXJ2ZXMHAwkAAAIFBGVycjEFBGVycjEEEG5ld0Fzc2V0UmVzZXJ2ZXMJALgCAgUNYXNzZXRSZXNlcnZlcwUMYW1vdW50VG9TZW5kBBNuZXdDdXJyZW5jeVJlc2VydmVzCQC4AgIJARVfbG9hZEN1cnJlbmN5UmVzZXJ2ZXMBBQhjdXJyZW5jeQUMYW1vdW50VG9TZW5kBARlcnIyAwkBD192YWxpZGF0ZUJpZ0ludAMFEG5ld0Fzc2V0UmVzZXJ2ZXMFC1pFUk9fQklHSU5UAiN3aXRoZHJhdzogbmVnYXRpdmUgbmV3QXNzZXRSZXNlcnZlcwkBD192YWxpZGF0ZUJpZ0ludAMFE25ld0N1cnJlbmN5UmVzZXJ2ZXMFC1pFUk9fQklHSU5UAiZ3aXRoZHJhdzogbmVnYXRpdmUgbmV3Q3VycmVuY3lSZXNlcnZlcwcDCQAAAgUEZXJyMgUEZXJyMgQSc3RvcmFnZUludm9jYXRpb24xCQD8BwQJARNfbG9hZEFjY291bnRTdG9yYWdlAAUNRlVOQ19XSVRIRFJBVwkAzAgCBQVmcm9tXwkAzAgCBQhjdXJyZW5jeQkAzAgCBQdhbW91bnRfBQNuaWwFA25pbAMJAAACBRJzdG9yYWdlSW52b2NhdGlvbjEFEnN0b3JhZ2VJbnZvY2F0aW9uMQQSc3RvcmFnZUludm9jYXRpb24yCQD8BwQJARNfbG9hZEFjY291bnRTdG9yYWdlAAUMRlVOQ19ERVBPU0lUCQDMCAIJARhfbG9hZFJlbGF5ZXJGZWVSZWNpcGllbnQACQDMCAIFCGN1cnJlbmN5CQDMCAIFC3JlbGF5ZXJGZWVfBQNuaWwFA25pbAMJAAACBRJzdG9yYWdlSW52b2NhdGlvbjIFEnN0b3JhZ2VJbnZvY2F0aW9uMgQSd2l0aGRyYXdJbnZvY2F0aW9uAwkAAAIJAQpfbG9hZENoYWluAQUJdG9DaGFpbklkBQVXQVZFUwkA/AcECQEPX2xvYWRXYXZlc1ZhdWx0AAUNRlVOQ19XSVRIRFJBVwkAzAgCBQN0b18JAMwIAgUGYXNzZXRfCQDMCAIFD2Ftb3VudFRvU2VuZFN0cgUDbmlsBQNuaWwJAPwHBAkBEV9sb2FkVmF1bHRBZGFwdGVyAAUNRlVOQ19XSVRIRFJBVwkAzAgCBQl0b0NoYWluSWQJAMwIAgUGYXNzZXRfCQDMCAIFD2Ftb3VudFRvU2VuZFN0cgkAzAgCBQN0b18JAMwIAgULcmVsYXllckZlZV8FA25pbAUDbmlsAwkAAAIFEndpdGhkcmF3SW52b2NhdGlvbgUSd2l0aGRyYXdJbnZvY2F0aW9uCQCUCgIJAM4IAgkAzggCCQESX3NhdmVBc3NldFJlc2VydmVzAwUJdG9DaGFpbklkBQZhc3NldF8FEG5ld0Fzc2V0UmVzZXJ2ZXMJARVfc2F2ZUN1cnJlbmN5UmVzZXJ2ZXMCBQhjdXJyZW5jeQUTbmV3Q3VycmVuY3lSZXNlcnZlcwkBE19zYXZlV2l0aGRyYXdhbEhhc2gCBQ53aXRoZHJhd2FsSGFzaAkA2AQBCAUBaQ10cmFuc2FjdGlvbklkBQR1bml0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBFGRlcG9zaXRTdGFraW5nUmV3YXJkBA9jYWxsZXJDb250cmFjdF8IY2hhaW5JZF8GYXNzZXRfB2Ftb3VudF8EB2NoYWluSWQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAtgkBBQhjaGFpbklkXwIlZGVwb3NpdFN0YWtpbmdSZXdhcmQ6IGNoYWluSWQgbm90IGludAQGYW1vdW50CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKgDAQUHYW1vdW50XwIkZGVwb3NpdFN0YWtpbmdSZXdhcmQ6IGFtb3VudCBub3QgaW50BANlcnIDAwMDCQEQX3doZW5Jbml0aWFsaXplZAAJAQ5fd2hlbk5vdFBhdXNlZAAHCQEMX2NoYWluRXhpc3RzAgUHY2hhaW5JZAIlZGVwb3NpdFN0YWtpbmdSZXdhcmQ6IGludmFsaWQgY2hhaW5JZAcJARRfYXNzZXRDdXJyZW5jeUV4aXN0cwMFB2NoYWluSWQFBmFzc2V0XwIjZGVwb3NpdFN0YWtpbmdSZXdhcmQ6IGludmFsaWQgYXNzZXQHCQEPX3ZhbGlkYXRlQmlnSW50AwUGYW1vdW50BQtaRVJPX0JJR0lOVAIkZGVwb3NpdFN0YWtpbmdSZXdhcmQ6IGludmFsaWQgYW1vdW50BwMJAAACBQNlcnIFA2VycgQEZXJyMQMJAAACCQEKX2xvYWRDaGFpbgEFB2NoYWluSWQFBVdBVkVTCQETX3ZhbGlkYXRlV2F2ZXNWYXVsdAIIBQFpBmNhbGxlcgIpZGVwb3NpdFN0YWtpbmdSZXdhcmQ6IGludmFsaWQgd2F2ZXMgdmF1bHQDCQERX3ZhbGlkYXRlRXhlY3V0b3ICCAUBaQZjYWxsZXICJmRlcG9zaXRTdGFraW5nUmV3YXJkOiBpbnZhbGlkIGV4ZWN1dG9yCQEXX3ZhbGlkYXRlQ2FsbGVyQ29udHJhY3QDBQdjaGFpbklkBQ9jYWxsZXJDb250cmFjdF8CLWRlcG9zaXRTdGFraW5nUmV3YXJkOiBpbnZhbGlkIGNhbGxlciBjb250cmFjdAcDCQAAAgUEZXJyMQUEZXJyMQQQbmV3QXNzZXRSZXNlcnZlcwkAtwICCQESX2xvYWRBc3NldFJlc2VydmVzAgUHY2hhaW5JZAUGYXNzZXRfBQZhbW91bnQECGN1cnJlbmN5CQESX2xvYWRBc3NldEN1cnJlbmN5AgUHY2hhaW5JZAUGYXNzZXRfBBNuZXdDdXJyZW5jeVJlc2VydmVzCQC3AgIJARVfbG9hZEN1cnJlbmN5UmVzZXJ2ZXMBBQhjdXJyZW5jeQUGYW1vdW50BAppbnZvY2F0aW9uCQD8BwQJARNfbG9hZEFjY291bnRTdG9yYWdlAAUbRlVOQ19ERVBPU0lUX1NUQUtJTkdfUkVXQVJECQDMCAIJARZfbG9hZFJld2FyZERpc3RyaWJ1dG9yAAkAzAgCBQhjdXJyZW5jeQkAzAgCBQdhbW91bnRfBQNuaWwFA25pbAMJAAACBQppbnZvY2F0aW9uBQppbnZvY2F0aW9uCQCUCgIJAM4IAgkBEl9zYXZlQXNzZXRSZXNlcnZlcwMFB2NoYWluSWQFBmFzc2V0XwUQbmV3QXNzZXRSZXNlcnZlcwkBFV9zYXZlQ3VycmVuY3lSZXNlcnZlcwIFCGN1cnJlbmN5BRNuZXdDdXJyZW5jeVJlc2VydmVzBQR1bml0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCGFkZENoYWluAwhjaGFpbklkXwVuYW1lXw9jYWxsZXJDb250cmFjdF8EA2VycgMDAwMDCQERX29ubHlUaGlzQ29udHJhY3QBCAUBaQZjYWxsZXIJARBfd2hlbkluaXRpYWxpemVkAAcJAQxfdmFsaWRhdGVJbnQEBQhjaGFpbklkXwAABQdNQVhfSU5UAhlhZGRDaGFpbjogaW52YWxpZCBjaGFpbklkBwkBD192YWxpZGF0ZVN0cmluZwIFBW5hbWVfAhZhZGRDaGFpbjogaW52YWxpZCBuYW1lBwkBD192YWxpZGF0ZVN0cmluZwIFD2NhbGxlckNvbnRyYWN0XwIgYWRkQ2hhaW46IGludmFsaWQgY2FsbGVyQ29udHJhY3QHCQEOX2NoYWluTm90RXhpc3QCBQhjaGFpbklkXwIYYWRkQ2hhaW46IGFscmVhZHkgZXhpc3RzBwMJAAACBQNlcnIFA2VycgkAlAoCCQDOCAIJAQpfc2F2ZUNoYWluAgUIY2hhaW5JZF8FBW5hbWVfCQETX3NhdmVDYWxsZXJDb250cmFjdAIFCGNoYWluSWRfBQ9jYWxsZXJDb250cmFjdF8FBHVuaXQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEIYWRkQXNzZXQDCGNoYWluSWRfBmFzc2V0XwljdXJyZW5jeV8EA2VycgMDAwMDCQERX29ubHlUaGlzQ29udHJhY3QBCAUBaQZjYWxsZXIJARBfd2hlbkluaXRpYWxpemVkAAcJAQxfY2hhaW5FeGlzdHMCBQhjaGFpbklkXwIZYWRkQXNzZXQ6IGludmFsaWQgY2hhaW5JZAcJAQ9fdmFsaWRhdGVTdHJpbmcCBQZhc3NldF8CF2FkZEFzc2V0OiBpbnZhbGlkIGFzc2V0BwkBD192YWxpZGF0ZVN0cmluZwIFCWN1cnJlbmN5XwIaYWRkQXNzZXQ6IGludmFsaWQgY3VycmVuY3kHCQEWX2Fzc2V0Q3VycmVuY3lOb3RFeGlzdAMFCGNoYWluSWRfBQZhc3NldF8CGGFkZEFzc2V0OiBhbHJlYWR5IGV4aXN0cwcDCQAAAgUDZXJyBQNlcnIJAJQKAgkBEl9zYXZlQXNzZXRDdXJyZW5jeQMFCGNoYWluSWRfBQZhc3NldF8FCWN1cnJlbmN5XwUEdW5pdAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAR5zZXRSZXF1ZXN0V2l0aGRyYXdhbEJsb2NrRGVsYXkBBmRlbGF5XwQDZXJyAwMJARFfb25seVRoaXNDb250cmFjdAEIBQFpBmNhbGxlcgkBEF93aGVuSW5pdGlhbGl6ZWQABwkBDF92YWxpZGF0ZUludAQFBmRlbGF5XwAABQdNQVhfSU5UAi1zZXRSZXF1ZXN0V2l0aGRyYXdhbEJsb2NrRGVsYXk6IGludmFsaWQgZGVsYXkHAwkAAAIFA2VycgUDZXJyCQCUCgIJASBfc2F2ZVJlcXVlc3RXaXRoZHJhd2FsQmxvY2tEZWxheQEFBmRlbGF5XwUEdW5pdAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARd1cGRhdGVSZXdhcmREaXN0cmlidXRvcgEScmV3YXJkRGlzdHJpYnV0b3JfBANlcnIDAwkBEV9vbmx5VGhpc0NvbnRyYWN0AQgFAWkGY2FsbGVyCQEQX3doZW5Jbml0aWFsaXplZAAHCQEPX3ZhbGlkYXRlU3RyaW5nAgUScmV3YXJkRGlzdHJpYnV0b3JfAjJ1cGRhdGVSZXdhcmREaXN0cmlidXRvcjogaW52YWxpZCByZXdhcmREaXN0cmlidXRvcgcDCQAAAgUDZXJyBQNlcnIJAJQKAgkBFl9zYXZlUmV3YXJkRGlzdHJpYnV0b3IBBRJyZXdhcmREaXN0cmlidXRvcl8FBHVuaXQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEZdXBkYXRlUmVsYXllckZlZVJlY2lwaWVudAEUcmVsYXllckZlZVJlY2lwaWVudF8EA2VycgMDCQERX29ubHlUaGlzQ29udHJhY3QBCAUBaQZjYWxsZXIJARBfd2hlbkluaXRpYWxpemVkAAcJAQ9fdmFsaWRhdGVTdHJpbmcCBRRyZWxheWVyRmVlUmVjaXBpZW50XwI2dXBkYXRlUmVsYXllckZlZVJlY2lwaWVudDogaW52YWxpZCByZWxheWVyRmVlUmVjaXBpZW50BwMJAAACBQNlcnIFA2VycgkAlAoCCQEYX3NhdmVSZWxheWVyRmVlUmVjaXBpZW50AQUUcmVsYXllckZlZVJlY2lwaWVudF8FBHVuaXQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEFcGF1c2UABANlcnIDAwkBC19vbmx5UGF1c2VyAQgFAWkGY2FsbGVyCQEQX3doZW5Jbml0aWFsaXplZAAHCQEOX3doZW5Ob3RQYXVzZWQABwMJAAACBQNlcnIFA2VycgkAlAoCCQEKX3NhdmVQYXVzZQEGBQR1bml0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBB3VucGF1c2UABANlcnIDAwkBC19vbmx5UGF1c2VyAQgFAWkGY2FsbGVyCQEQX3doZW5Jbml0aWFsaXplZAAHCQELX3doZW5QYXVzZWQABwMJAAACBQNlcnIFA2VycgkAlAoCCQEKX3NhdmVQYXVzZQEHBQR1bml0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDHVwZGF0ZVBhdXNlcgEHcGF1c2VyXwQDZXJyAwMJARFfb25seVRoaXNDb250cmFjdAEIBQFpBmNhbGxlcgkBEF93aGVuSW5pdGlhbGl6ZWQABwkBEF92YWxpZGF0ZUFkZHJlc3MCBQdwYXVzZXJfAhx1cGRhdGVQYXVzZXI6IGludmFsaWQgcGF1c2VyBwMJAAACBQNlcnIFA2VycgkAlAoCCQELX3NhdmVQYXVzZXIBCQERQGV4dHJOYXRpdmUoMTA2MikBBQdwYXVzZXJfBQR1bml0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBC3NldE11bHRpc2lnAQltdWx0aXNpZ18EA2VycgMJARFfb25seVRoaXNDb250cmFjdAEIBQFpBmNhbGxlcgkBEF92YWxpZGF0ZUFkZHJlc3MCBQltdWx0aXNpZ18CHXNldE11bHRpc2lnOiBpbnZhbGlkIG11bHRpc2lnBwMJAAACBQNlcnIFA2VycgkAlAoCCQENX3NhdmVNdWx0aXNpZwEJARFAZXh0ck5hdGl2ZSgxMDYyKQEFCW11bHRpc2lnXwUEdW5pdAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgECdHgBBnZlcmlmeQAEByRtYXRjaDAJAKIIAQUMS0VZX01VTFRJU0lHAwkAAQIFByRtYXRjaDACBlN0cmluZwQIbXVsdGlzaWcFByRtYXRjaDAJAQt2YWx1ZU9yRWxzZQIJAJsIAgkBEUBleHRyTmF0aXZlKDEwNjIpAQUIbXVsdGlzaWcJALkJAgkAzAgCBQpLRVlfU1RBVFVTCQDMCAIJAKUIAQUEdGhpcwkAzAgCCQDYBAEIBQJ0eAJpZAUDbmlsBQlTRVBBUkFUT1IHCQD0AwMIBQJ0eAlib2R5Qnl0ZXMJAJEDAggFAnR4BnByb29mcwAACAUCdHgPc2VuZGVyUHVibGljS2V5iKyIMg==", "height": 3381050, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: MaC2oQScPuim7GuNbSCMu3DQNKMuYRt8roEavL8JWZD Next: none Diff:
OldNewDifferences
2929
3030 let KEY_ASSET_RESERVES_LOCKED = "ASSET_RESERVES_LOCKED"
3131
32+let KEY_USER_LOCKED_CURRENCY = "USER_LOCKED_CURRENCY"
33+
3234 let KEY_CURRENCY_RESERVES = "CURRENCY_RESERVES"
3335
3436 let KEY_REQUEST_WITHDRAWAL_SIZE = "REQUEST_WITHDRAWAL_SIZE"
4446 let KEY_VAULT_ADAPTER = "VAULT_ADAPTER"
4547
4648 let KEY_REWARD_DISTRIBUTOR = "REWARD_DISTRIBUTOR"
49+
50+let KEY_RELAYER_FEE_RECIPIENT = "RELAYER_FEE_RECIPIENT"
4751
4852 let FUNC_DEPOSIT = "deposit"
4953
6468 let WAVES = "WAVES"
6569
6670 let SPOT_WALLET = "SPOT"
67-
68-let WITHDRAWALS_WALLET = "WITHDRAWALS"
6971
7072 let MAX_INT = 9223372036854775807
7173
9799
98100
99101 func _validateBigInt (val_,lowerBoundary_,err_) = if ((lowerBoundary_ > val_))
102+ then throw(err_)
103+ else true
104+
105+
106+func _validateBigInt_2 (val_,lowerBoundary_,upperBoundary_,err_) = if (if ((lowerBoundary_ > val_))
107+ then true
108+ else (val_ > upperBoundary_))
100109 then throw(err_)
101110 else true
102111
245254 func _saveAssetReservesLocked (chainId_,asset_,reserves_) = [StringEntry(makeString([KEY_ASSET_RESERVES_LOCKED, toString(chainId_), asset_], SEPARATOR), toString(reserves_))]
246255
247256
257+func _loadUserLockedCurrency (currency_,user_) = match getString(makeString([KEY_USER_LOCKED_CURRENCY, currency_, user_], SEPARATOR)) {
258+ case a: String =>
259+ parseBigIntValue(a)
260+ case _ =>
261+ ZERO_BIGINT
262+}
263+
264+
265+func _saveUserLockedCurrency (currency_,user_,amount_) = [StringEntry(makeString([KEY_USER_LOCKED_CURRENCY, currency_, user_], SEPARATOR), toString(amount_))]
266+
267+
248268 func _loadCurrencyReserves (currency_) = match getString(makeString([KEY_CURRENCY_RESERVES, currency_], SEPARATOR)) {
249269 case a: String =>
250270 parseBigIntValue(a)
332352
333353
334354 func _saveRewardDistributor (distributor_) = [StringEntry(KEY_REWARD_DISTRIBUTOR, distributor_)]
355+
356+
357+func _loadRelayerFeeRecipient () = match getString(KEY_RELAYER_FEE_RECIPIENT) {
358+ case a: String =>
359+ a
360+ case _ =>
361+ ""
362+}
363+
364+
365+func _saveRelayerFeeRecipient (relayerFeeRecipient_) = [StringEntry(KEY_RELAYER_FEE_RECIPIENT, relayerFeeRecipient_)]
335366
336367
337368 func _onlyThisContract (caller_) = if ((caller_ != this))
430461 else throw((err_ + ": inv alg"))
431462
432463
433-func _validatePublicKey (publicKey_,alg_,err_) = if ((alg_ == ALG_TYPE_WAVES))
434- then if ((size(publicKey_) != 32))
464+func _validateWeb3Id (web3Id_,alg_,err_) = if ((alg_ == ALG_TYPE_WAVES))
465+ then if ((size(web3Id_) != 32))
435466 then throw(err_)
436467 else true
437468 else if ((alg_ == ALG_TYPE_EVM))
438- then if ((size(publicKey_) != 20))
469+ then if ((size(web3Id_) != 20))
439470 then throw(err_)
440471 else true
441472 else throw((err_ + ": inv alg"))
442473
443474
444-func _validateWithdrawalSignature (withdrawalHash_,signature_,publicKey_,alg_,err_) = {
475+func _validateWithdrawalSignature (withdrawalHash_,signature_,web3Id_,alg_,err_) = {
445476 let result = if ((alg_ == ALG_TYPE_WAVES))
446- then sigVerify(withdrawalHash_, signature_, publicKey_)
477+ then sigVerify(withdrawalHash_, signature_, web3Id_)
447478 else if ((alg_ == ALG_TYPE_EVM))
448479 then {
449480 let hashWithPrefix = keccak256_16Kb((EVM_SIGNATURE_PREFIX + withdrawalHash_))
450- (takeRight(keccak256_16Kb(ecrecover(hashWithPrefix, signature_)), 20) == publicKey_)
481+ (takeRight(keccak256_16Kb(ecrecover(hashWithPrefix, signature_)), 20) == web3Id_)
451482 }
452483 else throw((err_ + ": inv alg"))
453484 if (!(result))
456487 }
457488
458489
459-func _validatePublicKeyMatchesAddress (publicKey_,from_,alg_,err_) = {
490+func _validateWeb3IdMatchesAddress (web3Id_,from_,alg_,err_) = {
460491 let address = if ((alg_ == ALG_TYPE_WAVES))
461- then toString(addressFromPublicKey(publicKey_))
492+ then toString(addressFromPublicKey(web3Id_))
462493 else if ((alg_ == ALG_TYPE_EVM))
463- then ("0x" + toBase16String(publicKey_))
494+ then ("0x" + toBase16String(web3Id_))
464495 else throw((err_ + ": inv alg"))
465496 if ((address != from_))
466497 then throw(err_)
572603 if ((availableBalance == availableBalance))
573604 then {
574605 let lockedReserves = _loadAssetReservesLocked(toChainId, asset_)
575- let $t01823518744 = if (if ((availableBalance >= amount))
606+ let userLockedCurrency = _loadUserLockedCurrency(currency, from_)
607+ let $t01929519750 = if (if (((availableBalance - userLockedCurrency) >= amount))
576608 then ((_loadAssetReserves(toChainId, asset_) - lockedReserves) >= amount)
577609 else false)
578- then $Tuple3(REQUEST_STATUS_CREATED, invoke(_loadAccountStorage(), FUNC_INTERNAL_TRANSFER, [from_, SPOT_WALLET, WITHDRAWALS_WALLET, currency, amount_], nil), _saveAssetReservesLocked(toChainId, asset_, (lockedReserves + amount)))
579- else $Tuple3(REQUEST_STATUS_REJECTED, unit, nil)
580- if (($t01823518744 == $t01823518744))
581- then {
582- let reservesActions = $t01823518744._3
583- let storageInvocation = $t01823518744._2
584- let requestStatus = $t01823518744._1
585- let requestWithdrawalSize = _loadRequestWithdrawalSize()
586- let requestWithdrawal = $Tuple8(from_, to_, toChainId, asset_, amount, height, toBase58String(i.transactionId), requestStatus)
587- $Tuple2(((_saveRequestWithdrawal(requestWithdrawalSize, requestWithdrawal) ++ _saveRequestWithdrawalSize((requestWithdrawalSize + 1))) ++ reservesActions), requestWithdrawalSize)
588- }
589- else throw("Strict value is not equal to itself.")
610+ then $Tuple2(REQUEST_STATUS_CREATED, (_saveAssetReservesLocked(toChainId, asset_, (lockedReserves + amount)) ++ _saveUserLockedCurrency(currency, from_, (amount + userLockedCurrency))))
611+ else $Tuple2(REQUEST_STATUS_REJECTED, nil)
612+ let requestStatus = $t01929519750._1
613+ let reservesActions = $t01929519750._2
614+ let requestWithdrawalSize = _loadRequestWithdrawalSize()
615+ let requestWithdrawal = $Tuple8(from_, to_, toChainId, asset_, amount, height, toBase58String(i.transactionId), requestStatus)
616+ $Tuple2(((_saveRequestWithdrawal(requestWithdrawalSize, requestWithdrawal) ++ _saveRequestWithdrawalSize((requestWithdrawalSize + 1))) ++ reservesActions), requestWithdrawalSize)
590617 }
591618 else throw("Strict value is not equal to itself.")
592619 }
628655 let newAssetReservesLocked = (_loadAssetReservesLocked(requestToChainId, requestAsset) - requestAmount)
629656 let currency = _loadAssetCurrency(requestToChainId, requestAsset)
630657 let newCurrencyReserves = (_loadCurrencyReserves(currency) - requestAmount)
631- let err2 = if (if (if (if (_validateBigInt(newAssetReserves, ZERO_BIGINT, "executeWithdrawal: negative newAssetReserves"))
658+ let newUserLockedCurrency = (_loadUserLockedCurrency(currency, requestFrom) - requestAmount)
659+ let err2 = if (if (if (if (if (_validateBigInt(newAssetReserves, ZERO_BIGINT, "executeWithdrawal: negative newAssetReserves"))
632660 then _validateBigInt(newAssetReservesLocked, ZERO_BIGINT, "executeWithdrawal: negative newAssetReservesLocked")
633661 else false)
634662 then _validateBigInt(newCurrencyReserves, ZERO_BIGINT, "executeWithdrawal: negative newCurrencyReserves")
663+ else false)
664+ then _validateBigInt(newUserLockedCurrency, ZERO_BIGINT, "executeWithdrawal: negative newUserLockedCurrency")
635665 else false)
636666 then _validateInt((height - requestHeight), _loadRequestWithdrawalBlockDelay(), MAX_INT, "executeWithdrawal: too early to execute")
637667 else false)
648678 if ((withdrawInvocation == withdrawInvocation))
649679 then {
650680 let requestUpdated = $Tuple8(request._1, request._2, request._3, request._4, request._5, request._6, request._7, REQUEST_STATUS_DONE)
651- $Tuple2((((_saveAssetReserves(requestToChainId, requestAsset, newAssetReserves) ++ _saveAssetReservesLocked(requestToChainId, requestAsset, newAssetReservesLocked)) ++ _saveCurrencyReserves(currency, newCurrencyReserves)) ++ _saveRequestWithdrawal(requestWithdrawalId, requestUpdated)), unit)
681+ $Tuple2(((((_saveAssetReserves(requestToChainId, requestAsset, newAssetReserves) ++ _saveAssetReservesLocked(requestToChainId, requestAsset, newAssetReservesLocked)) ++ _saveCurrencyReserves(currency, newCurrencyReserves)) ++ _saveUserLockedCurrency(currency, requestFrom, newUserLockedCurrency)) ++ _saveRequestWithdrawal(requestWithdrawalId, requestUpdated)), unit)
652682 }
653683 else throw("Strict value is not equal to itself.")
654684 }
664694
665695
666696 @Callable(i)
667-func withdraw (from_,to_,toChainId_,asset_,amount_,timestamp_,publicKey_,alg_,signature_) = {
697+func rejectWithdrawal (requestWithdrawalId_) = {
698+ let requestWithdrawalId = valueOrErrorMessage(parseInt(requestWithdrawalId_), "rejectWithdrawal: requestWithdrawalId not int")
699+ let requestWithdrawalSize = _loadRequestWithdrawalSize()
700+ let err = if (if (_whenInitialized())
701+ then _validateSequencer(i.caller, "rejectWithdrawal: invalid sequencer")
702+ else false)
703+ then _validateInt(requestWithdrawalId, 0, (requestWithdrawalSize - 1), "rejectWithdrawal: invalid requestWithdrawalId")
704+ else false
705+ if ((err == err))
706+ then {
707+ let request = _loadRequestWithdrawal(requestWithdrawalId)
708+ let requestFrom = request._1
709+ let requestTo = request._2
710+ let requestToChainId = request._3
711+ let requestAsset = request._4
712+ let requestAmount = request._5
713+ let requestHeight = request._6
714+ let requestStatus = request._8
715+ let currency = _loadAssetCurrency(requestToChainId, requestAsset)
716+ let newAssetReservesLocked = (_loadAssetReservesLocked(requestToChainId, requestAsset) - requestAmount)
717+ let newUserLockedCurrency = (_loadUserLockedCurrency(currency, requestFrom) - requestAmount)
718+ let err1 = if (if (_validateBigInt(newAssetReservesLocked, ZERO_BIGINT, "rejectWithdrawal: negative newAssetReservesLocked"))
719+ then _validateBigInt(newUserLockedCurrency, ZERO_BIGINT, "rejectWithdrawal: negative newUserLockedCurrency")
720+ else false)
721+ then _requestIsCreated(requestStatus, "rejectWithdrawal: request is resolved")
722+ else false
723+ if ((err1 == err1))
724+ then {
725+ let availableBalance = match invoke(_loadAccountStorage(), FUNC_GET_USER_BALANCE, [requestFrom, SPOT_WALLET, currency], nil) {
726+ case a: String =>
727+ parseBigIntValue(a)
728+ case _ =>
729+ throw("rejectWithdrawal: can't take available balance from storage")
730+ }
731+ if ((availableBalance == availableBalance))
732+ then if ((requestAmount > availableBalance))
733+ then {
734+ let requestUpdated = $Tuple8(request._1, request._2, request._3, request._4, request._5, request._6, request._7, REQUEST_STATUS_REJECTED)
735+ $Tuple2(((_saveAssetReservesLocked(requestToChainId, requestAsset, newAssetReservesLocked) ++ _saveUserLockedCurrency(currency, requestFrom, newUserLockedCurrency)) ++ _saveRequestWithdrawal(requestWithdrawalId, requestUpdated)), true)
736+ }
737+ else $Tuple2(nil, false)
738+ else throw("Strict value is not equal to itself.")
739+ }
740+ else throw("Strict value is not equal to itself.")
741+ }
742+ else throw("Strict value is not equal to itself.")
743+ }
744+
745+
746+
747+@Callable(i)
748+func withdraw (from_,to_,toChainId_,asset_,amount_,relayerFee_,timestamp_,web3Id_,alg_,signature_) = {
668749 let toChainId = valueOrErrorMessage(parseInt(toChainId_), "withdraw: toChainId not int")
669750 let amount = valueOrErrorMessage(parseBigInt(amount_), "withdraw: amount not int")
751+ let relayerFee = valueOrErrorMessage(parseBigInt(relayerFee_), "withdraw: relayerFee not int")
670752 let timestamp = valueOrErrorMessage(parseInt(timestamp_), "withdraw: timestamp not int")
671753 let alg = valueOrErrorMessage(parseInt(alg_), "withdraw: alg not int")
672- let publicKey = fromBase58String(publicKey_)
754+ let web3Id = fromBase58String(web3Id_)
673755 let signature = fromBase58String(signature_)
674- let err = if (if (if (if (if (if (if (if (if (if (_whenInitialized())
756+ let err = if (if (if (if (if (if (if (if (if (if (if (_whenInitialized())
675757 then _validateSequencer(i.caller, "withdraw: invalid sequencer")
676758 else false)
677759 then _validateString(from_, "withdraw: invalid from")
684766 else false)
685767 then _validateBigInt(amount, ZERO_BIGINT, "withdraw: invalid amount")
686768 else false)
769+ then _validateBigInt_2(relayerFee, ZERO_BIGINT, amount, "withdraw: invalid relayerFee")
770+ else false)
687771 then _validateInt((timestamp + ONE_DAY), lastBlock.timestamp, MAX_INT, "withdraw: invalid timestamp")
688772 else false)
689- then _validatePublicKey(publicKey, alg, "withdraw: inv public key")
773+ then _validateWeb3Id(web3Id, alg, "withdraw: inv web3Id")
690774 else false)
691775 then _validateSignatureFormat(signature, alg, "withdraw: inv sig format")
692776 else false)
693- then _validatePublicKeyMatchesAddress(publicKey, from_, alg, "withdraw: public key mismatch")
777+ then _validateWeb3IdMatchesAddress(web3Id, from_, alg, "withdraw: web3Id mismatch")
694778 else false
695779 if ((err == err))
696780 then {
697- let withdrawalBytes = ((((((((((toBytes(size(from_)) + toBytes(from_)) + toBytes(size(to_))) + toBytes(to_)) + toBytes(toChainId)) + toBytes(size(asset_))) + toBytes(asset_)) + toBytes(amount)) + toBytes(timestamp)) + publicKey) + toBytes(alg))
781+ let withdrawalBytes = (((((((((((toBytes(size(from_)) + toBytes(from_)) + toBytes(size(to_))) + toBytes(to_)) + toBytes(toChainId)) + toBytes(size(asset_))) + toBytes(asset_)) + toBytes(amount)) + toBytes(relayerFee)) + toBytes(timestamp)) + web3Id) + toBytes(alg))
698782 let withdrawalHash = keccak256_16Kb(withdrawalBytes)
699783 let currency = _loadAssetCurrency(toChainId, asset_)
700784 let availableBalance = match invoke(_loadAccountStorage(), FUNC_GET_USER_BALANCE, [from_, SPOT_WALLET, currency], nil) {
707791 then {
708792 let assetReserves = _loadAssetReserves(toChainId, asset_)
709793 let lockedReserves = _loadAssetReservesLocked(toChainId, asset_)
710- let err1 = if (if (if (_validateWithdrawalSignature(withdrawalHash, signature, publicKey, alg, "withdraw: invalid sig"))
794+ let amountToSend = (amount - relayerFee)
795+ let amountToSendStr = toString(amountToSend)
796+ let err1 = if (if (if (_validateWithdrawalSignature(withdrawalHash, signature, web3Id, alg, "withdraw: invalid sig"))
711797 then _checkWithdrawalHashNotExist(withdrawalHash, "withdraw: already executed")
712798 else false)
713- then _validateBigInt(availableBalance, amount, "withdraw: insufficient balance")
799+ then _validateBigInt(availableBalance, amountToSend, "withdraw: insufficient balance")
714800 else false)
715- then _validateBigInt((assetReserves - lockedReserves), amount, "withdraw: insufficient reserves")
801+ then _validateBigInt((assetReserves - lockedReserves), amountToSend, "withdraw: insufficient reserves")
716802 else false
717803 if ((err1 == err1))
718804 then {
719- let newAssetReserves = (assetReserves - amount)
720- let newCurrencyReserves = (_loadCurrencyReserves(currency) - amount)
805+ let newAssetReserves = (assetReserves - amountToSend)
806+ let newCurrencyReserves = (_loadCurrencyReserves(currency) - amountToSend)
721807 let err2 = if (_validateBigInt(newAssetReserves, ZERO_BIGINT, "withdraw: negative newAssetReserves"))
722808 then _validateBigInt(newCurrencyReserves, ZERO_BIGINT, "withdraw: negative newCurrencyReserves")
723809 else false
724810 if ((err2 == err2))
725811 then {
726- let storageInvocation = invoke(_loadAccountStorage(), FUNC_INTERNAL_TRANSFER, [from_, SPOT_WALLET, WITHDRAWALS_WALLET, currency, amount_], nil)
727- if ((storageInvocation == storageInvocation))
812+ let storageInvocation1 = invoke(_loadAccountStorage(), FUNC_WITHDRAW, [from_, currency, amount_], nil)
813+ if ((storageInvocation1 == storageInvocation1))
728814 then {
729- let storageInvocation1 = invoke(_loadAccountStorage(), FUNC_WITHDRAW, [from_, currency, amount_], nil)
730- if ((storageInvocation1 == storageInvocation1))
815+ let storageInvocation2 = invoke(_loadAccountStorage(), FUNC_DEPOSIT, [_loadRelayerFeeRecipient(), currency, relayerFee_], nil)
816+ if ((storageInvocation2 == storageInvocation2))
731817 then {
732818 let withdrawInvocation = if ((_loadChain(toChainId) == WAVES))
733- then invoke(_loadWavesVault(), FUNC_WITHDRAW, [to_, asset_, amount_], nil)
734- else invoke(_loadVaultAdapter(), FUNC_WITHDRAW, [toChainId, asset_, amount_, to_], nil)
819+ then invoke(_loadWavesVault(), FUNC_WITHDRAW, [to_, asset_, amountToSendStr], nil)
820+ else invoke(_loadVaultAdapter(), FUNC_WITHDRAW, [toChainId, asset_, amountToSendStr, to_, relayerFee_], nil)
735821 if ((withdrawInvocation == withdrawInvocation))
736822 then $Tuple2(((_saveAssetReserves(toChainId, asset_, newAssetReserves) ++ _saveCurrencyReserves(currency, newCurrencyReserves)) ++ _saveWithdrawalHash(withdrawalHash, toBase58String(i.transactionId))), unit)
737823 else throw("Strict value is not equal to itself.")
857943
858944
859945 @Callable(i)
946+func updateRelayerFeeRecipient (relayerFeeRecipient_) = {
947+ let err = if (if (_onlyThisContract(i.caller))
948+ then _whenInitialized()
949+ else false)
950+ then _validateString(relayerFeeRecipient_, "updateRelayerFeeRecipient: invalid relayerFeeRecipient")
951+ else false
952+ if ((err == err))
953+ then $Tuple2(_saveRelayerFeeRecipient(relayerFeeRecipient_), unit)
954+ else throw("Strict value is not equal to itself.")
955+ }
956+
957+
958+
959+@Callable(i)
860960 func pause () = {
861961 let err = if (if (_onlyPauser(i.caller))
862962 then _whenInitialized()
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 7 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let SEPARATOR = "__"
55
66 let KEY_MULTISIG = "MULTISIG"
77
88 let KEY_STATUS = "STATUS"
99
1010 let KEY_INIT = "INIT"
1111
1212 let KEY_PAUSED = "PAUSED"
1313
1414 let KEY_PAUSER = "PAUSER"
1515
1616 let KEY_EXECUTOR = "EXECUTOR"
1717
1818 let KEY_CALLER_CONTRACT = "CALLER_CONTRACT"
1919
2020 let KEY_WAVES_VAULT = "WAVES_VAULT"
2121
2222 let KEY_ACCOUNT_STORAGE = "ACCOUNT_STORAGE"
2323
2424 let KEY_CHAIN = "CHAIN"
2525
2626 let KEY_ASSET_CURRENCY = "ASSET_CURRENCY"
2727
2828 let KEY_ASSET_RESERVES = "ASSET_RESERVES"
2929
3030 let KEY_ASSET_RESERVES_LOCKED = "ASSET_RESERVES_LOCKED"
3131
32+let KEY_USER_LOCKED_CURRENCY = "USER_LOCKED_CURRENCY"
33+
3234 let KEY_CURRENCY_RESERVES = "CURRENCY_RESERVES"
3335
3436 let KEY_REQUEST_WITHDRAWAL_SIZE = "REQUEST_WITHDRAWAL_SIZE"
3537
3638 let KEY_REQUEST_WITHDRAWAL = "REQUEST_WITHDRAWAL"
3739
3840 let KEY_REQUEST_WITHDRAWAL_BLOCK_DELAY = "REQUEST_WITHDRAWAL_BLOCK_DELAY"
3941
4042 let KEY_SEQUENCER = "SEQUENCER"
4143
4244 let KEY_WITHDRAWAL_HASH = "WITHDRAWAL_HASH"
4345
4446 let KEY_VAULT_ADAPTER = "VAULT_ADAPTER"
4547
4648 let KEY_REWARD_DISTRIBUTOR = "REWARD_DISTRIBUTOR"
49+
50+let KEY_RELAYER_FEE_RECIPIENT = "RELAYER_FEE_RECIPIENT"
4751
4852 let FUNC_DEPOSIT = "deposit"
4953
5054 let FUNC_GET_USER_BALANCE = "getUserBalance"
5155
5256 let FUNC_INTERNAL_TRANSFER = "internalTransfer"
5357
5458 let FUNC_WITHDRAW = "withdraw"
5559
5660 let FUNC_DEPOSIT_STAKING_REWARD = "depositStakingReward"
5761
5862 let REQUEST_STATUS_CREATED = 0
5963
6064 let REQUEST_STATUS_DONE = 1
6165
6266 let REQUEST_STATUS_REJECTED = 2
6367
6468 let WAVES = "WAVES"
6569
6670 let SPOT_WALLET = "SPOT"
67-
68-let WITHDRAWALS_WALLET = "WITHDRAWALS"
6971
7072 let MAX_INT = 9223372036854775807
7173
7274 let ZERO_BIGINT = toBigInt(0)
7375
7476 let ONE_BIGINT = toBigInt(1)
7577
7678 let ONE_DAY = 86400000
7779
7880 let ALG_TYPE_WAVES = 1
7981
8082 let ALG_TYPE_EVM = 2
8183
8284 let EVM_SIGNATURE_PREFIX = base58'G5Nu92G2p7moXW9qjjN3na7gtq4dWCeVdaSjry'
8385
8486 func _validateAddress (address_,err_) = match addressFromString(address_) {
8587 case a: Address =>
8688 true
8789 case _ =>
8890 throw(err_)
8991 }
9092
9193
9294 func _validateInt (val_,lowerBoundary_,upperBoundary_,err_) = if (if ((lowerBoundary_ > val_))
9395 then true
9496 else (val_ > upperBoundary_))
9597 then throw(err_)
9698 else true
9799
98100
99101 func _validateBigInt (val_,lowerBoundary_,err_) = if ((lowerBoundary_ > val_))
102+ then throw(err_)
103+ else true
104+
105+
106+func _validateBigInt_2 (val_,lowerBoundary_,upperBoundary_,err_) = if (if ((lowerBoundary_ > val_))
107+ then true
108+ else (val_ > upperBoundary_))
100109 then throw(err_)
101110 else true
102111
103112
104113 func _validateString (val_,err_) = if (if ((0 >= size(val_)))
105114 then true
106115 else contains(val_, SEPARATOR))
107116 then throw(err_)
108117 else true
109118
110119
111120 func _validateStringEqual (val1_,val2_,err_) = if ((val1_ != val2_))
112121 then throw(err_)
113122 else true
114123
115124
116125 func _loadInit () = match getBoolean(KEY_INIT) {
117126 case a: Boolean =>
118127 a
119128 case _ =>
120129 false
121130 }
122131
123132
124133 func _saveInit (isInit_) = [BooleanEntry(KEY_INIT, isInit_)]
125134
126135
127136 func _loadPause () = match getBoolean(KEY_PAUSED) {
128137 case a: Boolean =>
129138 a
130139 case _ =>
131140 false
132141 }
133142
134143
135144 func _savePause (isPaused_) = [BooleanEntry(KEY_PAUSED, isPaused_)]
136145
137146
138147 func _loadPauser () = match getString(KEY_PAUSER) {
139148 case a: String =>
140149 addressFromStringValue(a)
141150 case _ =>
142151 Address(base58'')
143152 }
144153
145154
146155 func _savePauser (pauser_) = [StringEntry(KEY_PAUSER, toString(pauser_))]
147156
148157
149158 func _loadMultisig () = match getString(KEY_MULTISIG) {
150159 case a: String =>
151160 addressFromStringValue(a)
152161 case _ =>
153162 Address(base58'')
154163 }
155164
156165
157166 func _saveMultisig (multisig_) = [StringEntry(KEY_MULTISIG, toString(multisig_))]
158167
159168
160169 func _loadCallerContract (chainId_) = match getString(makeString([KEY_CALLER_CONTRACT, toString(chainId_)], SEPARATOR)) {
161170 case a: String =>
162171 a
163172 case _ =>
164173 ""
165174 }
166175
167176
168177 func _saveCallerContract (chainId_,callerContract_) = [StringEntry(makeString([KEY_CALLER_CONTRACT, toString(chainId_)], SEPARATOR), callerContract_)]
169178
170179
171180 func _loadExecutor () = match getString(KEY_EXECUTOR) {
172181 case a: String =>
173182 addressFromStringValue(a)
174183 case _ =>
175184 Address(base58'')
176185 }
177186
178187
179188 func _saveExecutor (executor_) = [StringEntry(KEY_EXECUTOR, toString(executor_))]
180189
181190
182191 func _loadAccountStorage () = match getString(KEY_ACCOUNT_STORAGE) {
183192 case a: String =>
184193 addressFromStringValue(a)
185194 case _ =>
186195 Address(base58'')
187196 }
188197
189198
190199 func _saveAccountStorage (accountStorage_) = [StringEntry(KEY_ACCOUNT_STORAGE, toString(accountStorage_))]
191200
192201
193202 func _loadWavesVault () = match getString(KEY_WAVES_VAULT) {
194203 case a: String =>
195204 addressFromStringValue(a)
196205 case _ =>
197206 Address(base58'')
198207 }
199208
200209
201210 func _saveWavesVault (wavesVault_) = [StringEntry(KEY_WAVES_VAULT, toString(wavesVault_))]
202211
203212
204213 func _loadChain (chainId_) = match getString(makeString([KEY_CHAIN, toString(chainId_)], SEPARATOR)) {
205214 case a: String =>
206215 a
207216 case _ =>
208217 ""
209218 }
210219
211220
212221 func _saveChain (chainId_,name_) = [StringEntry(makeString([KEY_CHAIN, toString(chainId_)], SEPARATOR), name_)]
213222
214223
215224 func _loadAssetCurrency (chainId_,asset_) = match getString(makeString([KEY_ASSET_CURRENCY, toString(chainId_), asset_], SEPARATOR)) {
216225 case a: String =>
217226 a
218227 case _ =>
219228 ""
220229 }
221230
222231
223232 func _saveAssetCurrency (chainId_,asset_,currency_) = [StringEntry(makeString([KEY_ASSET_CURRENCY, toString(chainId_), asset_], SEPARATOR), currency_)]
224233
225234
226235 func _loadAssetReserves (chainId_,asset_) = match getString(makeString([KEY_ASSET_RESERVES, toString(chainId_), asset_], SEPARATOR)) {
227236 case a: String =>
228237 parseBigIntValue(a)
229238 case _ =>
230239 ZERO_BIGINT
231240 }
232241
233242
234243 func _saveAssetReserves (chainId_,asset_,reserves_) = [StringEntry(makeString([KEY_ASSET_RESERVES, toString(chainId_), asset_], SEPARATOR), toString(reserves_))]
235244
236245
237246 func _loadAssetReservesLocked (chainId_,asset_) = match getString(makeString([KEY_ASSET_RESERVES_LOCKED, toString(chainId_), asset_], SEPARATOR)) {
238247 case a: String =>
239248 parseBigIntValue(a)
240249 case _ =>
241250 ZERO_BIGINT
242251 }
243252
244253
245254 func _saveAssetReservesLocked (chainId_,asset_,reserves_) = [StringEntry(makeString([KEY_ASSET_RESERVES_LOCKED, toString(chainId_), asset_], SEPARATOR), toString(reserves_))]
246255
247256
257+func _loadUserLockedCurrency (currency_,user_) = match getString(makeString([KEY_USER_LOCKED_CURRENCY, currency_, user_], SEPARATOR)) {
258+ case a: String =>
259+ parseBigIntValue(a)
260+ case _ =>
261+ ZERO_BIGINT
262+}
263+
264+
265+func _saveUserLockedCurrency (currency_,user_,amount_) = [StringEntry(makeString([KEY_USER_LOCKED_CURRENCY, currency_, user_], SEPARATOR), toString(amount_))]
266+
267+
248268 func _loadCurrencyReserves (currency_) = match getString(makeString([KEY_CURRENCY_RESERVES, currency_], SEPARATOR)) {
249269 case a: String =>
250270 parseBigIntValue(a)
251271 case _ =>
252272 ZERO_BIGINT
253273 }
254274
255275
256276 func _saveCurrencyReserves (currency_,reserves_) = [StringEntry(makeString([KEY_CURRENCY_RESERVES, currency_], SEPARATOR), toString(reserves_))]
257277
258278
259279 func _loadRequestWithdrawalSize () = match getInteger(KEY_REQUEST_WITHDRAWAL_SIZE) {
260280 case a: Int =>
261281 a
262282 case _ =>
263283 0
264284 }
265285
266286
267287 func _saveRequestWithdrawalSize (val_) = [IntegerEntry(KEY_REQUEST_WITHDRAWAL_SIZE, val_)]
268288
269289
270290 func _loadRequestWithdrawal (index_) = match getString(makeString([KEY_REQUEST_WITHDRAWAL, toString(index_)], SEPARATOR)) {
271291 case a: String =>
272292 let struct = split(a, SEPARATOR)
273293 $Tuple8(struct[0], struct[1], parseIntValue(struct[2]), struct[3], parseBigIntValue(struct[4]), parseIntValue(struct[5]), struct[6], parseIntValue(struct[7]))
274294 case _ =>
275295 $Tuple8("", "", 0, "", ZERO_BIGINT, 0, "", REQUEST_STATUS_CREATED)
276296 }
277297
278298
279299 func _saveRequestWithdrawal (index_,request_) = [StringEntry(makeString([KEY_REQUEST_WITHDRAWAL, toString(index_)], SEPARATOR), makeString([request_._1, request_._2, toString(request_._3), request_._4, toString(request_._5), toString(request_._6), request_._7, toString(request_._8)], SEPARATOR))]
280300
281301
282302 func _loadRequestWithdrawalBlockDelay () = match getInteger(KEY_REQUEST_WITHDRAWAL_BLOCK_DELAY) {
283303 case a: Int =>
284304 a
285305 case _ =>
286306 0
287307 }
288308
289309
290310 func _saveRequestWithdrawalBlockDelay (delay_) = [IntegerEntry(KEY_REQUEST_WITHDRAWAL_BLOCK_DELAY, delay_)]
291311
292312
293313 func _loadSequencer () = match getString(KEY_SEQUENCER) {
294314 case a: String =>
295315 addressFromStringValue(a)
296316 case _ =>
297317 Address(base58'')
298318 }
299319
300320
301321 func _saveSequencer (sequencer_) = [StringEntry(KEY_SEQUENCER, toString(sequencer_))]
302322
303323
304324 func _loadWithdrawalHash (withdrawalHash_) = match getString(makeString([KEY_WITHDRAWAL_HASH, toBase58String(withdrawalHash_)], SEPARATOR)) {
305325 case a: String =>
306326 a
307327 case _ =>
308328 ""
309329 }
310330
311331
312332 func _saveWithdrawalHash (withdrawalHash_,txId_) = [StringEntry(makeString([KEY_WITHDRAWAL_HASH, toBase58String(withdrawalHash_)], SEPARATOR), txId_)]
313333
314334
315335 func _loadVaultAdapter () = match getString(KEY_VAULT_ADAPTER) {
316336 case a: String =>
317337 addressFromStringValue(a)
318338 case _ =>
319339 Address(base58'')
320340 }
321341
322342
323343 func _saveVaultAdapter (vaultAdapter_) = [StringEntry(KEY_VAULT_ADAPTER, toString(vaultAdapter_))]
324344
325345
326346 func _loadRewardDistributor () = match getString(KEY_REWARD_DISTRIBUTOR) {
327347 case a: String =>
328348 a
329349 case _ =>
330350 ""
331351 }
332352
333353
334354 func _saveRewardDistributor (distributor_) = [StringEntry(KEY_REWARD_DISTRIBUTOR, distributor_)]
355+
356+
357+func _loadRelayerFeeRecipient () = match getString(KEY_RELAYER_FEE_RECIPIENT) {
358+ case a: String =>
359+ a
360+ case _ =>
361+ ""
362+}
363+
364+
365+func _saveRelayerFeeRecipient (relayerFeeRecipient_) = [StringEntry(KEY_RELAYER_FEE_RECIPIENT, relayerFeeRecipient_)]
335366
336367
337368 func _onlyThisContract (caller_) = if ((caller_ != this))
338369 then throw("_onlyThisContract: revert")
339370 else true
340371
341372
342373 func _whenMultisigSet () = if ((_loadMultisig() == Address(base58'')))
343374 then throw("_whenMultisigSet: revert")
344375 else true
345376
346377
347378 func _whenNotInitialized () = if (_loadInit())
348379 then throw("_whenNotInitialized: revert")
349380 else true
350381
351382
352383 func _whenInitialized () = if (!(_loadInit()))
353384 then throw("_whenInitialized: revert")
354385 else true
355386
356387
357388 func _whenNotPaused () = if (_loadPause())
358389 then throw("_whenNotPaused: revert")
359390 else true
360391
361392
362393 func _whenPaused () = if (!(_loadPause()))
363394 then throw("_whenPaused: revert")
364395 else true
365396
366397
367398 func _onlyPauser (caller_) = if ((caller_ != _loadPauser()))
368399 then throw("_onlyPauser: revert")
369400 else true
370401
371402
372403 func _validateExecutor (val_,err_) = if ((val_ != _loadExecutor()))
373404 then throw(err_)
374405 else true
375406
376407
377408 func _validateCallerContract (chainId_,callerContract_,err_) = if ((_loadCallerContract(chainId_) != callerContract_))
378409 then throw(err_)
379410 else true
380411
381412
382413 func _chainExists (chainId_,err_) = if ((0 >= size(_loadChain(chainId_))))
383414 then throw(err_)
384415 else true
385416
386417
387418 func _chainNotExist (chainId_,err_) = if ((size(_loadChain(chainId_)) > 0))
388419 then throw(err_)
389420 else true
390421
391422
392423 func _assetCurrencyExists (chainId_,asset_,err_) = if ((0 >= size(_loadAssetCurrency(chainId_, asset_))))
393424 then throw(err_)
394425 else true
395426
396427
397428 func _assetCurrencyNotExist (chainId_,asset_,err_) = if ((size(_loadAssetCurrency(chainId_, asset_)) > 0))
398429 then throw(err_)
399430 else true
400431
401432
402433 func _validateWavesVault (caller,err_) = if ((_loadWavesVault() != caller))
403434 then throw(err_)
404435 else true
405436
406437
407438 func _requestIsCreated (status_,err_) = if ((status_ != REQUEST_STATUS_CREATED))
408439 then throw(err_)
409440 else true
410441
411442
412443 func _validateSequencer (caller,err_) = if ((_loadSequencer() != caller))
413444 then throw(err_)
414445 else true
415446
416447
417448 func _checkWithdrawalHashNotExist (withdrawalHash_,err_) = if ((size(_loadWithdrawalHash(withdrawalHash_)) > 0))
418449 then throw(err_)
419450 else true
420451
421452
422453 func _validateSignatureFormat (signature_,alg_,err_) = if ((alg_ == ALG_TYPE_WAVES))
423454 then if ((size(signature_) != 64))
424455 then throw(err_)
425456 else true
426457 else if ((alg_ == ALG_TYPE_EVM))
427458 then if ((size(signature_) != 65))
428459 then throw(err_)
429460 else true
430461 else throw((err_ + ": inv alg"))
431462
432463
433-func _validatePublicKey (publicKey_,alg_,err_) = if ((alg_ == ALG_TYPE_WAVES))
434- then if ((size(publicKey_) != 32))
464+func _validateWeb3Id (web3Id_,alg_,err_) = if ((alg_ == ALG_TYPE_WAVES))
465+ then if ((size(web3Id_) != 32))
435466 then throw(err_)
436467 else true
437468 else if ((alg_ == ALG_TYPE_EVM))
438- then if ((size(publicKey_) != 20))
469+ then if ((size(web3Id_) != 20))
439470 then throw(err_)
440471 else true
441472 else throw((err_ + ": inv alg"))
442473
443474
444-func _validateWithdrawalSignature (withdrawalHash_,signature_,publicKey_,alg_,err_) = {
475+func _validateWithdrawalSignature (withdrawalHash_,signature_,web3Id_,alg_,err_) = {
445476 let result = if ((alg_ == ALG_TYPE_WAVES))
446- then sigVerify(withdrawalHash_, signature_, publicKey_)
477+ then sigVerify(withdrawalHash_, signature_, web3Id_)
447478 else if ((alg_ == ALG_TYPE_EVM))
448479 then {
449480 let hashWithPrefix = keccak256_16Kb((EVM_SIGNATURE_PREFIX + withdrawalHash_))
450- (takeRight(keccak256_16Kb(ecrecover(hashWithPrefix, signature_)), 20) == publicKey_)
481+ (takeRight(keccak256_16Kb(ecrecover(hashWithPrefix, signature_)), 20) == web3Id_)
451482 }
452483 else throw((err_ + ": inv alg"))
453484 if (!(result))
454485 then throw(err_)
455486 else true
456487 }
457488
458489
459-func _validatePublicKeyMatchesAddress (publicKey_,from_,alg_,err_) = {
490+func _validateWeb3IdMatchesAddress (web3Id_,from_,alg_,err_) = {
460491 let address = if ((alg_ == ALG_TYPE_WAVES))
461- then toString(addressFromPublicKey(publicKey_))
492+ then toString(addressFromPublicKey(web3Id_))
462493 else if ((alg_ == ALG_TYPE_EVM))
463- then ("0x" + toBase16String(publicKey_))
494+ then ("0x" + toBase16String(web3Id_))
464495 else throw((err_ + ": inv alg"))
465496 if ((address != from_))
466497 then throw(err_)
467498 else true
468499 }
469500
470501
471502 @Callable(i)
472503 func init (executor_,pauser_,accountStorage_,wavesVault_,sequencer_,vaultAdapter_) = {
473504 let err = if (if (if (if (if (if (if (if (_onlyThisContract(i.caller))
474505 then _whenNotInitialized()
475506 else false)
476507 then _whenMultisigSet()
477508 else false)
478509 then _validateAddress(executor_, "init: invalid executor")
479510 else false)
480511 then _validateAddress(pauser_, "init: invalid pauser")
481512 else false)
482513 then _validateAddress(accountStorage_, "init: invalid accountStorage")
483514 else false)
484515 then _validateAddress(wavesVault_, "init: invalid wavesVault")
485516 else false)
486517 then _validateAddress(sequencer_, "init: invalid sequencer")
487518 else false)
488519 then _validateAddress(vaultAdapter_, "init: invalid vaultAdapter")
489520 else false
490521 if ((err == err))
491522 then $Tuple2(((((((_saveInit(true) ++ _saveExecutor(addressFromStringValue(executor_))) ++ _savePauser(addressFromStringValue(pauser_))) ++ _saveAccountStorage(addressFromStringValue(accountStorage_))) ++ _saveWavesVault(addressFromStringValue(wavesVault_))) ++ _saveSequencer(addressFromStringValue(sequencer_))) ++ _saveVaultAdapter(addressFromStringValue(vaultAdapter_))), unit)
492523 else throw("Strict value is not equal to itself.")
493524 }
494525
495526
496527
497528 @Callable(i)
498529 func deposit (callerContract_,from_,to_,chainId_,asset_,amount_) = {
499530 let chainId = valueOrErrorMessage(parseInt(chainId_), "deposit: chainId not int")
500531 let amount = valueOrErrorMessage(parseBigInt(amount_), "deposit: amount not int")
501532 let err = if (if (if (if (if (if (_whenInitialized())
502533 then _whenNotPaused()
503534 else false)
504535 then _chainExists(chainId, "deposit: invalid chainId")
505536 else false)
506537 then _validateString(from_, "deposit: invalid from")
507538 else false)
508539 then _validateString(to_, "deposit: invalid to")
509540 else false)
510541 then _assetCurrencyExists(chainId, asset_, "deposit: invalid asset")
511542 else false)
512543 then _validateBigInt(amount, ZERO_BIGINT, "deposit: invalid amount")
513544 else false
514545 if ((err == err))
515546 then {
516547 let err1 = if ((_loadChain(chainId) == WAVES))
517548 then _validateWavesVault(i.caller, "deposit: invalid waves vault")
518549 else if (_validateExecutor(i.caller, "deposit: invalid executor"))
519550 then _validateCallerContract(chainId, callerContract_, "deposit: invalid caller contract")
520551 else false
521552 if ((err1 == err1))
522553 then {
523554 let newAssetReserves = (_loadAssetReserves(chainId, asset_) + amount)
524555 let currency = _loadAssetCurrency(chainId, asset_)
525556 let newCurrencyReserves = (_loadCurrencyReserves(currency) + amount)
526557 let invocation = invoke(_loadAccountStorage(), FUNC_DEPOSIT, [to_, currency, amount_], nil)
527558 if ((invocation == invocation))
528559 then $Tuple2((_saveAssetReserves(chainId, asset_, newAssetReserves) ++ _saveCurrencyReserves(currency, newCurrencyReserves)), unit)
529560 else throw("Strict value is not equal to itself.")
530561 }
531562 else throw("Strict value is not equal to itself.")
532563 }
533564 else throw("Strict value is not equal to itself.")
534565 }
535566
536567
537568
538569 @Callable(i)
539570 func requestWithdrawal (callerContract_,from_,to_,fromChainId_,toChainId_,asset_,amount_) = {
540571 let fromChainId = valueOrErrorMessage(parseInt(fromChainId_), "requestWithdrawal: fromChainId not int")
541572 let toChainId = valueOrErrorMessage(parseInt(toChainId_), "requestWithdrawal: toChainId not int")
542573 let amount = valueOrErrorMessage(parseBigInt(amount_), "requestWithdrawal: amount not int")
543574 let err = if (if (if (if (if (if (_whenInitialized())
544575 then _chainExists(fromChainId, "requestWithdrawal: invalid fromChainId")
545576 else false)
546577 then _chainExists(toChainId, "requestWithdrawal: invalid toChainId")
547578 else false)
548579 then _validateString(from_, "requestWithdrawal: invalid from")
549580 else false)
550581 then _validateString(to_, "requestWithdrawal: invalid to")
551582 else false)
552583 then _assetCurrencyExists(toChainId, asset_, "requestWithdrawal: invalid asset")
553584 else false)
554585 then _validateBigInt(amount, ZERO_BIGINT, "requestWithdrawal: invalid amount")
555586 else false
556587 if ((err == err))
557588 then {
558589 let err1 = if ((_loadChain(fromChainId) == WAVES))
559590 then _validateWavesVault(i.caller, "requestWithdrawal: invalid waves vault")
560591 else if (_validateExecutor(i.caller, "requestWithdrawal: invalid executor"))
561592 then _validateCallerContract(fromChainId, callerContract_, "requestWithdrawal: invalid caller contract")
562593 else false
563594 if ((err1 == err1))
564595 then {
565596 let currency = _loadAssetCurrency(toChainId, asset_)
566597 let availableBalance = match invoke(_loadAccountStorage(), FUNC_GET_USER_BALANCE, [from_, SPOT_WALLET, currency], nil) {
567598 case a: String =>
568599 parseBigIntValue(a)
569600 case _ =>
570601 throw("requestWithdrawal: can't take available balance from storage")
571602 }
572603 if ((availableBalance == availableBalance))
573604 then {
574605 let lockedReserves = _loadAssetReservesLocked(toChainId, asset_)
575- let $t01823518744 = if (if ((availableBalance >= amount))
606+ let userLockedCurrency = _loadUserLockedCurrency(currency, from_)
607+ let $t01929519750 = if (if (((availableBalance - userLockedCurrency) >= amount))
576608 then ((_loadAssetReserves(toChainId, asset_) - lockedReserves) >= amount)
577609 else false)
578- then $Tuple3(REQUEST_STATUS_CREATED, invoke(_loadAccountStorage(), FUNC_INTERNAL_TRANSFER, [from_, SPOT_WALLET, WITHDRAWALS_WALLET, currency, amount_], nil), _saveAssetReservesLocked(toChainId, asset_, (lockedReserves + amount)))
579- else $Tuple3(REQUEST_STATUS_REJECTED, unit, nil)
580- if (($t01823518744 == $t01823518744))
581- then {
582- let reservesActions = $t01823518744._3
583- let storageInvocation = $t01823518744._2
584- let requestStatus = $t01823518744._1
585- let requestWithdrawalSize = _loadRequestWithdrawalSize()
586- let requestWithdrawal = $Tuple8(from_, to_, toChainId, asset_, amount, height, toBase58String(i.transactionId), requestStatus)
587- $Tuple2(((_saveRequestWithdrawal(requestWithdrawalSize, requestWithdrawal) ++ _saveRequestWithdrawalSize((requestWithdrawalSize + 1))) ++ reservesActions), requestWithdrawalSize)
588- }
589- else throw("Strict value is not equal to itself.")
610+ then $Tuple2(REQUEST_STATUS_CREATED, (_saveAssetReservesLocked(toChainId, asset_, (lockedReserves + amount)) ++ _saveUserLockedCurrency(currency, from_, (amount + userLockedCurrency))))
611+ else $Tuple2(REQUEST_STATUS_REJECTED, nil)
612+ let requestStatus = $t01929519750._1
613+ let reservesActions = $t01929519750._2
614+ let requestWithdrawalSize = _loadRequestWithdrawalSize()
615+ let requestWithdrawal = $Tuple8(from_, to_, toChainId, asset_, amount, height, toBase58String(i.transactionId), requestStatus)
616+ $Tuple2(((_saveRequestWithdrawal(requestWithdrawalSize, requestWithdrawal) ++ _saveRequestWithdrawalSize((requestWithdrawalSize + 1))) ++ reservesActions), requestWithdrawalSize)
590617 }
591618 else throw("Strict value is not equal to itself.")
592619 }
593620 else throw("Strict value is not equal to itself.")
594621 }
595622 else throw("Strict value is not equal to itself.")
596623 }
597624
598625
599626
600627 @Callable(i)
601628 func executeWithdrawal (callerContract_,chainId_,requestWithdrawalId_) = {
602629 let chainId = valueOrErrorMessage(parseInt(chainId_), "executeWithdrawal: chainId not int")
603630 let requestWithdrawalId = valueOrErrorMessage(parseInt(requestWithdrawalId_), "executeWithdrawal: requestWithdrawalId not int")
604631 let requestWithdrawalSize = _loadRequestWithdrawalSize()
605632 let err = if (if (_whenInitialized())
606633 then _chainExists(chainId, "executeWithdrawal: invalid chainId")
607634 else false)
608635 then _validateInt(requestWithdrawalId, 0, (requestWithdrawalSize - 1), "executeWithdrawal: invalid requestWithdrawalId")
609636 else false
610637 if ((err == err))
611638 then {
612639 let err1 = if ((_loadChain(chainId) == WAVES))
613640 then _validateWavesVault(i.caller, "executeWithdrawal: invalid waves vault")
614641 else if (_validateExecutor(i.caller, "executeWithdrawal: invalid executor"))
615642 then _validateCallerContract(chainId, callerContract_, "executeWithdrawal: invalid caller contract")
616643 else false
617644 if ((err1 == err1))
618645 then {
619646 let request = _loadRequestWithdrawal(requestWithdrawalId)
620647 let requestFrom = request._1
621648 let requestTo = request._2
622649 let requestToChainId = request._3
623650 let requestAsset = request._4
624651 let requestAmount = request._5
625652 let requestHeight = request._6
626653 let requestStatus = request._8
627654 let newAssetReserves = (_loadAssetReserves(requestToChainId, requestAsset) - requestAmount)
628655 let newAssetReservesLocked = (_loadAssetReservesLocked(requestToChainId, requestAsset) - requestAmount)
629656 let currency = _loadAssetCurrency(requestToChainId, requestAsset)
630657 let newCurrencyReserves = (_loadCurrencyReserves(currency) - requestAmount)
631- let err2 = if (if (if (if (_validateBigInt(newAssetReserves, ZERO_BIGINT, "executeWithdrawal: negative newAssetReserves"))
658+ let newUserLockedCurrency = (_loadUserLockedCurrency(currency, requestFrom) - requestAmount)
659+ let err2 = if (if (if (if (if (_validateBigInt(newAssetReserves, ZERO_BIGINT, "executeWithdrawal: negative newAssetReserves"))
632660 then _validateBigInt(newAssetReservesLocked, ZERO_BIGINT, "executeWithdrawal: negative newAssetReservesLocked")
633661 else false)
634662 then _validateBigInt(newCurrencyReserves, ZERO_BIGINT, "executeWithdrawal: negative newCurrencyReserves")
663+ else false)
664+ then _validateBigInt(newUserLockedCurrency, ZERO_BIGINT, "executeWithdrawal: negative newUserLockedCurrency")
635665 else false)
636666 then _validateInt((height - requestHeight), _loadRequestWithdrawalBlockDelay(), MAX_INT, "executeWithdrawal: too early to execute")
637667 else false)
638668 then _requestIsCreated(requestStatus, "executeWithdrawal: request is resolved")
639669 else false
640670 if ((err2 == err2))
641671 then {
642672 let storageInvocation = invoke(_loadAccountStorage(), FUNC_WITHDRAW, [requestFrom, currency, toString(requestAmount)], nil)
643673 if ((storageInvocation == storageInvocation))
644674 then {
645675 let withdrawInvocation = if ((_loadChain(requestToChainId) == WAVES))
646676 then invoke(_loadWavesVault(), FUNC_WITHDRAW, [requestTo, requestAsset, toString(requestAmount)], nil)
647677 else invoke(_loadVaultAdapter(), FUNC_WITHDRAW, [requestToChainId, requestAsset, toString(requestAmount), requestTo], nil)
648678 if ((withdrawInvocation == withdrawInvocation))
649679 then {
650680 let requestUpdated = $Tuple8(request._1, request._2, request._3, request._4, request._5, request._6, request._7, REQUEST_STATUS_DONE)
651- $Tuple2((((_saveAssetReserves(requestToChainId, requestAsset, newAssetReserves) ++ _saveAssetReservesLocked(requestToChainId, requestAsset, newAssetReservesLocked)) ++ _saveCurrencyReserves(currency, newCurrencyReserves)) ++ _saveRequestWithdrawal(requestWithdrawalId, requestUpdated)), unit)
681+ $Tuple2(((((_saveAssetReserves(requestToChainId, requestAsset, newAssetReserves) ++ _saveAssetReservesLocked(requestToChainId, requestAsset, newAssetReservesLocked)) ++ _saveCurrencyReserves(currency, newCurrencyReserves)) ++ _saveUserLockedCurrency(currency, requestFrom, newUserLockedCurrency)) ++ _saveRequestWithdrawal(requestWithdrawalId, requestUpdated)), unit)
652682 }
653683 else throw("Strict value is not equal to itself.")
654684 }
655685 else throw("Strict value is not equal to itself.")
656686 }
657687 else throw("Strict value is not equal to itself.")
658688 }
659689 else throw("Strict value is not equal to itself.")
660690 }
661691 else throw("Strict value is not equal to itself.")
662692 }
663693
664694
665695
666696 @Callable(i)
667-func withdraw (from_,to_,toChainId_,asset_,amount_,timestamp_,publicKey_,alg_,signature_) = {
697+func rejectWithdrawal (requestWithdrawalId_) = {
698+ let requestWithdrawalId = valueOrErrorMessage(parseInt(requestWithdrawalId_), "rejectWithdrawal: requestWithdrawalId not int")
699+ let requestWithdrawalSize = _loadRequestWithdrawalSize()
700+ let err = if (if (_whenInitialized())
701+ then _validateSequencer(i.caller, "rejectWithdrawal: invalid sequencer")
702+ else false)
703+ then _validateInt(requestWithdrawalId, 0, (requestWithdrawalSize - 1), "rejectWithdrawal: invalid requestWithdrawalId")
704+ else false
705+ if ((err == err))
706+ then {
707+ let request = _loadRequestWithdrawal(requestWithdrawalId)
708+ let requestFrom = request._1
709+ let requestTo = request._2
710+ let requestToChainId = request._3
711+ let requestAsset = request._4
712+ let requestAmount = request._5
713+ let requestHeight = request._6
714+ let requestStatus = request._8
715+ let currency = _loadAssetCurrency(requestToChainId, requestAsset)
716+ let newAssetReservesLocked = (_loadAssetReservesLocked(requestToChainId, requestAsset) - requestAmount)
717+ let newUserLockedCurrency = (_loadUserLockedCurrency(currency, requestFrom) - requestAmount)
718+ let err1 = if (if (_validateBigInt(newAssetReservesLocked, ZERO_BIGINT, "rejectWithdrawal: negative newAssetReservesLocked"))
719+ then _validateBigInt(newUserLockedCurrency, ZERO_BIGINT, "rejectWithdrawal: negative newUserLockedCurrency")
720+ else false)
721+ then _requestIsCreated(requestStatus, "rejectWithdrawal: request is resolved")
722+ else false
723+ if ((err1 == err1))
724+ then {
725+ let availableBalance = match invoke(_loadAccountStorage(), FUNC_GET_USER_BALANCE, [requestFrom, SPOT_WALLET, currency], nil) {
726+ case a: String =>
727+ parseBigIntValue(a)
728+ case _ =>
729+ throw("rejectWithdrawal: can't take available balance from storage")
730+ }
731+ if ((availableBalance == availableBalance))
732+ then if ((requestAmount > availableBalance))
733+ then {
734+ let requestUpdated = $Tuple8(request._1, request._2, request._3, request._4, request._5, request._6, request._7, REQUEST_STATUS_REJECTED)
735+ $Tuple2(((_saveAssetReservesLocked(requestToChainId, requestAsset, newAssetReservesLocked) ++ _saveUserLockedCurrency(currency, requestFrom, newUserLockedCurrency)) ++ _saveRequestWithdrawal(requestWithdrawalId, requestUpdated)), true)
736+ }
737+ else $Tuple2(nil, false)
738+ else throw("Strict value is not equal to itself.")
739+ }
740+ else throw("Strict value is not equal to itself.")
741+ }
742+ else throw("Strict value is not equal to itself.")
743+ }
744+
745+
746+
747+@Callable(i)
748+func withdraw (from_,to_,toChainId_,asset_,amount_,relayerFee_,timestamp_,web3Id_,alg_,signature_) = {
668749 let toChainId = valueOrErrorMessage(parseInt(toChainId_), "withdraw: toChainId not int")
669750 let amount = valueOrErrorMessage(parseBigInt(amount_), "withdraw: amount not int")
751+ let relayerFee = valueOrErrorMessage(parseBigInt(relayerFee_), "withdraw: relayerFee not int")
670752 let timestamp = valueOrErrorMessage(parseInt(timestamp_), "withdraw: timestamp not int")
671753 let alg = valueOrErrorMessage(parseInt(alg_), "withdraw: alg not int")
672- let publicKey = fromBase58String(publicKey_)
754+ let web3Id = fromBase58String(web3Id_)
673755 let signature = fromBase58String(signature_)
674- let err = if (if (if (if (if (if (if (if (if (if (_whenInitialized())
756+ let err = if (if (if (if (if (if (if (if (if (if (if (_whenInitialized())
675757 then _validateSequencer(i.caller, "withdraw: invalid sequencer")
676758 else false)
677759 then _validateString(from_, "withdraw: invalid from")
678760 else false)
679761 then _validateString(to_, "withdraw: invalid to")
680762 else false)
681763 then _chainExists(toChainId, "withdraw: invalid toChainId")
682764 else false)
683765 then _assetCurrencyExists(toChainId, asset_, "withdraw: invalid asset")
684766 else false)
685767 then _validateBigInt(amount, ZERO_BIGINT, "withdraw: invalid amount")
686768 else false)
769+ then _validateBigInt_2(relayerFee, ZERO_BIGINT, amount, "withdraw: invalid relayerFee")
770+ else false)
687771 then _validateInt((timestamp + ONE_DAY), lastBlock.timestamp, MAX_INT, "withdraw: invalid timestamp")
688772 else false)
689- then _validatePublicKey(publicKey, alg, "withdraw: inv public key")
773+ then _validateWeb3Id(web3Id, alg, "withdraw: inv web3Id")
690774 else false)
691775 then _validateSignatureFormat(signature, alg, "withdraw: inv sig format")
692776 else false)
693- then _validatePublicKeyMatchesAddress(publicKey, from_, alg, "withdraw: public key mismatch")
777+ then _validateWeb3IdMatchesAddress(web3Id, from_, alg, "withdraw: web3Id mismatch")
694778 else false
695779 if ((err == err))
696780 then {
697- let withdrawalBytes = ((((((((((toBytes(size(from_)) + toBytes(from_)) + toBytes(size(to_))) + toBytes(to_)) + toBytes(toChainId)) + toBytes(size(asset_))) + toBytes(asset_)) + toBytes(amount)) + toBytes(timestamp)) + publicKey) + toBytes(alg))
781+ let withdrawalBytes = (((((((((((toBytes(size(from_)) + toBytes(from_)) + toBytes(size(to_))) + toBytes(to_)) + toBytes(toChainId)) + toBytes(size(asset_))) + toBytes(asset_)) + toBytes(amount)) + toBytes(relayerFee)) + toBytes(timestamp)) + web3Id) + toBytes(alg))
698782 let withdrawalHash = keccak256_16Kb(withdrawalBytes)
699783 let currency = _loadAssetCurrency(toChainId, asset_)
700784 let availableBalance = match invoke(_loadAccountStorage(), FUNC_GET_USER_BALANCE, [from_, SPOT_WALLET, currency], nil) {
701785 case a: String =>
702786 parseBigIntValue(a)
703787 case _ =>
704788 throw("withdraw: can't take available balance from storage")
705789 }
706790 if ((availableBalance == availableBalance))
707791 then {
708792 let assetReserves = _loadAssetReserves(toChainId, asset_)
709793 let lockedReserves = _loadAssetReservesLocked(toChainId, asset_)
710- let err1 = if (if (if (_validateWithdrawalSignature(withdrawalHash, signature, publicKey, alg, "withdraw: invalid sig"))
794+ let amountToSend = (amount - relayerFee)
795+ let amountToSendStr = toString(amountToSend)
796+ let err1 = if (if (if (_validateWithdrawalSignature(withdrawalHash, signature, web3Id, alg, "withdraw: invalid sig"))
711797 then _checkWithdrawalHashNotExist(withdrawalHash, "withdraw: already executed")
712798 else false)
713- then _validateBigInt(availableBalance, amount, "withdraw: insufficient balance")
799+ then _validateBigInt(availableBalance, amountToSend, "withdraw: insufficient balance")
714800 else false)
715- then _validateBigInt((assetReserves - lockedReserves), amount, "withdraw: insufficient reserves")
801+ then _validateBigInt((assetReserves - lockedReserves), amountToSend, "withdraw: insufficient reserves")
716802 else false
717803 if ((err1 == err1))
718804 then {
719- let newAssetReserves = (assetReserves - amount)
720- let newCurrencyReserves = (_loadCurrencyReserves(currency) - amount)
805+ let newAssetReserves = (assetReserves - amountToSend)
806+ let newCurrencyReserves = (_loadCurrencyReserves(currency) - amountToSend)
721807 let err2 = if (_validateBigInt(newAssetReserves, ZERO_BIGINT, "withdraw: negative newAssetReserves"))
722808 then _validateBigInt(newCurrencyReserves, ZERO_BIGINT, "withdraw: negative newCurrencyReserves")
723809 else false
724810 if ((err2 == err2))
725811 then {
726- let storageInvocation = invoke(_loadAccountStorage(), FUNC_INTERNAL_TRANSFER, [from_, SPOT_WALLET, WITHDRAWALS_WALLET, currency, amount_], nil)
727- if ((storageInvocation == storageInvocation))
812+ let storageInvocation1 = invoke(_loadAccountStorage(), FUNC_WITHDRAW, [from_, currency, amount_], nil)
813+ if ((storageInvocation1 == storageInvocation1))
728814 then {
729- let storageInvocation1 = invoke(_loadAccountStorage(), FUNC_WITHDRAW, [from_, currency, amount_], nil)
730- if ((storageInvocation1 == storageInvocation1))
815+ let storageInvocation2 = invoke(_loadAccountStorage(), FUNC_DEPOSIT, [_loadRelayerFeeRecipient(), currency, relayerFee_], nil)
816+ if ((storageInvocation2 == storageInvocation2))
731817 then {
732818 let withdrawInvocation = if ((_loadChain(toChainId) == WAVES))
733- then invoke(_loadWavesVault(), FUNC_WITHDRAW, [to_, asset_, amount_], nil)
734- else invoke(_loadVaultAdapter(), FUNC_WITHDRAW, [toChainId, asset_, amount_, to_], nil)
819+ then invoke(_loadWavesVault(), FUNC_WITHDRAW, [to_, asset_, amountToSendStr], nil)
820+ else invoke(_loadVaultAdapter(), FUNC_WITHDRAW, [toChainId, asset_, amountToSendStr, to_, relayerFee_], nil)
735821 if ((withdrawInvocation == withdrawInvocation))
736822 then $Tuple2(((_saveAssetReserves(toChainId, asset_, newAssetReserves) ++ _saveCurrencyReserves(currency, newCurrencyReserves)) ++ _saveWithdrawalHash(withdrawalHash, toBase58String(i.transactionId))), unit)
737823 else throw("Strict value is not equal to itself.")
738824 }
739825 else throw("Strict value is not equal to itself.")
740826 }
741827 else throw("Strict value is not equal to itself.")
742828 }
743829 else throw("Strict value is not equal to itself.")
744830 }
745831 else throw("Strict value is not equal to itself.")
746832 }
747833 else throw("Strict value is not equal to itself.")
748834 }
749835 else throw("Strict value is not equal to itself.")
750836 }
751837
752838
753839
754840 @Callable(i)
755841 func depositStakingReward (callerContract_,chainId_,asset_,amount_) = {
756842 let chainId = valueOrErrorMessage(parseInt(chainId_), "depositStakingReward: chainId not int")
757843 let amount = valueOrErrorMessage(parseBigInt(amount_), "depositStakingReward: amount not int")
758844 let err = if (if (if (if (_whenInitialized())
759845 then _whenNotPaused()
760846 else false)
761847 then _chainExists(chainId, "depositStakingReward: invalid chainId")
762848 else false)
763849 then _assetCurrencyExists(chainId, asset_, "depositStakingReward: invalid asset")
764850 else false)
765851 then _validateBigInt(amount, ZERO_BIGINT, "depositStakingReward: invalid amount")
766852 else false
767853 if ((err == err))
768854 then {
769855 let err1 = if ((_loadChain(chainId) == WAVES))
770856 then _validateWavesVault(i.caller, "depositStakingReward: invalid waves vault")
771857 else if (_validateExecutor(i.caller, "depositStakingReward: invalid executor"))
772858 then _validateCallerContract(chainId, callerContract_, "depositStakingReward: invalid caller contract")
773859 else false
774860 if ((err1 == err1))
775861 then {
776862 let newAssetReserves = (_loadAssetReserves(chainId, asset_) + amount)
777863 let currency = _loadAssetCurrency(chainId, asset_)
778864 let newCurrencyReserves = (_loadCurrencyReserves(currency) + amount)
779865 let invocation = invoke(_loadAccountStorage(), FUNC_DEPOSIT_STAKING_REWARD, [_loadRewardDistributor(), currency, amount_], nil)
780866 if ((invocation == invocation))
781867 then $Tuple2((_saveAssetReserves(chainId, asset_, newAssetReserves) ++ _saveCurrencyReserves(currency, newCurrencyReserves)), unit)
782868 else throw("Strict value is not equal to itself.")
783869 }
784870 else throw("Strict value is not equal to itself.")
785871 }
786872 else throw("Strict value is not equal to itself.")
787873 }
788874
789875
790876
791877 @Callable(i)
792878 func addChain (chainId_,name_,callerContract_) = {
793879 let err = if (if (if (if (if (_onlyThisContract(i.caller))
794880 then _whenInitialized()
795881 else false)
796882 then _validateInt(chainId_, 0, MAX_INT, "addChain: invalid chainId")
797883 else false)
798884 then _validateString(name_, "addChain: invalid name")
799885 else false)
800886 then _validateString(callerContract_, "addChain: invalid callerContract")
801887 else false)
802888 then _chainNotExist(chainId_, "addChain: already exists")
803889 else false
804890 if ((err == err))
805891 then $Tuple2((_saveChain(chainId_, name_) ++ _saveCallerContract(chainId_, callerContract_)), unit)
806892 else throw("Strict value is not equal to itself.")
807893 }
808894
809895
810896
811897 @Callable(i)
812898 func addAsset (chainId_,asset_,currency_) = {
813899 let err = if (if (if (if (if (_onlyThisContract(i.caller))
814900 then _whenInitialized()
815901 else false)
816902 then _chainExists(chainId_, "addAsset: invalid chainId")
817903 else false)
818904 then _validateString(asset_, "addAsset: invalid asset")
819905 else false)
820906 then _validateString(currency_, "addAsset: invalid currency")
821907 else false)
822908 then _assetCurrencyNotExist(chainId_, asset_, "addAsset: already exists")
823909 else false
824910 if ((err == err))
825911 then $Tuple2(_saveAssetCurrency(chainId_, asset_, currency_), unit)
826912 else throw("Strict value is not equal to itself.")
827913 }
828914
829915
830916
831917 @Callable(i)
832918 func setRequestWithdrawalBlockDelay (delay_) = {
833919 let err = if (if (_onlyThisContract(i.caller))
834920 then _whenInitialized()
835921 else false)
836922 then _validateInt(delay_, 0, MAX_INT, "setRequestWithdrawalBlockDelay: invalid delay")
837923 else false
838924 if ((err == err))
839925 then $Tuple2(_saveRequestWithdrawalBlockDelay(delay_), unit)
840926 else throw("Strict value is not equal to itself.")
841927 }
842928
843929
844930
845931 @Callable(i)
846932 func updateRewardDistributor (rewardDistributor_) = {
847933 let err = if (if (_onlyThisContract(i.caller))
848934 then _whenInitialized()
849935 else false)
850936 then _validateString(rewardDistributor_, "updateRewardDistributor: invalid rewardDistributor")
851937 else false
852938 if ((err == err))
853939 then $Tuple2(_saveRewardDistributor(rewardDistributor_), unit)
854940 else throw("Strict value is not equal to itself.")
855941 }
856942
857943
858944
859945 @Callable(i)
946+func updateRelayerFeeRecipient (relayerFeeRecipient_) = {
947+ let err = if (if (_onlyThisContract(i.caller))
948+ then _whenInitialized()
949+ else false)
950+ then _validateString(relayerFeeRecipient_, "updateRelayerFeeRecipient: invalid relayerFeeRecipient")
951+ else false
952+ if ((err == err))
953+ then $Tuple2(_saveRelayerFeeRecipient(relayerFeeRecipient_), unit)
954+ else throw("Strict value is not equal to itself.")
955+ }
956+
957+
958+
959+@Callable(i)
860960 func pause () = {
861961 let err = if (if (_onlyPauser(i.caller))
862962 then _whenInitialized()
863963 else false)
864964 then _whenNotPaused()
865965 else false
866966 if ((err == err))
867967 then $Tuple2(_savePause(true), unit)
868968 else throw("Strict value is not equal to itself.")
869969 }
870970
871971
872972
873973 @Callable(i)
874974 func unpause () = {
875975 let err = if (if (_onlyPauser(i.caller))
876976 then _whenInitialized()
877977 else false)
878978 then _whenPaused()
879979 else false
880980 if ((err == err))
881981 then $Tuple2(_savePause(false), unit)
882982 else throw("Strict value is not equal to itself.")
883983 }
884984
885985
886986
887987 @Callable(i)
888988 func updatePauser (pauser_) = {
889989 let err = if (if (_onlyThisContract(i.caller))
890990 then _whenInitialized()
891991 else false)
892992 then _validateAddress(pauser_, "updatePauser: invalid pauser")
893993 else false
894994 if ((err == err))
895995 then $Tuple2(_savePauser(addressFromStringValue(pauser_)), unit)
896996 else throw("Strict value is not equal to itself.")
897997 }
898998
899999
9001000
9011001 @Callable(i)
9021002 func setMultisig (multisig_) = {
9031003 let err = if (_onlyThisContract(i.caller))
9041004 then _validateAddress(multisig_, "setMultisig: invalid multisig")
9051005 else false
9061006 if ((err == err))
9071007 then $Tuple2(_saveMultisig(addressFromStringValue(multisig_)), unit)
9081008 else throw("Strict value is not equal to itself.")
9091009 }
9101010
9111011
9121012 @Verifier(tx)
9131013 func verify () = match getString(KEY_MULTISIG) {
9141014 case multisig: String =>
9151015 valueOrElse(getBoolean(addressFromStringValue(multisig), makeString([KEY_STATUS, toString(this), toBase58String(tx.id)], SEPARATOR)), false)
9161016 case _ =>
9171017 sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
9181018 }
9191019

github/deemru/w8io/026f985 
100.63 ms