tx · 59XkgwYmq5mHKfEiwAkDae3jNdFQgF8gfUfxuAgAXJf8 3N3kKNoJohjVQYNLTrYTGTesr3nq3PZNh37: -0.02100000 Waves 2024.05.14 13:48 [3105589] smart account 3N3kKNoJohjVQYNLTrYTGTesr3nq3PZNh37 > SELF 0.00000000 Waves
{ "type": 13, "id": "59XkgwYmq5mHKfEiwAkDae3jNdFQgF8gfUfxuAgAXJf8", "fee": 2100000, "feeAssetId": null, "timestamp": 1715683730637, "version": 2, "chainId": 84, "sender": "3N3kKNoJohjVQYNLTrYTGTesr3nq3PZNh37", "senderPublicKey": "vmMXxwQAMUAoisvL193ptPiTtaWQqL5YNu2zs1ouTbY", "proofs": [ "5ghrmYfVVrN8AooDeP2Fxq1Ycx3ezNvPooSL8Xc7DEyXWawwSabbDvDqWfoFUH7PSpPHbze51vYgJsKXhhfg4UW1" ], "script": "base64:BwI9CAISAwoBCBIECgICGBIECgICGBIECgICGBIECgICGBIECgICGBIECgICGBIECgICGBIECgICGBIECgICGE4ACXNlcGFyYXRvcgICX18AB2NoYWluSWQJAMkBAgkAygECCAUEdGhpcwVieXRlcwABAAEACGNoYWluSWRXAQFXABBjb250cmFjdEZpbGVuYW1lAhdmdXR1cmVzX2NhbGN1bGF0b3IucmlkZQAFbXVsdDgAgMLXLwAMbXVsdDE4QmlnSW50CQC2AgEAgICQu7rWrfANAA13YXZlc0RlY2ltYWxzAAgADHVzZHREZWNpbWFscwAGAAt3YXZlc1N0cmluZwIFV0FWRVMADXF1ZXVlSXRlbVNpemUAIAAJa011bHRpc2lnAgwlc19fbXVsdGlzaWcBB2tTdGF0dXMCBGRhcHAEdHhJZAkAuQkCCQDMCAICCiVzX19zdGF0dXMJAMwIAgUEZGFwcAkAzAgCBQR0eElkBQNuaWwFCXNlcGFyYXRvcgAJa1NodXRkb3duAgwlc19fc2h1dGRvd24AC2tQdWJsaWNLZXlzAg4lc19fcHVibGljS2V5cwARa01hdGNoZXJQdWJsaWNLZXkCFCVzX19tYXRjaGVyUHVibGljS2V5AQV0b1gxOAIHb3JpZ1ZhbA1vcmlnU2NhbGVNdWx0CQC8AgMJALYCAQUHb3JpZ1ZhbAUMbXVsdDE4QmlnSW50CQC2AgEFDW9yaWdTY2FsZU11bHQBB2Zyb21YMTgCA3ZhbA9yZXN1bHRTY2FsZU11bHQJAKADAQkAvAIDBQN2YWwJALYCAQUPcmVzdWx0U2NhbGVNdWx0BQxtdWx0MThCaWdJbnQBD3ZhbGlkYXRlQWRkcmVzcwEHYWRkcmVzcwkBCWlzRGVmaW5lZAEJAKYIAQUHYWRkcmVzcwEHd3JhcEVycgEBcwkArAICCQCsAgIFEGNvbnRyYWN0RmlsZW5hbWUCAjogBQFzAQh0aHJvd0VycgEBcwkAAgEJAQd3cmFwRXJyAQUBcwEMcGFyc2VBc3NldElkAQVpbnB1dAMJAAACBQVpbnB1dAULd2F2ZXNTdHJpbmcFBHVuaXQJANkEAQUFaW5wdXQBD2Fzc2V0SWRUb1N0cmluZwEFaW5wdXQDCQAAAgUFaW5wdXQFBHVuaXQFC3dhdmVzU3RyaW5nCQDYBAEJAQV2YWx1ZQEFBWlucHV0AA9rRmFjdG9yeUFkZHJlc3MCEiVzX19mYWN0b3J5QWRkcmVzcwAUZmFjdG9yeUFkZHJlc3NPcHRpb24EByRtYXRjaDAJAJ0IAgUEdGhpcwUPa0ZhY3RvcnlBZGRyZXNzAwkAAQIFByRtYXRjaDACBlN0cmluZwQBcwUHJG1hdGNoMAkApggBBQFzAwkAAQIFByRtYXRjaDACBFVuaXQFBHVuaXQJAAIBAgtNYXRjaCBlcnJvcgAOZmFjdG9yeUFkZHJlc3MJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgUUZmFjdG9yeUFkZHJlc3NPcHRpb24JAQd3cmFwRXJyAQIXaW52YWxpZCBmYWN0b3J5IGFkZHJlc3MADGtVc2R0QXNzZXRJZAIPJXNfX3VzZHRBc3NldElkABF1c2R0QXNzZXRJZE9wdGlvbgQHJG1hdGNoMAkAnQgCBQR0aGlzBQxrVXNkdEFzc2V0SWQDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFzBQckbWF0Y2gwCQEMcGFyc2VBc3NldElkAQUBcwMJAAECBQckbWF0Y2gwAgRVbml0BQR1bml0CQACAQILTWF0Y2ggZXJyb3IAC3VzZHRBc3NldElkCQETdmFsdWVPckVycm9yTWVzc2FnZQIFEXVzZHRBc3NldElkT3B0aW9uCQEHd3JhcEVycgECFWludmFsaWQgdXNkdCBhc3NldCBpZAAOa1ByaWNlc0FkZHJlc3MCFSVzX19jYWxjdWxhdG9yQWRkcmVzcwAIc2h1dGRvd24JAQt2YWx1ZU9yRWxzZQIJAJsIAgUOZmFjdG9yeUFkZHJlc3MFCWtTaHV0ZG93bgcBC211c3RBZGRyZXNzAgZjYWxsZXIHYWRkcmVzcwMJAAACBQZjYWxsZXIFB2FkZHJlc3MGCQEIdGhyb3dFcnIBAhFwZXJtaXNzaW9uIGRlbmllZAEIbXVzdFRoaXMBBmNhbGxlcgkBC211c3RBZGRyZXNzAgUGY2FsbGVyBQR0aGlzAQttdXN0RmFjdG9yeQEGY2FsbGVyCQELbXVzdEFkZHJlc3MCBQZjYWxsZXIFDmZhY3RvcnlBZGRyZXNzAQltdXN0QWRtaW4BD2NhbGxlclB1YmxpY0tleQQIbXVsdGlzaWcJARFAZXh0ck5hdGl2ZSgxMDYyKQEJARFAZXh0ck5hdGl2ZSgxMDUzKQIFDmZhY3RvcnlBZGRyZXNzBQlrTXVsdGlzaWcEDnB1YmxpY0tleXNMaXN0CQC1CQIJARFAZXh0ck5hdGl2ZSgxMDUzKQIFCG11bHRpc2lnBQtrUHVibGljS2V5cwUJc2VwYXJhdG9yAwkBD2NvbnRhaW5zRWxlbWVudAIFDnB1YmxpY0tleXNMaXN0CQDYBAEFD2NhbGxlclB1YmxpY0tleQYJAQh0aHJvd0VycgECC25vdCBhbGxvd2VkAA5rQWNjb3VudFNjcmlwdAIRJXNfX2FjY291bnRTY3JpcHQBDWFjY291bnRTY3JpcHQACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJwIAgUOZmFjdG9yeUFkZHJlc3MFDmtBY2NvdW50U2NyaXB0CQEHd3JhcEVycgECGWFjY291bnQgc2NyaXB0IGlzIG5vdCBzZXQADWtSZXdhcmRBbW91bnQCECVzX19yZXdhcmRBbW91bnQBDHJld2FyZEFtb3VudAAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBQ5mYWN0b3J5QWRkcmVzcwUNa1Jld2FyZEFtb3VudAkBB3dyYXBFcnIBAhhyZXdhcmQgYW1vdW50IGlzIG5vdCBzZXQADmtBY2NvdW50c0xpbWl0AhElc19fYWNjb3VudHNMaW1pdAAUYWNjb3VudHNMaW1pdERlZmF1bHQAFAENYWNjb3VudHNMaW1pdAAJAQt2YWx1ZU9yRWxzZQIJAJoIAgUOZmFjdG9yeUFkZHJlc3MFDmtBY2NvdW50c0xpbWl0BRRhY2NvdW50c0xpbWl0RGVmYXVsdAEKa0RlcG9zaXRlZAEOYWNjb3VudEFkZHJlc3MJALkJAgkAzAgCAgQlcyVzCQDMCAICCWRlcG9zaXRlZAkAzAgCCQClCAEFDmFjY291bnRBZGRyZXNzBQNuaWwFCXNlcGFyYXRvcgEPZGVwb3NpdGVkT3B0aW9uAQ5hY2NvdW50QWRkcmVzcwkAmggCBQ5mYWN0b3J5QWRkcmVzcwkBCmtEZXBvc2l0ZWQBBQ5hY2NvdW50QWRkcmVzcwEHa0NyZWRpdAIOYWNjb3VudEFkZHJlc3MHYXNzZXRJZAkAuQkCCQDMCAICBiVzJXMlcwkAzAgCAgZjcmVkaXQJAMwIAgkApQgBBQ5hY2NvdW50QWRkcmVzcwkAzAgCCQEPYXNzZXRJZFRvU3RyaW5nAQUHYXNzZXRJZAUDbmlsBQlzZXBhcmF0b3IBCWtMZXZlcmFnZQEOYWNjb3VudEFkZHJlc3MJALkJAgkAzAgCAgQlcyVzCQDMCAICCGxldmVyYWdlCQDMCAIJAKUIAQUOYWNjb3VudEFkZHJlc3MFA25pbAUJc2VwYXJhdG9yARFrU3ludGhldGljQXNzZXRJZAELYmFzZUFzc2V0SWQJALkJAgkAzAgCAgQlcyVzCQDMCAICEHN5bnRoZXRpY0Fzc2V0SWQJAMwIAgkBD2Fzc2V0SWRUb1N0cmluZwEFC2Jhc2VBc3NldElkBQNuaWwFCXNlcGFyYXRvcgEMa0Jhc2VBc3NldElkARBzeW50aGV0aWNBc3NldElkCQC5CQIJAMwIAgIEJXMlcwkAzAgCAgtiYXNlQXNzZXRJZAkAzAgCCQEPYXNzZXRJZFRvU3RyaW5nAQUQc3ludGhldGljQXNzZXRJZAUDbmlsBQlzZXBhcmF0b3IAFFJFUVVFU1RfU1RBVFVTX0VNUFRZAAAAFFJFUVVFU1RfU1RBVFVTX1JFQURZAAEBDmtSZXF1ZXN0U3RhdHVzAQlyZXF1ZXN0SWQJALkJAgkAzAgCAgQlcyVzCQDMCAIJANgEAQUJcmVxdWVzdElkCQDMCAICBnN0YXR1cwUDbmlsBQlzZXBhcmF0b3IBGGtBY2NvdW50Q3JlYXRvclB1YmxpY0tleQEOYWNjb3VudEFkZHJlc3MJALkJAgkAzAgCAgQlcyVzCQDMCAIJAKUIAQUOYWNjb3VudEFkZHJlc3MJAMwIAgIQY3JlYXRvclB1YmxpY0tleQUDbmlsBQlzZXBhcmF0b3IBFmtSZXF1ZXN0T3duZXJQdWJsaWNLZXkBCXJlcXVlc3RJZAkAuQkCCQDMCAICBCVzJXMJAMwIAgkA2AQBBQlyZXF1ZXN0SWQJAMwIAgIOb3duZXJQdWJsaWNLZXkFA25pbAUJc2VwYXJhdG9yARVrUmVxdWVzdEFtb3VudEFzc2V0SWQBCXJlcXVlc3RJZAkAuQkCCQDMCAICBCVzJXMJAMwIAgkA2AQBBQlyZXF1ZXN0SWQJAMwIAgINYW1vdW50QXNzZXRJZAUDbmlsBQlzZXBhcmF0b3IBFGtSZXF1ZXN0UHJpY2VBc3NldElkAQlyZXF1ZXN0SWQJALkJAgkAzAgCAgQlcyVzCQDMCAIJANgEAQUJcmVxdWVzdElkCQDMCAICDHByaWNlQXNzZXRJZAUDbmlsBQlzZXBhcmF0b3IBHGtSZXF1ZXN0SWRUb0FjY291bnRQdWJsaWNLZXkBCXJlcXVlc3RJZAkAuQkCCQDMCAICBCVzJXMJAMwIAgkA2AQBBQlyZXF1ZXN0SWQJAMwIAgIbcmVxdWVzdElkVG9BY2NvdW50UHVibGljS2V5BQNuaWwFCXNlcGFyYXRvcgEaa0FjY291bnRBZGRyZXNzVG9SZXF1ZXN0SWQBDmFjY291bnRBZGRyZXNzCQC5CQIJAMwIAgIEJXMlcwkAzAgCCQClCAEFDmFjY291bnRBZGRyZXNzCQDMCAICGWFjY291bnRBZGRyZXNzVG9SZXF1ZXN0SWQFA25pbAUJc2VwYXJhdG9yAQ5rUmVxdWVzdHNRdWV1ZQAJALkJAgkAzAgCAgIlcwkAzAgCAg1yZXF1ZXN0c1F1ZXVlBQNuaWwFCXNlcGFyYXRvcgENcmVxdWVzdHNRdWV1ZQAJAQt2YWx1ZU9yRWxzZQIJAJwIAgUOZmFjdG9yeUFkZHJlc3MJAQ5rUmVxdWVzdHNRdWV1ZQABAAEOa0FjY291bnRzUXVldWUACQC5CQIJAMwIAgICJXMJAMwIAgINYWNjb3VudHNRdWV1ZQUDbmlsBQlzZXBhcmF0b3IBDWFjY291bnRzUXVldWUACQELdmFsdWVPckVsc2UCCQCcCAIFDmZhY3RvcnlBZGRyZXNzCQEOa0FjY291bnRzUXVldWUAAQABEGtSZXF1ZXN0c0J5T3duZXIBDG93bmVyQWRkcmVzcwkAuQkCCQDMCAICBCVzJXMJAMwIAgIIcmVxdWVzdHMJAMwIAgkApQgBBQxvd25lckFkZHJlc3MFA25pbAUJc2VwYXJhdG9yAQ9yZXF1ZXN0c0J5T3duZXIBDG93bmVyQWRkcmVzcwkBC3ZhbHVlT3JFbHNlAgkAnAgCBQ5mYWN0b3J5QWRkcmVzcwkBEGtSZXF1ZXN0c0J5T3duZXIBBQxvd25lckFkZHJlc3MBAAEMa1BhaXJBbGxvd2VkAg1hbW91bnRBc3NldElkDHByaWNlQXNzZXRJZAkAuQkCCQDMCAICBiVzJXMlcwkAzAgCCQEPYXNzZXRJZFRvU3RyaW5nAQUNYW1vdW50QXNzZXRJZAkAzAgCCQEPYXNzZXRJZFRvU3RyaW5nAQUMcHJpY2VBc3NldElkCQDMCAICC3BhaXJBbGxvd2VkBQNuaWwFCXNlcGFyYXRvcgELcGFpckFsbG93ZWQCDWFtb3VudEFzc2V0SWQMcHJpY2VBc3NldElkCQELdmFsdWVPckVsc2UCCQCbCAIFDmZhY3RvcnlBZGRyZXNzCQEMa1BhaXJBbGxvd2VkAgUNYW1vdW50QXNzZXRJZAUMcHJpY2VBc3NldElkBwEGa1ByaWNlAQdhc3NldElkCQC5CQIJAMwIAgICJXMJAMwIAgkBD2Fzc2V0SWRUb1N0cmluZwEFB2Fzc2V0SWQFA25pbAUJc2VwYXJhdG9yAQ9nZXRDdXJyZW50UHJpY2UBB2Fzc2V0SWQEEG1hdGNoZXJQdWJsaWNLZXkJANkEAQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFDmZhY3RvcnlBZGRyZXNzBRFrTWF0Y2hlclB1YmxpY0tleQkBB3dyYXBFcnIBAhppbnZhbGlkIG1hdGNoZXIgcHVibGljIGtleQQObWF0Y2hlckFkZHJlc3MJAKcIAQUQbWF0Y2hlclB1YmxpY0tleQQFcHJpY2UJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBQ5tYXRjaGVyQWRkcmVzcwkBBmtQcmljZQEFB2Fzc2V0SWQJAQd3cmFwRXJyAQkArAICAhlpbnZhbGlkIHByaWNlLCBhc3NldElkID0gCQEPYXNzZXRJZFRvU3RyaW5nAQUHYXNzZXRJZAUFcHJpY2UBD2NhbGNUb3RhbENyZWRpdAMHY3JlZGl0QQdjcmVkaXRCDGN1cnJlbnRQcmljZQkAZAIJAGgCBQdjcmVkaXRBBQxjdXJyZW50UHJpY2UFB2NyZWRpdEIBEGNhbGNUb3RhbEJhbGFuY2UDCGJhbGFuY2VBCGJhbGFuY2VCDGN1cnJlbnRQcmljZQkAZAIJAGgCBQhiYWxhbmNlQQUMY3VycmVudFByaWNlBQhiYWxhbmNlQgEHY2FsY1BubAIMdG90YWxCYWxhbmNlC3RvdGFsQ3JlZGl0CQBlAgUMdG90YWxCYWxhbmNlBQt0b3RhbENyZWRpdAETY2FsY0NyZWRpdEF2YWlsYWJsZQMHZGVwb3NpdAhsZXZlcmFnZQt0b3RhbENyZWRpdAkAZQIJAGgCBQdkZXBvc2l0BQhsZXZlcmFnZQULdG90YWxDcmVkaXQBEGNhbGNSZWFsSW5DcmVkaXQCBmNyZWRpdAdiYWxhbmNlAwkAZgIFBmNyZWRpdAAACQBlAgUGY3JlZGl0BQdiYWxhbmNlAAABCGNhbGNGcmVlAgZjcmVkaXQHYmFsYW5jZQMJAGYCBQZjcmVkaXQAAAkAZQIFB2JhbGFuY2UFBmNyZWRpdAAAAQ5jYWxjU2hvcnRQcmljZQIEZnJlZQxyZWFsSW5DcmVkaXQDCQBmAgUMcmVhbEluQ3JlZGl0AAAJAJYDAQkAzAgCAAAJAMwIAgkAaQIFBGZyZWUFDHJlYWxJbkNyZWRpdAUDbmlsAAABDWNhbGNMb25nUHJpY2UCBGZyZWUMcmVhbEluQ3JlZGl0AwkAZgIFDHJlYWxJbkNyZWRpdAAACQCWAwEJAMwIAgAACQDMCAIJAGkCBQxyZWFsSW5DcmVkaXQFBGZyZWUFA25pbAAAAQ9jYWxjU3RhcnRNYXJnaW4EDXJlYWxJbkNyZWRpdEENcmVhbEluQ3JlZGl0QgxjdXJyZW50UHJpY2UOc2V0dGluZ3NNYXJnaW4JAGgCCQBkAgkAaAIFDXJlYWxJbkNyZWRpdEEFDGN1cnJlbnRQcmljZQUNcmVhbEluQ3JlZGl0QgUOc2V0dGluZ3NNYXJnaW4BEGNhbGNNYXJnaW5TdXBwbHkDFHNldHRpbmdzTWFyZ2luU3VwcGx5DnNldHRpbmdzTWFyZ2luC3N0YXJ0TWFyZ2luCQBoAgkAaQIFFHNldHRpbmdzTWFyZ2luU3VwcGx5BQ5zZXR0aW5nc01hcmdpbgULc3RhcnRNYXJnaW4BFGNhbGNMaXF1aWRhdGlvblByaWNlBgdkZXBvc2l0DG1hcmdpblN1cHBseQ1yZWFsSW5DcmVkaXRBDXJlYWxJbkNyZWRpdEIKc2hvcnRQcmljZQlsb25nUHJpY2UEEWxpcXVpZGF0aW9uUHJpY2VBAwkAZgIFDXJlYWxJbkNyZWRpdEEAAAkAZAIJAGkCCQBlAgUHZGVwb3NpdAUMbWFyZ2luU3VwcGx5BQ1yZWFsSW5DcmVkaXRBBQpzaG9ydFByaWNlAAAEEWxpcXVpZGF0aW9uUHJpY2VCAwkAZgIFDXJlYWxJbkNyZWRpdEIAAAkAZQIFCWxvbmdQcmljZQkAaQIJAGUCBQdkZXBvc2l0BQxtYXJnaW5TdXBwbHkJAGkCBQ1yZWFsSW5DcmVkaXRBBQlsb25nUHJpY2UAAAkAZAIFEWxpcXVpZGF0aW9uUHJpY2VBBRFsaXF1aWRhdGlvblByaWNlQgEZZ2V0QXNzZXRzQnlBY2NvdW50QWRkcmVzcwEOYWNjb3VudEFkZHJlc3MECXJlcXVlc3RJZAkA2QQBCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ0IAgUOZmFjdG9yeUFkZHJlc3MJARprQWNjb3VudEFkZHJlc3NUb1JlcXVlc3RJZAEFDmFjY291bnRBZGRyZXNzCQEHd3JhcEVycgECF2ludmFsaWQgYWNjb3VudCBhZGRyZXNzBA1hbW91bnRBc3NldElkCQEMcGFyc2VBc3NldElkAQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFDmZhY3RvcnlBZGRyZXNzCQEVa1JlcXVlc3RBbW91bnRBc3NldElkAQUJcmVxdWVzdElkCQEHd3JhcEVycgECF2ludmFsaWQgYW1vdW50IGFzc2V0IGlkBAxwcmljZUFzc2V0SWQJAQxwYXJzZUFzc2V0SWQBCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ0IAgUOZmFjdG9yeUFkZHJlc3MJARRrUmVxdWVzdFByaWNlQXNzZXRJZAEFCXJlcXVlc3RJZAkBB3dyYXBFcnIBAhdpbnZhbGlkIGFtb3VudCBwcmljZSBpZAkAlAoCBQ1hbW91bnRBc3NldElkBQxwcmljZUFzc2V0SWQKAWkBBGluaXQBEWZhY3RvcnlBZGRyZXNzU3RyBAtjaGVja0NhbGxlcgkBCG11c3RUaGlzAQgFAWkGY2FsbGVyAwkAAAIFC2NoZWNrQ2FsbGVyBQtjaGVja0NhbGxlcgkAlAoCCQDMCAIJAQtTdHJpbmdFbnRyeQIFD2tGYWN0b3J5QWRkcmVzcwURZmFjdG9yeUFkZHJlc3NTdHIFA25pbAUEdW5pdAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ5yZXF1ZXN0QWNjb3VudAIPY2FsbGVyUHVibGljS2V5BGFyZ3MEBmNrZWNrcwkAzAgCAwkBASEBBQhzaHV0ZG93bgYJAQh0aHJvd0VycgECC25vdCBhbGxvd2VkCQDMCAIJAQttdXN0RmFjdG9yeQEIBQFpBmNhbGxlcgUDbmlsAwkAAAIFBmNrZWNrcwUGY2tlY2tzBBBhbW91bnRBc3NldElkU3RyCQCRAwIFBGFyZ3MAAAQPcHJpY2VBc3NldElkU3RyCQCRAwIFBGFyZ3MAAQQLdXNlckFkZHJlc3MJAKcIAQUPY2FsbGVyUHVibGljS2V5BAlyZXF1ZXN0SWQJAPcDAQkAywECCQDLAQIIBQt1c2VyQWRkcmVzcwVieXRlcwkA2QQBBRBhbW91bnRBc3NldElkU3RyCQDZBAEFD3ByaWNlQXNzZXRJZFN0cgQNYW1vdW50QXNzZXRJZAkBDHBhcnNlQXNzZXRJZAEFEGFtb3VudEFzc2V0SWRTdHIEDHByaWNlQXNzZXRJZAkBDHBhcnNlQXNzZXRJZAEFD3ByaWNlQXNzZXRJZFN0cgQSdXNlclJlcXVlc3RzTnVtYmVyCQBpAgkAsQIBCQEQa1JlcXVlc3RzQnlPd25lcgEFC3VzZXJBZGRyZXNzBQ1xdWV1ZUl0ZW1TaXplBAZjaGVja3MJAMwIAgMJAAACCQCQAwEIBQFpCHBheW1lbnRzAAEGCQEIdGhyb3dFcnIBAhUxIHBheW1lbnQgaXMgcmVxdWlyZWQJAMwIAgMJAAACCAkAkQMCCAUBaQhwYXltZW50cwAAB2Fzc2V0SWQFBHVuaXQGCQEIdGhyb3dFcnIBAg1pbnZhbGlkIGFzc2V0CQDMCAIDCQAAAggJAJEDAggFAWkIcGF5bWVudHMAAAZhbW91bnQJAQxyZXdhcmRBbW91bnQABgkBCHRocm93RXJyAQIOaW52YWxpZCBhbW91bnQJAMwIAgMJAQtwYWlyQWxsb3dlZAIFDWFtb3VudEFzc2V0SWQFDHByaWNlQXNzZXRJZAYJAQh0aHJvd0VycgECE3BhaXIgaXMgbm90IGFsbG93ZWQJAMwIAgMJAAACCQCaCAIFDmZhY3RvcnlBZGRyZXNzCQEOa1JlcXVlc3RTdGF0dXMBBQlyZXF1ZXN0SWQFBHVuaXQGCQEIdGhyb3dFcnIBAhlhY2NvdW50IGlzIGFscmVhZHkgZXhpc3RzCQDMCAIDCQBmAgkBDWFjY291bnRzTGltaXQABRJ1c2VyUmVxdWVzdHNOdW1iZXIGCQEIdGhyb3dFcnIBCQCsAgICEmFjY291bnRzIGxpbWl0IGlzIAkApAMBCQENYWNjb3VudHNMaW1pdAAFA25pbAMJAAACBQZjaGVja3MFBmNoZWNrcwQNJHQwMTAwMDMxMTM1OQMJAAACCQDIAQEJAQ1hY2NvdW50c1F1ZXVlAAAACQCUCgIJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwUOZmFjdG9yeUFkZHJlc3MJAQxyZXdhcmRBbW91bnQABQR1bml0BQNuaWwJAMwIAgkA/AcEBQ5mYWN0b3J5QWRkcmVzcwIMaW50ZWdlckVudHJ5CQDMCAIJAQ5rUmVxdWVzdFN0YXR1cwEFCXJlcXVlc3RJZAkAzAgCBRRSRVFVRVNUX1NUQVRVU19FTVBUWQUDbmlsBQNuaWwJAMwIAgkA/AcEBQ5mYWN0b3J5QWRkcmVzcwILYmluYXJ5RW50cnkJAMwIAgkBDmtSZXF1ZXN0c1F1ZXVlAAkAzAgCCQDLAQIJAQ1yZXF1ZXN0c1F1ZXVlAAUJcmVxdWVzdElkBQNuaWwFA25pbAUDbmlsBBBhY2NvdW50UHVibGljS2V5CQDJAQIJAQ1hY2NvdW50c1F1ZXVlAAUNcXVldWVJdGVtU2l6ZQQOYWNjb3VudEFkZHJlc3MJAKcIAQUQYWNjb3VudFB1YmxpY0tleQQOY3JlYXRvckFkZHJlc3MJAKcIAQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCcCAIFDmZhY3RvcnlBZGRyZXNzCQEYa0FjY291bnRDcmVhdG9yUHVibGljS2V5AQUOYWNjb3VudEFkZHJlc3MJAQd3cmFwRXJyAQIaaW52YWxpZCBjcmVhdG9yIHB1YmxpYyBrZXkJAJQKAgkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDBQ5jcmVhdG9yQWRkcmVzcwkBDHJld2FyZEFtb3VudAAFBHVuaXQFA25pbAkAzAgCCQD8BwQFDmZhY3RvcnlBZGRyZXNzAgtiaW5hcnlFbnRyeQkAzAgCCQEOa0FjY291bnRzUXVldWUACQDMCAIJAMoBAgkBDWFjY291bnRzUXVldWUABQ1xdWV1ZUl0ZW1TaXplBQNuaWwFA25pbAkAzAgCCQD8BwQFDmZhY3RvcnlBZGRyZXNzAgxpbnRlZ2VyRW50cnkJAMwIAgkBDmtSZXF1ZXN0U3RhdHVzAQUJcmVxdWVzdElkCQDMCAIFFFJFUVVFU1RfU1RBVFVTX1JFQURZBQNuaWwFA25pbAkAzAgCCQD8BwQFDmZhY3RvcnlBZGRyZXNzAgtiaW5hcnlFbnRyeQkAzAgCCQEca1JlcXVlc3RJZFRvQWNjb3VudFB1YmxpY0tleQEFCXJlcXVlc3RJZAkAzAgCBRBhY2NvdW50UHVibGljS2V5BQNuaWwFA25pbAkAzAgCCQD8BwQFDmZhY3RvcnlBZGRyZXNzAgtzdHJpbmdFbnRyeQkAzAgCCQEaa0FjY291bnRBZGRyZXNzVG9SZXF1ZXN0SWQBBQ5hY2NvdW50QWRkcmVzcwkAzAgCCQDYBAEFCXJlcXVlc3RJZAUDbmlsBQNuaWwFA25pbAQHYWN0aW9ucwgFDSR0MDEwMDAzMTEzNTkCXzEEDmZhY3RvcnlBY3Rpb25zCAUNJHQwMTAwMDMxMTM1OQJfMgkAlAoCBQdhY3Rpb25zCQDOCAIFDmZhY3RvcnlBY3Rpb25zCQDMCAIJAPwHBAUOZmFjdG9yeUFkZHJlc3MCC2JpbmFyeUVudHJ5CQDMCAIJARZrUmVxdWVzdE93bmVyUHVibGljS2V5AQUJcmVxdWVzdElkCQDMCAIFD2NhbGxlclB1YmxpY0tleQUDbmlsBQNuaWwJAMwIAgkA/AcEBQ5mYWN0b3J5QWRkcmVzcwILYmluYXJ5RW50cnkJAMwIAgkBEGtSZXF1ZXN0c0J5T3duZXIBBQt1c2VyQWRkcmVzcwkAzAgCCQDLAQIJAQ9yZXF1ZXN0c0J5T3duZXIBBQt1c2VyQWRkcmVzcwUJcmVxdWVzdElkBQNuaWwFA25pbAkAzAgCCQD8BwQFDmZhY3RvcnlBZGRyZXNzAgtzdHJpbmdFbnRyeQkAzAgCCQEVa1JlcXVlc3RBbW91bnRBc3NldElkAQUJcmVxdWVzdElkCQDMCAIFEGFtb3VudEFzc2V0SWRTdHIFA25pbAUDbmlsCQDMCAIJAPwHBAUOZmFjdG9yeUFkZHJlc3MCC3N0cmluZ0VudHJ5CQDMCAIJARRrUmVxdWVzdFByaWNlQXNzZXRJZAEFCXJlcXVlc3RJZAkAzAgCBQ9wcmljZUFzc2V0SWRTdHIFA25pbAUDbmlsBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEKYWRkQWNjb3VudAIPY2FsbGVyUHVibGljS2V5BGFyZ3MEBmNrZWNrcwkAzAgCAwkBASEBBQhzaHV0ZG93bgYJAQh0aHJvd0VycgECC25vdCBhbGxvd2VkCQDMCAIJAQttdXN0RmFjdG9yeQEIBQFpBmNhbGxlcgUDbmlsAwkAAAIFBmNrZWNrcwUGY2tlY2tzBBBjcmVhdG9yUHVibGljS2V5CQDZBAEJAJEDAgUEYXJncwAABBBhY2NvdW50UHVibGljS2V5BQ9jYWxsZXJQdWJsaWNLZXkEDmFjY291bnRBZGRyZXNzCQCnCAEFD2NhbGxlclB1YmxpY0tleQQOY3JlYXRvckFkZHJlc3MJAKcIAQUQY3JlYXRvclB1YmxpY0tleQQGY2hlY2tzCQDMCAIDCQAAAgkAnAgCBQ5mYWN0b3J5QWRkcmVzcwkBGGtBY2NvdW50Q3JlYXRvclB1YmxpY0tleQEFDmFjY291bnRBZGRyZXNzBQR1bml0BgkBCHRocm93RXJyAQIZYWNjb3VudCBpcyBhbHJlYWR5IGV4aXN0cwkAzAgCAwQHJG1hdGNoMAkA8QcBBQ5hY2NvdW50QWRkcmVzcwMJAAECBQckbWF0Y2gwAgpCeXRlVmVjdG9yBAFiBQckbWF0Y2gwCQAAAgUBYgkA8RUBCQENYWNjb3VudFNjcmlwdAAHBgkBCHRocm93RXJyAQIOaW52YWxpZCBzY3JpcHQFA25pbAMJAAACBQZjaGVja3MFBmNoZWNrcwQNJHQwMTI2MTQxMzYxNgMJAAACCQDIAQEJAQ1yZXF1ZXN0c1F1ZXVlAAAACQCUCgIFA25pbAkAzAgCCQD8BwQFDmZhY3RvcnlBZGRyZXNzAgtiaW5hcnlFbnRyeQkAzAgCCQEOa0FjY291bnRzUXVldWUACQDMCAIJAMsBAgkBDWFjY291bnRzUXVldWUABRBhY2NvdW50UHVibGljS2V5BQNuaWwFA25pbAUDbmlsBAlyZXF1ZXN0SWQJAMkBAgkBDXJlcXVlc3RzUXVldWUABQ1xdWV1ZUl0ZW1TaXplCQCUCgIFA25pbAkAzAgCCQD8BwQFDmZhY3RvcnlBZGRyZXNzAgxpbnRlZ2VyRW50cnkJAMwIAgkBDmtSZXF1ZXN0U3RhdHVzAQUJcmVxdWVzdElkCQDMCAIFFFJFUVVFU1RfU1RBVFVTX1JFQURZBQNuaWwFA25pbAkAzAgCCQD8BwQFDmZhY3RvcnlBZGRyZXNzAgtiaW5hcnlFbnRyeQkAzAgCCQEca1JlcXVlc3RJZFRvQWNjb3VudFB1YmxpY0tleQEFCXJlcXVlc3RJZAkAzAgCBRBhY2NvdW50UHVibGljS2V5BQNuaWwFA25pbAkAzAgCCQD8BwQFDmZhY3RvcnlBZGRyZXNzAgtiaW5hcnlFbnRyeQkAzAgCCQEOa1JlcXVlc3RzUXVldWUACQDMCAIJAMoBAgkBDXJlcXVlc3RzUXVldWUABQ1xdWV1ZUl0ZW1TaXplBQNuaWwFA25pbAkAzAgCCQD8BwQFDmZhY3RvcnlBZGRyZXNzAgtzdHJpbmdFbnRyeQkAzAgCCQEaa0FjY291bnRBZGRyZXNzVG9SZXF1ZXN0SWQBBQ5hY2NvdW50QWRkcmVzcwkAzAgCCQDYBAEFCXJlcXVlc3RJZAUDbmlsBQNuaWwJAMwIAgkA/AcEBQ5mYWN0b3J5QWRkcmVzcwINdHJhbnNmZXJXYXZlcwkAzAgCCAUOY3JlYXRvckFkZHJlc3MFYnl0ZXMJAMwIAgkBDHJld2FyZEFtb3VudAAFA25pbAUDbmlsBQNuaWwEB2FjdGlvbnMIBQ0kdDAxMjYxNDEzNjE2Al8xBA5mYWN0b3J5QWN0aW9ucwgFDSR0MDEyNjE0MTM2MTYCXzIJAJQKAgUHYWN0aW9ucwkAzggCBQ5mYWN0b3J5QWN0aW9ucwkAzAgCCQD8BwQFDmZhY3RvcnlBZGRyZXNzAgtiaW5hcnlFbnRyeQkAzAgCCQEYa0FjY291bnRDcmVhdG9yUHVibGljS2V5AQUOYWNjb3VudEFkZHJlc3MJAMwIAgUQY3JlYXRvclB1YmxpY0tleQUDbmlsBQNuaWwFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQdkZXBvc2l0Ag9jYWxsZXJQdWJsaWNLZXkEYXJncwQHcGF5bWVudAkAkQMCCAUBaQhwYXltZW50cwAABAZja2Vja3MJAMwIAgMJAQEhAQUIc2h1dGRvd24GCQEIdGhyb3dFcnIBAgtub3QgYWxsb3dlZAkAzAgCCQELbXVzdEZhY3RvcnkBCAUBaQZjYWxsZXIJAMwIAgMJAAACCQCQAwEIBQFpCHBheW1lbnRzAAEGCQEIdGhyb3dFcnIBAhUxIHBheW1lbnQgaXMgcmVxdWlyZWQJAMwIAgMJAAACCAUHcGF5bWVudAdhc3NldElkBQt1c2R0QXNzZXRJZAYJAQh0aHJvd0VycgECDWludmFsaWQgYXNzZXQFA25pbAMJAAACBQZja2Vja3MFBmNrZWNrcwQOYWNjb3VudEFkZHJlc3MJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQCRAwIFBGFyZ3MAAAkBB3dyYXBFcnIBAhdpbnZhbGlkIGFjY291bnQgYWRkcmVzcwQHYWN0aW9ucwkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDBQ5hY2NvdW50QWRkcmVzcwgFB3BheW1lbnQGYW1vdW50CAUHcGF5bWVudAdhc3NldElkBQNuaWwEDmZhY3RvcnlBY3Rpb25zCQDMCAIJAPwHBAUOZmFjdG9yeUFkZHJlc3MCDGludGVnZXJFbnRyeQkAzAgCCQEKa0RlcG9zaXRlZAEFDmFjY291bnRBZGRyZXNzCQDMCAIJAGQCCQELdmFsdWVPckVsc2UCCQEPZGVwb3NpdGVkT3B0aW9uAQUOYWNjb3VudEFkZHJlc3MAAAgFB3BheW1lbnQGYW1vdW50BQNuaWwFA25pbAUDbmlsCQCUCgIFB2FjdGlvbnMFDmZhY3RvcnlBY3Rpb25zCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCHdpdGhkcmF3Ag9jYWxsZXJQdWJsaWNLZXkEYXJncwQGY2tlY2tzCQDMCAIDCQEBIQEFCHNodXRkb3duBgkBCHRocm93RXJyAQILbm90IGFsbG93ZWQJAMwIAgkBC211c3RGYWN0b3J5AQgFAWkGY2FsbGVyBQNuaWwDCQAAAgUGY2tlY2tzBQZja2Vja3MEC3VzZXJBZGRyZXNzCQCnCAEFD2NhbGxlclB1YmxpY0tleQQOYWNjb3VudEFkZHJlc3MJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQCRAwIFBGFyZ3MAAAkBB3dyYXBFcnIBAhdpbnZhbGlkIGFjY291bnQgYWRkcmVzcwQGYW1vdW50CQETdmFsdWVPckVycm9yTWVzc2FnZQIJALYJAQkAkQMCBQRhcmdzAAEJAQd3cmFwRXJyAQIOaW52YWxpZCBhbW91bnQEB2Fzc2V0SWQJAQxwYXJzZUFzc2V0SWQBCQCRAwIFBGFyZ3MAAgQLaW52b2NhdGlvbnMJAMwIAgkA/AcEBQ5hY2NvdW50QWRkcmVzcwINdHJhbnNmZXJBc3NldAkAzAgCCAULdXNlckFkZHJlc3MFYnl0ZXMJAMwIAgUGYW1vdW50CQDMCAIFB2Fzc2V0SWQFA25pbAUDbmlsBQNuaWwJAJQKAgUDbmlsBQtpbnZvY2F0aW9ucwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQZib3Jyb3cCD2NhbGxlclB1YmxpY0tleQRhcmdzBAZja2Vja3MJAMwIAgMJAQEhAQUIc2h1dGRvd24GCQEIdGhyb3dFcnIBAgtub3QgYWxsb3dlZAkAzAgCCQELbXVzdEZhY3RvcnkBCAUBaQZjYWxsZXIFA25pbAMJAAACBQZja2Vja3MFBmNrZWNrcwQOYWNjb3VudEFkZHJlc3MJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQCRAwIFBGFyZ3MAAAkBB3dyYXBFcnIBAhdpbnZhbGlkIGFjY291bnQgYWRkcmVzcwQHYXNzZXRJZAkBDHBhcnNlQXNzZXRJZAEJAJEDAgUEYXJncwABBAlhbW91bnRSYXcJALYJAQkAkQMCBQRhcmdzAAIECWRlcG9zaXRlZAkBC3ZhbHVlT3JFbHNlAgkBD2RlcG9zaXRlZE9wdGlvbgEFDmFjY291bnRBZGRyZXNzAAAEDSR0MDE1NzU2MTU4MzMJARlnZXRBc3NldHNCeUFjY291bnRBZGRyZXNzAQUOYWNjb3VudEFkZHJlc3MEDWFtb3VudEFzc2V0SWQIBQ0kdDAxNTc1NjE1ODMzAl8xBAxwcmljZUFzc2V0SWQIBQ0kdDAxNTc1NjE1ODMzAl8yBAxjdXJyZW50UHJpY2UJAQ9nZXRDdXJyZW50UHJpY2UBBQ1hbW91bnRBc3NldElkBAdjcmVkaXRBCQELdmFsdWVPckVsc2UCCQCaCAIFDmZhY3RvcnlBZGRyZXNzCQEHa0NyZWRpdAIFDmFjY291bnRBZGRyZXNzBQ1hbW91bnRBc3NldElkAAAEB2NyZWRpdEIJAQt2YWx1ZU9yRWxzZQIJAJoIAgUOZmFjdG9yeUFkZHJlc3MJAQdrQ3JlZGl0AgUOYWNjb3VudEFkZHJlc3MFDHByaWNlQXNzZXRJZAAABAt0b3RhbENyZWRpdAkBD2NhbGNUb3RhbENyZWRpdAMFB2NyZWRpdEEFB2NyZWRpdEIFDGN1cnJlbnRQcmljZQQPbGV2ZXJhZ2VEZWZhdWx0AAMECGxldmVyYWdlCQELdmFsdWVPckVsc2UCCQCaCAIFDmZhY3RvcnlBZGRyZXNzCQEJa0xldmVyYWdlAQUOYWNjb3VudEFkZHJlc3MFD2xldmVyYWdlRGVmYXVsdAQPY3JlZGl0QXZhaWxhYmxlCQETY2FsY0NyZWRpdEF2YWlsYWJsZQMFCWRlcG9zaXRlZAUIbGV2ZXJhZ2UFC3RvdGFsQ3JlZGl0CQCUCgIFA25pbAkAzAgCBQ9jcmVkaXRBdmFpbGFibGUFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQVyZXBheQIPY2FsbGVyUHVibGljS2V5BGFyZ3MEBmNrZWNrcwkAzAgCAwkBASEBBQhzaHV0ZG93bgYJAQh0aHJvd0VycgECC25vdCBhbGxvd2VkCQDMCAIJAQttdXN0RmFjdG9yeQEIBQFpBmNhbGxlcgUDbmlsAwkAAAIFBmNrZWNrcwUGY2tlY2tzCQCUCgIFA25pbAUEdW5pdAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARBzZXRQYWlyQWxsb3dhbmNlAg9jYWxsZXJQdWJsaWNLZXkEYXJncwQGY2tlY2tzCQDMCAIDCQEBIQEFCHNodXRkb3duBgkBCHRocm93RXJyAQILbm90IGFsbG93ZWQJAMwIAgkBC211c3RGYWN0b3J5AQgFAWkGY2FsbGVyCQDMCAIJAQltdXN0QWRtaW4BBQ9jYWxsZXJQdWJsaWNLZXkFA25pbAMJAAACBQZja2Vja3MFBmNrZWNrcwQQYW1vdW50QXNzZXRJZFN0cgkAkQMCBQRhcmdzAAAED3ByaWNlQXNzZXRJZFN0cgkAkQMCBQRhcmdzAAEECGFsbG93U3RyCQCRAwIFBGFyZ3MAAgQNYW1vdW50QXNzZXRJZAkBDHBhcnNlQXNzZXRJZAEFEGFtb3VudEFzc2V0SWRTdHIEDHByaWNlQXNzZXRJZAkBDHBhcnNlQXNzZXRJZAEFD3ByaWNlQXNzZXRJZFN0cgQFYWxsb3cJAAACBQhhbGxvd1N0cgIEdHJ1ZQQLaW52b2NhdGlvbnMJAMwIAgkA/AcEBQ5mYWN0b3J5QWRkcmVzcwIMYm9vbGVhbkVudHJ5CQDMCAIJAQxrUGFpckFsbG93ZWQCBQ1hbW91bnRBc3NldElkBQxwcmljZUFzc2V0SWQJAMwIAgUFYWxsb3cFA25pbAUDbmlsBQNuaWwJAJQKAgUDbmlsBQtpbnZvY2F0aW9ucwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARFhZGRTeW50aGV0aWNBc3NldAIPY2FsbGVyUHVibGljS2V5BGFyZ3MEDmJhc2VBc3NldElkU3RyCQCRAwIFBGFyZ3MAAAQLYmFzZUFzc2V0SWQJAQxwYXJzZUFzc2V0SWQBBQ5iYXNlQXNzZXRJZFN0cgQQc3ludGhldGljQXNzZXRJZAgJAJEDAggFAWkIcGF5bWVudHMAAAdhc3NldElkBAZja2Vja3MJAMwIAgMJAQEhAQUIc2h1dGRvd24GCQEIdGhyb3dFcnIBAgtub3QgYWxsb3dlZAkAzAgCCQELbXVzdEZhY3RvcnkBCAUBaQZjYWxsZXIJAMwIAgkBCW11c3RBZG1pbgEFD2NhbGxlclB1YmxpY0tleQkAzAgCAwkAAAIJAJ0IAgUOZmFjdG9yeUFkZHJlc3MJARFrU3ludGhldGljQXNzZXRJZAEFC2Jhc2VBc3NldElkBQR1bml0BgkBCHRocm93RXJyAQISaW52YWxpZCBiYXNlIGFzc2V0CQDMCAIDCQAAAgkAkAMBCAUBaQhwYXltZW50cwABBgkBCHRocm93RXJyAQIQaW52YWxpZCBwYXltZW50cwkAzAgCAwkAAAIJAJ0IAgUOZmFjdG9yeUFkZHJlc3MJAQxrQmFzZUFzc2V0SWQBBRBzeW50aGV0aWNBc3NldElkBQR1bml0BgkBCHRocm93RXJyAQIXaW52YWxpZCBzeW50aGV0aWMgYXNzZXQFA25pbAMJAAACBQZja2Vja3MFBmNrZWNrcwQLaW52b2NhdGlvbnMJAMwIAgkA/AcEBQ5mYWN0b3J5QWRkcmVzcwILc3RyaW5nRW50cnkJAMwIAgkBEWtTeW50aGV0aWNBc3NldElkAQULYmFzZUFzc2V0SWQJAMwIAgkBD2Fzc2V0SWRUb1N0cmluZwEFEHN5bnRoZXRpY0Fzc2V0SWQFA25pbAUDbmlsCQDMCAIJAPwHBAUOZmFjdG9yeUFkZHJlc3MCC3N0cmluZ0VudHJ5CQDMCAIJAQxrQmFzZUFzc2V0SWQBBRBzeW50aGV0aWNBc3NldElkCQDMCAIJAQ9hc3NldElkVG9TdHJpbmcBBQtiYXNlQXNzZXRJZAUDbmlsBQNuaWwFA25pbAkAlAoCBQNuaWwFC2ludm9jYXRpb25zCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCmRvU2h1dGRvd24CD2NhbGxlclB1YmxpY0tleQRhcmdzBAZjaGVja3MJAMwIAgkBC211c3RGYWN0b3J5AQgFAWkGY2FsbGVyCQDMCAIJAQltdXN0QWRtaW4BBQ9jYWxsZXJQdWJsaWNLZXkFA25pbAMJAAACBQZjaGVja3MFBmNoZWNrcwQLaW52b2NhdGlvbnMJAMwIAgkA/AcEBQ5mYWN0b3J5QWRkcmVzcwIMYm9vbGVhbkVudHJ5CQDMCAIFCWtTaHV0ZG93bgkAzAgCBgUDbmlsBQNuaWwFA25pbAkAlAoCBQNuaWwFC2ludm9jYXRpb25zCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAQJ0eAEGdmVyaWZ5AAMDCQEJaXNEZWZpbmVkAQUUZmFjdG9yeUFkZHJlc3NPcHRpb24JAQlpc0RlZmluZWQBCQCdCAIFDmZhY3RvcnlBZGRyZXNzBQlrTXVsdGlzaWcHBAckbWF0Y2gwCQCdCAIFDmZhY3RvcnlBZGRyZXNzBQlrTXVsdGlzaWcDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAhtdWx0aXNpZwUHJG1hdGNoMAQJc3RhdHVzS2V5CQEHa1N0YXR1cwIJAKUIAQUEdGhpcwkA2AQBCAUCdHgCaWQEBnN0YXR1cwkBC3ZhbHVlT3JFbHNlAgkAmwgCCQERQGV4dHJOYXRpdmUoMTA2MikBBQhtdWx0aXNpZwUJc3RhdHVzS2V5BwUGc3RhdHVzBwkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAAgFAnR4D3NlbmRlclB1YmxpY0tleedNLWY=", "height": 3105589, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: AeE9HsMec7dmamH2zeLctPppdFspzLQdfdpsaXCAjDFS Next: 7xFZNz985VKPzaYDyMqb8ESKpoCmugPRbvKHGek6khZg Diff:
Old | New | Differences | |
---|---|---|---|
16 | 16 | let wavesDecimals = 8 | |
17 | 17 | ||
18 | 18 | let usdtDecimals = 6 | |
19 | + | ||
20 | + | let wavesString = "WAVES" | |
21 | + | ||
22 | + | let queueItemSize = 32 | |
19 | 23 | ||
20 | 24 | let kMultisig = "%s__multisig" | |
21 | 25 | ||
43 | 47 | func throwErr (s) = throw(wrapErr(s)) | |
44 | 48 | ||
45 | 49 | ||
50 | + | func parseAssetId (input) = if ((input == wavesString)) | |
51 | + | then unit | |
52 | + | else fromBase58String(input) | |
53 | + | ||
54 | + | ||
55 | + | func assetIdToString (input) = if ((input == unit)) | |
56 | + | then wavesString | |
57 | + | else toBase58String(value(input)) | |
58 | + | ||
59 | + | ||
46 | 60 | let kFactoryAddress = "%s__factoryAddress" | |
47 | 61 | ||
48 | 62 | let factoryAddressOption = match getString(this, kFactoryAddress) { | |
55 | 69 | } | |
56 | 70 | ||
57 | 71 | let factoryAddress = valueOrErrorMessage(factoryAddressOption, wrapErr("invalid factory address")) | |
72 | + | ||
73 | + | let kUsdtAssetId = "%s__usdtAssetId" | |
74 | + | ||
75 | + | let usdtAssetIdOption = match getString(this, kUsdtAssetId) { | |
76 | + | case s: String => | |
77 | + | parseAssetId(s) | |
78 | + | case _: Unit => | |
79 | + | unit | |
80 | + | case _ => | |
81 | + | throw("Match error") | |
82 | + | } | |
83 | + | ||
84 | + | let usdtAssetId = valueOrErrorMessage(usdtAssetIdOption, wrapErr("invalid usdt asset id")) | |
58 | 85 | ||
59 | 86 | let kPricesAddress = "%s__calculatorAddress" | |
60 | 87 | ||
78 | 105 | then true | |
79 | 106 | else throwErr("not allowed") | |
80 | 107 | } | |
81 | - | ||
82 | - | ||
83 | - | let wavesString = "WAVES" | |
84 | - | ||
85 | - | let queueItemSize = 32 | |
86 | - | ||
87 | - | func parseAssetId (input) = if ((input == wavesString)) | |
88 | - | then unit | |
89 | - | else fromBase58String(input) | |
90 | - | ||
91 | - | ||
92 | - | func assetIdToString (input) = if ((input == unit)) | |
93 | - | then wavesString | |
94 | - | else toBase58String(value(input)) | |
95 | 108 | ||
96 | 109 | ||
97 | 110 | let kAccountScript = "%s__accountScript" | |
166 | 179 | func accountsQueue () = valueOrElse(getBinary(factoryAddress, kAccountsQueue()), base58'') | |
167 | 180 | ||
168 | 181 | ||
169 | - | func kRequestsByOwner (ownerAddress) = makeString(["%s%s", " | |
182 | + | func kRequestsByOwner (ownerAddress) = makeString(["%s%s", "requests", toString(ownerAddress)], separator) | |
170 | 183 | ||
171 | 184 | ||
172 | 185 | func requestsByOwner (ownerAddress) = valueOrElse(getBinary(factoryAddress, kRequestsByOwner(ownerAddress)), base58'') | |
285 | 298 | else throwErr(("accounts limit is " + toString(accountsLimit())))] | |
286 | 299 | if ((checks == checks)) | |
287 | 300 | then { | |
288 | - | let $ | |
301 | + | let $t01000311359 = if ((size(accountsQueue()) == 0)) | |
289 | 302 | then $Tuple2([ScriptTransfer(factoryAddress, rewardAmount(), unit)], [invoke(factoryAddress, "integerEntry", [kRequestStatus(requestId), REQUEST_STATUS_EMPTY], nil), invoke(factoryAddress, "binaryEntry", [kRequestsQueue(), (requestsQueue() + requestId)], nil)]) | |
290 | 303 | else { | |
291 | 304 | let accountPublicKey = take(accountsQueue(), queueItemSize) | |
293 | 306 | let creatorAddress = addressFromPublicKey(valueOrErrorMessage(getBinary(factoryAddress, kAccountCreatorPublicKey(accountAddress)), wrapErr("invalid creator public key"))) | |
294 | 307 | $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)]) | |
295 | 308 | } | |
296 | - | let actions = $ | |
297 | - | let factoryActions = $ | |
309 | + | let actions = $t01000311359._1 | |
310 | + | let factoryActions = $t01000311359._2 | |
298 | 311 | $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)])) | |
299 | 312 | } | |
300 | 313 | else throw("Strict value is not equal to itself.") | |
327 | 340 | else throwErr("invalid script")] | |
328 | 341 | if ((checks == checks)) | |
329 | 342 | then { | |
330 | - | let $ | |
343 | + | let $t01261413616 = if ((size(requestsQueue()) == 0)) | |
331 | 344 | then $Tuple2(nil, [invoke(factoryAddress, "binaryEntry", [kAccountsQueue(), (accountsQueue() + accountPublicKey)], nil)]) | |
332 | 345 | else { | |
333 | 346 | let requestId = take(requestsQueue(), queueItemSize) | |
334 | 347 | $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)]) | |
335 | 348 | } | |
336 | - | let actions = $ | |
337 | - | let factoryActions = $ | |
349 | + | let actions = $t01261413616._1 | |
350 | + | let factoryActions = $t01261413616._2 | |
338 | 351 | $Tuple2(actions, (factoryActions ++ [invoke(factoryAddress, "binaryEntry", [kAccountCreatorPublicKey(accountAddress), creatorPublicKey], nil)])) | |
339 | 352 | } | |
340 | 353 | else throw("Strict value is not equal to itself.") | |
346 | 359 | ||
347 | 360 | @Callable(i) | |
348 | 361 | func deposit (callerPublicKey,args) = { | |
362 | + | let payment = i.payments[0] | |
349 | 363 | let ckecks = [if (!(shutdown)) | |
350 | 364 | then true | |
351 | - | else throwErr("not allowed"), mustFactory(i.caller)] | |
365 | + | else throwErr("not allowed"), mustFactory(i.caller), if ((size(i.payments) == 1)) | |
366 | + | then true | |
367 | + | else throwErr("1 payment is required"), if ((payment.assetId == usdtAssetId)) | |
368 | + | then true | |
369 | + | else throwErr("invalid asset")] | |
352 | 370 | if ((ckecks == ckecks)) | |
353 | 371 | then { | |
354 | 372 | let accountAddress = valueOrErrorMessage(addressFromString(args[0]), wrapErr("invalid account address")) | |
355 | - | let payment = i.payments[0] | |
356 | 373 | let actions = [ScriptTransfer(accountAddress, payment.amount, payment.assetId)] | |
357 | 374 | let factoryActions = [invoke(factoryAddress, "integerEntry", [kDeposited(accountAddress), (valueOrElse(depositedOption(accountAddress), 0) + payment.amount)], nil)] | |
358 | 375 | $Tuple2(actions, factoryActions) | |
392 | 409 | let assetId = parseAssetId(args[1]) | |
393 | 410 | let amountRaw = parseInt(args[2]) | |
394 | 411 | let deposited = valueOrElse(depositedOption(accountAddress), 0) | |
395 | - | let $ | |
396 | - | let amountAssetId = $ | |
397 | - | let priceAssetId = $ | |
412 | + | let $t01575615833 = getAssetsByAccountAddress(accountAddress) | |
413 | + | let amountAssetId = $t01575615833._1 | |
414 | + | let priceAssetId = $t01575615833._2 | |
398 | 415 | let currentPrice = getCurrentPrice(amountAssetId) | |
399 | 416 | let creditA = valueOrElse(getInteger(factoryAddress, kCredit(accountAddress, amountAssetId)), 0) | |
400 | 417 | let creditB = valueOrElse(getInteger(factoryAddress, kCredit(accountAddress, priceAssetId)), 0) |
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 chainId = take(drop(this.bytes, 1), 1) | |
7 | 7 | ||
8 | 8 | let chainIdW = base58'2W' | |
9 | 9 | ||
10 | 10 | let contractFilename = "futures_calculator.ride" | |
11 | 11 | ||
12 | 12 | let mult8 = 100000000 | |
13 | 13 | ||
14 | 14 | let mult18BigInt = toBigInt(1000000000000000000) | |
15 | 15 | ||
16 | 16 | let wavesDecimals = 8 | |
17 | 17 | ||
18 | 18 | let usdtDecimals = 6 | |
19 | + | ||
20 | + | let wavesString = "WAVES" | |
21 | + | ||
22 | + | let queueItemSize = 32 | |
19 | 23 | ||
20 | 24 | let kMultisig = "%s__multisig" | |
21 | 25 | ||
22 | 26 | func kStatus (dapp,txId) = makeString(["%s__status", dapp, txId], separator) | |
23 | 27 | ||
24 | 28 | ||
25 | 29 | let kShutdown = "%s__shutdown" | |
26 | 30 | ||
27 | 31 | let kPublicKeys = "%s__publicKeys" | |
28 | 32 | ||
29 | 33 | let kMatcherPublicKey = "%s__matcherPublicKey" | |
30 | 34 | ||
31 | 35 | func toX18 (origVal,origScaleMult) = fraction(toBigInt(origVal), mult18BigInt, toBigInt(origScaleMult)) | |
32 | 36 | ||
33 | 37 | ||
34 | 38 | func fromX18 (val,resultScaleMult) = toInt(fraction(val, toBigInt(resultScaleMult), mult18BigInt)) | |
35 | 39 | ||
36 | 40 | ||
37 | 41 | func validateAddress (address) = isDefined(addressFromString(address)) | |
38 | 42 | ||
39 | 43 | ||
40 | 44 | func wrapErr (s) = ((contractFilename + ": ") + s) | |
41 | 45 | ||
42 | 46 | ||
43 | 47 | func throwErr (s) = throw(wrapErr(s)) | |
44 | 48 | ||
45 | 49 | ||
50 | + | func parseAssetId (input) = if ((input == wavesString)) | |
51 | + | then unit | |
52 | + | else fromBase58String(input) | |
53 | + | ||
54 | + | ||
55 | + | func assetIdToString (input) = if ((input == unit)) | |
56 | + | then wavesString | |
57 | + | else toBase58String(value(input)) | |
58 | + | ||
59 | + | ||
46 | 60 | let kFactoryAddress = "%s__factoryAddress" | |
47 | 61 | ||
48 | 62 | let factoryAddressOption = match getString(this, kFactoryAddress) { | |
49 | 63 | case s: String => | |
50 | 64 | addressFromString(s) | |
51 | 65 | case _: Unit => | |
52 | 66 | unit | |
53 | 67 | case _ => | |
54 | 68 | throw("Match error") | |
55 | 69 | } | |
56 | 70 | ||
57 | 71 | let factoryAddress = valueOrErrorMessage(factoryAddressOption, wrapErr("invalid factory address")) | |
72 | + | ||
73 | + | let kUsdtAssetId = "%s__usdtAssetId" | |
74 | + | ||
75 | + | let usdtAssetIdOption = match getString(this, kUsdtAssetId) { | |
76 | + | case s: String => | |
77 | + | parseAssetId(s) | |
78 | + | case _: Unit => | |
79 | + | unit | |
80 | + | case _ => | |
81 | + | throw("Match error") | |
82 | + | } | |
83 | + | ||
84 | + | let usdtAssetId = valueOrErrorMessage(usdtAssetIdOption, wrapErr("invalid usdt asset id")) | |
58 | 85 | ||
59 | 86 | let kPricesAddress = "%s__calculatorAddress" | |
60 | 87 | ||
61 | 88 | let shutdown = valueOrElse(getBoolean(factoryAddress, kShutdown), false) | |
62 | 89 | ||
63 | 90 | func mustAddress (caller,address) = if ((caller == address)) | |
64 | 91 | then true | |
65 | 92 | else throwErr("permission denied") | |
66 | 93 | ||
67 | 94 | ||
68 | 95 | func mustThis (caller) = mustAddress(caller, this) | |
69 | 96 | ||
70 | 97 | ||
71 | 98 | func mustFactory (caller) = mustAddress(caller, factoryAddress) | |
72 | 99 | ||
73 | 100 | ||
74 | 101 | func mustAdmin (callerPublicKey) = { | |
75 | 102 | let multisig = addressFromStringValue(getStringValue(factoryAddress, kMultisig)) | |
76 | 103 | let publicKeysList = split(getStringValue(multisig, kPublicKeys), separator) | |
77 | 104 | if (containsElement(publicKeysList, toBase58String(callerPublicKey))) | |
78 | 105 | then true | |
79 | 106 | else throwErr("not allowed") | |
80 | 107 | } | |
81 | - | ||
82 | - | ||
83 | - | let wavesString = "WAVES" | |
84 | - | ||
85 | - | let queueItemSize = 32 | |
86 | - | ||
87 | - | func parseAssetId (input) = if ((input == wavesString)) | |
88 | - | then unit | |
89 | - | else fromBase58String(input) | |
90 | - | ||
91 | - | ||
92 | - | func assetIdToString (input) = if ((input == unit)) | |
93 | - | then wavesString | |
94 | - | else toBase58String(value(input)) | |
95 | 108 | ||
96 | 109 | ||
97 | 110 | let kAccountScript = "%s__accountScript" | |
98 | 111 | ||
99 | 112 | func accountScript () = valueOrErrorMessage(getBinary(factoryAddress, kAccountScript), wrapErr("account script is not set")) | |
100 | 113 | ||
101 | 114 | ||
102 | 115 | let kRewardAmount = "%s__rewardAmount" | |
103 | 116 | ||
104 | 117 | func rewardAmount () = valueOrErrorMessage(getInteger(factoryAddress, kRewardAmount), wrapErr("reward amount is not set")) | |
105 | 118 | ||
106 | 119 | ||
107 | 120 | let kAccountsLimit = "%s__accountsLimit" | |
108 | 121 | ||
109 | 122 | let accountsLimitDefault = 20 | |
110 | 123 | ||
111 | 124 | func accountsLimit () = valueOrElse(getInteger(factoryAddress, kAccountsLimit), accountsLimitDefault) | |
112 | 125 | ||
113 | 126 | ||
114 | 127 | func kDeposited (accountAddress) = makeString(["%s%s", "deposited", toString(accountAddress)], separator) | |
115 | 128 | ||
116 | 129 | ||
117 | 130 | func depositedOption (accountAddress) = getInteger(factoryAddress, kDeposited(accountAddress)) | |
118 | 131 | ||
119 | 132 | ||
120 | 133 | func kCredit (accountAddress,assetId) = makeString(["%s%s%s", "credit", toString(accountAddress), assetIdToString(assetId)], separator) | |
121 | 134 | ||
122 | 135 | ||
123 | 136 | func kLeverage (accountAddress) = makeString(["%s%s", "leverage", toString(accountAddress)], separator) | |
124 | 137 | ||
125 | 138 | ||
126 | 139 | func kSyntheticAssetId (baseAssetId) = makeString(["%s%s", "syntheticAssetId", assetIdToString(baseAssetId)], separator) | |
127 | 140 | ||
128 | 141 | ||
129 | 142 | func kBaseAssetId (syntheticAssetId) = makeString(["%s%s", "baseAssetId", assetIdToString(syntheticAssetId)], separator) | |
130 | 143 | ||
131 | 144 | ||
132 | 145 | let REQUEST_STATUS_EMPTY = 0 | |
133 | 146 | ||
134 | 147 | let REQUEST_STATUS_READY = 1 | |
135 | 148 | ||
136 | 149 | func kRequestStatus (requestId) = makeString(["%s%s", toBase58String(requestId), "status"], separator) | |
137 | 150 | ||
138 | 151 | ||
139 | 152 | func kAccountCreatorPublicKey (accountAddress) = makeString(["%s%s", toString(accountAddress), "creatorPublicKey"], separator) | |
140 | 153 | ||
141 | 154 | ||
142 | 155 | func kRequestOwnerPublicKey (requestId) = makeString(["%s%s", toBase58String(requestId), "ownerPublicKey"], separator) | |
143 | 156 | ||
144 | 157 | ||
145 | 158 | func kRequestAmountAssetId (requestId) = makeString(["%s%s", toBase58String(requestId), "amountAssetId"], separator) | |
146 | 159 | ||
147 | 160 | ||
148 | 161 | func kRequestPriceAssetId (requestId) = makeString(["%s%s", toBase58String(requestId), "priceAssetId"], separator) | |
149 | 162 | ||
150 | 163 | ||
151 | 164 | func kRequestIdToAccountPublicKey (requestId) = makeString(["%s%s", toBase58String(requestId), "requestIdToAccountPublicKey"], separator) | |
152 | 165 | ||
153 | 166 | ||
154 | 167 | func kAccountAddressToRequestId (accountAddress) = makeString(["%s%s", toString(accountAddress), "accountAddressToRequestId"], separator) | |
155 | 168 | ||
156 | 169 | ||
157 | 170 | func kRequestsQueue () = makeString(["%s", "requestsQueue"], separator) | |
158 | 171 | ||
159 | 172 | ||
160 | 173 | func requestsQueue () = valueOrElse(getBinary(factoryAddress, kRequestsQueue()), base58'') | |
161 | 174 | ||
162 | 175 | ||
163 | 176 | func kAccountsQueue () = makeString(["%s", "accountsQueue"], separator) | |
164 | 177 | ||
165 | 178 | ||
166 | 179 | func accountsQueue () = valueOrElse(getBinary(factoryAddress, kAccountsQueue()), base58'') | |
167 | 180 | ||
168 | 181 | ||
169 | - | func kRequestsByOwner (ownerAddress) = makeString(["%s%s", " | |
182 | + | func kRequestsByOwner (ownerAddress) = makeString(["%s%s", "requests", toString(ownerAddress)], separator) | |
170 | 183 | ||
171 | 184 | ||
172 | 185 | func requestsByOwner (ownerAddress) = valueOrElse(getBinary(factoryAddress, kRequestsByOwner(ownerAddress)), base58'') | |
173 | 186 | ||
174 | 187 | ||
175 | 188 | func kPairAllowed (amountAssetId,priceAssetId) = makeString(["%s%s%s", assetIdToString(amountAssetId), assetIdToString(priceAssetId), "pairAllowed"], separator) | |
176 | 189 | ||
177 | 190 | ||
178 | 191 | func pairAllowed (amountAssetId,priceAssetId) = valueOrElse(getBoolean(factoryAddress, kPairAllowed(amountAssetId, priceAssetId)), false) | |
179 | 192 | ||
180 | 193 | ||
181 | 194 | func kPrice (assetId) = makeString(["%s", assetIdToString(assetId)], separator) | |
182 | 195 | ||
183 | 196 | ||
184 | 197 | func getCurrentPrice (assetId) = { | |
185 | 198 | let matcherPublicKey = fromBase58String(valueOrErrorMessage(getString(factoryAddress, kMatcherPublicKey), wrapErr("invalid matcher public key"))) | |
186 | 199 | let matcherAddress = addressFromPublicKey(matcherPublicKey) | |
187 | 200 | let price = valueOrErrorMessage(getInteger(matcherAddress, kPrice(assetId)), wrapErr(("invalid price, assetId = " + assetIdToString(assetId)))) | |
188 | 201 | price | |
189 | 202 | } | |
190 | 203 | ||
191 | 204 | ||
192 | 205 | func calcTotalCredit (creditA,creditB,currentPrice) = ((creditA * currentPrice) + creditB) | |
193 | 206 | ||
194 | 207 | ||
195 | 208 | func calcTotalBalance (balanceA,balanceB,currentPrice) = ((balanceA * currentPrice) + balanceB) | |
196 | 209 | ||
197 | 210 | ||
198 | 211 | func calcPnl (totalBalance,totalCredit) = (totalBalance - totalCredit) | |
199 | 212 | ||
200 | 213 | ||
201 | 214 | func calcCreditAvailable (deposit,leverage,totalCredit) = ((deposit * leverage) - totalCredit) | |
202 | 215 | ||
203 | 216 | ||
204 | 217 | func calcRealInCredit (credit,balance) = if ((credit > 0)) | |
205 | 218 | then (credit - balance) | |
206 | 219 | else 0 | |
207 | 220 | ||
208 | 221 | ||
209 | 222 | func calcFree (credit,balance) = if ((credit > 0)) | |
210 | 223 | then (balance - credit) | |
211 | 224 | else 0 | |
212 | 225 | ||
213 | 226 | ||
214 | 227 | func calcShortPrice (free,realInCredit) = if ((realInCredit > 0)) | |
215 | 228 | then max([0, (free / realInCredit)]) | |
216 | 229 | else 0 | |
217 | 230 | ||
218 | 231 | ||
219 | 232 | func calcLongPrice (free,realInCredit) = if ((realInCredit > 0)) | |
220 | 233 | then max([0, (realInCredit / free)]) | |
221 | 234 | else 0 | |
222 | 235 | ||
223 | 236 | ||
224 | 237 | func calcStartMargin (realInCreditA,realInCreditB,currentPrice,settingsMargin) = (((realInCreditA * currentPrice) + realInCreditB) * settingsMargin) | |
225 | 238 | ||
226 | 239 | ||
227 | 240 | func calcMarginSupply (settingsMarginSupply,settingsMargin,startMargin) = ((settingsMarginSupply / settingsMargin) * startMargin) | |
228 | 241 | ||
229 | 242 | ||
230 | 243 | func calcLiquidationPrice (deposit,marginSupply,realInCreditA,realInCreditB,shortPrice,longPrice) = { | |
231 | 244 | let liquidationPriceA = if ((realInCreditA > 0)) | |
232 | 245 | then (((deposit - marginSupply) / realInCreditA) + shortPrice) | |
233 | 246 | else 0 | |
234 | 247 | let liquidationPriceB = if ((realInCreditB > 0)) | |
235 | 248 | then (longPrice - ((deposit - marginSupply) / (realInCreditA / longPrice))) | |
236 | 249 | else 0 | |
237 | 250 | (liquidationPriceA + liquidationPriceB) | |
238 | 251 | } | |
239 | 252 | ||
240 | 253 | ||
241 | 254 | func getAssetsByAccountAddress (accountAddress) = { | |
242 | 255 | let requestId = fromBase58String(valueOrErrorMessage(getString(factoryAddress, kAccountAddressToRequestId(accountAddress)), wrapErr("invalid account address"))) | |
243 | 256 | let amountAssetId = parseAssetId(valueOrErrorMessage(getString(factoryAddress, kRequestAmountAssetId(requestId)), wrapErr("invalid amount asset id"))) | |
244 | 257 | let priceAssetId = parseAssetId(valueOrErrorMessage(getString(factoryAddress, kRequestPriceAssetId(requestId)), wrapErr("invalid amount price id"))) | |
245 | 258 | $Tuple2(amountAssetId, priceAssetId) | |
246 | 259 | } | |
247 | 260 | ||
248 | 261 | ||
249 | 262 | @Callable(i) | |
250 | 263 | func init (factoryAddressStr) = { | |
251 | 264 | let checkCaller = mustThis(i.caller) | |
252 | 265 | if ((checkCaller == checkCaller)) | |
253 | 266 | then $Tuple2([StringEntry(kFactoryAddress, factoryAddressStr)], unit) | |
254 | 267 | else throw("Strict value is not equal to itself.") | |
255 | 268 | } | |
256 | 269 | ||
257 | 270 | ||
258 | 271 | ||
259 | 272 | @Callable(i) | |
260 | 273 | func requestAccount (callerPublicKey,args) = { | |
261 | 274 | let ckecks = [if (!(shutdown)) | |
262 | 275 | then true | |
263 | 276 | else throwErr("not allowed"), mustFactory(i.caller)] | |
264 | 277 | if ((ckecks == ckecks)) | |
265 | 278 | then { | |
266 | 279 | let amountAssetIdStr = args[0] | |
267 | 280 | let priceAssetIdStr = args[1] | |
268 | 281 | let userAddress = addressFromPublicKey(callerPublicKey) | |
269 | 282 | let requestId = sha256(((userAddress.bytes + fromBase58String(amountAssetIdStr)) + fromBase58String(priceAssetIdStr))) | |
270 | 283 | let amountAssetId = parseAssetId(amountAssetIdStr) | |
271 | 284 | let priceAssetId = parseAssetId(priceAssetIdStr) | |
272 | 285 | let userRequestsNumber = (size(kRequestsByOwner(userAddress)) / queueItemSize) | |
273 | 286 | let checks = [if ((size(i.payments) == 1)) | |
274 | 287 | then true | |
275 | 288 | else throwErr("1 payment is required"), if ((i.payments[0].assetId == unit)) | |
276 | 289 | then true | |
277 | 290 | else throwErr("invalid asset"), if ((i.payments[0].amount == rewardAmount())) | |
278 | 291 | then true | |
279 | 292 | else throwErr("invalid amount"), if (pairAllowed(amountAssetId, priceAssetId)) | |
280 | 293 | then true | |
281 | 294 | else throwErr("pair is not allowed"), if ((getInteger(factoryAddress, kRequestStatus(requestId)) == unit)) | |
282 | 295 | then true | |
283 | 296 | else throwErr("account is already exists"), if ((accountsLimit() > userRequestsNumber)) | |
284 | 297 | then true | |
285 | 298 | else throwErr(("accounts limit is " + toString(accountsLimit())))] | |
286 | 299 | if ((checks == checks)) | |
287 | 300 | then { | |
288 | - | let $ | |
301 | + | let $t01000311359 = if ((size(accountsQueue()) == 0)) | |
289 | 302 | then $Tuple2([ScriptTransfer(factoryAddress, rewardAmount(), unit)], [invoke(factoryAddress, "integerEntry", [kRequestStatus(requestId), REQUEST_STATUS_EMPTY], nil), invoke(factoryAddress, "binaryEntry", [kRequestsQueue(), (requestsQueue() + requestId)], nil)]) | |
290 | 303 | else { | |
291 | 304 | let accountPublicKey = take(accountsQueue(), queueItemSize) | |
292 | 305 | let accountAddress = addressFromPublicKey(accountPublicKey) | |
293 | 306 | let creatorAddress = addressFromPublicKey(valueOrErrorMessage(getBinary(factoryAddress, kAccountCreatorPublicKey(accountAddress)), wrapErr("invalid creator public key"))) | |
294 | 307 | $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)]) | |
295 | 308 | } | |
296 | - | let actions = $ | |
297 | - | let factoryActions = $ | |
309 | + | let actions = $t01000311359._1 | |
310 | + | let factoryActions = $t01000311359._2 | |
298 | 311 | $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)])) | |
299 | 312 | } | |
300 | 313 | else throw("Strict value is not equal to itself.") | |
301 | 314 | } | |
302 | 315 | else throw("Strict value is not equal to itself.") | |
303 | 316 | } | |
304 | 317 | ||
305 | 318 | ||
306 | 319 | ||
307 | 320 | @Callable(i) | |
308 | 321 | func addAccount (callerPublicKey,args) = { | |
309 | 322 | let ckecks = [if (!(shutdown)) | |
310 | 323 | then true | |
311 | 324 | else throwErr("not allowed"), mustFactory(i.caller)] | |
312 | 325 | if ((ckecks == ckecks)) | |
313 | 326 | then { | |
314 | 327 | let creatorPublicKey = fromBase58String(args[0]) | |
315 | 328 | let accountPublicKey = callerPublicKey | |
316 | 329 | let accountAddress = addressFromPublicKey(callerPublicKey) | |
317 | 330 | let creatorAddress = addressFromPublicKey(creatorPublicKey) | |
318 | 331 | let checks = [if ((getBinary(factoryAddress, kAccountCreatorPublicKey(accountAddress)) == unit)) | |
319 | 332 | then true | |
320 | 333 | else throwErr("account is already exists"), if ( match scriptHash(accountAddress) { | |
321 | 334 | case b: ByteVector => | |
322 | 335 | (b == blake2b256_32Kb(accountScript())) | |
323 | 336 | case _ => | |
324 | 337 | false | |
325 | 338 | }) | |
326 | 339 | then true | |
327 | 340 | else throwErr("invalid script")] | |
328 | 341 | if ((checks == checks)) | |
329 | 342 | then { | |
330 | - | let $ | |
343 | + | let $t01261413616 = if ((size(requestsQueue()) == 0)) | |
331 | 344 | then $Tuple2(nil, [invoke(factoryAddress, "binaryEntry", [kAccountsQueue(), (accountsQueue() + accountPublicKey)], nil)]) | |
332 | 345 | else { | |
333 | 346 | let requestId = take(requestsQueue(), queueItemSize) | |
334 | 347 | $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)]) | |
335 | 348 | } | |
336 | - | let actions = $ | |
337 | - | let factoryActions = $ | |
349 | + | let actions = $t01261413616._1 | |
350 | + | let factoryActions = $t01261413616._2 | |
338 | 351 | $Tuple2(actions, (factoryActions ++ [invoke(factoryAddress, "binaryEntry", [kAccountCreatorPublicKey(accountAddress), creatorPublicKey], nil)])) | |
339 | 352 | } | |
340 | 353 | else throw("Strict value is not equal to itself.") | |
341 | 354 | } | |
342 | 355 | else throw("Strict value is not equal to itself.") | |
343 | 356 | } | |
344 | 357 | ||
345 | 358 | ||
346 | 359 | ||
347 | 360 | @Callable(i) | |
348 | 361 | func deposit (callerPublicKey,args) = { | |
362 | + | let payment = i.payments[0] | |
349 | 363 | let ckecks = [if (!(shutdown)) | |
350 | 364 | then true | |
351 | - | else throwErr("not allowed"), mustFactory(i.caller)] | |
365 | + | else throwErr("not allowed"), mustFactory(i.caller), if ((size(i.payments) == 1)) | |
366 | + | then true | |
367 | + | else throwErr("1 payment is required"), if ((payment.assetId == usdtAssetId)) | |
368 | + | then true | |
369 | + | else throwErr("invalid asset")] | |
352 | 370 | if ((ckecks == ckecks)) | |
353 | 371 | then { | |
354 | 372 | let accountAddress = valueOrErrorMessage(addressFromString(args[0]), wrapErr("invalid account address")) | |
355 | - | let payment = i.payments[0] | |
356 | 373 | let actions = [ScriptTransfer(accountAddress, payment.amount, payment.assetId)] | |
357 | 374 | let factoryActions = [invoke(factoryAddress, "integerEntry", [kDeposited(accountAddress), (valueOrElse(depositedOption(accountAddress), 0) + payment.amount)], nil)] | |
358 | 375 | $Tuple2(actions, factoryActions) | |
359 | 376 | } | |
360 | 377 | else throw("Strict value is not equal to itself.") | |
361 | 378 | } | |
362 | 379 | ||
363 | 380 | ||
364 | 381 | ||
365 | 382 | @Callable(i) | |
366 | 383 | func withdraw (callerPublicKey,args) = { | |
367 | 384 | let ckecks = [if (!(shutdown)) | |
368 | 385 | then true | |
369 | 386 | else throwErr("not allowed"), mustFactory(i.caller)] | |
370 | 387 | if ((ckecks == ckecks)) | |
371 | 388 | then { | |
372 | 389 | let userAddress = addressFromPublicKey(callerPublicKey) | |
373 | 390 | let accountAddress = valueOrErrorMessage(addressFromString(args[0]), wrapErr("invalid account address")) | |
374 | 391 | let amount = valueOrErrorMessage(parseInt(args[1]), wrapErr("invalid amount")) | |
375 | 392 | let assetId = parseAssetId(args[2]) | |
376 | 393 | let invocations = [invoke(accountAddress, "transferAsset", [userAddress.bytes, amount, assetId], nil)] | |
377 | 394 | $Tuple2(nil, invocations) | |
378 | 395 | } | |
379 | 396 | else throw("Strict value is not equal to itself.") | |
380 | 397 | } | |
381 | 398 | ||
382 | 399 | ||
383 | 400 | ||
384 | 401 | @Callable(i) | |
385 | 402 | func borrow (callerPublicKey,args) = { | |
386 | 403 | let ckecks = [if (!(shutdown)) | |
387 | 404 | then true | |
388 | 405 | else throwErr("not allowed"), mustFactory(i.caller)] | |
389 | 406 | if ((ckecks == ckecks)) | |
390 | 407 | then { | |
391 | 408 | let accountAddress = valueOrErrorMessage(addressFromString(args[0]), wrapErr("invalid account address")) | |
392 | 409 | let assetId = parseAssetId(args[1]) | |
393 | 410 | let amountRaw = parseInt(args[2]) | |
394 | 411 | let deposited = valueOrElse(depositedOption(accountAddress), 0) | |
395 | - | let $ | |
396 | - | let amountAssetId = $ | |
397 | - | let priceAssetId = $ | |
412 | + | let $t01575615833 = getAssetsByAccountAddress(accountAddress) | |
413 | + | let amountAssetId = $t01575615833._1 | |
414 | + | let priceAssetId = $t01575615833._2 | |
398 | 415 | let currentPrice = getCurrentPrice(amountAssetId) | |
399 | 416 | let creditA = valueOrElse(getInteger(factoryAddress, kCredit(accountAddress, amountAssetId)), 0) | |
400 | 417 | let creditB = valueOrElse(getInteger(factoryAddress, kCredit(accountAddress, priceAssetId)), 0) | |
401 | 418 | let totalCredit = calcTotalCredit(creditA, creditB, currentPrice) | |
402 | 419 | let leverageDefault = 3 | |
403 | 420 | let leverage = valueOrElse(getInteger(factoryAddress, kLeverage(accountAddress)), leverageDefault) | |
404 | 421 | let creditAvailable = calcCreditAvailable(deposited, leverage, totalCredit) | |
405 | 422 | $Tuple2(nil, [creditAvailable]) | |
406 | 423 | } | |
407 | 424 | else throw("Strict value is not equal to itself.") | |
408 | 425 | } | |
409 | 426 | ||
410 | 427 | ||
411 | 428 | ||
412 | 429 | @Callable(i) | |
413 | 430 | func repay (callerPublicKey,args) = { | |
414 | 431 | let ckecks = [if (!(shutdown)) | |
415 | 432 | then true | |
416 | 433 | else throwErr("not allowed"), mustFactory(i.caller)] | |
417 | 434 | if ((ckecks == ckecks)) | |
418 | 435 | then $Tuple2(nil, unit) | |
419 | 436 | else throw("Strict value is not equal to itself.") | |
420 | 437 | } | |
421 | 438 | ||
422 | 439 | ||
423 | 440 | ||
424 | 441 | @Callable(i) | |
425 | 442 | func setPairAllowance (callerPublicKey,args) = { | |
426 | 443 | let ckecks = [if (!(shutdown)) | |
427 | 444 | then true | |
428 | 445 | else throwErr("not allowed"), mustFactory(i.caller), mustAdmin(callerPublicKey)] | |
429 | 446 | if ((ckecks == ckecks)) | |
430 | 447 | then { | |
431 | 448 | let amountAssetIdStr = args[0] | |
432 | 449 | let priceAssetIdStr = args[1] | |
433 | 450 | let allowStr = args[2] | |
434 | 451 | let amountAssetId = parseAssetId(amountAssetIdStr) | |
435 | 452 | let priceAssetId = parseAssetId(priceAssetIdStr) | |
436 | 453 | let allow = (allowStr == "true") | |
437 | 454 | let invocations = [invoke(factoryAddress, "booleanEntry", [kPairAllowed(amountAssetId, priceAssetId), allow], nil)] | |
438 | 455 | $Tuple2(nil, invocations) | |
439 | 456 | } | |
440 | 457 | else throw("Strict value is not equal to itself.") | |
441 | 458 | } | |
442 | 459 | ||
443 | 460 | ||
444 | 461 | ||
445 | 462 | @Callable(i) | |
446 | 463 | func addSyntheticAsset (callerPublicKey,args) = { | |
447 | 464 | let baseAssetIdStr = args[0] | |
448 | 465 | let baseAssetId = parseAssetId(baseAssetIdStr) | |
449 | 466 | let syntheticAssetId = i.payments[0].assetId | |
450 | 467 | let ckecks = [if (!(shutdown)) | |
451 | 468 | then true | |
452 | 469 | else throwErr("not allowed"), mustFactory(i.caller), mustAdmin(callerPublicKey), if ((getString(factoryAddress, kSyntheticAssetId(baseAssetId)) == unit)) | |
453 | 470 | then true | |
454 | 471 | else throwErr("invalid base asset"), if ((size(i.payments) == 1)) | |
455 | 472 | then true | |
456 | 473 | else throwErr("invalid payments"), if ((getString(factoryAddress, kBaseAssetId(syntheticAssetId)) == unit)) | |
457 | 474 | then true | |
458 | 475 | else throwErr("invalid synthetic asset")] | |
459 | 476 | if ((ckecks == ckecks)) | |
460 | 477 | then { | |
461 | 478 | let invocations = [invoke(factoryAddress, "stringEntry", [kSyntheticAssetId(baseAssetId), assetIdToString(syntheticAssetId)], nil), invoke(factoryAddress, "stringEntry", [kBaseAssetId(syntheticAssetId), assetIdToString(baseAssetId)], nil)] | |
462 | 479 | $Tuple2(nil, invocations) | |
463 | 480 | } | |
464 | 481 | else throw("Strict value is not equal to itself.") | |
465 | 482 | } | |
466 | 483 | ||
467 | 484 | ||
468 | 485 | ||
469 | 486 | @Callable(i) | |
470 | 487 | func doShutdown (callerPublicKey,args) = { | |
471 | 488 | let checks = [mustFactory(i.caller), mustAdmin(callerPublicKey)] | |
472 | 489 | if ((checks == checks)) | |
473 | 490 | then { | |
474 | 491 | let invocations = [invoke(factoryAddress, "booleanEntry", [kShutdown, true], nil)] | |
475 | 492 | $Tuple2(nil, invocations) | |
476 | 493 | } | |
477 | 494 | else throw("Strict value is not equal to itself.") | |
478 | 495 | } | |
479 | 496 | ||
480 | 497 | ||
481 | 498 | @Verifier(tx) | |
482 | 499 | func verify () = if (if (isDefined(factoryAddressOption)) | |
483 | 500 | then isDefined(getString(factoryAddress, kMultisig)) | |
484 | 501 | else false) | |
485 | 502 | then match getString(factoryAddress, kMultisig) { | |
486 | 503 | case multisig: String => | |
487 | 504 | let statusKey = kStatus(toString(this), toBase58String(tx.id)) | |
488 | 505 | let status = valueOrElse(getBoolean(addressFromStringValue(multisig), statusKey), false) | |
489 | 506 | status | |
490 | 507 | case _ => | |
491 | 508 | false | |
492 | 509 | } | |
493 | 510 | else sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey) | |
494 | 511 |
github/deemru/w8io/169f3d6 78.20 ms ◑