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