tx · AeE9HsMec7dmamH2zeLctPppdFspzLQdfdpsaXCAjDFS

3N3kKNoJohjVQYNLTrYTGTesr3nq3PZNh37:  -0.01600000 Waves

2024.05.14 11:48 [3105469] smart account 3N3kKNoJohjVQYNLTrYTGTesr3nq3PZNh37 > SELF 0.00000000 Waves

{ "type": 13, "id": "AeE9HsMec7dmamH2zeLctPppdFspzLQdfdpsaXCAjDFS", "fee": 1600000, "feeAssetId": null, "timestamp": 1715676516061, "version": 2, "chainId": 84, "sender": "3N3kKNoJohjVQYNLTrYTGTesr3nq3PZNh37", "senderPublicKey": "vmMXxwQAMUAoisvL193ptPiTtaWQqL5YNu2zs1ouTbY", "proofs": [ "5VwWEu46ga92MMjMQTnCi613M9nahr9vfKpEHW4vixcaw6n68rcAmCnwBx8kdt6aAqhFjAH9ECS3e3QLkbtRez4t" ], "script": "base64:BwI9CAISAwoBCBIECgICGBIECgICGBIECgICGBIECgICGBIECgICGBIECgICGBIECgICGBIECgICGBIECgICGEsACXNlcGFyYXRvcgICX18AB2NoYWluSWQJAMkBAgkAygECCAUEdGhpcwVieXRlcwABAAEACGNoYWluSWRXAQFXABBjb250cmFjdEZpbGVuYW1lAhdmdXR1cmVzX2NhbGN1bGF0b3IucmlkZQAFbXVsdDgAgMLXLwAMbXVsdDE4QmlnSW50CQC2AgEAgICQu7rWrfANAA13YXZlc0RlY2ltYWxzAAgADHVzZHREZWNpbWFscwAGAAlrTXVsdGlzaWcCDCVzX19tdWx0aXNpZwEHa1N0YXR1cwIEZGFwcAR0eElkCQC5CQIJAMwIAgIKJXNfX3N0YXR1cwkAzAgCBQRkYXBwCQDMCAIFBHR4SWQFA25pbAUJc2VwYXJhdG9yAAlrU2h1dGRvd24CDCVzX19zaHV0ZG93bgALa1B1YmxpY0tleXMCDiVzX19wdWJsaWNLZXlzABFrTWF0Y2hlclB1YmxpY0tleQIUJXNfX21hdGNoZXJQdWJsaWNLZXkBBXRvWDE4AgdvcmlnVmFsDW9yaWdTY2FsZU11bHQJALwCAwkAtgIBBQdvcmlnVmFsBQxtdWx0MThCaWdJbnQJALYCAQUNb3JpZ1NjYWxlTXVsdAEHZnJvbVgxOAIDdmFsD3Jlc3VsdFNjYWxlTXVsdAkAoAMBCQC8AgMFA3ZhbAkAtgIBBQ9yZXN1bHRTY2FsZU11bHQFDG11bHQxOEJpZ0ludAEPdmFsaWRhdGVBZGRyZXNzAQdhZGRyZXNzCQEJaXNEZWZpbmVkAQkApggBBQdhZGRyZXNzAQd3cmFwRXJyAQFzCQCsAgIJAKwCAgUQY29udHJhY3RGaWxlbmFtZQICOiAFAXMBCHRocm93RXJyAQFzCQACAQkBB3dyYXBFcnIBBQFzAA9rRmFjdG9yeUFkZHJlc3MCEiVzX19mYWN0b3J5QWRkcmVzcwAUZmFjdG9yeUFkZHJlc3NPcHRpb24EByRtYXRjaDAJAJ0IAgUEdGhpcwUPa0ZhY3RvcnlBZGRyZXNzAwkAAQIFByRtYXRjaDACBlN0cmluZwQBcwUHJG1hdGNoMAkApggBBQFzAwkAAQIFByRtYXRjaDACBFVuaXQFBHVuaXQJAAIBAgtNYXRjaCBlcnJvcgAOZmFjdG9yeUFkZHJlc3MJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgUUZmFjdG9yeUFkZHJlc3NPcHRpb24JAQd3cmFwRXJyAQIXaW52YWxpZCBmYWN0b3J5IGFkZHJlc3MADmtQcmljZXNBZGRyZXNzAhUlc19fY2FsY3VsYXRvckFkZHJlc3MACHNodXRkb3duCQELdmFsdWVPckVsc2UCCQCbCAIFDmZhY3RvcnlBZGRyZXNzBQlrU2h1dGRvd24HAQttdXN0QWRkcmVzcwIGY2FsbGVyB2FkZHJlc3MDCQAAAgUGY2FsbGVyBQdhZGRyZXNzBgkBCHRocm93RXJyAQIRcGVybWlzc2lvbiBkZW5pZWQBCG11c3RUaGlzAQZjYWxsZXIJAQttdXN0QWRkcmVzcwIFBmNhbGxlcgUEdGhpcwELbXVzdEZhY3RvcnkBBmNhbGxlcgkBC211c3RBZGRyZXNzAgUGY2FsbGVyBQ5mYWN0b3J5QWRkcmVzcwEJbXVzdEFkbWluAQ9jYWxsZXJQdWJsaWNLZXkECG11bHRpc2lnCQERQGV4dHJOYXRpdmUoMTA2MikBCQERQGV4dHJOYXRpdmUoMTA1MykCBQ5mYWN0b3J5QWRkcmVzcwUJa011bHRpc2lnBA5wdWJsaWNLZXlzTGlzdAkAtQkCCQERQGV4dHJOYXRpdmUoMTA1MykCBQhtdWx0aXNpZwULa1B1YmxpY0tleXMFCXNlcGFyYXRvcgMJAQ9jb250YWluc0VsZW1lbnQCBQ5wdWJsaWNLZXlzTGlzdAkA2AQBBQ9jYWxsZXJQdWJsaWNLZXkGCQEIdGhyb3dFcnIBAgtub3QgYWxsb3dlZAALd2F2ZXNTdHJpbmcCBVdBVkVTAA1xdWV1ZUl0ZW1TaXplACABDHBhcnNlQXNzZXRJZAEFaW5wdXQDCQAAAgUFaW5wdXQFC3dhdmVzU3RyaW5nBQR1bml0CQDZBAEFBWlucHV0AQ9hc3NldElkVG9TdHJpbmcBBWlucHV0AwkAAAIFBWlucHV0BQR1bml0BQt3YXZlc1N0cmluZwkA2AQBCQEFdmFsdWUBBQVpbnB1dAAOa0FjY291bnRTY3JpcHQCESVzX19hY2NvdW50U2NyaXB0AQ1hY2NvdW50U2NyaXB0AAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCcCAIFDmZhY3RvcnlBZGRyZXNzBQ5rQWNjb3VudFNjcmlwdAkBB3dyYXBFcnIBAhlhY2NvdW50IHNjcmlwdCBpcyBub3Qgc2V0AA1rUmV3YXJkQW1vdW50AhAlc19fcmV3YXJkQW1vdW50AQxyZXdhcmRBbW91bnQACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUOZmFjdG9yeUFkZHJlc3MFDWtSZXdhcmRBbW91bnQJAQd3cmFwRXJyAQIYcmV3YXJkIGFtb3VudCBpcyBub3Qgc2V0AA5rQWNjb3VudHNMaW1pdAIRJXNfX2FjY291bnRzTGltaXQAFGFjY291bnRzTGltaXREZWZhdWx0ABQBDWFjY291bnRzTGltaXQACQELdmFsdWVPckVsc2UCCQCaCAIFDmZhY3RvcnlBZGRyZXNzBQ5rQWNjb3VudHNMaW1pdAUUYWNjb3VudHNMaW1pdERlZmF1bHQBCmtEZXBvc2l0ZWQBDmFjY291bnRBZGRyZXNzCQC5CQIJAMwIAgIEJXMlcwkAzAgCAglkZXBvc2l0ZWQJAMwIAgkApQgBBQ5hY2NvdW50QWRkcmVzcwUDbmlsBQlzZXBhcmF0b3IBD2RlcG9zaXRlZE9wdGlvbgEOYWNjb3VudEFkZHJlc3MJAJoIAgUOZmFjdG9yeUFkZHJlc3MJAQprRGVwb3NpdGVkAQUOYWNjb3VudEFkZHJlc3MBB2tDcmVkaXQCDmFjY291bnRBZGRyZXNzB2Fzc2V0SWQJALkJAgkAzAgCAgYlcyVzJXMJAMwIAgIGY3JlZGl0CQDMCAIJAKUIAQUOYWNjb3VudEFkZHJlc3MJAMwIAgkBD2Fzc2V0SWRUb1N0cmluZwEFB2Fzc2V0SWQFA25pbAUJc2VwYXJhdG9yAQlrTGV2ZXJhZ2UBDmFjY291bnRBZGRyZXNzCQC5CQIJAMwIAgIEJXMlcwkAzAgCAghsZXZlcmFnZQkAzAgCCQClCAEFDmFjY291bnRBZGRyZXNzBQNuaWwFCXNlcGFyYXRvcgERa1N5bnRoZXRpY0Fzc2V0SWQBC2Jhc2VBc3NldElkCQC5CQIJAMwIAgIEJXMlcwkAzAgCAhBzeW50aGV0aWNBc3NldElkCQDMCAIJAQ9hc3NldElkVG9TdHJpbmcBBQtiYXNlQXNzZXRJZAUDbmlsBQlzZXBhcmF0b3IBDGtCYXNlQXNzZXRJZAEQc3ludGhldGljQXNzZXRJZAkAuQkCCQDMCAICBCVzJXMJAMwIAgILYmFzZUFzc2V0SWQJAMwIAgkBD2Fzc2V0SWRUb1N0cmluZwEFEHN5bnRoZXRpY0Fzc2V0SWQFA25pbAUJc2VwYXJhdG9yABRSRVFVRVNUX1NUQVRVU19FTVBUWQAAABRSRVFVRVNUX1NUQVRVU19SRUFEWQABAQ5rUmVxdWVzdFN0YXR1cwEJcmVxdWVzdElkCQC5CQIJAMwIAgIEJXMlcwkAzAgCCQDYBAEFCXJlcXVlc3RJZAkAzAgCAgZzdGF0dXMFA25pbAUJc2VwYXJhdG9yARhrQWNjb3VudENyZWF0b3JQdWJsaWNLZXkBDmFjY291bnRBZGRyZXNzCQC5CQIJAMwIAgIEJXMlcwkAzAgCCQClCAEFDmFjY291bnRBZGRyZXNzCQDMCAICEGNyZWF0b3JQdWJsaWNLZXkFA25pbAUJc2VwYXJhdG9yARZrUmVxdWVzdE93bmVyUHVibGljS2V5AQlyZXF1ZXN0SWQJALkJAgkAzAgCAgQlcyVzCQDMCAIJANgEAQUJcmVxdWVzdElkCQDMCAICDm93bmVyUHVibGljS2V5BQNuaWwFCXNlcGFyYXRvcgEVa1JlcXVlc3RBbW91bnRBc3NldElkAQlyZXF1ZXN0SWQJALkJAgkAzAgCAgQlcyVzCQDMCAIJANgEAQUJcmVxdWVzdElkCQDMCAICDWFtb3VudEFzc2V0SWQFA25pbAUJc2VwYXJhdG9yARRrUmVxdWVzdFByaWNlQXNzZXRJZAEJcmVxdWVzdElkCQC5CQIJAMwIAgIEJXMlcwkAzAgCCQDYBAEFCXJlcXVlc3RJZAkAzAgCAgxwcmljZUFzc2V0SWQFA25pbAUJc2VwYXJhdG9yARxrUmVxdWVzdElkVG9BY2NvdW50UHVibGljS2V5AQlyZXF1ZXN0SWQJALkJAgkAzAgCAgQlcyVzCQDMCAIJANgEAQUJcmVxdWVzdElkCQDMCAICG3JlcXVlc3RJZFRvQWNjb3VudFB1YmxpY0tleQUDbmlsBQlzZXBhcmF0b3IBGmtBY2NvdW50QWRkcmVzc1RvUmVxdWVzdElkAQ5hY2NvdW50QWRkcmVzcwkAuQkCCQDMCAICBCVzJXMJAMwIAgkApQgBBQ5hY2NvdW50QWRkcmVzcwkAzAgCAhlhY2NvdW50QWRkcmVzc1RvUmVxdWVzdElkBQNuaWwFCXNlcGFyYXRvcgEOa1JlcXVlc3RzUXVldWUACQC5CQIJAMwIAgICJXMJAMwIAgINcmVxdWVzdHNRdWV1ZQUDbmlsBQlzZXBhcmF0b3IBDXJlcXVlc3RzUXVldWUACQELdmFsdWVPckVsc2UCCQCcCAIFDmZhY3RvcnlBZGRyZXNzCQEOa1JlcXVlc3RzUXVldWUAAQABDmtBY2NvdW50c1F1ZXVlAAkAuQkCCQDMCAICAiVzCQDMCAICDWFjY291bnRzUXVldWUFA25pbAUJc2VwYXJhdG9yAQ1hY2NvdW50c1F1ZXVlAAkBC3ZhbHVlT3JFbHNlAgkAnAgCBQ5mYWN0b3J5QWRkcmVzcwkBDmtBY2NvdW50c1F1ZXVlAAEAARBrUmVxdWVzdHNCeU93bmVyAQxvd25lckFkZHJlc3MJALkJAgkAzAgCAgQlcyVzCQDMCAICCGFjY291bnRzCQDMCAIJAKUIAQUMb3duZXJBZGRyZXNzBQNuaWwFCXNlcGFyYXRvcgEPcmVxdWVzdHNCeU93bmVyAQxvd25lckFkZHJlc3MJAQt2YWx1ZU9yRWxzZQIJAJwIAgUOZmFjdG9yeUFkZHJlc3MJARBrUmVxdWVzdHNCeU93bmVyAQUMb3duZXJBZGRyZXNzAQABDGtQYWlyQWxsb3dlZAINYW1vdW50QXNzZXRJZAxwcmljZUFzc2V0SWQJALkJAgkAzAgCAgYlcyVzJXMJAMwIAgkBD2Fzc2V0SWRUb1N0cmluZwEFDWFtb3VudEFzc2V0SWQJAMwIAgkBD2Fzc2V0SWRUb1N0cmluZwEFDHByaWNlQXNzZXRJZAkAzAgCAgtwYWlyQWxsb3dlZAUDbmlsBQlzZXBhcmF0b3IBC3BhaXJBbGxvd2VkAg1hbW91bnRBc3NldElkDHByaWNlQXNzZXRJZAkBC3ZhbHVlT3JFbHNlAgkAmwgCBQ5mYWN0b3J5QWRkcmVzcwkBDGtQYWlyQWxsb3dlZAIFDWFtb3VudEFzc2V0SWQFDHByaWNlQXNzZXRJZAcBBmtQcmljZQEHYXNzZXRJZAkAuQkCCQDMCAICAiVzCQDMCAIJAQ9hc3NldElkVG9TdHJpbmcBBQdhc3NldElkBQNuaWwFCXNlcGFyYXRvcgEPZ2V0Q3VycmVudFByaWNlAQdhc3NldElkBBBtYXRjaGVyUHVibGljS2V5CQDZBAEJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBQ5mYWN0b3J5QWRkcmVzcwURa01hdGNoZXJQdWJsaWNLZXkJAQd3cmFwRXJyAQIaaW52YWxpZCBtYXRjaGVyIHB1YmxpYyBrZXkEDm1hdGNoZXJBZGRyZXNzCQCnCAEFEG1hdGNoZXJQdWJsaWNLZXkEBXByaWNlCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUObWF0Y2hlckFkZHJlc3MJAQZrUHJpY2UBBQdhc3NldElkCQEHd3JhcEVycgEJAKwCAgIZaW52YWxpZCBwcmljZSwgYXNzZXRJZCA9IAkBD2Fzc2V0SWRUb1N0cmluZwEFB2Fzc2V0SWQFBXByaWNlAQ9jYWxjVG90YWxDcmVkaXQDB2NyZWRpdEEHY3JlZGl0QgxjdXJyZW50UHJpY2UJAGQCCQBoAgUHY3JlZGl0QQUMY3VycmVudFByaWNlBQdjcmVkaXRCARBjYWxjVG90YWxCYWxhbmNlAwhiYWxhbmNlQQhiYWxhbmNlQgxjdXJyZW50UHJpY2UJAGQCCQBoAgUIYmFsYW5jZUEFDGN1cnJlbnRQcmljZQUIYmFsYW5jZUIBB2NhbGNQbmwCDHRvdGFsQmFsYW5jZQt0b3RhbENyZWRpdAkAZQIFDHRvdGFsQmFsYW5jZQULdG90YWxDcmVkaXQBE2NhbGNDcmVkaXRBdmFpbGFibGUDB2RlcG9zaXQIbGV2ZXJhZ2ULdG90YWxDcmVkaXQJAGUCCQBoAgUHZGVwb3NpdAUIbGV2ZXJhZ2UFC3RvdGFsQ3JlZGl0ARBjYWxjUmVhbEluQ3JlZGl0AgZjcmVkaXQHYmFsYW5jZQMJAGYCBQZjcmVkaXQAAAkAZQIFBmNyZWRpdAUHYmFsYW5jZQAAAQhjYWxjRnJlZQIGY3JlZGl0B2JhbGFuY2UDCQBmAgUGY3JlZGl0AAAJAGUCBQdiYWxhbmNlBQZjcmVkaXQAAAEOY2FsY1Nob3J0UHJpY2UCBGZyZWUMcmVhbEluQ3JlZGl0AwkAZgIFDHJlYWxJbkNyZWRpdAAACQCWAwEJAMwIAgAACQDMCAIJAGkCBQRmcmVlBQxyZWFsSW5DcmVkaXQFA25pbAAAAQ1jYWxjTG9uZ1ByaWNlAgRmcmVlDHJlYWxJbkNyZWRpdAMJAGYCBQxyZWFsSW5DcmVkaXQAAAkAlgMBCQDMCAIAAAkAzAgCCQBpAgUMcmVhbEluQ3JlZGl0BQRmcmVlBQNuaWwAAAEPY2FsY1N0YXJ0TWFyZ2luBA1yZWFsSW5DcmVkaXRBDXJlYWxJbkNyZWRpdEIMY3VycmVudFByaWNlDnNldHRpbmdzTWFyZ2luCQBoAgkAZAIJAGgCBQ1yZWFsSW5DcmVkaXRBBQxjdXJyZW50UHJpY2UFDXJlYWxJbkNyZWRpdEIFDnNldHRpbmdzTWFyZ2luARBjYWxjTWFyZ2luU3VwcGx5AxRzZXR0aW5nc01hcmdpblN1cHBseQ5zZXR0aW5nc01hcmdpbgtzdGFydE1hcmdpbgkAaAIJAGkCBRRzZXR0aW5nc01hcmdpblN1cHBseQUOc2V0dGluZ3NNYXJnaW4FC3N0YXJ0TWFyZ2luARRjYWxjTGlxdWlkYXRpb25QcmljZQYHZGVwb3NpdAxtYXJnaW5TdXBwbHkNcmVhbEluQ3JlZGl0QQ1yZWFsSW5DcmVkaXRCCnNob3J0UHJpY2UJbG9uZ1ByaWNlBBFsaXF1aWRhdGlvblByaWNlQQMJAGYCBQ1yZWFsSW5DcmVkaXRBAAAJAGQCCQBpAgkAZQIFB2RlcG9zaXQFDG1hcmdpblN1cHBseQUNcmVhbEluQ3JlZGl0QQUKc2hvcnRQcmljZQAABBFsaXF1aWRhdGlvblByaWNlQgMJAGYCBQ1yZWFsSW5DcmVkaXRCAAAJAGUCBQlsb25nUHJpY2UJAGkCCQBlAgUHZGVwb3NpdAUMbWFyZ2luU3VwcGx5CQBpAgUNcmVhbEluQ3JlZGl0QQUJbG9uZ1ByaWNlAAAJAGQCBRFsaXF1aWRhdGlvblByaWNlQQURbGlxdWlkYXRpb25QcmljZUIBGWdldEFzc2V0c0J5QWNjb3VudEFkZHJlc3MBDmFjY291bnRBZGRyZXNzBAlyZXF1ZXN0SWQJANkEAQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFDmZhY3RvcnlBZGRyZXNzCQEaa0FjY291bnRBZGRyZXNzVG9SZXF1ZXN0SWQBBQ5hY2NvdW50QWRkcmVzcwkBB3dyYXBFcnIBAhdpbnZhbGlkIGFjY291bnQgYWRkcmVzcwQNYW1vdW50QXNzZXRJZAkBDHBhcnNlQXNzZXRJZAEJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBQ5mYWN0b3J5QWRkcmVzcwkBFWtSZXF1ZXN0QW1vdW50QXNzZXRJZAEFCXJlcXVlc3RJZAkBB3dyYXBFcnIBAhdpbnZhbGlkIGFtb3VudCBhc3NldCBpZAQMcHJpY2VBc3NldElkCQEMcGFyc2VBc3NldElkAQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFDmZhY3RvcnlBZGRyZXNzCQEUa1JlcXVlc3RQcmljZUFzc2V0SWQBBQlyZXF1ZXN0SWQJAQd3cmFwRXJyAQIXaW52YWxpZCBhbW91bnQgcHJpY2UgaWQJAJQKAgUNYW1vdW50QXNzZXRJZAUMcHJpY2VBc3NldElkCgFpAQRpbml0ARFmYWN0b3J5QWRkcmVzc1N0cgQLY2hlY2tDYWxsZXIJAQhtdXN0VGhpcwEIBQFpBmNhbGxlcgMJAAACBQtjaGVja0NhbGxlcgULY2hlY2tDYWxsZXIJAJQKAgkAzAgCCQELU3RyaW5nRW50cnkCBQ9rRmFjdG9yeUFkZHJlc3MFEWZhY3RvcnlBZGRyZXNzU3RyBQNuaWwFBHVuaXQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEOcmVxdWVzdEFjY291bnQCD2NhbGxlclB1YmxpY0tleQRhcmdzBAZja2Vja3MJAMwIAgMJAQEhAQUIc2h1dGRvd24GCQEIdGhyb3dFcnIBAgtub3QgYWxsb3dlZAkAzAgCCQELbXVzdEZhY3RvcnkBCAUBaQZjYWxsZXIFA25pbAMJAAACBQZja2Vja3MFBmNrZWNrcwQQYW1vdW50QXNzZXRJZFN0cgkAkQMCBQRhcmdzAAAED3ByaWNlQXNzZXRJZFN0cgkAkQMCBQRhcmdzAAEEC3VzZXJBZGRyZXNzCQCnCAEFD2NhbGxlclB1YmxpY0tleQQJcmVxdWVzdElkCQD3AwEJAMsBAgkAywECCAULdXNlckFkZHJlc3MFYnl0ZXMJANkEAQUQYW1vdW50QXNzZXRJZFN0cgkA2QQBBQ9wcmljZUFzc2V0SWRTdHIEDWFtb3VudEFzc2V0SWQJAQxwYXJzZUFzc2V0SWQBBRBhbW91bnRBc3NldElkU3RyBAxwcmljZUFzc2V0SWQJAQxwYXJzZUFzc2V0SWQBBQ9wcmljZUFzc2V0SWRTdHIEEnVzZXJSZXF1ZXN0c051bWJlcgkAaQIJALECAQkBEGtSZXF1ZXN0c0J5T3duZXIBBQt1c2VyQWRkcmVzcwUNcXVldWVJdGVtU2l6ZQQGY2hlY2tzCQDMCAIDCQAAAgkAkAMBCAUBaQhwYXltZW50cwABBgkBCHRocm93RXJyAQIVMSBwYXltZW50IGlzIHJlcXVpcmVkCQDMCAIDCQAAAggJAJEDAggFAWkIcGF5bWVudHMAAAdhc3NldElkBQR1bml0BgkBCHRocm93RXJyAQINaW52YWxpZCBhc3NldAkAzAgCAwkAAAIICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50CQEMcmV3YXJkQW1vdW50AAYJAQh0aHJvd0VycgECDmludmFsaWQgYW1vdW50CQDMCAIDCQELcGFpckFsbG93ZWQCBQ1hbW91bnRBc3NldElkBQxwcmljZUFzc2V0SWQGCQEIdGhyb3dFcnIBAhNwYWlyIGlzIG5vdCBhbGxvd2VkCQDMCAIDCQAAAgkAmggCBQ5mYWN0b3J5QWRkcmVzcwkBDmtSZXF1ZXN0U3RhdHVzAQUJcmVxdWVzdElkBQR1bml0BgkBCHRocm93RXJyAQIZYWNjb3VudCBpcyBhbHJlYWR5IGV4aXN0cwkAzAgCAwkAZgIJAQ1hY2NvdW50c0xpbWl0AAUSdXNlclJlcXVlc3RzTnVtYmVyBgkBCHRocm93RXJyAQkArAICAhJhY2NvdW50cyBsaW1pdCBpcyAJAKQDAQkBDWFjY291bnRzTGltaXQABQNuaWwDCQAAAgUGY2hlY2tzBQZjaGVja3MEDCR0MDk3NTQxMTExMAMJAAACCQDIAQEJAQ1hY2NvdW50c1F1ZXVlAAAACQCUCgIJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwUOZmFjdG9yeUFkZHJlc3MJAQxyZXdhcmRBbW91bnQABQR1bml0BQNuaWwJAMwIAgkA/AcEBQ5mYWN0b3J5QWRkcmVzcwIMaW50ZWdlckVudHJ5CQDMCAIJAQ5rUmVxdWVzdFN0YXR1cwEFCXJlcXVlc3RJZAkAzAgCBRRSRVFVRVNUX1NUQVRVU19FTVBUWQUDbmlsBQNuaWwJAMwIAgkA/AcEBQ5mYWN0b3J5QWRkcmVzcwILYmluYXJ5RW50cnkJAMwIAgkBDmtSZXF1ZXN0c1F1ZXVlAAkAzAgCCQDLAQIJAQ1yZXF1ZXN0c1F1ZXVlAAUJcmVxdWVzdElkBQNuaWwFA25pbAUDbmlsBBBhY2NvdW50UHVibGljS2V5CQDJAQIJAQ1hY2NvdW50c1F1ZXVlAAUNcXVldWVJdGVtU2l6ZQQOYWNjb3VudEFkZHJlc3MJAKcIAQUQYWNjb3VudFB1YmxpY0tleQQOY3JlYXRvckFkZHJlc3MJAKcIAQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCcCAIFDmZhY3RvcnlBZGRyZXNzCQEYa0FjY291bnRDcmVhdG9yUHVibGljS2V5AQUOYWNjb3VudEFkZHJlc3MJAQd3cmFwRXJyAQIaaW52YWxpZCBjcmVhdG9yIHB1YmxpYyBrZXkJAJQKAgkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDBQ5jcmVhdG9yQWRkcmVzcwkBDHJld2FyZEFtb3VudAAFBHVuaXQFA25pbAkAzAgCCQD8BwQFDmZhY3RvcnlBZGRyZXNzAgtiaW5hcnlFbnRyeQkAzAgCCQEOa0FjY291bnRzUXVldWUACQDMCAIJAMoBAgkBDWFjY291bnRzUXVldWUABQ1xdWV1ZUl0ZW1TaXplBQNuaWwFA25pbAkAzAgCCQD8BwQFDmZhY3RvcnlBZGRyZXNzAgxpbnRlZ2VyRW50cnkJAMwIAgkBDmtSZXF1ZXN0U3RhdHVzAQUJcmVxdWVzdElkCQDMCAIFFFJFUVVFU1RfU1RBVFVTX1JFQURZBQNuaWwFA25pbAkAzAgCCQD8BwQFDmZhY3RvcnlBZGRyZXNzAgtiaW5hcnlFbnRyeQkAzAgCCQEca1JlcXVlc3RJZFRvQWNjb3VudFB1YmxpY0tleQEFCXJlcXVlc3RJZAkAzAgCBRBhY2NvdW50UHVibGljS2V5BQNuaWwFA25pbAkAzAgCCQD8BwQFDmZhY3RvcnlBZGRyZXNzAgtzdHJpbmdFbnRyeQkAzAgCCQEaa0FjY291bnRBZGRyZXNzVG9SZXF1ZXN0SWQBBQ5hY2NvdW50QWRkcmVzcwkAzAgCCQDYBAEFCXJlcXVlc3RJZAUDbmlsBQNuaWwFA25pbAQHYWN0aW9ucwgFDCR0MDk3NTQxMTExMAJfMQQOZmFjdG9yeUFjdGlvbnMIBQwkdDA5NzU0MTExMTACXzIJAJQKAgUHYWN0aW9ucwkAzggCBQ5mYWN0b3J5QWN0aW9ucwkAzAgCCQD8BwQFDmZhY3RvcnlBZGRyZXNzAgtiaW5hcnlFbnRyeQkAzAgCCQEWa1JlcXVlc3RPd25lclB1YmxpY0tleQEFCXJlcXVlc3RJZAkAzAgCBQ9jYWxsZXJQdWJsaWNLZXkFA25pbAUDbmlsCQDMCAIJAPwHBAUOZmFjdG9yeUFkZHJlc3MCC2JpbmFyeUVudHJ5CQDMCAIJARBrUmVxdWVzdHNCeU93bmVyAQULdXNlckFkZHJlc3MJAMwIAgkAywECCQEPcmVxdWVzdHNCeU93bmVyAQULdXNlckFkZHJlc3MFCXJlcXVlc3RJZAUDbmlsBQNuaWwJAMwIAgkA/AcEBQ5mYWN0b3J5QWRkcmVzcwILc3RyaW5nRW50cnkJAMwIAgkBFWtSZXF1ZXN0QW1vdW50QXNzZXRJZAEFCXJlcXVlc3RJZAkAzAgCBRBhbW91bnRBc3NldElkU3RyBQNuaWwFA25pbAkAzAgCCQD8BwQFDmZhY3RvcnlBZGRyZXNzAgtzdHJpbmdFbnRyeQkAzAgCCQEUa1JlcXVlc3RQcmljZUFzc2V0SWQBBQlyZXF1ZXN0SWQJAMwIAgUPcHJpY2VBc3NldElkU3RyBQNuaWwFA25pbAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCmFkZEFjY291bnQCD2NhbGxlclB1YmxpY0tleQRhcmdzBAZja2Vja3MJAMwIAgMJAQEhAQUIc2h1dGRvd24GCQEIdGhyb3dFcnIBAgtub3QgYWxsb3dlZAkAzAgCCQELbXVzdEZhY3RvcnkBCAUBaQZjYWxsZXIFA25pbAMJAAACBQZja2Vja3MFBmNrZWNrcwQQY3JlYXRvclB1YmxpY0tleQkA2QQBCQCRAwIFBGFyZ3MAAAQQYWNjb3VudFB1YmxpY0tleQUPY2FsbGVyUHVibGljS2V5BA5hY2NvdW50QWRkcmVzcwkApwgBBQ9jYWxsZXJQdWJsaWNLZXkEDmNyZWF0b3JBZGRyZXNzCQCnCAEFEGNyZWF0b3JQdWJsaWNLZXkEBmNoZWNrcwkAzAgCAwkAAAIJAJwIAgUOZmFjdG9yeUFkZHJlc3MJARhrQWNjb3VudENyZWF0b3JQdWJsaWNLZXkBBQ5hY2NvdW50QWRkcmVzcwUEdW5pdAYJAQh0aHJvd0VycgECGWFjY291bnQgaXMgYWxyZWFkeSBleGlzdHMJAMwIAgMEByRtYXRjaDAJAPEHAQUOYWNjb3VudEFkZHJlc3MDCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQBYgUHJG1hdGNoMAkAAAIFAWIJAPEVAQkBDWFjY291bnRTY3JpcHQABwYJAQh0aHJvd0VycgECDmludmFsaWQgc2NyaXB0BQNuaWwDCQAAAgUGY2hlY2tzBQZjaGVja3MEDSR0MDEyMzY1MTMzNjcDCQAAAgkAyAEBCQENcmVxdWVzdHNRdWV1ZQAAAAkAlAoCBQNuaWwJAMwIAgkA/AcEBQ5mYWN0b3J5QWRkcmVzcwILYmluYXJ5RW50cnkJAMwIAgkBDmtBY2NvdW50c1F1ZXVlAAkAzAgCCQDLAQIJAQ1hY2NvdW50c1F1ZXVlAAUQYWNjb3VudFB1YmxpY0tleQUDbmlsBQNuaWwFA25pbAQJcmVxdWVzdElkCQDJAQIJAQ1yZXF1ZXN0c1F1ZXVlAAUNcXVldWVJdGVtU2l6ZQkAlAoCBQNuaWwJAMwIAgkA/AcEBQ5mYWN0b3J5QWRkcmVzcwIMaW50ZWdlckVudHJ5CQDMCAIJAQ5rUmVxdWVzdFN0YXR1cwEFCXJlcXVlc3RJZAkAzAgCBRRSRVFVRVNUX1NUQVRVU19SRUFEWQUDbmlsBQNuaWwJAMwIAgkA/AcEBQ5mYWN0b3J5QWRkcmVzcwILYmluYXJ5RW50cnkJAMwIAgkBHGtSZXF1ZXN0SWRUb0FjY291bnRQdWJsaWNLZXkBBQlyZXF1ZXN0SWQJAMwIAgUQYWNjb3VudFB1YmxpY0tleQUDbmlsBQNuaWwJAMwIAgkA/AcEBQ5mYWN0b3J5QWRkcmVzcwILYmluYXJ5RW50cnkJAMwIAgkBDmtSZXF1ZXN0c1F1ZXVlAAkAzAgCCQDKAQIJAQ1yZXF1ZXN0c1F1ZXVlAAUNcXVldWVJdGVtU2l6ZQUDbmlsBQNuaWwJAMwIAgkA/AcEBQ5mYWN0b3J5QWRkcmVzcwILc3RyaW5nRW50cnkJAMwIAgkBGmtBY2NvdW50QWRkcmVzc1RvUmVxdWVzdElkAQUOYWNjb3VudEFkZHJlc3MJAMwIAgkA2AQBBQlyZXF1ZXN0SWQFA25pbAUDbmlsCQDMCAIJAPwHBAUOZmFjdG9yeUFkZHJlc3MCDXRyYW5zZmVyV2F2ZXMJAMwIAggFDmNyZWF0b3JBZGRyZXNzBWJ5dGVzCQDMCAIJAQxyZXdhcmRBbW91bnQABQNuaWwFA25pbAUDbmlsBAdhY3Rpb25zCAUNJHQwMTIzNjUxMzM2NwJfMQQOZmFjdG9yeUFjdGlvbnMIBQ0kdDAxMjM2NTEzMzY3Al8yCQCUCgIFB2FjdGlvbnMJAM4IAgUOZmFjdG9yeUFjdGlvbnMJAMwIAgkA/AcEBQ5mYWN0b3J5QWRkcmVzcwILYmluYXJ5RW50cnkJAMwIAgkBGGtBY2NvdW50Q3JlYXRvclB1YmxpY0tleQEFDmFjY291bnRBZGRyZXNzCQDMCAIFEGNyZWF0b3JQdWJsaWNLZXkFA25pbAUDbmlsBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEHZGVwb3NpdAIPY2FsbGVyUHVibGljS2V5BGFyZ3MEBmNrZWNrcwkAzAgCAwkBASEBBQhzaHV0ZG93bgYJAQh0aHJvd0VycgECC25vdCBhbGxvd2VkCQDMCAIJAQttdXN0RmFjdG9yeQEIBQFpBmNhbGxlcgUDbmlsAwkAAAIFBmNrZWNrcwUGY2tlY2tzBA5hY2NvdW50QWRkcmVzcwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJAJEDAgUEYXJncwAACQEHd3JhcEVycgECF2ludmFsaWQgYWNjb3VudCBhZGRyZXNzBAdwYXltZW50CQCRAwIIBQFpCHBheW1lbnRzAAAEB2FjdGlvbnMJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwUOYWNjb3VudEFkZHJlc3MIBQdwYXltZW50BmFtb3VudAgFB3BheW1lbnQHYXNzZXRJZAUDbmlsBA5mYWN0b3J5QWN0aW9ucwkAzAgCCQD8BwQFDmZhY3RvcnlBZGRyZXNzAgxpbnRlZ2VyRW50cnkJAMwIAgkBCmtEZXBvc2l0ZWQBBQ5hY2NvdW50QWRkcmVzcwkAzAgCCQBkAgkBC3ZhbHVlT3JFbHNlAgkBD2RlcG9zaXRlZE9wdGlvbgEFDmFjY291bnRBZGRyZXNzAAAIBQdwYXltZW50BmFtb3VudAUDbmlsBQNuaWwFA25pbAkAlAoCBQdhY3Rpb25zBQ5mYWN0b3J5QWN0aW9ucwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQh3aXRoZHJhdwIPY2FsbGVyUHVibGljS2V5BGFyZ3MEBmNrZWNrcwkAzAgCAwkBASEBBQhzaHV0ZG93bgYJAQh0aHJvd0VycgECC25vdCBhbGxvd2VkCQDMCAIJAQttdXN0RmFjdG9yeQEIBQFpBmNhbGxlcgUDbmlsAwkAAAIFBmNrZWNrcwUGY2tlY2tzBAt1c2VyQWRkcmVzcwkApwgBBQ9jYWxsZXJQdWJsaWNLZXkEDmFjY291bnRBZGRyZXNzCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkAkQMCBQRhcmdzAAAJAQd3cmFwRXJyAQIXaW52YWxpZCBhY2NvdW50IGFkZHJlc3MEBmFtb3VudAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEJAJEDAgUEYXJncwABCQEHd3JhcEVycgECDmludmFsaWQgYW1vdW50BAdhc3NldElkCQEMcGFyc2VBc3NldElkAQkAkQMCBQRhcmdzAAIEC2ludm9jYXRpb25zCQDMCAIJAPwHBAUOYWNjb3VudEFkZHJlc3MCDXRyYW5zZmVyQXNzZXQJAMwIAggFC3VzZXJBZGRyZXNzBWJ5dGVzCQDMCAIFBmFtb3VudAkAzAgCBQdhc3NldElkBQNuaWwFA25pbAUDbmlsCQCUCgIFA25pbAULaW52b2NhdGlvbnMJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEGYm9ycm93Ag9jYWxsZXJQdWJsaWNLZXkEYXJncwQGY2tlY2tzCQDMCAIDCQEBIQEFCHNodXRkb3duBgkBCHRocm93RXJyAQILbm90IGFsbG93ZWQJAMwIAgkBC211c3RGYWN0b3J5AQgFAWkGY2FsbGVyBQNuaWwDCQAAAgUGY2tlY2tzBQZja2Vja3MEDmFjY291bnRBZGRyZXNzCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkAkQMCBQRhcmdzAAAJAQd3cmFwRXJyAQIXaW52YWxpZCBhY2NvdW50IGFkZHJlc3MEB2Fzc2V0SWQJAQxwYXJzZUFzc2V0SWQBCQCRAwIFBGFyZ3MAAQQJYW1vdW50UmF3CQC2CQEJAJEDAgUEYXJncwACBAlkZXBvc2l0ZWQJAQt2YWx1ZU9yRWxzZQIJAQ9kZXBvc2l0ZWRPcHRpb24BBQ5hY2NvdW50QWRkcmVzcwAABA0kdDAxNTQxMzE1NDkwCQEZZ2V0QXNzZXRzQnlBY2NvdW50QWRkcmVzcwEFDmFjY291bnRBZGRyZXNzBA1hbW91bnRBc3NldElkCAUNJHQwMTU0MTMxNTQ5MAJfMQQMcHJpY2VBc3NldElkCAUNJHQwMTU0MTMxNTQ5MAJfMgQMY3VycmVudFByaWNlCQEPZ2V0Q3VycmVudFByaWNlAQUNYW1vdW50QXNzZXRJZAQHY3JlZGl0QQkBC3ZhbHVlT3JFbHNlAgkAmggCBQ5mYWN0b3J5QWRkcmVzcwkBB2tDcmVkaXQCBQ5hY2NvdW50QWRkcmVzcwUNYW1vdW50QXNzZXRJZAAABAdjcmVkaXRCCQELdmFsdWVPckVsc2UCCQCaCAIFDmZhY3RvcnlBZGRyZXNzCQEHa0NyZWRpdAIFDmFjY291bnRBZGRyZXNzBQxwcmljZUFzc2V0SWQAAAQLdG90YWxDcmVkaXQJAQ9jYWxjVG90YWxDcmVkaXQDBQdjcmVkaXRBBQdjcmVkaXRCBQxjdXJyZW50UHJpY2UED2xldmVyYWdlRGVmYXVsdAADBAhsZXZlcmFnZQkBC3ZhbHVlT3JFbHNlAgkAmggCBQ5mYWN0b3J5QWRkcmVzcwkBCWtMZXZlcmFnZQEFDmFjY291bnRBZGRyZXNzBQ9sZXZlcmFnZURlZmF1bHQED2NyZWRpdEF2YWlsYWJsZQkBE2NhbGNDcmVkaXRBdmFpbGFibGUDBQlkZXBvc2l0ZWQFCGxldmVyYWdlBQt0b3RhbENyZWRpdAkAlAoCBQNuaWwJAMwIAgUPY3JlZGl0QXZhaWxhYmxlBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEFcmVwYXkCD2NhbGxlclB1YmxpY0tleQRhcmdzBAZja2Vja3MJAMwIAgMJAQEhAQUIc2h1dGRvd24GCQEIdGhyb3dFcnIBAgtub3QgYWxsb3dlZAkAzAgCCQELbXVzdEZhY3RvcnkBCAUBaQZjYWxsZXIFA25pbAMJAAACBQZja2Vja3MFBmNrZWNrcwkAlAoCBQNuaWwFBHVuaXQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEQc2V0UGFpckFsbG93YW5jZQIPY2FsbGVyUHVibGljS2V5BGFyZ3MEBmNrZWNrcwkAzAgCAwkBASEBBQhzaHV0ZG93bgYJAQh0aHJvd0VycgECC25vdCBhbGxvd2VkCQDMCAIJAQttdXN0RmFjdG9yeQEIBQFpBmNhbGxlcgkAzAgCCQEJbXVzdEFkbWluAQUPY2FsbGVyUHVibGljS2V5BQNuaWwDCQAAAgUGY2tlY2tzBQZja2Vja3MEEGFtb3VudEFzc2V0SWRTdHIJAJEDAgUEYXJncwAABA9wcmljZUFzc2V0SWRTdHIJAJEDAgUEYXJncwABBAhhbGxvd1N0cgkAkQMCBQRhcmdzAAIEDWFtb3VudEFzc2V0SWQJAQxwYXJzZUFzc2V0SWQBBRBhbW91bnRBc3NldElkU3RyBAxwcmljZUFzc2V0SWQJAQxwYXJzZUFzc2V0SWQBBQ9wcmljZUFzc2V0SWRTdHIEBWFsbG93CQAAAgUIYWxsb3dTdHICBHRydWUEC2ludm9jYXRpb25zCQDMCAIJAPwHBAUOZmFjdG9yeUFkZHJlc3MCDGJvb2xlYW5FbnRyeQkAzAgCCQEMa1BhaXJBbGxvd2VkAgUNYW1vdW50QXNzZXRJZAUMcHJpY2VBc3NldElkCQDMCAIFBWFsbG93BQNuaWwFA25pbAUDbmlsCQCUCgIFA25pbAULaW52b2NhdGlvbnMJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQERYWRkU3ludGhldGljQXNzZXQCD2NhbGxlclB1YmxpY0tleQRhcmdzBA5iYXNlQXNzZXRJZFN0cgkAkQMCBQRhcmdzAAAEC2Jhc2VBc3NldElkCQEMcGFyc2VBc3NldElkAQUOYmFzZUFzc2V0SWRTdHIEEHN5bnRoZXRpY0Fzc2V0SWQICQCRAwIIBQFpCHBheW1lbnRzAAAHYXNzZXRJZAQGY2tlY2tzCQDMCAIDCQEBIQEFCHNodXRkb3duBgkBCHRocm93RXJyAQILbm90IGFsbG93ZWQJAMwIAgkBC211c3RGYWN0b3J5AQgFAWkGY2FsbGVyCQDMCAIJAQltdXN0QWRtaW4BBQ9jYWxsZXJQdWJsaWNLZXkJAMwIAgMJAAACCQCdCAIFDmZhY3RvcnlBZGRyZXNzCQERa1N5bnRoZXRpY0Fzc2V0SWQBBQtiYXNlQXNzZXRJZAUEdW5pdAYJAQh0aHJvd0VycgECEmludmFsaWQgYmFzZSBhc3NldAkAzAgCAwkAAAIJAJADAQgFAWkIcGF5bWVudHMAAQYJAQh0aHJvd0VycgECEGludmFsaWQgcGF5bWVudHMJAMwIAgMJAAACCQCdCAIFDmZhY3RvcnlBZGRyZXNzCQEMa0Jhc2VBc3NldElkAQUQc3ludGhldGljQXNzZXRJZAUEdW5pdAYJAQh0aHJvd0VycgECF2ludmFsaWQgc3ludGhldGljIGFzc2V0BQNuaWwDCQAAAgUGY2tlY2tzBQZja2Vja3MEC2ludm9jYXRpb25zCQDMCAIJAPwHBAUOZmFjdG9yeUFkZHJlc3MCC3N0cmluZ0VudHJ5CQDMCAIJARFrU3ludGhldGljQXNzZXRJZAEFC2Jhc2VBc3NldElkCQDMCAIJAQ9hc3NldElkVG9TdHJpbmcBBRBzeW50aGV0aWNBc3NldElkBQNuaWwFA25pbAkAzAgCCQD8BwQFDmZhY3RvcnlBZGRyZXNzAgtzdHJpbmdFbnRyeQkAzAgCCQEMa0Jhc2VBc3NldElkAQUQc3ludGhldGljQXNzZXRJZAkAzAgCCQEPYXNzZXRJZFRvU3RyaW5nAQULYmFzZUFzc2V0SWQFA25pbAUDbmlsBQNuaWwJAJQKAgUDbmlsBQtpbnZvY2F0aW9ucwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQpkb1NodXRkb3duAg9jYWxsZXJQdWJsaWNLZXkEYXJncwQGY2hlY2tzCQDMCAIJAQttdXN0RmFjdG9yeQEIBQFpBmNhbGxlcgkAzAgCCQEJbXVzdEFkbWluAQUPY2FsbGVyUHVibGljS2V5BQNuaWwDCQAAAgUGY2hlY2tzBQZjaGVja3MEC2ludm9jYXRpb25zCQDMCAIJAPwHBAUOZmFjdG9yeUFkZHJlc3MCDGJvb2xlYW5FbnRyeQkAzAgCBQlrU2h1dGRvd24JAMwIAgYFA25pbAUDbmlsBQNuaWwJAJQKAgUDbmlsBQtpbnZvY2F0aW9ucwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgECdHgBBnZlcmlmeQADAwkBCWlzRGVmaW5lZAEFFGZhY3RvcnlBZGRyZXNzT3B0aW9uCQEJaXNEZWZpbmVkAQkAnQgCBQ5mYWN0b3J5QWRkcmVzcwUJa011bHRpc2lnBwQHJG1hdGNoMAkAnQgCBQ5mYWN0b3J5QWRkcmVzcwUJa011bHRpc2lnAwkAAQIFByRtYXRjaDACBlN0cmluZwQIbXVsdGlzaWcFByRtYXRjaDAECXN0YXR1c0tleQkBB2tTdGF0dXMCCQClCAEFBHRoaXMJANgEAQgFAnR4AmlkBAZzdGF0dXMJAQt2YWx1ZU9yRWxzZQIJAJsIAgkBEUBleHRyTmF0aXZlKDEwNjIpAQUIbXVsdGlzaWcFCXN0YXR1c0tleQcFBnN0YXR1cwcJAPQDAwgFAnR4CWJvZHlCeXRlcwkAkQMCCAUCdHgGcHJvb2ZzAAAIBQJ0eA9zZW5kZXJQdWJsaWNLZXkB1bYk", "height": 3105469, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 5zzWw2qQYEvxnqh3evKVySAUAWQj1kBBHrN9RfJ2k13b Next: 59XkgwYmq5mHKfEiwAkDae3jNdFQgF8gfUfxuAgAXJf8 Diff:
OldNewDifferences
88 let chainIdW = base58'2W'
99
1010 let contractFilename = "futures_calculator.ride"
11+
12+let mult8 = 100000000
13+
14+let mult18BigInt = toBigInt(1000000000000000000)
15+
16+let wavesDecimals = 8
17+
18+let usdtDecimals = 6
19+
20+let kMultisig = "%s__multisig"
21+
22+func kStatus (dapp,txId) = makeString(["%s__status", dapp, txId], separator)
23+
24+
25+let kShutdown = "%s__shutdown"
26+
27+let kPublicKeys = "%s__publicKeys"
28+
29+let kMatcherPublicKey = "%s__matcherPublicKey"
30+
31+func toX18 (origVal,origScaleMult) = fraction(toBigInt(origVal), mult18BigInt, toBigInt(origScaleMult))
32+
33+
34+func fromX18 (val,resultScaleMult) = toInt(fraction(val, toBigInt(resultScaleMult), mult18BigInt))
35+
36+
37+func validateAddress (address) = isDefined(addressFromString(address))
38+
1139
1240 func wrapErr (s) = ((contractFilename + ": ") + s)
1341
2856
2957 let factoryAddress = valueOrErrorMessage(factoryAddressOption, wrapErr("invalid factory address"))
3058
31-func mustAddress (i,address) = if ((i.caller == address))
59+let kPricesAddress = "%s__calculatorAddress"
60+
61+let shutdown = valueOrElse(getBoolean(factoryAddress, kShutdown), false)
62+
63+func mustAddress (caller,address) = if ((caller == address))
3264 then true
3365 else throwErr("permission denied")
3466
3567
36-func mustThis (i) = mustAddress(i, this)
68+func mustThis (caller) = mustAddress(caller, this)
3769
3870
39-func mustFactory (i) = mustAddress(i, factoryAddress)
71+func mustFactory (caller) = mustAddress(caller, factoryAddress)
72+
73+
74+func mustAdmin (callerPublicKey) = {
75+ let multisig = addressFromStringValue(getStringValue(factoryAddress, kMultisig))
76+ let publicKeysList = split(getStringValue(multisig, kPublicKeys), separator)
77+ if (containsElement(publicKeysList, toBase58String(callerPublicKey)))
78+ then true
79+ else throwErr("not allowed")
80+ }
4081
4182
4283 let wavesString = "WAVES"
68109 let accountsLimitDefault = 20
69110
70111 func accountsLimit () = valueOrElse(getInteger(factoryAddress, kAccountsLimit), accountsLimitDefault)
112+
113+
114+func kDeposited (accountAddress) = makeString(["%s%s", "deposited", toString(accountAddress)], separator)
115+
116+
117+func depositedOption (accountAddress) = getInteger(factoryAddress, kDeposited(accountAddress))
118+
119+
120+func kCredit (accountAddress,assetId) = makeString(["%s%s%s", "credit", toString(accountAddress), assetIdToString(assetId)], separator)
121+
122+
123+func kLeverage (accountAddress) = makeString(["%s%s", "leverage", toString(accountAddress)], separator)
124+
125+
126+func kSyntheticAssetId (baseAssetId) = makeString(["%s%s", "syntheticAssetId", assetIdToString(baseAssetId)], separator)
127+
128+
129+func kBaseAssetId (syntheticAssetId) = makeString(["%s%s", "baseAssetId", assetIdToString(syntheticAssetId)], separator)
71130
72131
73132 let REQUEST_STATUS_EMPTY = 0
119178 func pairAllowed (amountAssetId,priceAssetId) = valueOrElse(getBoolean(factoryAddress, kPairAllowed(amountAssetId, priceAssetId)), false)
120179
121180
181+func kPrice (assetId) = makeString(["%s", assetIdToString(assetId)], separator)
182+
183+
184+func getCurrentPrice (assetId) = {
185+ let matcherPublicKey = fromBase58String(valueOrErrorMessage(getString(factoryAddress, kMatcherPublicKey), wrapErr("invalid matcher public key")))
186+ let matcherAddress = addressFromPublicKey(matcherPublicKey)
187+ let price = valueOrErrorMessage(getInteger(matcherAddress, kPrice(assetId)), wrapErr(("invalid price, assetId = " + assetIdToString(assetId))))
188+ price
189+ }
190+
191+
192+func calcTotalCredit (creditA,creditB,currentPrice) = ((creditA * currentPrice) + creditB)
193+
194+
195+func calcTotalBalance (balanceA,balanceB,currentPrice) = ((balanceA * currentPrice) + balanceB)
196+
197+
198+func calcPnl (totalBalance,totalCredit) = (totalBalance - totalCredit)
199+
200+
201+func calcCreditAvailable (deposit,leverage,totalCredit) = ((deposit * leverage) - totalCredit)
202+
203+
204+func calcRealInCredit (credit,balance) = if ((credit > 0))
205+ then (credit - balance)
206+ else 0
207+
208+
209+func calcFree (credit,balance) = if ((credit > 0))
210+ then (balance - credit)
211+ else 0
212+
213+
214+func calcShortPrice (free,realInCredit) = if ((realInCredit > 0))
215+ then max([0, (free / realInCredit)])
216+ else 0
217+
218+
219+func calcLongPrice (free,realInCredit) = if ((realInCredit > 0))
220+ then max([0, (realInCredit / free)])
221+ else 0
222+
223+
224+func calcStartMargin (realInCreditA,realInCreditB,currentPrice,settingsMargin) = (((realInCreditA * currentPrice) + realInCreditB) * settingsMargin)
225+
226+
227+func calcMarginSupply (settingsMarginSupply,settingsMargin,startMargin) = ((settingsMarginSupply / settingsMargin) * startMargin)
228+
229+
230+func calcLiquidationPrice (deposit,marginSupply,realInCreditA,realInCreditB,shortPrice,longPrice) = {
231+ let liquidationPriceA = if ((realInCreditA > 0))
232+ then (((deposit - marginSupply) / realInCreditA) + shortPrice)
233+ else 0
234+ let liquidationPriceB = if ((realInCreditB > 0))
235+ then (longPrice - ((deposit - marginSupply) / (realInCreditA / longPrice)))
236+ else 0
237+ (liquidationPriceA + liquidationPriceB)
238+ }
239+
240+
241+func getAssetsByAccountAddress (accountAddress) = {
242+ let requestId = fromBase58String(valueOrErrorMessage(getString(factoryAddress, kAccountAddressToRequestId(accountAddress)), wrapErr("invalid account address")))
243+ let amountAssetId = parseAssetId(valueOrErrorMessage(getString(factoryAddress, kRequestAmountAssetId(requestId)), wrapErr("invalid amount asset id")))
244+ let priceAssetId = parseAssetId(valueOrErrorMessage(getString(factoryAddress, kRequestPriceAssetId(requestId)), wrapErr("invalid amount price id")))
245+ $Tuple2(amountAssetId, priceAssetId)
246+ }
247+
248+
122249 @Callable(i)
123250 func init (factoryAddressStr) = {
124- let checkCaller = mustThis(i)
251+ let checkCaller = mustThis(i.caller)
125252 if ((checkCaller == checkCaller))
126253 then $Tuple2([StringEntry(kFactoryAddress, factoryAddressStr)], unit)
127254 else throw("Strict value is not equal to itself.")
131258
132259 @Callable(i)
133260 func requestAccount (callerPublicKey,args) = {
134- let checkCaller = mustFactory(i)
135- if ((checkCaller == checkCaller))
261+ let ckecks = [if (!(shutdown))
262+ then true
263+ else throwErr("not allowed"), mustFactory(i.caller)]
264+ if ((ckecks == ckecks))
136265 then {
137266 let amountAssetIdStr = args[0]
138267 let priceAssetIdStr = args[1]
156285 else throwErr(("accounts limit is " + toString(accountsLimit())))]
157286 if ((checks == checks))
158287 then {
159- let $t050206376 = if ((size(accountsQueue()) == 0))
288+ let $t0975411110 = if ((size(accountsQueue()) == 0))
160289 then $Tuple2([ScriptTransfer(factoryAddress, rewardAmount(), unit)], [invoke(factoryAddress, "integerEntry", [kRequestStatus(requestId), REQUEST_STATUS_EMPTY], nil), invoke(factoryAddress, "binaryEntry", [kRequestsQueue(), (requestsQueue() + requestId)], nil)])
161290 else {
162291 let accountPublicKey = take(accountsQueue(), queueItemSize)
164293 let creatorAddress = addressFromPublicKey(valueOrErrorMessage(getBinary(factoryAddress, kAccountCreatorPublicKey(accountAddress)), wrapErr("invalid creator public key")))
165294 $Tuple2([ScriptTransfer(creatorAddress, rewardAmount(), unit)], [invoke(factoryAddress, "binaryEntry", [kAccountsQueue(), drop(accountsQueue(), queueItemSize)], nil), invoke(factoryAddress, "integerEntry", [kRequestStatus(requestId), REQUEST_STATUS_READY], nil), invoke(factoryAddress, "binaryEntry", [kRequestIdToAccountPublicKey(requestId), accountPublicKey], nil), invoke(factoryAddress, "stringEntry", [kAccountAddressToRequestId(accountAddress), toBase58String(requestId)], nil)])
166295 }
167- let actions = $t050206376._1
168- let factoryActions = $t050206376._2
296+ let actions = $t0975411110._1
297+ let factoryActions = $t0975411110._2
169298 $Tuple2(actions, (factoryActions ++ [invoke(factoryAddress, "binaryEntry", [kRequestOwnerPublicKey(requestId), callerPublicKey], nil), invoke(factoryAddress, "binaryEntry", [kRequestsByOwner(userAddress), (requestsByOwner(userAddress) + requestId)], nil), invoke(factoryAddress, "stringEntry", [kRequestAmountAssetId(requestId), amountAssetIdStr], nil), invoke(factoryAddress, "stringEntry", [kRequestPriceAssetId(requestId), priceAssetIdStr], nil)]))
170299 }
171300 else throw("Strict value is not equal to itself.")
177306
178307 @Callable(i)
179308 func addAccount (callerPublicKey,args) = {
180- let checkCaller = mustFactory(i)
181- if ((checkCaller == checkCaller))
309+ let ckecks = [if (!(shutdown))
310+ then true
311+ else throwErr("not allowed"), mustFactory(i.caller)]
312+ if ((ckecks == ckecks))
182313 then {
183314 let creatorPublicKey = fromBase58String(args[0])
184315 let accountPublicKey = callerPublicKey
196327 else throwErr("invalid script")]
197328 if ((checks == checks))
198329 then {
199- let $t075778579 = if ((size(requestsQueue()) == 0))
330+ let $t01236513367 = if ((size(requestsQueue()) == 0))
200331 then $Tuple2(nil, [invoke(factoryAddress, "binaryEntry", [kAccountsQueue(), (accountsQueue() + accountPublicKey)], nil)])
201332 else {
202333 let requestId = take(requestsQueue(), queueItemSize)
203334 $Tuple2(nil, [invoke(factoryAddress, "integerEntry", [kRequestStatus(requestId), REQUEST_STATUS_READY], nil), invoke(factoryAddress, "binaryEntry", [kRequestIdToAccountPublicKey(requestId), accountPublicKey], nil), invoke(factoryAddress, "binaryEntry", [kRequestsQueue(), drop(requestsQueue(), queueItemSize)], nil), invoke(factoryAddress, "stringEntry", [kAccountAddressToRequestId(accountAddress), toBase58String(requestId)], nil), invoke(factoryAddress, "transferWaves", [creatorAddress.bytes, rewardAmount()], nil)])
204335 }
205- let actions = $t075778579._1
206- let factoryActions = $t075778579._2
336+ let actions = $t01236513367._1
337+ let factoryActions = $t01236513367._2
207338 $Tuple2(actions, (factoryActions ++ [invoke(factoryAddress, "binaryEntry", [kAccountCreatorPublicKey(accountAddress), creatorPublicKey], nil)]))
208339 }
209340 else throw("Strict value is not equal to itself.")
215346
216347 @Callable(i)
217348 func deposit (callerPublicKey,args) = {
218- let checkCaller = mustFactory(i)
219- if ((checkCaller == checkCaller))
349+ let ckecks = [if (!(shutdown))
350+ then true
351+ else throwErr("not allowed"), mustFactory(i.caller)]
352+ if ((ckecks == ckecks))
220353 then {
221354 let accountAddress = valueOrErrorMessage(addressFromString(args[0]), wrapErr("invalid account address"))
222355 let payment = i.payments[0]
223356 let actions = [ScriptTransfer(accountAddress, payment.amount, payment.assetId)]
224- let factoryActions = nil
357+ let factoryActions = [invoke(factoryAddress, "integerEntry", [kDeposited(accountAddress), (valueOrElse(depositedOption(accountAddress), 0) + payment.amount)], nil)]
225358 $Tuple2(actions, factoryActions)
226359 }
227360 else throw("Strict value is not equal to itself.")
231364
232365 @Callable(i)
233366 func withdraw (callerPublicKey,args) = {
234- let checkCaller = mustFactory(i)
235- if ((checkCaller == checkCaller))
367+ let ckecks = [if (!(shutdown))
368+ then true
369+ else throwErr("not allowed"), mustFactory(i.caller)]
370+ if ((ckecks == ckecks))
236371 then {
237372 let userAddress = addressFromPublicKey(callerPublicKey)
238373 let accountAddress = valueOrErrorMessage(addressFromString(args[0]), wrapErr("invalid account address"))
247382
248383
249384 @Callable(i)
250-func pairAllowance (callerPublicKey,args) = {
251- let checkCaller = mustFactory(i)
252- if ((checkCaller == checkCaller))
385+func borrow (callerPublicKey,args) = {
386+ let ckecks = [if (!(shutdown))
387+ then true
388+ else throwErr("not allowed"), mustFactory(i.caller)]
389+ if ((ckecks == ckecks))
390+ then {
391+ let accountAddress = valueOrErrorMessage(addressFromString(args[0]), wrapErr("invalid account address"))
392+ let assetId = parseAssetId(args[1])
393+ let amountRaw = parseInt(args[2])
394+ let deposited = valueOrElse(depositedOption(accountAddress), 0)
395+ let $t01541315490 = getAssetsByAccountAddress(accountAddress)
396+ let amountAssetId = $t01541315490._1
397+ let priceAssetId = $t01541315490._2
398+ let currentPrice = getCurrentPrice(amountAssetId)
399+ let creditA = valueOrElse(getInteger(factoryAddress, kCredit(accountAddress, amountAssetId)), 0)
400+ let creditB = valueOrElse(getInteger(factoryAddress, kCredit(accountAddress, priceAssetId)), 0)
401+ let totalCredit = calcTotalCredit(creditA, creditB, currentPrice)
402+ let leverageDefault = 3
403+ let leverage = valueOrElse(getInteger(factoryAddress, kLeverage(accountAddress)), leverageDefault)
404+ let creditAvailable = calcCreditAvailable(deposited, leverage, totalCredit)
405+ $Tuple2(nil, [creditAvailable])
406+ }
407+ else throw("Strict value is not equal to itself.")
408+ }
409+
410+
411+
412+@Callable(i)
413+func repay (callerPublicKey,args) = {
414+ let ckecks = [if (!(shutdown))
415+ then true
416+ else throwErr("not allowed"), mustFactory(i.caller)]
417+ if ((ckecks == ckecks))
418+ then $Tuple2(nil, unit)
419+ else throw("Strict value is not equal to itself.")
420+ }
421+
422+
423+
424+@Callable(i)
425+func setPairAllowance (callerPublicKey,args) = {
426+ let ckecks = [if (!(shutdown))
427+ then true
428+ else throwErr("not allowed"), mustFactory(i.caller), mustAdmin(callerPublicKey)]
429+ if ((ckecks == ckecks))
253430 then {
254431 let amountAssetIdStr = args[0]
255432 let priceAssetIdStr = args[1]
264441 }
265442
266443
444+
445+@Callable(i)
446+func addSyntheticAsset (callerPublicKey,args) = {
447+ let baseAssetIdStr = args[0]
448+ let baseAssetId = parseAssetId(baseAssetIdStr)
449+ let syntheticAssetId = i.payments[0].assetId
450+ let ckecks = [if (!(shutdown))
451+ then true
452+ else throwErr("not allowed"), mustFactory(i.caller), mustAdmin(callerPublicKey), if ((getString(factoryAddress, kSyntheticAssetId(baseAssetId)) == unit))
453+ then true
454+ else throwErr("invalid base asset"), if ((size(i.payments) == 1))
455+ then true
456+ else throwErr("invalid payments"), if ((getString(factoryAddress, kBaseAssetId(syntheticAssetId)) == unit))
457+ then true
458+ else throwErr("invalid synthetic asset")]
459+ if ((ckecks == ckecks))
460+ then {
461+ let invocations = [invoke(factoryAddress, "stringEntry", [kSyntheticAssetId(baseAssetId), assetIdToString(syntheticAssetId)], nil), invoke(factoryAddress, "stringEntry", [kBaseAssetId(syntheticAssetId), assetIdToString(baseAssetId)], nil)]
462+ $Tuple2(nil, invocations)
463+ }
464+ else throw("Strict value is not equal to itself.")
465+ }
466+
467+
468+
469+@Callable(i)
470+func doShutdown (callerPublicKey,args) = {
471+ let checks = [mustFactory(i.caller), mustAdmin(callerPublicKey)]
472+ if ((checks == checks))
473+ then {
474+ let invocations = [invoke(factoryAddress, "booleanEntry", [kShutdown, true], nil)]
475+ $Tuple2(nil, invocations)
476+ }
477+ else throw("Strict value is not equal to itself.")
478+ }
479+
480+
481+@Verifier(tx)
482+func verify () = if (if (isDefined(factoryAddressOption))
483+ then isDefined(getString(factoryAddress, kMultisig))
484+ else false)
485+ then match getString(factoryAddress, kMultisig) {
486+ case multisig: String =>
487+ let statusKey = kStatus(toString(this), toBase58String(tx.id))
488+ let status = valueOrElse(getBoolean(addressFromStringValue(multisig), statusKey), false)
489+ status
490+ case _ =>
491+ false
492+ }
493+ else sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
494+
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 7 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let separator = "__"
55
66 let chainId = take(drop(this.bytes, 1), 1)
77
88 let chainIdW = base58'2W'
99
1010 let contractFilename = "futures_calculator.ride"
11+
12+let mult8 = 100000000
13+
14+let mult18BigInt = toBigInt(1000000000000000000)
15+
16+let wavesDecimals = 8
17+
18+let usdtDecimals = 6
19+
20+let kMultisig = "%s__multisig"
21+
22+func kStatus (dapp,txId) = makeString(["%s__status", dapp, txId], separator)
23+
24+
25+let kShutdown = "%s__shutdown"
26+
27+let kPublicKeys = "%s__publicKeys"
28+
29+let kMatcherPublicKey = "%s__matcherPublicKey"
30+
31+func toX18 (origVal,origScaleMult) = fraction(toBigInt(origVal), mult18BigInt, toBigInt(origScaleMult))
32+
33+
34+func fromX18 (val,resultScaleMult) = toInt(fraction(val, toBigInt(resultScaleMult), mult18BigInt))
35+
36+
37+func validateAddress (address) = isDefined(addressFromString(address))
38+
1139
1240 func wrapErr (s) = ((contractFilename + ": ") + s)
1341
1442
1543 func throwErr (s) = throw(wrapErr(s))
1644
1745
1846 let kFactoryAddress = "%s__factoryAddress"
1947
2048 let factoryAddressOption = match getString(this, kFactoryAddress) {
2149 case s: String =>
2250 addressFromString(s)
2351 case _: Unit =>
2452 unit
2553 case _ =>
2654 throw("Match error")
2755 }
2856
2957 let factoryAddress = valueOrErrorMessage(factoryAddressOption, wrapErr("invalid factory address"))
3058
31-func mustAddress (i,address) = if ((i.caller == address))
59+let kPricesAddress = "%s__calculatorAddress"
60+
61+let shutdown = valueOrElse(getBoolean(factoryAddress, kShutdown), false)
62+
63+func mustAddress (caller,address) = if ((caller == address))
3264 then true
3365 else throwErr("permission denied")
3466
3567
36-func mustThis (i) = mustAddress(i, this)
68+func mustThis (caller) = mustAddress(caller, this)
3769
3870
39-func mustFactory (i) = mustAddress(i, factoryAddress)
71+func mustFactory (caller) = mustAddress(caller, factoryAddress)
72+
73+
74+func mustAdmin (callerPublicKey) = {
75+ let multisig = addressFromStringValue(getStringValue(factoryAddress, kMultisig))
76+ let publicKeysList = split(getStringValue(multisig, kPublicKeys), separator)
77+ if (containsElement(publicKeysList, toBase58String(callerPublicKey)))
78+ then true
79+ else throwErr("not allowed")
80+ }
4081
4182
4283 let wavesString = "WAVES"
4384
4485 let queueItemSize = 32
4586
4687 func parseAssetId (input) = if ((input == wavesString))
4788 then unit
4889 else fromBase58String(input)
4990
5091
5192 func assetIdToString (input) = if ((input == unit))
5293 then wavesString
5394 else toBase58String(value(input))
5495
5596
5697 let kAccountScript = "%s__accountScript"
5798
5899 func accountScript () = valueOrErrorMessage(getBinary(factoryAddress, kAccountScript), wrapErr("account script is not set"))
59100
60101
61102 let kRewardAmount = "%s__rewardAmount"
62103
63104 func rewardAmount () = valueOrErrorMessage(getInteger(factoryAddress, kRewardAmount), wrapErr("reward amount is not set"))
64105
65106
66107 let kAccountsLimit = "%s__accountsLimit"
67108
68109 let accountsLimitDefault = 20
69110
70111 func accountsLimit () = valueOrElse(getInteger(factoryAddress, kAccountsLimit), accountsLimitDefault)
112+
113+
114+func kDeposited (accountAddress) = makeString(["%s%s", "deposited", toString(accountAddress)], separator)
115+
116+
117+func depositedOption (accountAddress) = getInteger(factoryAddress, kDeposited(accountAddress))
118+
119+
120+func kCredit (accountAddress,assetId) = makeString(["%s%s%s", "credit", toString(accountAddress), assetIdToString(assetId)], separator)
121+
122+
123+func kLeverage (accountAddress) = makeString(["%s%s", "leverage", toString(accountAddress)], separator)
124+
125+
126+func kSyntheticAssetId (baseAssetId) = makeString(["%s%s", "syntheticAssetId", assetIdToString(baseAssetId)], separator)
127+
128+
129+func kBaseAssetId (syntheticAssetId) = makeString(["%s%s", "baseAssetId", assetIdToString(syntheticAssetId)], separator)
71130
72131
73132 let REQUEST_STATUS_EMPTY = 0
74133
75134 let REQUEST_STATUS_READY = 1
76135
77136 func kRequestStatus (requestId) = makeString(["%s%s", toBase58String(requestId), "status"], separator)
78137
79138
80139 func kAccountCreatorPublicKey (accountAddress) = makeString(["%s%s", toString(accountAddress), "creatorPublicKey"], separator)
81140
82141
83142 func kRequestOwnerPublicKey (requestId) = makeString(["%s%s", toBase58String(requestId), "ownerPublicKey"], separator)
84143
85144
86145 func kRequestAmountAssetId (requestId) = makeString(["%s%s", toBase58String(requestId), "amountAssetId"], separator)
87146
88147
89148 func kRequestPriceAssetId (requestId) = makeString(["%s%s", toBase58String(requestId), "priceAssetId"], separator)
90149
91150
92151 func kRequestIdToAccountPublicKey (requestId) = makeString(["%s%s", toBase58String(requestId), "requestIdToAccountPublicKey"], separator)
93152
94153
95154 func kAccountAddressToRequestId (accountAddress) = makeString(["%s%s", toString(accountAddress), "accountAddressToRequestId"], separator)
96155
97156
98157 func kRequestsQueue () = makeString(["%s", "requestsQueue"], separator)
99158
100159
101160 func requestsQueue () = valueOrElse(getBinary(factoryAddress, kRequestsQueue()), base58'')
102161
103162
104163 func kAccountsQueue () = makeString(["%s", "accountsQueue"], separator)
105164
106165
107166 func accountsQueue () = valueOrElse(getBinary(factoryAddress, kAccountsQueue()), base58'')
108167
109168
110169 func kRequestsByOwner (ownerAddress) = makeString(["%s%s", "accounts", toString(ownerAddress)], separator)
111170
112171
113172 func requestsByOwner (ownerAddress) = valueOrElse(getBinary(factoryAddress, kRequestsByOwner(ownerAddress)), base58'')
114173
115174
116175 func kPairAllowed (amountAssetId,priceAssetId) = makeString(["%s%s%s", assetIdToString(amountAssetId), assetIdToString(priceAssetId), "pairAllowed"], separator)
117176
118177
119178 func pairAllowed (amountAssetId,priceAssetId) = valueOrElse(getBoolean(factoryAddress, kPairAllowed(amountAssetId, priceAssetId)), false)
120179
121180
181+func kPrice (assetId) = makeString(["%s", assetIdToString(assetId)], separator)
182+
183+
184+func getCurrentPrice (assetId) = {
185+ let matcherPublicKey = fromBase58String(valueOrErrorMessage(getString(factoryAddress, kMatcherPublicKey), wrapErr("invalid matcher public key")))
186+ let matcherAddress = addressFromPublicKey(matcherPublicKey)
187+ let price = valueOrErrorMessage(getInteger(matcherAddress, kPrice(assetId)), wrapErr(("invalid price, assetId = " + assetIdToString(assetId))))
188+ price
189+ }
190+
191+
192+func calcTotalCredit (creditA,creditB,currentPrice) = ((creditA * currentPrice) + creditB)
193+
194+
195+func calcTotalBalance (balanceA,balanceB,currentPrice) = ((balanceA * currentPrice) + balanceB)
196+
197+
198+func calcPnl (totalBalance,totalCredit) = (totalBalance - totalCredit)
199+
200+
201+func calcCreditAvailable (deposit,leverage,totalCredit) = ((deposit * leverage) - totalCredit)
202+
203+
204+func calcRealInCredit (credit,balance) = if ((credit > 0))
205+ then (credit - balance)
206+ else 0
207+
208+
209+func calcFree (credit,balance) = if ((credit > 0))
210+ then (balance - credit)
211+ else 0
212+
213+
214+func calcShortPrice (free,realInCredit) = if ((realInCredit > 0))
215+ then max([0, (free / realInCredit)])
216+ else 0
217+
218+
219+func calcLongPrice (free,realInCredit) = if ((realInCredit > 0))
220+ then max([0, (realInCredit / free)])
221+ else 0
222+
223+
224+func calcStartMargin (realInCreditA,realInCreditB,currentPrice,settingsMargin) = (((realInCreditA * currentPrice) + realInCreditB) * settingsMargin)
225+
226+
227+func calcMarginSupply (settingsMarginSupply,settingsMargin,startMargin) = ((settingsMarginSupply / settingsMargin) * startMargin)
228+
229+
230+func calcLiquidationPrice (deposit,marginSupply,realInCreditA,realInCreditB,shortPrice,longPrice) = {
231+ let liquidationPriceA = if ((realInCreditA > 0))
232+ then (((deposit - marginSupply) / realInCreditA) + shortPrice)
233+ else 0
234+ let liquidationPriceB = if ((realInCreditB > 0))
235+ then (longPrice - ((deposit - marginSupply) / (realInCreditA / longPrice)))
236+ else 0
237+ (liquidationPriceA + liquidationPriceB)
238+ }
239+
240+
241+func getAssetsByAccountAddress (accountAddress) = {
242+ let requestId = fromBase58String(valueOrErrorMessage(getString(factoryAddress, kAccountAddressToRequestId(accountAddress)), wrapErr("invalid account address")))
243+ let amountAssetId = parseAssetId(valueOrErrorMessage(getString(factoryAddress, kRequestAmountAssetId(requestId)), wrapErr("invalid amount asset id")))
244+ let priceAssetId = parseAssetId(valueOrErrorMessage(getString(factoryAddress, kRequestPriceAssetId(requestId)), wrapErr("invalid amount price id")))
245+ $Tuple2(amountAssetId, priceAssetId)
246+ }
247+
248+
122249 @Callable(i)
123250 func init (factoryAddressStr) = {
124- let checkCaller = mustThis(i)
251+ let checkCaller = mustThis(i.caller)
125252 if ((checkCaller == checkCaller))
126253 then $Tuple2([StringEntry(kFactoryAddress, factoryAddressStr)], unit)
127254 else throw("Strict value is not equal to itself.")
128255 }
129256
130257
131258
132259 @Callable(i)
133260 func requestAccount (callerPublicKey,args) = {
134- let checkCaller = mustFactory(i)
135- if ((checkCaller == checkCaller))
261+ let ckecks = [if (!(shutdown))
262+ then true
263+ else throwErr("not allowed"), mustFactory(i.caller)]
264+ if ((ckecks == ckecks))
136265 then {
137266 let amountAssetIdStr = args[0]
138267 let priceAssetIdStr = args[1]
139268 let userAddress = addressFromPublicKey(callerPublicKey)
140269 let requestId = sha256(((userAddress.bytes + fromBase58String(amountAssetIdStr)) + fromBase58String(priceAssetIdStr)))
141270 let amountAssetId = parseAssetId(amountAssetIdStr)
142271 let priceAssetId = parseAssetId(priceAssetIdStr)
143272 let userRequestsNumber = (size(kRequestsByOwner(userAddress)) / queueItemSize)
144273 let checks = [if ((size(i.payments) == 1))
145274 then true
146275 else throwErr("1 payment is required"), if ((i.payments[0].assetId == unit))
147276 then true
148277 else throwErr("invalid asset"), if ((i.payments[0].amount == rewardAmount()))
149278 then true
150279 else throwErr("invalid amount"), if (pairAllowed(amountAssetId, priceAssetId))
151280 then true
152281 else throwErr("pair is not allowed"), if ((getInteger(factoryAddress, kRequestStatus(requestId)) == unit))
153282 then true
154283 else throwErr("account is already exists"), if ((accountsLimit() > userRequestsNumber))
155284 then true
156285 else throwErr(("accounts limit is " + toString(accountsLimit())))]
157286 if ((checks == checks))
158287 then {
159- let $t050206376 = if ((size(accountsQueue()) == 0))
288+ let $t0975411110 = if ((size(accountsQueue()) == 0))
160289 then $Tuple2([ScriptTransfer(factoryAddress, rewardAmount(), unit)], [invoke(factoryAddress, "integerEntry", [kRequestStatus(requestId), REQUEST_STATUS_EMPTY], nil), invoke(factoryAddress, "binaryEntry", [kRequestsQueue(), (requestsQueue() + requestId)], nil)])
161290 else {
162291 let accountPublicKey = take(accountsQueue(), queueItemSize)
163292 let accountAddress = addressFromPublicKey(accountPublicKey)
164293 let creatorAddress = addressFromPublicKey(valueOrErrorMessage(getBinary(factoryAddress, kAccountCreatorPublicKey(accountAddress)), wrapErr("invalid creator public key")))
165294 $Tuple2([ScriptTransfer(creatorAddress, rewardAmount(), unit)], [invoke(factoryAddress, "binaryEntry", [kAccountsQueue(), drop(accountsQueue(), queueItemSize)], nil), invoke(factoryAddress, "integerEntry", [kRequestStatus(requestId), REQUEST_STATUS_READY], nil), invoke(factoryAddress, "binaryEntry", [kRequestIdToAccountPublicKey(requestId), accountPublicKey], nil), invoke(factoryAddress, "stringEntry", [kAccountAddressToRequestId(accountAddress), toBase58String(requestId)], nil)])
166295 }
167- let actions = $t050206376._1
168- let factoryActions = $t050206376._2
296+ let actions = $t0975411110._1
297+ let factoryActions = $t0975411110._2
169298 $Tuple2(actions, (factoryActions ++ [invoke(factoryAddress, "binaryEntry", [kRequestOwnerPublicKey(requestId), callerPublicKey], nil), invoke(factoryAddress, "binaryEntry", [kRequestsByOwner(userAddress), (requestsByOwner(userAddress) + requestId)], nil), invoke(factoryAddress, "stringEntry", [kRequestAmountAssetId(requestId), amountAssetIdStr], nil), invoke(factoryAddress, "stringEntry", [kRequestPriceAssetId(requestId), priceAssetIdStr], nil)]))
170299 }
171300 else throw("Strict value is not equal to itself.")
172301 }
173302 else throw("Strict value is not equal to itself.")
174303 }
175304
176305
177306
178307 @Callable(i)
179308 func addAccount (callerPublicKey,args) = {
180- let checkCaller = mustFactory(i)
181- if ((checkCaller == checkCaller))
309+ let ckecks = [if (!(shutdown))
310+ then true
311+ else throwErr("not allowed"), mustFactory(i.caller)]
312+ if ((ckecks == ckecks))
182313 then {
183314 let creatorPublicKey = fromBase58String(args[0])
184315 let accountPublicKey = callerPublicKey
185316 let accountAddress = addressFromPublicKey(callerPublicKey)
186317 let creatorAddress = addressFromPublicKey(creatorPublicKey)
187318 let checks = [if ((getBinary(factoryAddress, kAccountCreatorPublicKey(accountAddress)) == unit))
188319 then true
189320 else throwErr("account is already exists"), if ( match scriptHash(accountAddress) {
190321 case b: ByteVector =>
191322 (b == blake2b256_32Kb(accountScript()))
192323 case _ =>
193324 false
194325 })
195326 then true
196327 else throwErr("invalid script")]
197328 if ((checks == checks))
198329 then {
199- let $t075778579 = if ((size(requestsQueue()) == 0))
330+ let $t01236513367 = if ((size(requestsQueue()) == 0))
200331 then $Tuple2(nil, [invoke(factoryAddress, "binaryEntry", [kAccountsQueue(), (accountsQueue() + accountPublicKey)], nil)])
201332 else {
202333 let requestId = take(requestsQueue(), queueItemSize)
203334 $Tuple2(nil, [invoke(factoryAddress, "integerEntry", [kRequestStatus(requestId), REQUEST_STATUS_READY], nil), invoke(factoryAddress, "binaryEntry", [kRequestIdToAccountPublicKey(requestId), accountPublicKey], nil), invoke(factoryAddress, "binaryEntry", [kRequestsQueue(), drop(requestsQueue(), queueItemSize)], nil), invoke(factoryAddress, "stringEntry", [kAccountAddressToRequestId(accountAddress), toBase58String(requestId)], nil), invoke(factoryAddress, "transferWaves", [creatorAddress.bytes, rewardAmount()], nil)])
204335 }
205- let actions = $t075778579._1
206- let factoryActions = $t075778579._2
336+ let actions = $t01236513367._1
337+ let factoryActions = $t01236513367._2
207338 $Tuple2(actions, (factoryActions ++ [invoke(factoryAddress, "binaryEntry", [kAccountCreatorPublicKey(accountAddress), creatorPublicKey], nil)]))
208339 }
209340 else throw("Strict value is not equal to itself.")
210341 }
211342 else throw("Strict value is not equal to itself.")
212343 }
213344
214345
215346
216347 @Callable(i)
217348 func deposit (callerPublicKey,args) = {
218- let checkCaller = mustFactory(i)
219- if ((checkCaller == checkCaller))
349+ let ckecks = [if (!(shutdown))
350+ then true
351+ else throwErr("not allowed"), mustFactory(i.caller)]
352+ if ((ckecks == ckecks))
220353 then {
221354 let accountAddress = valueOrErrorMessage(addressFromString(args[0]), wrapErr("invalid account address"))
222355 let payment = i.payments[0]
223356 let actions = [ScriptTransfer(accountAddress, payment.amount, payment.assetId)]
224- let factoryActions = nil
357+ let factoryActions = [invoke(factoryAddress, "integerEntry", [kDeposited(accountAddress), (valueOrElse(depositedOption(accountAddress), 0) + payment.amount)], nil)]
225358 $Tuple2(actions, factoryActions)
226359 }
227360 else throw("Strict value is not equal to itself.")
228361 }
229362
230363
231364
232365 @Callable(i)
233366 func withdraw (callerPublicKey,args) = {
234- let checkCaller = mustFactory(i)
235- if ((checkCaller == checkCaller))
367+ let ckecks = [if (!(shutdown))
368+ then true
369+ else throwErr("not allowed"), mustFactory(i.caller)]
370+ if ((ckecks == ckecks))
236371 then {
237372 let userAddress = addressFromPublicKey(callerPublicKey)
238373 let accountAddress = valueOrErrorMessage(addressFromString(args[0]), wrapErr("invalid account address"))
239374 let amount = valueOrErrorMessage(parseInt(args[1]), wrapErr("invalid amount"))
240375 let assetId = parseAssetId(args[2])
241376 let invocations = [invoke(accountAddress, "transferAsset", [userAddress.bytes, amount, assetId], nil)]
242377 $Tuple2(nil, invocations)
243378 }
244379 else throw("Strict value is not equal to itself.")
245380 }
246381
247382
248383
249384 @Callable(i)
250-func pairAllowance (callerPublicKey,args) = {
251- let checkCaller = mustFactory(i)
252- if ((checkCaller == checkCaller))
385+func borrow (callerPublicKey,args) = {
386+ let ckecks = [if (!(shutdown))
387+ then true
388+ else throwErr("not allowed"), mustFactory(i.caller)]
389+ if ((ckecks == ckecks))
390+ then {
391+ let accountAddress = valueOrErrorMessage(addressFromString(args[0]), wrapErr("invalid account address"))
392+ let assetId = parseAssetId(args[1])
393+ let amountRaw = parseInt(args[2])
394+ let deposited = valueOrElse(depositedOption(accountAddress), 0)
395+ let $t01541315490 = getAssetsByAccountAddress(accountAddress)
396+ let amountAssetId = $t01541315490._1
397+ let priceAssetId = $t01541315490._2
398+ let currentPrice = getCurrentPrice(amountAssetId)
399+ let creditA = valueOrElse(getInteger(factoryAddress, kCredit(accountAddress, amountAssetId)), 0)
400+ let creditB = valueOrElse(getInteger(factoryAddress, kCredit(accountAddress, priceAssetId)), 0)
401+ let totalCredit = calcTotalCredit(creditA, creditB, currentPrice)
402+ let leverageDefault = 3
403+ let leverage = valueOrElse(getInteger(factoryAddress, kLeverage(accountAddress)), leverageDefault)
404+ let creditAvailable = calcCreditAvailable(deposited, leverage, totalCredit)
405+ $Tuple2(nil, [creditAvailable])
406+ }
407+ else throw("Strict value is not equal to itself.")
408+ }
409+
410+
411+
412+@Callable(i)
413+func repay (callerPublicKey,args) = {
414+ let ckecks = [if (!(shutdown))
415+ then true
416+ else throwErr("not allowed"), mustFactory(i.caller)]
417+ if ((ckecks == ckecks))
418+ then $Tuple2(nil, unit)
419+ else throw("Strict value is not equal to itself.")
420+ }
421+
422+
423+
424+@Callable(i)
425+func setPairAllowance (callerPublicKey,args) = {
426+ let ckecks = [if (!(shutdown))
427+ then true
428+ else throwErr("not allowed"), mustFactory(i.caller), mustAdmin(callerPublicKey)]
429+ if ((ckecks == ckecks))
253430 then {
254431 let amountAssetIdStr = args[0]
255432 let priceAssetIdStr = args[1]
256433 let allowStr = args[2]
257434 let amountAssetId = parseAssetId(amountAssetIdStr)
258435 let priceAssetId = parseAssetId(priceAssetIdStr)
259436 let allow = (allowStr == "true")
260437 let invocations = [invoke(factoryAddress, "booleanEntry", [kPairAllowed(amountAssetId, priceAssetId), allow], nil)]
261438 $Tuple2(nil, invocations)
262439 }
263440 else throw("Strict value is not equal to itself.")
264441 }
265442
266443
444+
445+@Callable(i)
446+func addSyntheticAsset (callerPublicKey,args) = {
447+ let baseAssetIdStr = args[0]
448+ let baseAssetId = parseAssetId(baseAssetIdStr)
449+ let syntheticAssetId = i.payments[0].assetId
450+ let ckecks = [if (!(shutdown))
451+ then true
452+ else throwErr("not allowed"), mustFactory(i.caller), mustAdmin(callerPublicKey), if ((getString(factoryAddress, kSyntheticAssetId(baseAssetId)) == unit))
453+ then true
454+ else throwErr("invalid base asset"), if ((size(i.payments) == 1))
455+ then true
456+ else throwErr("invalid payments"), if ((getString(factoryAddress, kBaseAssetId(syntheticAssetId)) == unit))
457+ then true
458+ else throwErr("invalid synthetic asset")]
459+ if ((ckecks == ckecks))
460+ then {
461+ let invocations = [invoke(factoryAddress, "stringEntry", [kSyntheticAssetId(baseAssetId), assetIdToString(syntheticAssetId)], nil), invoke(factoryAddress, "stringEntry", [kBaseAssetId(syntheticAssetId), assetIdToString(baseAssetId)], nil)]
462+ $Tuple2(nil, invocations)
463+ }
464+ else throw("Strict value is not equal to itself.")
465+ }
466+
467+
468+
469+@Callable(i)
470+func doShutdown (callerPublicKey,args) = {
471+ let checks = [mustFactory(i.caller), mustAdmin(callerPublicKey)]
472+ if ((checks == checks))
473+ then {
474+ let invocations = [invoke(factoryAddress, "booleanEntry", [kShutdown, true], nil)]
475+ $Tuple2(nil, invocations)
476+ }
477+ else throw("Strict value is not equal to itself.")
478+ }
479+
480+
481+@Verifier(tx)
482+func verify () = if (if (isDefined(factoryAddressOption))
483+ then isDefined(getString(factoryAddress, kMultisig))
484+ else false)
485+ then match getString(factoryAddress, kMultisig) {
486+ case multisig: String =>
487+ let statusKey = kStatus(toString(this), toBase58String(tx.id))
488+ let status = valueOrElse(getBoolean(addressFromStringValue(multisig), statusKey), false)
489+ status
490+ case _ =>
491+ false
492+ }
493+ else sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
494+

github/deemru/w8io/3ef1775 
164.74 ms