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:
Old | New | Differences | |
---|---|---|---|
29 | 29 | ||
30 | 30 | let KEY_ASSET_RESERVES_LOCKED = "ASSET_RESERVES_LOCKED" | |
31 | 31 | ||
32 | + | let KEY_USER_LOCKED_CURRENCY = "USER_LOCKED_CURRENCY" | |
33 | + | ||
32 | 34 | let KEY_CURRENCY_RESERVES = "CURRENCY_RESERVES" | |
33 | 35 | ||
34 | 36 | let KEY_REQUEST_WITHDRAWAL_SIZE = "REQUEST_WITHDRAWAL_SIZE" | |
44 | 46 | let KEY_VAULT_ADAPTER = "VAULT_ADAPTER" | |
45 | 47 | ||
46 | 48 | let KEY_REWARD_DISTRIBUTOR = "REWARD_DISTRIBUTOR" | |
49 | + | ||
50 | + | let KEY_RELAYER_FEE_RECIPIENT = "RELAYER_FEE_RECIPIENT" | |
47 | 51 | ||
48 | 52 | let FUNC_DEPOSIT = "deposit" | |
49 | 53 | ||
64 | 68 | let WAVES = "WAVES" | |
65 | 69 | ||
66 | 70 | let SPOT_WALLET = "SPOT" | |
67 | - | ||
68 | - | let WITHDRAWALS_WALLET = "WITHDRAWALS" | |
69 | 71 | ||
70 | 72 | let MAX_INT = 9223372036854775807 | |
71 | 73 | ||
97 | 99 | ||
98 | 100 | ||
99 | 101 | 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_)) | |
100 | 109 | then throw(err_) | |
101 | 110 | else true | |
102 | 111 | ||
245 | 254 | func _saveAssetReservesLocked (chainId_,asset_,reserves_) = [StringEntry(makeString([KEY_ASSET_RESERVES_LOCKED, toString(chainId_), asset_], SEPARATOR), toString(reserves_))] | |
246 | 255 | ||
247 | 256 | ||
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 | + | ||
248 | 268 | func _loadCurrencyReserves (currency_) = match getString(makeString([KEY_CURRENCY_RESERVES, currency_], SEPARATOR)) { | |
249 | 269 | case a: String => | |
250 | 270 | parseBigIntValue(a) | |
332 | 352 | ||
333 | 353 | ||
334 | 354 | 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_)] | |
335 | 366 | ||
336 | 367 | ||
337 | 368 | func _onlyThisContract (caller_) = if ((caller_ != this)) | |
430 | 461 | else throw((err_ + ": inv alg")) | |
431 | 462 | ||
432 | 463 | ||
433 | - | func _ | |
434 | - | then if ((size( | |
464 | + | func _validateWeb3Id (web3Id_,alg_,err_) = if ((alg_ == ALG_TYPE_WAVES)) | |
465 | + | then if ((size(web3Id_) != 32)) | |
435 | 466 | then throw(err_) | |
436 | 467 | else true | |
437 | 468 | else if ((alg_ == ALG_TYPE_EVM)) | |
438 | - | then if ((size( | |
469 | + | then if ((size(web3Id_) != 20)) | |
439 | 470 | then throw(err_) | |
440 | 471 | else true | |
441 | 472 | else throw((err_ + ": inv alg")) | |
442 | 473 | ||
443 | 474 | ||
444 | - | func _validateWithdrawalSignature (withdrawalHash_,signature_, | |
475 | + | func _validateWithdrawalSignature (withdrawalHash_,signature_,web3Id_,alg_,err_) = { | |
445 | 476 | let result = if ((alg_ == ALG_TYPE_WAVES)) | |
446 | - | then sigVerify(withdrawalHash_, signature_, | |
477 | + | then sigVerify(withdrawalHash_, signature_, web3Id_) | |
447 | 478 | else if ((alg_ == ALG_TYPE_EVM)) | |
448 | 479 | then { | |
449 | 480 | let hashWithPrefix = keccak256_16Kb((EVM_SIGNATURE_PREFIX + withdrawalHash_)) | |
450 | - | (takeRight(keccak256_16Kb(ecrecover(hashWithPrefix, signature_)), 20) == | |
481 | + | (takeRight(keccak256_16Kb(ecrecover(hashWithPrefix, signature_)), 20) == web3Id_) | |
451 | 482 | } | |
452 | 483 | else throw((err_ + ": inv alg")) | |
453 | 484 | if (!(result)) | |
456 | 487 | } | |
457 | 488 | ||
458 | 489 | ||
459 | - | func _ | |
490 | + | func _validateWeb3IdMatchesAddress (web3Id_,from_,alg_,err_) = { | |
460 | 491 | let address = if ((alg_ == ALG_TYPE_WAVES)) | |
461 | - | then toString(addressFromPublicKey( | |
492 | + | then toString(addressFromPublicKey(web3Id_)) | |
462 | 493 | else if ((alg_ == ALG_TYPE_EVM)) | |
463 | - | then ("0x" + toBase16String( | |
494 | + | then ("0x" + toBase16String(web3Id_)) | |
464 | 495 | else throw((err_ + ": inv alg")) | |
465 | 496 | if ((address != from_)) | |
466 | 497 | then throw(err_) | |
572 | 603 | if ((availableBalance == availableBalance)) | |
573 | 604 | then { | |
574 | 605 | 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)) | |
576 | 608 | then ((_loadAssetReserves(toChainId, asset_) - lockedReserves) >= amount) | |
577 | 609 | 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) | |
590 | 617 | } | |
591 | 618 | else throw("Strict value is not equal to itself.") | |
592 | 619 | } | |
628 | 655 | let newAssetReservesLocked = (_loadAssetReservesLocked(requestToChainId, requestAsset) - requestAmount) | |
629 | 656 | let currency = _loadAssetCurrency(requestToChainId, requestAsset) | |
630 | 657 | 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")) | |
632 | 660 | then _validateBigInt(newAssetReservesLocked, ZERO_BIGINT, "executeWithdrawal: negative newAssetReservesLocked") | |
633 | 661 | else false) | |
634 | 662 | then _validateBigInt(newCurrencyReserves, ZERO_BIGINT, "executeWithdrawal: negative newCurrencyReserves") | |
663 | + | else false) | |
664 | + | then _validateBigInt(newUserLockedCurrency, ZERO_BIGINT, "executeWithdrawal: negative newUserLockedCurrency") | |
635 | 665 | else false) | |
636 | 666 | then _validateInt((height - requestHeight), _loadRequestWithdrawalBlockDelay(), MAX_INT, "executeWithdrawal: too early to execute") | |
637 | 667 | else false) | |
648 | 678 | if ((withdrawInvocation == withdrawInvocation)) | |
649 | 679 | then { | |
650 | 680 | 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) | |
652 | 682 | } | |
653 | 683 | else throw("Strict value is not equal to itself.") | |
654 | 684 | } | |
664 | 694 | ||
665 | 695 | ||
666 | 696 | @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_) = { | |
668 | 749 | let toChainId = valueOrErrorMessage(parseInt(toChainId_), "withdraw: toChainId not int") | |
669 | 750 | let amount = valueOrErrorMessage(parseBigInt(amount_), "withdraw: amount not int") | |
751 | + | let relayerFee = valueOrErrorMessage(parseBigInt(relayerFee_), "withdraw: relayerFee not int") | |
670 | 752 | let timestamp = valueOrErrorMessage(parseInt(timestamp_), "withdraw: timestamp not int") | |
671 | 753 | let alg = valueOrErrorMessage(parseInt(alg_), "withdraw: alg not int") | |
672 | - | let | |
754 | + | let web3Id = fromBase58String(web3Id_) | |
673 | 755 | 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()) | |
675 | 757 | then _validateSequencer(i.caller, "withdraw: invalid sequencer") | |
676 | 758 | else false) | |
677 | 759 | then _validateString(from_, "withdraw: invalid from") | |
684 | 766 | else false) | |
685 | 767 | then _validateBigInt(amount, ZERO_BIGINT, "withdraw: invalid amount") | |
686 | 768 | else false) | |
769 | + | then _validateBigInt_2(relayerFee, ZERO_BIGINT, amount, "withdraw: invalid relayerFee") | |
770 | + | else false) | |
687 | 771 | then _validateInt((timestamp + ONE_DAY), lastBlock.timestamp, MAX_INT, "withdraw: invalid timestamp") | |
688 | 772 | else false) | |
689 | - | then _ | |
773 | + | then _validateWeb3Id(web3Id, alg, "withdraw: inv web3Id") | |
690 | 774 | else false) | |
691 | 775 | then _validateSignatureFormat(signature, alg, "withdraw: inv sig format") | |
692 | 776 | else false) | |
693 | - | then _ | |
777 | + | then _validateWeb3IdMatchesAddress(web3Id, from_, alg, "withdraw: web3Id mismatch") | |
694 | 778 | else false | |
695 | 779 | if ((err == err)) | |
696 | 780 | 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)) + | |
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)) | |
698 | 782 | let withdrawalHash = keccak256_16Kb(withdrawalBytes) | |
699 | 783 | let currency = _loadAssetCurrency(toChainId, asset_) | |
700 | 784 | let availableBalance = match invoke(_loadAccountStorage(), FUNC_GET_USER_BALANCE, [from_, SPOT_WALLET, currency], nil) { | |
707 | 791 | then { | |
708 | 792 | let assetReserves = _loadAssetReserves(toChainId, asset_) | |
709 | 793 | 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")) | |
711 | 797 | then _checkWithdrawalHashNotExist(withdrawalHash, "withdraw: already executed") | |
712 | 798 | else false) | |
713 | - | then _validateBigInt(availableBalance, | |
799 | + | then _validateBigInt(availableBalance, amountToSend, "withdraw: insufficient balance") | |
714 | 800 | else false) | |
715 | - | then _validateBigInt((assetReserves - lockedReserves), | |
801 | + | then _validateBigInt((assetReserves - lockedReserves), amountToSend, "withdraw: insufficient reserves") | |
716 | 802 | else false | |
717 | 803 | if ((err1 == err1)) | |
718 | 804 | then { | |
719 | - | let newAssetReserves = (assetReserves - | |
720 | - | let newCurrencyReserves = (_loadCurrencyReserves(currency) - | |
805 | + | let newAssetReserves = (assetReserves - amountToSend) | |
806 | + | let newCurrencyReserves = (_loadCurrencyReserves(currency) - amountToSend) | |
721 | 807 | let err2 = if (_validateBigInt(newAssetReserves, ZERO_BIGINT, "withdraw: negative newAssetReserves")) | |
722 | 808 | then _validateBigInt(newCurrencyReserves, ZERO_BIGINT, "withdraw: negative newCurrencyReserves") | |
723 | 809 | else false | |
724 | 810 | if ((err2 == err2)) | |
725 | 811 | then { | |
726 | - | let | |
727 | - | if (( | |
812 | + | let storageInvocation1 = invoke(_loadAccountStorage(), FUNC_WITHDRAW, [from_, currency, amount_], nil) | |
813 | + | if ((storageInvocation1 == storageInvocation1)) | |
728 | 814 | then { | |
729 | - | let | |
730 | - | if (( | |
815 | + | let storageInvocation2 = invoke(_loadAccountStorage(), FUNC_DEPOSIT, [_loadRelayerFeeRecipient(), currency, relayerFee_], nil) | |
816 | + | if ((storageInvocation2 == storageInvocation2)) | |
731 | 817 | then { | |
732 | 818 | let withdrawInvocation = if ((_loadChain(toChainId) == WAVES)) | |
733 | - | then invoke(_loadWavesVault(), FUNC_WITHDRAW, [to_, asset_, | |
734 | - | else invoke(_loadVaultAdapter(), FUNC_WITHDRAW, [toChainId, asset_, | |
819 | + | then invoke(_loadWavesVault(), FUNC_WITHDRAW, [to_, asset_, amountToSendStr], nil) | |
820 | + | else invoke(_loadVaultAdapter(), FUNC_WITHDRAW, [toChainId, asset_, amountToSendStr, to_, relayerFee_], nil) | |
735 | 821 | if ((withdrawInvocation == withdrawInvocation)) | |
736 | 822 | then $Tuple2(((_saveAssetReserves(toChainId, asset_, newAssetReserves) ++ _saveCurrencyReserves(currency, newCurrencyReserves)) ++ _saveWithdrawalHash(withdrawalHash, toBase58String(i.transactionId))), unit) | |
737 | 823 | else throw("Strict value is not equal to itself.") | |
857 | 943 | ||
858 | 944 | ||
859 | 945 | @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) | |
860 | 960 | func pause () = { | |
861 | 961 | let err = if (if (_onlyPauser(i.caller)) | |
862 | 962 | then _whenInitialized() |
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 7 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | 4 | let SEPARATOR = "__" | |
5 | 5 | ||
6 | 6 | let KEY_MULTISIG = "MULTISIG" | |
7 | 7 | ||
8 | 8 | let KEY_STATUS = "STATUS" | |
9 | 9 | ||
10 | 10 | let KEY_INIT = "INIT" | |
11 | 11 | ||
12 | 12 | let KEY_PAUSED = "PAUSED" | |
13 | 13 | ||
14 | 14 | let KEY_PAUSER = "PAUSER" | |
15 | 15 | ||
16 | 16 | let KEY_EXECUTOR = "EXECUTOR" | |
17 | 17 | ||
18 | 18 | let KEY_CALLER_CONTRACT = "CALLER_CONTRACT" | |
19 | 19 | ||
20 | 20 | let KEY_WAVES_VAULT = "WAVES_VAULT" | |
21 | 21 | ||
22 | 22 | let KEY_ACCOUNT_STORAGE = "ACCOUNT_STORAGE" | |
23 | 23 | ||
24 | 24 | let KEY_CHAIN = "CHAIN" | |
25 | 25 | ||
26 | 26 | let KEY_ASSET_CURRENCY = "ASSET_CURRENCY" | |
27 | 27 | ||
28 | 28 | let KEY_ASSET_RESERVES = "ASSET_RESERVES" | |
29 | 29 | ||
30 | 30 | let KEY_ASSET_RESERVES_LOCKED = "ASSET_RESERVES_LOCKED" | |
31 | 31 | ||
32 | + | let KEY_USER_LOCKED_CURRENCY = "USER_LOCKED_CURRENCY" | |
33 | + | ||
32 | 34 | let KEY_CURRENCY_RESERVES = "CURRENCY_RESERVES" | |
33 | 35 | ||
34 | 36 | let KEY_REQUEST_WITHDRAWAL_SIZE = "REQUEST_WITHDRAWAL_SIZE" | |
35 | 37 | ||
36 | 38 | let KEY_REQUEST_WITHDRAWAL = "REQUEST_WITHDRAWAL" | |
37 | 39 | ||
38 | 40 | let KEY_REQUEST_WITHDRAWAL_BLOCK_DELAY = "REQUEST_WITHDRAWAL_BLOCK_DELAY" | |
39 | 41 | ||
40 | 42 | let KEY_SEQUENCER = "SEQUENCER" | |
41 | 43 | ||
42 | 44 | let KEY_WITHDRAWAL_HASH = "WITHDRAWAL_HASH" | |
43 | 45 | ||
44 | 46 | let KEY_VAULT_ADAPTER = "VAULT_ADAPTER" | |
45 | 47 | ||
46 | 48 | let KEY_REWARD_DISTRIBUTOR = "REWARD_DISTRIBUTOR" | |
49 | + | ||
50 | + | let KEY_RELAYER_FEE_RECIPIENT = "RELAYER_FEE_RECIPIENT" | |
47 | 51 | ||
48 | 52 | let FUNC_DEPOSIT = "deposit" | |
49 | 53 | ||
50 | 54 | let FUNC_GET_USER_BALANCE = "getUserBalance" | |
51 | 55 | ||
52 | 56 | let FUNC_INTERNAL_TRANSFER = "internalTransfer" | |
53 | 57 | ||
54 | 58 | let FUNC_WITHDRAW = "withdraw" | |
55 | 59 | ||
56 | 60 | let FUNC_DEPOSIT_STAKING_REWARD = "depositStakingReward" | |
57 | 61 | ||
58 | 62 | let REQUEST_STATUS_CREATED = 0 | |
59 | 63 | ||
60 | 64 | let REQUEST_STATUS_DONE = 1 | |
61 | 65 | ||
62 | 66 | let REQUEST_STATUS_REJECTED = 2 | |
63 | 67 | ||
64 | 68 | let WAVES = "WAVES" | |
65 | 69 | ||
66 | 70 | let SPOT_WALLET = "SPOT" | |
67 | - | ||
68 | - | let WITHDRAWALS_WALLET = "WITHDRAWALS" | |
69 | 71 | ||
70 | 72 | let MAX_INT = 9223372036854775807 | |
71 | 73 | ||
72 | 74 | let ZERO_BIGINT = toBigInt(0) | |
73 | 75 | ||
74 | 76 | let ONE_BIGINT = toBigInt(1) | |
75 | 77 | ||
76 | 78 | let ONE_DAY = 86400000 | |
77 | 79 | ||
78 | 80 | let ALG_TYPE_WAVES = 1 | |
79 | 81 | ||
80 | 82 | let ALG_TYPE_EVM = 2 | |
81 | 83 | ||
82 | 84 | let EVM_SIGNATURE_PREFIX = base58'G5Nu92G2p7moXW9qjjN3na7gtq4dWCeVdaSjry' | |
83 | 85 | ||
84 | 86 | func _validateAddress (address_,err_) = match addressFromString(address_) { | |
85 | 87 | case a: Address => | |
86 | 88 | true | |
87 | 89 | case _ => | |
88 | 90 | throw(err_) | |
89 | 91 | } | |
90 | 92 | ||
91 | 93 | ||
92 | 94 | func _validateInt (val_,lowerBoundary_,upperBoundary_,err_) = if (if ((lowerBoundary_ > val_)) | |
93 | 95 | then true | |
94 | 96 | else (val_ > upperBoundary_)) | |
95 | 97 | then throw(err_) | |
96 | 98 | else true | |
97 | 99 | ||
98 | 100 | ||
99 | 101 | 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_)) | |
100 | 109 | then throw(err_) | |
101 | 110 | else true | |
102 | 111 | ||
103 | 112 | ||
104 | 113 | func _validateString (val_,err_) = if (if ((0 >= size(val_))) | |
105 | 114 | then true | |
106 | 115 | else contains(val_, SEPARATOR)) | |
107 | 116 | then throw(err_) | |
108 | 117 | else true | |
109 | 118 | ||
110 | 119 | ||
111 | 120 | func _validateStringEqual (val1_,val2_,err_) = if ((val1_ != val2_)) | |
112 | 121 | then throw(err_) | |
113 | 122 | else true | |
114 | 123 | ||
115 | 124 | ||
116 | 125 | func _loadInit () = match getBoolean(KEY_INIT) { | |
117 | 126 | case a: Boolean => | |
118 | 127 | a | |
119 | 128 | case _ => | |
120 | 129 | false | |
121 | 130 | } | |
122 | 131 | ||
123 | 132 | ||
124 | 133 | func _saveInit (isInit_) = [BooleanEntry(KEY_INIT, isInit_)] | |
125 | 134 | ||
126 | 135 | ||
127 | 136 | func _loadPause () = match getBoolean(KEY_PAUSED) { | |
128 | 137 | case a: Boolean => | |
129 | 138 | a | |
130 | 139 | case _ => | |
131 | 140 | false | |
132 | 141 | } | |
133 | 142 | ||
134 | 143 | ||
135 | 144 | func _savePause (isPaused_) = [BooleanEntry(KEY_PAUSED, isPaused_)] | |
136 | 145 | ||
137 | 146 | ||
138 | 147 | func _loadPauser () = match getString(KEY_PAUSER) { | |
139 | 148 | case a: String => | |
140 | 149 | addressFromStringValue(a) | |
141 | 150 | case _ => | |
142 | 151 | Address(base58'') | |
143 | 152 | } | |
144 | 153 | ||
145 | 154 | ||
146 | 155 | func _savePauser (pauser_) = [StringEntry(KEY_PAUSER, toString(pauser_))] | |
147 | 156 | ||
148 | 157 | ||
149 | 158 | func _loadMultisig () = match getString(KEY_MULTISIG) { | |
150 | 159 | case a: String => | |
151 | 160 | addressFromStringValue(a) | |
152 | 161 | case _ => | |
153 | 162 | Address(base58'') | |
154 | 163 | } | |
155 | 164 | ||
156 | 165 | ||
157 | 166 | func _saveMultisig (multisig_) = [StringEntry(KEY_MULTISIG, toString(multisig_))] | |
158 | 167 | ||
159 | 168 | ||
160 | 169 | func _loadCallerContract (chainId_) = match getString(makeString([KEY_CALLER_CONTRACT, toString(chainId_)], SEPARATOR)) { | |
161 | 170 | case a: String => | |
162 | 171 | a | |
163 | 172 | case _ => | |
164 | 173 | "" | |
165 | 174 | } | |
166 | 175 | ||
167 | 176 | ||
168 | 177 | func _saveCallerContract (chainId_,callerContract_) = [StringEntry(makeString([KEY_CALLER_CONTRACT, toString(chainId_)], SEPARATOR), callerContract_)] | |
169 | 178 | ||
170 | 179 | ||
171 | 180 | func _loadExecutor () = match getString(KEY_EXECUTOR) { | |
172 | 181 | case a: String => | |
173 | 182 | addressFromStringValue(a) | |
174 | 183 | case _ => | |
175 | 184 | Address(base58'') | |
176 | 185 | } | |
177 | 186 | ||
178 | 187 | ||
179 | 188 | func _saveExecutor (executor_) = [StringEntry(KEY_EXECUTOR, toString(executor_))] | |
180 | 189 | ||
181 | 190 | ||
182 | 191 | func _loadAccountStorage () = match getString(KEY_ACCOUNT_STORAGE) { | |
183 | 192 | case a: String => | |
184 | 193 | addressFromStringValue(a) | |
185 | 194 | case _ => | |
186 | 195 | Address(base58'') | |
187 | 196 | } | |
188 | 197 | ||
189 | 198 | ||
190 | 199 | func _saveAccountStorage (accountStorage_) = [StringEntry(KEY_ACCOUNT_STORAGE, toString(accountStorage_))] | |
191 | 200 | ||
192 | 201 | ||
193 | 202 | func _loadWavesVault () = match getString(KEY_WAVES_VAULT) { | |
194 | 203 | case a: String => | |
195 | 204 | addressFromStringValue(a) | |
196 | 205 | case _ => | |
197 | 206 | Address(base58'') | |
198 | 207 | } | |
199 | 208 | ||
200 | 209 | ||
201 | 210 | func _saveWavesVault (wavesVault_) = [StringEntry(KEY_WAVES_VAULT, toString(wavesVault_))] | |
202 | 211 | ||
203 | 212 | ||
204 | 213 | func _loadChain (chainId_) = match getString(makeString([KEY_CHAIN, toString(chainId_)], SEPARATOR)) { | |
205 | 214 | case a: String => | |
206 | 215 | a | |
207 | 216 | case _ => | |
208 | 217 | "" | |
209 | 218 | } | |
210 | 219 | ||
211 | 220 | ||
212 | 221 | func _saveChain (chainId_,name_) = [StringEntry(makeString([KEY_CHAIN, toString(chainId_)], SEPARATOR), name_)] | |
213 | 222 | ||
214 | 223 | ||
215 | 224 | func _loadAssetCurrency (chainId_,asset_) = match getString(makeString([KEY_ASSET_CURRENCY, toString(chainId_), asset_], SEPARATOR)) { | |
216 | 225 | case a: String => | |
217 | 226 | a | |
218 | 227 | case _ => | |
219 | 228 | "" | |
220 | 229 | } | |
221 | 230 | ||
222 | 231 | ||
223 | 232 | func _saveAssetCurrency (chainId_,asset_,currency_) = [StringEntry(makeString([KEY_ASSET_CURRENCY, toString(chainId_), asset_], SEPARATOR), currency_)] | |
224 | 233 | ||
225 | 234 | ||
226 | 235 | func _loadAssetReserves (chainId_,asset_) = match getString(makeString([KEY_ASSET_RESERVES, toString(chainId_), asset_], SEPARATOR)) { | |
227 | 236 | case a: String => | |
228 | 237 | parseBigIntValue(a) | |
229 | 238 | case _ => | |
230 | 239 | ZERO_BIGINT | |
231 | 240 | } | |
232 | 241 | ||
233 | 242 | ||
234 | 243 | func _saveAssetReserves (chainId_,asset_,reserves_) = [StringEntry(makeString([KEY_ASSET_RESERVES, toString(chainId_), asset_], SEPARATOR), toString(reserves_))] | |
235 | 244 | ||
236 | 245 | ||
237 | 246 | func _loadAssetReservesLocked (chainId_,asset_) = match getString(makeString([KEY_ASSET_RESERVES_LOCKED, toString(chainId_), asset_], SEPARATOR)) { | |
238 | 247 | case a: String => | |
239 | 248 | parseBigIntValue(a) | |
240 | 249 | case _ => | |
241 | 250 | ZERO_BIGINT | |
242 | 251 | } | |
243 | 252 | ||
244 | 253 | ||
245 | 254 | func _saveAssetReservesLocked (chainId_,asset_,reserves_) = [StringEntry(makeString([KEY_ASSET_RESERVES_LOCKED, toString(chainId_), asset_], SEPARATOR), toString(reserves_))] | |
246 | 255 | ||
247 | 256 | ||
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 | + | ||
248 | 268 | func _loadCurrencyReserves (currency_) = match getString(makeString([KEY_CURRENCY_RESERVES, currency_], SEPARATOR)) { | |
249 | 269 | case a: String => | |
250 | 270 | parseBigIntValue(a) | |
251 | 271 | case _ => | |
252 | 272 | ZERO_BIGINT | |
253 | 273 | } | |
254 | 274 | ||
255 | 275 | ||
256 | 276 | func _saveCurrencyReserves (currency_,reserves_) = [StringEntry(makeString([KEY_CURRENCY_RESERVES, currency_], SEPARATOR), toString(reserves_))] | |
257 | 277 | ||
258 | 278 | ||
259 | 279 | func _loadRequestWithdrawalSize () = match getInteger(KEY_REQUEST_WITHDRAWAL_SIZE) { | |
260 | 280 | case a: Int => | |
261 | 281 | a | |
262 | 282 | case _ => | |
263 | 283 | 0 | |
264 | 284 | } | |
265 | 285 | ||
266 | 286 | ||
267 | 287 | func _saveRequestWithdrawalSize (val_) = [IntegerEntry(KEY_REQUEST_WITHDRAWAL_SIZE, val_)] | |
268 | 288 | ||
269 | 289 | ||
270 | 290 | func _loadRequestWithdrawal (index_) = match getString(makeString([KEY_REQUEST_WITHDRAWAL, toString(index_)], SEPARATOR)) { | |
271 | 291 | case a: String => | |
272 | 292 | let struct = split(a, SEPARATOR) | |
273 | 293 | $Tuple8(struct[0], struct[1], parseIntValue(struct[2]), struct[3], parseBigIntValue(struct[4]), parseIntValue(struct[5]), struct[6], parseIntValue(struct[7])) | |
274 | 294 | case _ => | |
275 | 295 | $Tuple8("", "", 0, "", ZERO_BIGINT, 0, "", REQUEST_STATUS_CREATED) | |
276 | 296 | } | |
277 | 297 | ||
278 | 298 | ||
279 | 299 | 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))] | |
280 | 300 | ||
281 | 301 | ||
282 | 302 | func _loadRequestWithdrawalBlockDelay () = match getInteger(KEY_REQUEST_WITHDRAWAL_BLOCK_DELAY) { | |
283 | 303 | case a: Int => | |
284 | 304 | a | |
285 | 305 | case _ => | |
286 | 306 | 0 | |
287 | 307 | } | |
288 | 308 | ||
289 | 309 | ||
290 | 310 | func _saveRequestWithdrawalBlockDelay (delay_) = [IntegerEntry(KEY_REQUEST_WITHDRAWAL_BLOCK_DELAY, delay_)] | |
291 | 311 | ||
292 | 312 | ||
293 | 313 | func _loadSequencer () = match getString(KEY_SEQUENCER) { | |
294 | 314 | case a: String => | |
295 | 315 | addressFromStringValue(a) | |
296 | 316 | case _ => | |
297 | 317 | Address(base58'') | |
298 | 318 | } | |
299 | 319 | ||
300 | 320 | ||
301 | 321 | func _saveSequencer (sequencer_) = [StringEntry(KEY_SEQUENCER, toString(sequencer_))] | |
302 | 322 | ||
303 | 323 | ||
304 | 324 | func _loadWithdrawalHash (withdrawalHash_) = match getString(makeString([KEY_WITHDRAWAL_HASH, toBase58String(withdrawalHash_)], SEPARATOR)) { | |
305 | 325 | case a: String => | |
306 | 326 | a | |
307 | 327 | case _ => | |
308 | 328 | "" | |
309 | 329 | } | |
310 | 330 | ||
311 | 331 | ||
312 | 332 | func _saveWithdrawalHash (withdrawalHash_,txId_) = [StringEntry(makeString([KEY_WITHDRAWAL_HASH, toBase58String(withdrawalHash_)], SEPARATOR), txId_)] | |
313 | 333 | ||
314 | 334 | ||
315 | 335 | func _loadVaultAdapter () = match getString(KEY_VAULT_ADAPTER) { | |
316 | 336 | case a: String => | |
317 | 337 | addressFromStringValue(a) | |
318 | 338 | case _ => | |
319 | 339 | Address(base58'') | |
320 | 340 | } | |
321 | 341 | ||
322 | 342 | ||
323 | 343 | func _saveVaultAdapter (vaultAdapter_) = [StringEntry(KEY_VAULT_ADAPTER, toString(vaultAdapter_))] | |
324 | 344 | ||
325 | 345 | ||
326 | 346 | func _loadRewardDistributor () = match getString(KEY_REWARD_DISTRIBUTOR) { | |
327 | 347 | case a: String => | |
328 | 348 | a | |
329 | 349 | case _ => | |
330 | 350 | "" | |
331 | 351 | } | |
332 | 352 | ||
333 | 353 | ||
334 | 354 | 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_)] | |
335 | 366 | ||
336 | 367 | ||
337 | 368 | func _onlyThisContract (caller_) = if ((caller_ != this)) | |
338 | 369 | then throw("_onlyThisContract: revert") | |
339 | 370 | else true | |
340 | 371 | ||
341 | 372 | ||
342 | 373 | func _whenMultisigSet () = if ((_loadMultisig() == Address(base58''))) | |
343 | 374 | then throw("_whenMultisigSet: revert") | |
344 | 375 | else true | |
345 | 376 | ||
346 | 377 | ||
347 | 378 | func _whenNotInitialized () = if (_loadInit()) | |
348 | 379 | then throw("_whenNotInitialized: revert") | |
349 | 380 | else true | |
350 | 381 | ||
351 | 382 | ||
352 | 383 | func _whenInitialized () = if (!(_loadInit())) | |
353 | 384 | then throw("_whenInitialized: revert") | |
354 | 385 | else true | |
355 | 386 | ||
356 | 387 | ||
357 | 388 | func _whenNotPaused () = if (_loadPause()) | |
358 | 389 | then throw("_whenNotPaused: revert") | |
359 | 390 | else true | |
360 | 391 | ||
361 | 392 | ||
362 | 393 | func _whenPaused () = if (!(_loadPause())) | |
363 | 394 | then throw("_whenPaused: revert") | |
364 | 395 | else true | |
365 | 396 | ||
366 | 397 | ||
367 | 398 | func _onlyPauser (caller_) = if ((caller_ != _loadPauser())) | |
368 | 399 | then throw("_onlyPauser: revert") | |
369 | 400 | else true | |
370 | 401 | ||
371 | 402 | ||
372 | 403 | func _validateExecutor (val_,err_) = if ((val_ != _loadExecutor())) | |
373 | 404 | then throw(err_) | |
374 | 405 | else true | |
375 | 406 | ||
376 | 407 | ||
377 | 408 | func _validateCallerContract (chainId_,callerContract_,err_) = if ((_loadCallerContract(chainId_) != callerContract_)) | |
378 | 409 | then throw(err_) | |
379 | 410 | else true | |
380 | 411 | ||
381 | 412 | ||
382 | 413 | func _chainExists (chainId_,err_) = if ((0 >= size(_loadChain(chainId_)))) | |
383 | 414 | then throw(err_) | |
384 | 415 | else true | |
385 | 416 | ||
386 | 417 | ||
387 | 418 | func _chainNotExist (chainId_,err_) = if ((size(_loadChain(chainId_)) > 0)) | |
388 | 419 | then throw(err_) | |
389 | 420 | else true | |
390 | 421 | ||
391 | 422 | ||
392 | 423 | func _assetCurrencyExists (chainId_,asset_,err_) = if ((0 >= size(_loadAssetCurrency(chainId_, asset_)))) | |
393 | 424 | then throw(err_) | |
394 | 425 | else true | |
395 | 426 | ||
396 | 427 | ||
397 | 428 | func _assetCurrencyNotExist (chainId_,asset_,err_) = if ((size(_loadAssetCurrency(chainId_, asset_)) > 0)) | |
398 | 429 | then throw(err_) | |
399 | 430 | else true | |
400 | 431 | ||
401 | 432 | ||
402 | 433 | func _validateWavesVault (caller,err_) = if ((_loadWavesVault() != caller)) | |
403 | 434 | then throw(err_) | |
404 | 435 | else true | |
405 | 436 | ||
406 | 437 | ||
407 | 438 | func _requestIsCreated (status_,err_) = if ((status_ != REQUEST_STATUS_CREATED)) | |
408 | 439 | then throw(err_) | |
409 | 440 | else true | |
410 | 441 | ||
411 | 442 | ||
412 | 443 | func _validateSequencer (caller,err_) = if ((_loadSequencer() != caller)) | |
413 | 444 | then throw(err_) | |
414 | 445 | else true | |
415 | 446 | ||
416 | 447 | ||
417 | 448 | func _checkWithdrawalHashNotExist (withdrawalHash_,err_) = if ((size(_loadWithdrawalHash(withdrawalHash_)) > 0)) | |
418 | 449 | then throw(err_) | |
419 | 450 | else true | |
420 | 451 | ||
421 | 452 | ||
422 | 453 | func _validateSignatureFormat (signature_,alg_,err_) = if ((alg_ == ALG_TYPE_WAVES)) | |
423 | 454 | then if ((size(signature_) != 64)) | |
424 | 455 | then throw(err_) | |
425 | 456 | else true | |
426 | 457 | else if ((alg_ == ALG_TYPE_EVM)) | |
427 | 458 | then if ((size(signature_) != 65)) | |
428 | 459 | then throw(err_) | |
429 | 460 | else true | |
430 | 461 | else throw((err_ + ": inv alg")) | |
431 | 462 | ||
432 | 463 | ||
433 | - | func _ | |
434 | - | then if ((size( | |
464 | + | func _validateWeb3Id (web3Id_,alg_,err_) = if ((alg_ == ALG_TYPE_WAVES)) | |
465 | + | then if ((size(web3Id_) != 32)) | |
435 | 466 | then throw(err_) | |
436 | 467 | else true | |
437 | 468 | else if ((alg_ == ALG_TYPE_EVM)) | |
438 | - | then if ((size( | |
469 | + | then if ((size(web3Id_) != 20)) | |
439 | 470 | then throw(err_) | |
440 | 471 | else true | |
441 | 472 | else throw((err_ + ": inv alg")) | |
442 | 473 | ||
443 | 474 | ||
444 | - | func _validateWithdrawalSignature (withdrawalHash_,signature_, | |
475 | + | func _validateWithdrawalSignature (withdrawalHash_,signature_,web3Id_,alg_,err_) = { | |
445 | 476 | let result = if ((alg_ == ALG_TYPE_WAVES)) | |
446 | - | then sigVerify(withdrawalHash_, signature_, | |
477 | + | then sigVerify(withdrawalHash_, signature_, web3Id_) | |
447 | 478 | else if ((alg_ == ALG_TYPE_EVM)) | |
448 | 479 | then { | |
449 | 480 | let hashWithPrefix = keccak256_16Kb((EVM_SIGNATURE_PREFIX + withdrawalHash_)) | |
450 | - | (takeRight(keccak256_16Kb(ecrecover(hashWithPrefix, signature_)), 20) == | |
481 | + | (takeRight(keccak256_16Kb(ecrecover(hashWithPrefix, signature_)), 20) == web3Id_) | |
451 | 482 | } | |
452 | 483 | else throw((err_ + ": inv alg")) | |
453 | 484 | if (!(result)) | |
454 | 485 | then throw(err_) | |
455 | 486 | else true | |
456 | 487 | } | |
457 | 488 | ||
458 | 489 | ||
459 | - | func _ | |
490 | + | func _validateWeb3IdMatchesAddress (web3Id_,from_,alg_,err_) = { | |
460 | 491 | let address = if ((alg_ == ALG_TYPE_WAVES)) | |
461 | - | then toString(addressFromPublicKey( | |
492 | + | then toString(addressFromPublicKey(web3Id_)) | |
462 | 493 | else if ((alg_ == ALG_TYPE_EVM)) | |
463 | - | then ("0x" + toBase16String( | |
494 | + | then ("0x" + toBase16String(web3Id_)) | |
464 | 495 | else throw((err_ + ": inv alg")) | |
465 | 496 | if ((address != from_)) | |
466 | 497 | then throw(err_) | |
467 | 498 | else true | |
468 | 499 | } | |
469 | 500 | ||
470 | 501 | ||
471 | 502 | @Callable(i) | |
472 | 503 | func init (executor_,pauser_,accountStorage_,wavesVault_,sequencer_,vaultAdapter_) = { | |
473 | 504 | let err = if (if (if (if (if (if (if (if (_onlyThisContract(i.caller)) | |
474 | 505 | then _whenNotInitialized() | |
475 | 506 | else false) | |
476 | 507 | then _whenMultisigSet() | |
477 | 508 | else false) | |
478 | 509 | then _validateAddress(executor_, "init: invalid executor") | |
479 | 510 | else false) | |
480 | 511 | then _validateAddress(pauser_, "init: invalid pauser") | |
481 | 512 | else false) | |
482 | 513 | then _validateAddress(accountStorage_, "init: invalid accountStorage") | |
483 | 514 | else false) | |
484 | 515 | then _validateAddress(wavesVault_, "init: invalid wavesVault") | |
485 | 516 | else false) | |
486 | 517 | then _validateAddress(sequencer_, "init: invalid sequencer") | |
487 | 518 | else false) | |
488 | 519 | then _validateAddress(vaultAdapter_, "init: invalid vaultAdapter") | |
489 | 520 | else false | |
490 | 521 | if ((err == err)) | |
491 | 522 | then $Tuple2(((((((_saveInit(true) ++ _saveExecutor(addressFromStringValue(executor_))) ++ _savePauser(addressFromStringValue(pauser_))) ++ _saveAccountStorage(addressFromStringValue(accountStorage_))) ++ _saveWavesVault(addressFromStringValue(wavesVault_))) ++ _saveSequencer(addressFromStringValue(sequencer_))) ++ _saveVaultAdapter(addressFromStringValue(vaultAdapter_))), unit) | |
492 | 523 | else throw("Strict value is not equal to itself.") | |
493 | 524 | } | |
494 | 525 | ||
495 | 526 | ||
496 | 527 | ||
497 | 528 | @Callable(i) | |
498 | 529 | func deposit (callerContract_,from_,to_,chainId_,asset_,amount_) = { | |
499 | 530 | let chainId = valueOrErrorMessage(parseInt(chainId_), "deposit: chainId not int") | |
500 | 531 | let amount = valueOrErrorMessage(parseBigInt(amount_), "deposit: amount not int") | |
501 | 532 | let err = if (if (if (if (if (if (_whenInitialized()) | |
502 | 533 | then _whenNotPaused() | |
503 | 534 | else false) | |
504 | 535 | then _chainExists(chainId, "deposit: invalid chainId") | |
505 | 536 | else false) | |
506 | 537 | then _validateString(from_, "deposit: invalid from") | |
507 | 538 | else false) | |
508 | 539 | then _validateString(to_, "deposit: invalid to") | |
509 | 540 | else false) | |
510 | 541 | then _assetCurrencyExists(chainId, asset_, "deposit: invalid asset") | |
511 | 542 | else false) | |
512 | 543 | then _validateBigInt(amount, ZERO_BIGINT, "deposit: invalid amount") | |
513 | 544 | else false | |
514 | 545 | if ((err == err)) | |
515 | 546 | then { | |
516 | 547 | let err1 = if ((_loadChain(chainId) == WAVES)) | |
517 | 548 | then _validateWavesVault(i.caller, "deposit: invalid waves vault") | |
518 | 549 | else if (_validateExecutor(i.caller, "deposit: invalid executor")) | |
519 | 550 | then _validateCallerContract(chainId, callerContract_, "deposit: invalid caller contract") | |
520 | 551 | else false | |
521 | 552 | if ((err1 == err1)) | |
522 | 553 | then { | |
523 | 554 | let newAssetReserves = (_loadAssetReserves(chainId, asset_) + amount) | |
524 | 555 | let currency = _loadAssetCurrency(chainId, asset_) | |
525 | 556 | let newCurrencyReserves = (_loadCurrencyReserves(currency) + amount) | |
526 | 557 | let invocation = invoke(_loadAccountStorage(), FUNC_DEPOSIT, [to_, currency, amount_], nil) | |
527 | 558 | if ((invocation == invocation)) | |
528 | 559 | then $Tuple2((_saveAssetReserves(chainId, asset_, newAssetReserves) ++ _saveCurrencyReserves(currency, newCurrencyReserves)), unit) | |
529 | 560 | else throw("Strict value is not equal to itself.") | |
530 | 561 | } | |
531 | 562 | else throw("Strict value is not equal to itself.") | |
532 | 563 | } | |
533 | 564 | else throw("Strict value is not equal to itself.") | |
534 | 565 | } | |
535 | 566 | ||
536 | 567 | ||
537 | 568 | ||
538 | 569 | @Callable(i) | |
539 | 570 | func requestWithdrawal (callerContract_,from_,to_,fromChainId_,toChainId_,asset_,amount_) = { | |
540 | 571 | let fromChainId = valueOrErrorMessage(parseInt(fromChainId_), "requestWithdrawal: fromChainId not int") | |
541 | 572 | let toChainId = valueOrErrorMessage(parseInt(toChainId_), "requestWithdrawal: toChainId not int") | |
542 | 573 | let amount = valueOrErrorMessage(parseBigInt(amount_), "requestWithdrawal: amount not int") | |
543 | 574 | let err = if (if (if (if (if (if (_whenInitialized()) | |
544 | 575 | then _chainExists(fromChainId, "requestWithdrawal: invalid fromChainId") | |
545 | 576 | else false) | |
546 | 577 | then _chainExists(toChainId, "requestWithdrawal: invalid toChainId") | |
547 | 578 | else false) | |
548 | 579 | then _validateString(from_, "requestWithdrawal: invalid from") | |
549 | 580 | else false) | |
550 | 581 | then _validateString(to_, "requestWithdrawal: invalid to") | |
551 | 582 | else false) | |
552 | 583 | then _assetCurrencyExists(toChainId, asset_, "requestWithdrawal: invalid asset") | |
553 | 584 | else false) | |
554 | 585 | then _validateBigInt(amount, ZERO_BIGINT, "requestWithdrawal: invalid amount") | |
555 | 586 | else false | |
556 | 587 | if ((err == err)) | |
557 | 588 | then { | |
558 | 589 | let err1 = if ((_loadChain(fromChainId) == WAVES)) | |
559 | 590 | then _validateWavesVault(i.caller, "requestWithdrawal: invalid waves vault") | |
560 | 591 | else if (_validateExecutor(i.caller, "requestWithdrawal: invalid executor")) | |
561 | 592 | then _validateCallerContract(fromChainId, callerContract_, "requestWithdrawal: invalid caller contract") | |
562 | 593 | else false | |
563 | 594 | if ((err1 == err1)) | |
564 | 595 | then { | |
565 | 596 | let currency = _loadAssetCurrency(toChainId, asset_) | |
566 | 597 | let availableBalance = match invoke(_loadAccountStorage(), FUNC_GET_USER_BALANCE, [from_, SPOT_WALLET, currency], nil) { | |
567 | 598 | case a: String => | |
568 | 599 | parseBigIntValue(a) | |
569 | 600 | case _ => | |
570 | 601 | throw("requestWithdrawal: can't take available balance from storage") | |
571 | 602 | } | |
572 | 603 | if ((availableBalance == availableBalance)) | |
573 | 604 | then { | |
574 | 605 | 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)) | |
576 | 608 | then ((_loadAssetReserves(toChainId, asset_) - lockedReserves) >= amount) | |
577 | 609 | 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) | |
590 | 617 | } | |
591 | 618 | else throw("Strict value is not equal to itself.") | |
592 | 619 | } | |
593 | 620 | else throw("Strict value is not equal to itself.") | |
594 | 621 | } | |
595 | 622 | else throw("Strict value is not equal to itself.") | |
596 | 623 | } | |
597 | 624 | ||
598 | 625 | ||
599 | 626 | ||
600 | 627 | @Callable(i) | |
601 | 628 | func executeWithdrawal (callerContract_,chainId_,requestWithdrawalId_) = { | |
602 | 629 | let chainId = valueOrErrorMessage(parseInt(chainId_), "executeWithdrawal: chainId not int") | |
603 | 630 | let requestWithdrawalId = valueOrErrorMessage(parseInt(requestWithdrawalId_), "executeWithdrawal: requestWithdrawalId not int") | |
604 | 631 | let requestWithdrawalSize = _loadRequestWithdrawalSize() | |
605 | 632 | let err = if (if (_whenInitialized()) | |
606 | 633 | then _chainExists(chainId, "executeWithdrawal: invalid chainId") | |
607 | 634 | else false) | |
608 | 635 | then _validateInt(requestWithdrawalId, 0, (requestWithdrawalSize - 1), "executeWithdrawal: invalid requestWithdrawalId") | |
609 | 636 | else false | |
610 | 637 | if ((err == err)) | |
611 | 638 | then { | |
612 | 639 | let err1 = if ((_loadChain(chainId) == WAVES)) | |
613 | 640 | then _validateWavesVault(i.caller, "executeWithdrawal: invalid waves vault") | |
614 | 641 | else if (_validateExecutor(i.caller, "executeWithdrawal: invalid executor")) | |
615 | 642 | then _validateCallerContract(chainId, callerContract_, "executeWithdrawal: invalid caller contract") | |
616 | 643 | else false | |
617 | 644 | if ((err1 == err1)) | |
618 | 645 | then { | |
619 | 646 | let request = _loadRequestWithdrawal(requestWithdrawalId) | |
620 | 647 | let requestFrom = request._1 | |
621 | 648 | let requestTo = request._2 | |
622 | 649 | let requestToChainId = request._3 | |
623 | 650 | let requestAsset = request._4 | |
624 | 651 | let requestAmount = request._5 | |
625 | 652 | let requestHeight = request._6 | |
626 | 653 | let requestStatus = request._8 | |
627 | 654 | let newAssetReserves = (_loadAssetReserves(requestToChainId, requestAsset) - requestAmount) | |
628 | 655 | let newAssetReservesLocked = (_loadAssetReservesLocked(requestToChainId, requestAsset) - requestAmount) | |
629 | 656 | let currency = _loadAssetCurrency(requestToChainId, requestAsset) | |
630 | 657 | 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")) | |
632 | 660 | then _validateBigInt(newAssetReservesLocked, ZERO_BIGINT, "executeWithdrawal: negative newAssetReservesLocked") | |
633 | 661 | else false) | |
634 | 662 | then _validateBigInt(newCurrencyReserves, ZERO_BIGINT, "executeWithdrawal: negative newCurrencyReserves") | |
663 | + | else false) | |
664 | + | then _validateBigInt(newUserLockedCurrency, ZERO_BIGINT, "executeWithdrawal: negative newUserLockedCurrency") | |
635 | 665 | else false) | |
636 | 666 | then _validateInt((height - requestHeight), _loadRequestWithdrawalBlockDelay(), MAX_INT, "executeWithdrawal: too early to execute") | |
637 | 667 | else false) | |
638 | 668 | then _requestIsCreated(requestStatus, "executeWithdrawal: request is resolved") | |
639 | 669 | else false | |
640 | 670 | if ((err2 == err2)) | |
641 | 671 | then { | |
642 | 672 | let storageInvocation = invoke(_loadAccountStorage(), FUNC_WITHDRAW, [requestFrom, currency, toString(requestAmount)], nil) | |
643 | 673 | if ((storageInvocation == storageInvocation)) | |
644 | 674 | then { | |
645 | 675 | let withdrawInvocation = if ((_loadChain(requestToChainId) == WAVES)) | |
646 | 676 | then invoke(_loadWavesVault(), FUNC_WITHDRAW, [requestTo, requestAsset, toString(requestAmount)], nil) | |
647 | 677 | else invoke(_loadVaultAdapter(), FUNC_WITHDRAW, [requestToChainId, requestAsset, toString(requestAmount), requestTo], nil) | |
648 | 678 | if ((withdrawInvocation == withdrawInvocation)) | |
649 | 679 | then { | |
650 | 680 | 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) | |
652 | 682 | } | |
653 | 683 | else throw("Strict value is not equal to itself.") | |
654 | 684 | } | |
655 | 685 | else throw("Strict value is not equal to itself.") | |
656 | 686 | } | |
657 | 687 | else throw("Strict value is not equal to itself.") | |
658 | 688 | } | |
659 | 689 | else throw("Strict value is not equal to itself.") | |
660 | 690 | } | |
661 | 691 | else throw("Strict value is not equal to itself.") | |
662 | 692 | } | |
663 | 693 | ||
664 | 694 | ||
665 | 695 | ||
666 | 696 | @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_) = { | |
668 | 749 | let toChainId = valueOrErrorMessage(parseInt(toChainId_), "withdraw: toChainId not int") | |
669 | 750 | let amount = valueOrErrorMessage(parseBigInt(amount_), "withdraw: amount not int") | |
751 | + | let relayerFee = valueOrErrorMessage(parseBigInt(relayerFee_), "withdraw: relayerFee not int") | |
670 | 752 | let timestamp = valueOrErrorMessage(parseInt(timestamp_), "withdraw: timestamp not int") | |
671 | 753 | let alg = valueOrErrorMessage(parseInt(alg_), "withdraw: alg not int") | |
672 | - | let | |
754 | + | let web3Id = fromBase58String(web3Id_) | |
673 | 755 | 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()) | |
675 | 757 | then _validateSequencer(i.caller, "withdraw: invalid sequencer") | |
676 | 758 | else false) | |
677 | 759 | then _validateString(from_, "withdraw: invalid from") | |
678 | 760 | else false) | |
679 | 761 | then _validateString(to_, "withdraw: invalid to") | |
680 | 762 | else false) | |
681 | 763 | then _chainExists(toChainId, "withdraw: invalid toChainId") | |
682 | 764 | else false) | |
683 | 765 | then _assetCurrencyExists(toChainId, asset_, "withdraw: invalid asset") | |
684 | 766 | else false) | |
685 | 767 | then _validateBigInt(amount, ZERO_BIGINT, "withdraw: invalid amount") | |
686 | 768 | else false) | |
769 | + | then _validateBigInt_2(relayerFee, ZERO_BIGINT, amount, "withdraw: invalid relayerFee") | |
770 | + | else false) | |
687 | 771 | then _validateInt((timestamp + ONE_DAY), lastBlock.timestamp, MAX_INT, "withdraw: invalid timestamp") | |
688 | 772 | else false) | |
689 | - | then _ | |
773 | + | then _validateWeb3Id(web3Id, alg, "withdraw: inv web3Id") | |
690 | 774 | else false) | |
691 | 775 | then _validateSignatureFormat(signature, alg, "withdraw: inv sig format") | |
692 | 776 | else false) | |
693 | - | then _ | |
777 | + | then _validateWeb3IdMatchesAddress(web3Id, from_, alg, "withdraw: web3Id mismatch") | |
694 | 778 | else false | |
695 | 779 | if ((err == err)) | |
696 | 780 | 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)) + | |
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)) | |
698 | 782 | let withdrawalHash = keccak256_16Kb(withdrawalBytes) | |
699 | 783 | let currency = _loadAssetCurrency(toChainId, asset_) | |
700 | 784 | let availableBalance = match invoke(_loadAccountStorage(), FUNC_GET_USER_BALANCE, [from_, SPOT_WALLET, currency], nil) { | |
701 | 785 | case a: String => | |
702 | 786 | parseBigIntValue(a) | |
703 | 787 | case _ => | |
704 | 788 | throw("withdraw: can't take available balance from storage") | |
705 | 789 | } | |
706 | 790 | if ((availableBalance == availableBalance)) | |
707 | 791 | then { | |
708 | 792 | let assetReserves = _loadAssetReserves(toChainId, asset_) | |
709 | 793 | 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")) | |
711 | 797 | then _checkWithdrawalHashNotExist(withdrawalHash, "withdraw: already executed") | |
712 | 798 | else false) | |
713 | - | then _validateBigInt(availableBalance, | |
799 | + | then _validateBigInt(availableBalance, amountToSend, "withdraw: insufficient balance") | |
714 | 800 | else false) | |
715 | - | then _validateBigInt((assetReserves - lockedReserves), | |
801 | + | then _validateBigInt((assetReserves - lockedReserves), amountToSend, "withdraw: insufficient reserves") | |
716 | 802 | else false | |
717 | 803 | if ((err1 == err1)) | |
718 | 804 | then { | |
719 | - | let newAssetReserves = (assetReserves - | |
720 | - | let newCurrencyReserves = (_loadCurrencyReserves(currency) - | |
805 | + | let newAssetReserves = (assetReserves - amountToSend) | |
806 | + | let newCurrencyReserves = (_loadCurrencyReserves(currency) - amountToSend) | |
721 | 807 | let err2 = if (_validateBigInt(newAssetReserves, ZERO_BIGINT, "withdraw: negative newAssetReserves")) | |
722 | 808 | then _validateBigInt(newCurrencyReserves, ZERO_BIGINT, "withdraw: negative newCurrencyReserves") | |
723 | 809 | else false | |
724 | 810 | if ((err2 == err2)) | |
725 | 811 | then { | |
726 | - | let | |
727 | - | if (( | |
812 | + | let storageInvocation1 = invoke(_loadAccountStorage(), FUNC_WITHDRAW, [from_, currency, amount_], nil) | |
813 | + | if ((storageInvocation1 == storageInvocation1)) | |
728 | 814 | then { | |
729 | - | let | |
730 | - | if (( | |
815 | + | let storageInvocation2 = invoke(_loadAccountStorage(), FUNC_DEPOSIT, [_loadRelayerFeeRecipient(), currency, relayerFee_], nil) | |
816 | + | if ((storageInvocation2 == storageInvocation2)) | |
731 | 817 | then { | |
732 | 818 | let withdrawInvocation = if ((_loadChain(toChainId) == WAVES)) | |
733 | - | then invoke(_loadWavesVault(), FUNC_WITHDRAW, [to_, asset_, | |
734 | - | else invoke(_loadVaultAdapter(), FUNC_WITHDRAW, [toChainId, asset_, | |
819 | + | then invoke(_loadWavesVault(), FUNC_WITHDRAW, [to_, asset_, amountToSendStr], nil) | |
820 | + | else invoke(_loadVaultAdapter(), FUNC_WITHDRAW, [toChainId, asset_, amountToSendStr, to_, relayerFee_], nil) | |
735 | 821 | if ((withdrawInvocation == withdrawInvocation)) | |
736 | 822 | then $Tuple2(((_saveAssetReserves(toChainId, asset_, newAssetReserves) ++ _saveCurrencyReserves(currency, newCurrencyReserves)) ++ _saveWithdrawalHash(withdrawalHash, toBase58String(i.transactionId))), unit) | |
737 | 823 | else throw("Strict value is not equal to itself.") | |
738 | 824 | } | |
739 | 825 | else throw("Strict value is not equal to itself.") | |
740 | 826 | } | |
741 | 827 | else throw("Strict value is not equal to itself.") | |
742 | 828 | } | |
743 | 829 | else throw("Strict value is not equal to itself.") | |
744 | 830 | } | |
745 | 831 | else throw("Strict value is not equal to itself.") | |
746 | 832 | } | |
747 | 833 | else throw("Strict value is not equal to itself.") | |
748 | 834 | } | |
749 | 835 | else throw("Strict value is not equal to itself.") | |
750 | 836 | } | |
751 | 837 | ||
752 | 838 | ||
753 | 839 | ||
754 | 840 | @Callable(i) | |
755 | 841 | func depositStakingReward (callerContract_,chainId_,asset_,amount_) = { | |
756 | 842 | let chainId = valueOrErrorMessage(parseInt(chainId_), "depositStakingReward: chainId not int") | |
757 | 843 | let amount = valueOrErrorMessage(parseBigInt(amount_), "depositStakingReward: amount not int") | |
758 | 844 | let err = if (if (if (if (_whenInitialized()) | |
759 | 845 | then _whenNotPaused() | |
760 | 846 | else false) | |
761 | 847 | then _chainExists(chainId, "depositStakingReward: invalid chainId") | |
762 | 848 | else false) | |
763 | 849 | then _assetCurrencyExists(chainId, asset_, "depositStakingReward: invalid asset") | |
764 | 850 | else false) | |
765 | 851 | then _validateBigInt(amount, ZERO_BIGINT, "depositStakingReward: invalid amount") | |
766 | 852 | else false | |
767 | 853 | if ((err == err)) | |
768 | 854 | then { | |
769 | 855 | let err1 = if ((_loadChain(chainId) == WAVES)) | |
770 | 856 | then _validateWavesVault(i.caller, "depositStakingReward: invalid waves vault") | |
771 | 857 | else if (_validateExecutor(i.caller, "depositStakingReward: invalid executor")) | |
772 | 858 | then _validateCallerContract(chainId, callerContract_, "depositStakingReward: invalid caller contract") | |
773 | 859 | else false | |
774 | 860 | if ((err1 == err1)) | |
775 | 861 | then { | |
776 | 862 | let newAssetReserves = (_loadAssetReserves(chainId, asset_) + amount) | |
777 | 863 | let currency = _loadAssetCurrency(chainId, asset_) | |
778 | 864 | let newCurrencyReserves = (_loadCurrencyReserves(currency) + amount) | |
779 | 865 | let invocation = invoke(_loadAccountStorage(), FUNC_DEPOSIT_STAKING_REWARD, [_loadRewardDistributor(), currency, amount_], nil) | |
780 | 866 | if ((invocation == invocation)) | |
781 | 867 | then $Tuple2((_saveAssetReserves(chainId, asset_, newAssetReserves) ++ _saveCurrencyReserves(currency, newCurrencyReserves)), unit) | |
782 | 868 | else throw("Strict value is not equal to itself.") | |
783 | 869 | } | |
784 | 870 | else throw("Strict value is not equal to itself.") | |
785 | 871 | } | |
786 | 872 | else throw("Strict value is not equal to itself.") | |
787 | 873 | } | |
788 | 874 | ||
789 | 875 | ||
790 | 876 | ||
791 | 877 | @Callable(i) | |
792 | 878 | func addChain (chainId_,name_,callerContract_) = { | |
793 | 879 | let err = if (if (if (if (if (_onlyThisContract(i.caller)) | |
794 | 880 | then _whenInitialized() | |
795 | 881 | else false) | |
796 | 882 | then _validateInt(chainId_, 0, MAX_INT, "addChain: invalid chainId") | |
797 | 883 | else false) | |
798 | 884 | then _validateString(name_, "addChain: invalid name") | |
799 | 885 | else false) | |
800 | 886 | then _validateString(callerContract_, "addChain: invalid callerContract") | |
801 | 887 | else false) | |
802 | 888 | then _chainNotExist(chainId_, "addChain: already exists") | |
803 | 889 | else false | |
804 | 890 | if ((err == err)) | |
805 | 891 | then $Tuple2((_saveChain(chainId_, name_) ++ _saveCallerContract(chainId_, callerContract_)), unit) | |
806 | 892 | else throw("Strict value is not equal to itself.") | |
807 | 893 | } | |
808 | 894 | ||
809 | 895 | ||
810 | 896 | ||
811 | 897 | @Callable(i) | |
812 | 898 | func addAsset (chainId_,asset_,currency_) = { | |
813 | 899 | let err = if (if (if (if (if (_onlyThisContract(i.caller)) | |
814 | 900 | then _whenInitialized() | |
815 | 901 | else false) | |
816 | 902 | then _chainExists(chainId_, "addAsset: invalid chainId") | |
817 | 903 | else false) | |
818 | 904 | then _validateString(asset_, "addAsset: invalid asset") | |
819 | 905 | else false) | |
820 | 906 | then _validateString(currency_, "addAsset: invalid currency") | |
821 | 907 | else false) | |
822 | 908 | then _assetCurrencyNotExist(chainId_, asset_, "addAsset: already exists") | |
823 | 909 | else false | |
824 | 910 | if ((err == err)) | |
825 | 911 | then $Tuple2(_saveAssetCurrency(chainId_, asset_, currency_), unit) | |
826 | 912 | else throw("Strict value is not equal to itself.") | |
827 | 913 | } | |
828 | 914 | ||
829 | 915 | ||
830 | 916 | ||
831 | 917 | @Callable(i) | |
832 | 918 | func setRequestWithdrawalBlockDelay (delay_) = { | |
833 | 919 | let err = if (if (_onlyThisContract(i.caller)) | |
834 | 920 | then _whenInitialized() | |
835 | 921 | else false) | |
836 | 922 | then _validateInt(delay_, 0, MAX_INT, "setRequestWithdrawalBlockDelay: invalid delay") | |
837 | 923 | else false | |
838 | 924 | if ((err == err)) | |
839 | 925 | then $Tuple2(_saveRequestWithdrawalBlockDelay(delay_), unit) | |
840 | 926 | else throw("Strict value is not equal to itself.") | |
841 | 927 | } | |
842 | 928 | ||
843 | 929 | ||
844 | 930 | ||
845 | 931 | @Callable(i) | |
846 | 932 | func updateRewardDistributor (rewardDistributor_) = { | |
847 | 933 | let err = if (if (_onlyThisContract(i.caller)) | |
848 | 934 | then _whenInitialized() | |
849 | 935 | else false) | |
850 | 936 | then _validateString(rewardDistributor_, "updateRewardDistributor: invalid rewardDistributor") | |
851 | 937 | else false | |
852 | 938 | if ((err == err)) | |
853 | 939 | then $Tuple2(_saveRewardDistributor(rewardDistributor_), unit) | |
854 | 940 | else throw("Strict value is not equal to itself.") | |
855 | 941 | } | |
856 | 942 | ||
857 | 943 | ||
858 | 944 | ||
859 | 945 | @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) | |
860 | 960 | func pause () = { | |
861 | 961 | let err = if (if (_onlyPauser(i.caller)) | |
862 | 962 | then _whenInitialized() | |
863 | 963 | else false) | |
864 | 964 | then _whenNotPaused() | |
865 | 965 | else false | |
866 | 966 | if ((err == err)) | |
867 | 967 | then $Tuple2(_savePause(true), unit) | |
868 | 968 | else throw("Strict value is not equal to itself.") | |
869 | 969 | } | |
870 | 970 | ||
871 | 971 | ||
872 | 972 | ||
873 | 973 | @Callable(i) | |
874 | 974 | func unpause () = { | |
875 | 975 | let err = if (if (_onlyPauser(i.caller)) | |
876 | 976 | then _whenInitialized() | |
877 | 977 | else false) | |
878 | 978 | then _whenPaused() | |
879 | 979 | else false | |
880 | 980 | if ((err == err)) | |
881 | 981 | then $Tuple2(_savePause(false), unit) | |
882 | 982 | else throw("Strict value is not equal to itself.") | |
883 | 983 | } | |
884 | 984 | ||
885 | 985 | ||
886 | 986 | ||
887 | 987 | @Callable(i) | |
888 | 988 | func updatePauser (pauser_) = { | |
889 | 989 | let err = if (if (_onlyThisContract(i.caller)) | |
890 | 990 | then _whenInitialized() | |
891 | 991 | else false) | |
892 | 992 | then _validateAddress(pauser_, "updatePauser: invalid pauser") | |
893 | 993 | else false | |
894 | 994 | if ((err == err)) | |
895 | 995 | then $Tuple2(_savePauser(addressFromStringValue(pauser_)), unit) | |
896 | 996 | else throw("Strict value is not equal to itself.") | |
897 | 997 | } | |
898 | 998 | ||
899 | 999 | ||
900 | 1000 | ||
901 | 1001 | @Callable(i) | |
902 | 1002 | func setMultisig (multisig_) = { | |
903 | 1003 | let err = if (_onlyThisContract(i.caller)) | |
904 | 1004 | then _validateAddress(multisig_, "setMultisig: invalid multisig") | |
905 | 1005 | else false | |
906 | 1006 | if ((err == err)) | |
907 | 1007 | then $Tuple2(_saveMultisig(addressFromStringValue(multisig_)), unit) | |
908 | 1008 | else throw("Strict value is not equal to itself.") | |
909 | 1009 | } | |
910 | 1010 | ||
911 | 1011 | ||
912 | 1012 | @Verifier(tx) | |
913 | 1013 | func verify () = match getString(KEY_MULTISIG) { | |
914 | 1014 | case multisig: String => | |
915 | 1015 | valueOrElse(getBoolean(addressFromStringValue(multisig), makeString([KEY_STATUS, toString(this), toBase58String(tx.id)], SEPARATOR)), false) | |
916 | 1016 | case _ => | |
917 | 1017 | sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey) | |
918 | 1018 | } | |
919 | 1019 |
github/deemru/w8io/026f985 100.63 ms ◑