2020.10.04 12:23 [2269310] smart account 3P9ZegsKUtsEpdRPNVrMH7nHEEqY5MrmjDp > SELF 0.00000000 Waves
{ "type": 13, "id": "G42cQY3f5JPRXNq6pueQRSjVp2z2FAMFESEinZmDJJjN", "fee": 1400000, "feeAssetId": null, "timestamp": 1601801946992, "version": 1, "sender": "3P9ZegsKUtsEpdRPNVrMH7nHEEqY5MrmjDp", "senderPublicKey": "7ziFsWp9eo6kUB6ovqQzJfjgQarifNfpCGNW9DZi8YhN", "proofs": [ "39435aHe8FkdRYiEwACkmEoWAoCKqk5Jka6X5R2NJc83ZUo18GbUczdvRx3s2pPiw8EVwgtMxrmtLHpe2Gzy74Fe", "4wFwib69yP3A7n9hvxEX8EnwDomz9cifh27sSASPzWGuSnH8KWZWgyY2SC44z6HNubzMtn7aknq7tj2ZxaSMYKsn" ], "script": "base64:AAIEAAAAAAAAADoIAhIHCgUICAgICBIICgYBAQEBAQQSAwoBCBIFCgMICAgSAwoBARIAEgMKAQgSABIDCgEIEgASABIAAAAAUQAAAAAEdGVuNgAAAAAAAA9CQAAAAAAEdGVuOAAAAAAABfXhAAAAAAAHQlVMTEtleQIAAAAGQlVMTElkAAAAAAdCRUFSS2V5AgAAAAZCRUFSSWQAAAAADG1haW5Ub2tlbktleQIAAAALbWFpblRva2VuSWQAAAAAEWJ1bGxDb2xsYXRlcmFsS2V5AgAAAA5idWxsQ29sbGF0ZXJhbAAAAAARYmVhckNvbGxhdGVyYWxLZXkCAAAADmJlYXJDb2xsYXRlcmFsAAAAABJidWxsQ2lyY3VsYXRpb25LZXkCAAAAD2J1bGxDaXJjdWxhdGlvbgAAAAASYmVhckNpcmN1bGF0aW9uS2V5AgAAAA9iZWFyQ2lyY3VsYXRpb24AAAAAEmlzc3VlUGVyY2VudGlsZUtleQIAAAAPaXNzdWVQZXJjZW50aWxlAAAAABNyZWRlZW1QZXJjZW50aWxlS2V5AgAAABByZWRlZW1QZXJjZW50aWxlAAAAAAttaW5Jc3N1ZUtleQIAAAAIbWluSXNzdWUAAAAADG1pblJlZGVlbUtleQIAAAAJbWluUmVkZWVtAAAAAAptaW5Qb29sS2V5AgAAAAdtaW5Qb29sAAAAABJmZWVzQWNjdW11bGF0ZWRLZXkCAAAAD2ZlZXNBY2N1bXVsYXRlZAAAAAAQd2hpdGVsaXN0T25seUtleQIAAAANd2hpdGVsaXN0T25seQAAAAAMd2hpdGVsaXN0S2V5AgAAAA5pc3N1ZVdoaXRlTGlzdAAAAAALb3JhY2xlUEtLZXkCAAAABm9yYWNsZQAAAAARbGFzdFByaWNlSW5kZXhLZXkCAAAAC3ByaWNlX2luZGV4AAAAABBwcmljZUluZGV4UHJlZml4AgAAAAxwcmljZV9pbmRleF8AAAAAEXByaWNlSGVpZ2h0UHJlZml4AgAAAAZwcmljZV8AAAAAGm9yYWNsZUN1cnJlbnRQcmljZUluZGV4S2V5AgAAAAtwcmljZV9pbmRleAAAAAAabGFzdFJlYmFsYW5jZVByaWNlSW5kZXhLZXkCAAAAFWxhc3RTZXR0bGVtZW50UHJpY2VJZAAAAAAOaGVhZFBvaW50ZXJLZXkCAAAAC2hlYWRQb2ludGVyAAAAAA50YWlsUG9pbnRlcktleQIAAAALdGFpbFBvaW50ZXIAAAAADHF1ZXVlU2l6ZUtleQIAAAAJcXVldWVTaXplAAAAABVwb29sTWFpblRva2VuVmFsdWVLZXkCAAAAEnBvb2xNYWluVG9rZW5WYWx1ZQAAAAAJcG9vbFVwS2V5AgAAAAZwb29sVXAAAAAACnBvb2xEd25LZXkCAAAAB3Bvb2xEd24AAAAADnBvb2xFbmFibGVkS2V5AgAAAAtwb29sRW5hYmxlZAAAAAAXcG9vbFRva2VuQ2lyY3VsYXRpb25LZXkCAAAAFHBvb2xUb2tlbkNpcmN1bGF0aW9uAAAAAAxwb29sVG9rZW5LZXkCAAAACXBvb2xUb2tlbgAAAAAHYnVsbENvbAkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEGgAAAAIFAAAABHRoaXMFAAAAEWJ1bGxDb2xsYXRlcmFsS2V5AgAAABRubyBidWxsQ29sbGF0ZXJhbEtleQAAAAAHYmVhckNvbAkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEGgAAAAIFAAAABHRoaXMFAAAAEWJlYXJDb2xsYXRlcmFsS2V5AgAAABRubyBiZWFyQ29sbGF0ZXJhbEtleQAAAAAIYnVsbENpcmMJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABBoAAAACBQAAAAR0aGlzBQAAABJidWxsQ2lyY3VsYXRpb25LZXkCAAAAFW5vIGJ1bGxDaXJjdWxhdGlvbktleQAAAAAIYmVhckNpcmMJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABBoAAAACBQAAAAR0aGlzBQAAABJiZWFyQ2lyY3VsYXRpb25LZXkCAAAAFW5vIGJlYXJDaXJjdWxhdGlvbktleQAAAAAEQlVMTAkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEHQAAAAIFAAAABHRoaXMFAAAAB0JVTExLZXkCAAAACm5vIEJVTExLZXkAAAAABEJFQVIJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABB0AAAACBQAAAAR0aGlzBQAAAAdCRUFSS2V5AgAAAApubyBCRUFSS2V5AAAAAAltYWluVG9rZW4JAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABB0AAAACBQAAAAR0aGlzBQAAAAxtYWluVG9rZW5LZXkCAAAAD25vIG1haW5Ub2tlbktleQAAAAAPaXNzdWVQZXJjZW50aWxlCQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQaAAAAAgUAAAAEdGhpcwUAAAASaXNzdWVQZXJjZW50aWxlS2V5AgAAABVubyBpc3N1ZVBlcmNlbnRpbGVLZXkAAAAAEHJlZGVlbVBlcmNlbnRpbGUJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABBoAAAACBQAAAAR0aGlzBQAAABNyZWRlZW1QZXJjZW50aWxlS2V5AgAAABZubyByZWRlZW1QZXJjZW50aWxlS2V5AAAAAAhtaW5Jc3N1ZQkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEGgAAAAIFAAAABHRoaXMFAAAAC21pbklzc3VlS2V5AgAAAA5ubyBtaW5Jc3N1ZUtleQAAAAAJbWluUmVkZWVtCQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQaAAAAAgUAAAAEdGhpcwUAAAAMbWluUmVkZWVtS2V5AgAAAA9ubyBtaW5SZWRlZW1LZXkAAAAAB21pblBvb2wJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABBoAAAACBQAAAAR0aGlzBQAAAAptaW5Qb29sS2V5AgAAAA1ubyBtaW5Qb29sS2V5AAAAAA13aGl0ZWxpc3RPbmx5CQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQbAAAAAgUAAAAEdGhpcwUAAAAQd2hpdGVsaXN0T25seUtleQIAAAATbm8gd2hpdGVsaXN0T25seUtleQAAAAAJd2hpdGVsaXN0CQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQdAAAAAgUAAAAEdGhpcwUAAAAMd2hpdGVsaXN0S2V5AgAAABRubyBidWxsQ29sbGF0ZXJhbEtleQAAAAAPcG9vbEluaXRpYWxpemVkCQEAAAAJaXNEZWZpbmVkAAAAAQkABBsAAAACBQAAAAR0aGlzBQAAABVwb29sTWFpblRva2VuVmFsdWVLZXkAAAAAC3Bvb2xFbmFibGVkCQAAAAAAAAIJAAQbAAAAAgUAAAAEdGhpcwUAAAAOcG9vbEVuYWJsZWRLZXkGAAAAAAhwb29sTWFpbgkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEGgAAAAIFAAAABHRoaXMFAAAAFXBvb2xNYWluVG9rZW5WYWx1ZUtleQIAAAAYbm8gcG9vbE1haW5Ub2tlblZhbHVlS2V5AAAAAAZwb29sVXAJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABBoAAAACBQAAAAR0aGlzBQAAAAlwb29sVXBLZXkCAAAADG5vIHBvb2xVcEtleQAAAAAHcG9vbER3bgkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEGgAAAAIFAAAABHRoaXMFAAAACnBvb2xEd25LZXkCAAAADW5vIHBvb2xEd25LZXkAAAAACXBvb2xUb2tlbgkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEHQAAAAIFAAAABHRoaXMFAAAADHBvb2xUb2tlbktleQIAAAAPbm8gcG9vbFRva2VuS2V5AAAAABRwb29sVG9rZW5DaXJjdWxhdGlvbgkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEGgAAAAIFAAAABHRoaXMFAAAAF3Bvb2xUb2tlbkNpcmN1bGF0aW9uS2V5AgAAABpubyBwb29sVG9rZW5DaXJjdWxhdGlvbktleQAAAAAJcG9vbFZhbHVlCQAAZAAAAAIJAABkAAAAAgUAAAAIcG9vbE1haW4JAABrAAAAAwUAAAAHYnVsbENvbAUAAAAGcG9vbFVwBQAAAAhidWxsQ2lyYwkAAGsAAAADBQAAAAdiZWFyQ29sBQAAAAdwb29sRHduBQAAAAhiZWFyQ2lyYwAAAAAGb3JhY2xlCQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAQAAABRhZGRyZXNzRnJvbVB1YmxpY0tleQAAAAEJAAJZAAAAAQkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEHQAAAAIFAAAABHRoaXMFAAAAC29yYWNsZVBLS2V5AgAAAA5ubyBvcmFjbGVQS0tleQIAAAASYmFkIG9yYWNsZSBhZGRyZXNzAAAAABRyZWJhbGFuY2VkUHJpY2VJbmRleAkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEGgAAAAIFAAAABHRoaXMFAAAAGmxhc3RSZWJhbGFuY2VQcmljZUluZGV4S2V5AgAAABdubyBsYXN0IHJlYmFsYW5jZSBwcmljZQAAAAAQb3JhY2xlUHJpY2VJbmRleAkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEGgAAAAIFAAAABm9yYWNsZQUAAAARbGFzdFByaWNlSW5kZXhLZXkJAAEsAAAAAgkAASwAAAACCQABLAAAAAICAAAAE2JhZCBvcmFjbGUgZGF0YSBhdCAJAAQlAAAAAQUAAAAGb3JhY2xlAgAAABA6IG5vIGludGVnZXIgYXQgBQAAABFsYXN0UHJpY2VJbmRleEtleQAAAAAJcXVldWVTaXplCQEAAAALdmFsdWVPckVsc2UAAAACCQAEGgAAAAIFAAAABHRoaXMFAAAADHF1ZXVlU2l6ZUtleQAAAAAAAAAAAAAAAAALaGVhZFBvaW50ZXIJAQAAAAt2YWx1ZU9yRWxzZQAAAAIJAAQdAAAAAgUAAAAEdGhpcwUAAAAOaGVhZFBvaW50ZXJLZXkCAAAAAAAAAAALdGFpbFBvaW50ZXIJAQAAAAt2YWx1ZU9yRWxzZQAAAAIJAAQdAAAAAgUAAAAEdGhpcwUAAAAOdGFpbFBvaW50ZXJLZXkCAAAAAAAAAAAPZmVlc0FjY3VtdWxhdGVkCQEAAAALdmFsdWVPckVsc2UAAAACCQAEGgAAAAIFAAAABHRoaXMFAAAAEmZlZXNBY2N1bXVsYXRlZEtleQAAAAAAAAAAAAAAAAAFSVNTVUUCAAAABUlTU1VFAAAAAAZSRURFRU0CAAAABlJFREVFTQAAAAAEUE9PTAIAAAAEUE9PTAAAAAAGVU5QT09MAgAAAAZVTlBPT0wAAAAACmZlZUFkZHJLZXkCAAAACmZlZUFkZHJlc3MAAAAADnN0YWtpbmdBZGRyS2V5AgAAAA5zdGFraW5nQWRkcmVzcwAAAAAPZGFlbW9uUHViS2V5S2V5AgAAAA9kYWVtb25QdWJsaWNLZXkAAAAACmZlZUFkZHJlc3MJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABCYAAAABCQEA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UG9vbFVwBQAAAAtjdXJCdWxsQ2lyYwQAAAAQbGlxdWlkYXRlZFRva2VucwMJAABmAAAAAgUAAAAEZGlmZgUAAAAIZXhwb3N1cmUFAAAACWN1clBvb2xVcAkAAGsAAAADBQAAAARkaWZmBQAAAAtjdXJCdWxsQ2lyYwUAAAAKY3VyQnVsbENvbAQAAAAPbGlxdWlkYXRlZFZhbHVlAwkAAGYAAAACBQAAAARkaWZmBQAAAAhleHBvc3VyZQUAAAAIZXhwb3N1cmUJAABrAAAAAwUAAAAQbGlxdWlkYXRlZFRva2VucwUAAAAKY3VyQnVsbENvbAUAAAALY3VyQnVsbENpcmMJAAUZAAAABwkAAGUAAAACBQAAAApjdXJCdWxsQ29sBQAAAA9saXF1aWRhdGVkVmFsdWUFAAAACmN1ckJlYXJDb2wJAABlAAAAAgUAAAALY3VyQnVsbENpcmMFAAAAEGxpcXVpZGF0ZWRUb2tlbnMFAAAAC2N1ckJlYXJDaXJjCQAAZAAAAAIFAAAAC2N1clBvb2xNYWluBQAAAA9saXF1aWRhdGVkVmFsdWUJAABlAAAAAgUAAAAJY3VyUG9vbFVwBQAAABBsaXF1aWRhdGVkVG9rZW5zBQAAAApjdXJQb29sRHduCgEAAAAIY2xvc2VEd24AAAAHAAAACmN1ckJ1bGxDb2wAAAAKY3VyQmVhckNvbAAAAAtjdXJCdWxsQ2lyYwAAAAtjdXJCZWFyQ2lyYwAAAAtjdXJQb29sTWFpbgAAAAljdXJQb29sVXAAAAAKY3VyUG9vbER3bgQAAAAEZGlmZgkAAGUAAAACBQAAAApjdXJCZWFyQ29sBQAAAApjdXJCdWxsQ29sBAAAAAhleHBvc3VyZQkAAGsAAAADBQAAAApjdXJCZWFyQ29sBQAAAApjdXJQb29sRHduBQAAAAtjdXJCZWFyQ2lyYwQAAAAQbGlxdWlkYXRlZFRva2VucwMJAABmAAAAAgUAAAAEZGlmZgUAAAAIZXhwb3N1cmUFAAAACmN1clBvb2xEd24JAABrAAAAAwUAAAAEZGlmZgUAAAALY3VyQmVhckNpcmMFAAAACmN1ckJlYXJDb2wEAAAAD2xpcXVpZGF0ZWRWYWx1ZQMJAABmAAAAAgUAAAAEZGlmZgUAAAAIZXhwb3N1cmUFAAAACGV4cG9zdXJlCQAAawAAAAMFAAAAEGxpcXVpZGF0ZWRUb2tlbnMFAAAACmN1ckJlYXJDb2wFAAAAC2N1ckJlYXJDaXJjCQAFGQAAAAcFAAAACmN1ckJ1bGxDb2wJAABlAAAAAgUAAAAKY3VyQmVhckNvbAUAAAAPbGlxdWlkYXRlZFZhbHVlBQAAAAtjdXJCdWxsQ2lyYwkAAGUAAAACBQAAAAtjdXJCZWFyQ2lyYwUAAAAQbGlxdWlkYXRlZFRva2VucwkAAGQAAAACBQAAAAtjdXJQb29sTWFpbgUAAAAPbGlxdWlkYXRlZFZhbHVlBQAAAAljdXJQb29sVXAJAABlAAAAAgUAAAAKY3VyUG9vbER3bgUAAAAQbGlxdWlkYXRlZFRva2VucwoBAAAAB29wZW5Ed24AAAAHAAAACmN1ckJ1bGxDb2wAAAAKY3VyQmVhckNvbAAAAAtjdXJCdWxsQ2lyYwAAAAtjdXJCZWFyQ2lyYwAAAAtjdXJQb29sTWFpbgAAAAljdXJQb29sVXAAAAAKY3VyUG9vbER3bgQAAAAEZGlmZgkAAGUAAAACBQAAAApjdXJCdWxsQ29sBQAAAApjdXJCZWFyQ29sBAAAAA5zcGVudFBvb2xWYWx1ZQMJAABmAAAAAgUAAAALY3VyUG9vbE1haW4FAAAABGRpZmYFAAAABGRpZmYFAAAAC2N1clBvb2xNYWluBAAAAA5hY3F1aXJlZFRva2VucwkAAGsAAAADBQAAAA5zcGVudFBvb2xWYWx1ZQUAAAALY3VyQmVhckNpcmMFAAAACmN1ckJlYXJDb2wJAAUZAAAABwUAAAAKY3VyQnVsbENvbAkAAGQAAAACBQAAAApjdXJCZWFyQ29sBQAAAA5zcGVudFBvb2xWYWx1ZQUAAAALY3VyQnVsbENpcmMJAABkAAAAAgUAAAALY3VyQmVhckNpcmMFAAAADmFjcXVpcmVkVG9rZW5zCQAAZQAAAAIFAAAAC2N1clBvb2xNYWluBQAAAA5zcGVudFBvb2xWYWx1ZQUAAAAJY3VyUG9vbFVwCQAAZAAAAAIFAAAACmN1clBvb2xEd24FAAAADmFjcXVpcmVkVG9rZW5zCgEAAAAGb3BlblVwAAAABwAAAApjdXJCdWxsQ29sAAAACmN1ckJlYXJDb2wAAAALY3VyQnVsbENpcmMAAAALY3VyQmVhckNpcmMAAAALY3VyUG9vbE1haW4AAAAJY3VyUG9vbFVwAAAACmN1clBvb2xEd24EAAAABGRpZmYJAABlAAAAAgUAAAAKY3VyQmVhckNvbAUAAAAKY3VyQnVsbENvbAQAAAAOc3BlbnRQb29sVmFsdWUDCQAAZgAAAAIFAAAAC2N1clBvb2xNYWluBQAAAARkaWZmBQAAAARkaWZmBQAAAAtjdXJQb29sTWFpbgQAAAAOYWNxdWlyZWRUb2tlbnMJAABrAAAAAwUAAAAOc3BlbnRQb29sVmFsdWUFAAAAC2N1ckJ1bGxDaXJjBQAAAApjdXJCdWxsQ29sCQAFGQAAAAcJAABkAAAAAgUAAAAKY3VyQnVsbENvbAUAAAAOc3BlbnRQb29sVmFsdWUFAAAACmN1ckJlYXJDb2wJAABkAAAAAgUAAAALY3VyQnVsbENpcmMFAAAADmFjcXVpcmVkVG9rZW5zBQAAAAtjdXJCZWFyQ2lyYwkAAGUAAAACBQAAAAtjdXJQb29sTWFpbgUAAAAOc3BlbnRQb29sVmFsdWUJAABkAAAAAgUAAAAJY3VyUG9vbFVwBQAAAA5hY3F1aXJlZFRva2VucwUAAAAKY3VyUG9vbER3bgMJAABmAAAAAgUAAAALY3VyQnVsbENvbDAFAAAAC2N1ckJlYXJDb2wwBAAAAAxhZnRlckNsb3NlVXAJAQAAAAdjbG9zZVVwAAAABwUAAAALY3VyQnVsbENvbDAFAAAAC2N1ckJlYXJDb2wwBQAAAAxjdXJCdWxsQ2lyYzAFAAAADGN1ckJlYXJDaXJjMAUAAAAMY3VyUG9vbE1haW4wBQAAAApjdXJQb29sVXAwBQAAAAtjdXJQb29sRHduMAQAAAAMJHQwOTk0NjEwMDgzBQAAAAxhZnRlckNsb3NlVXAEAAAAAWEIBQAAAAwkdDA5OTQ2MTAwODMAAAACXzEEAAAAAWIIBQAAAAwkdDA5OTQ2MTAwODMAAAACXzIEAAAAAWMIBQAAAAwkdDA5OTQ2MTAwODMAAAACXzMEAAAAAWQIBQAAAAwkdDA5OTQ2MTAwODMAAAACXzQEAAAAAWUIBQAAAAwkdDA5OTQ2MTAwODMAAAACXzUEAAAAAWYIBQAAAAwkdDA5OTQ2MTAwODMAAAACXzYEAAAAAWcIBQAAAAwkdDA5OTQ2MTAwODMAAAACXzcDCQAAZgAAAAIFAAAAAWYAAAAAAAAAAAAFAAAADGFmdGVyQ2xvc2VVcAMJAAAAAAAAAgUAAAABZgAAAAAAAAAAAAkBAAAAB29wZW5Ed24AAAAHBQAAAAFhBQAAAAFiBQAAAAFjBQAAAAFkBQAAAAFlBQAAAAFmBQAAAAFnCQAAAgAAAAECAAAACnBvb2xVcCA8IDAEAAAADWFmdGVyQ2xvc2VEd24JAQAAAAhjbG9zZUR3bgAAAAcFAAAAC2N1ckJ1bGxDb2wwBQAAAAtjdXJCZWFyQ29sMAUAAAAMY3VyQnVsbENpcmMwBQAAAAxjdXJCZWFyQ2lyYzAFAAAADGN1clBvb2xNYWluMAUAAAAKY3VyUG9vbFVwMAUAAAALY3VyUG9vbER3bjAEAAAADSR0MDEwNDM0MTA1NzQFAAAADWFmdGVyQ2xvc2VEd24EAAAAAWEIBQAAAA0kdDAxMDQzNDEwNTc0AAAAAl8xBAAAAAFiCAUAAAANJHQwMTA0MzQxMDU3NAAAAAJfMgQAAAABYwgFAAAADSR0MDEwNDM0MTA1NzQAAAACXzMEAAAAAWQIBQAAAA0kdDAxMDQzNDEwNTc0AAAAAl80BAAAAAFlCAUAAAANJHQwMTA0MzQxMDU3NAAAAAJfNQQAAAABZggFAAAADSR0MDEwNDM0MTA1NzQAAAACXzYEAAAAAWcIBQAAAA0kdDAxMDQzNDEwNTc0AAAAAl83AwkAAGYAAAACBQAAAAFnAAAAAAAAAAAABQAAAA1hZnRlckNsb3NlRHduAwkAAAAAAAACBQAAAAFnAAAAAAAAAAAACQEAAAAGb3BlblVwAAAABwUAAAABYQUAAAABYgUAAAABYwUAAAABZAUAAAABZQUAAAABZgUAAAABZwkAAAIAAAABAgAAAAtwb29sRHduIDwgMAEAAAAUYWN0aW9uc1dpdGhNYXliZVBvb2wAAAAEAAAAC2N1ckJ1bGxDb2wwAAAAC2N1ckJlYXJDb2wwAAAADGN1ckJ1bGxDaXJjMAAAAAxjdXJCZWFyQ2lyYzADBQAAAAtwb29sRW5hYmxlZAQAAAANJHQwMTA4OTgxMTA4MQkBAAAAC3Bvb2xTdXBwb3J0AAAABwUAAAALY3VyQnVsbENvbDAFAAAAC2N1ckJlYXJDb2wwBQAAAAxjdXJCdWxsQ2lyYzAFAAAADGN1ckJlYXJDaXJjMAUAAAAIcG9vbE1haW4FAAAABnBvb2xVcAUAAAAHcG9vbER3bgQAAAAIYnVsbENvbDEIBQAAAA0kdDAxMDg5ODExMDgxAAAAAl8xBAAAAAhiZWFyQ29sMQgFAAAADSR0MDEwODk4MTEwODEAAAACXzIEAAAACGJ1bGxDaWMxCAUAAAANJHQwMTA4OTgxMTA4MQAAAAJfMwQAAAAJYmVhckNpcmMxCAUAAAANJHQwMTA4OTgxMTA4MQAAAAJfNAQAAAAJcG9vbE1haW4xCAUAAAANJHQwMTA4OTgxMTA4MQAAAAJfNQQAAAAHcG9vbFVwMQgFAAAADSR0MDEwODk4MTEwODEAAAACXzYEAAAACHBvb2xEd24xCAUAAAANJHQwMTA4OTgxMTA4MQAAAAJfNwkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAARYnVsbENvbGxhdGVyYWxLZXkFAAAACGJ1bGxDb2wxCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAABJidWxsQ2lyY3VsYXRpb25LZXkFAAAACGJ1bGxDaWMxCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAABFiZWFyQ29sbGF0ZXJhbEtleQUAAAAIYmVhckNvbDEJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAAEmJlYXJDaXJjdWxhdGlvbktleQUAAAAJYmVhckNpcmMxCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAABVwb29sTWFpblRva2VuVmFsdWVLZXkFAAAACXBvb2xNYWluMQkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAAJcG9vbFVwS2V5BQAAAAdwb29sVXAxCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAAApwb29sRHduS2V5BQAAAAhwb29sRHduMQUAAAADbmlsCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAABFidWxsQ29sbGF0ZXJhbEtleQUAAAALY3VyQnVsbENvbDAJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAAEmJ1bGxDaXJjdWxhdGlvbktleQUAAAAM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DlNjcmlwdFRyYW5zZmVyAAAAAwUAAAAHaW52b2tlcgUAAAASYWRkZWRUb0NpcmN1bGF0aW9uCQACWQAAAAEFAAAABEJVTEwFAAAAA25pbAMJAAAAAAAAAgUAAAAFdG9rZW4FAAAABEJFQVIEAAAAEmFkZGVkVG9DaXJjdWxhdGlvbgkAAGsAAAADBQAAAAhiZWFyQ2lyYwUAAAAPYWRkZWRDb2xsYXRlcmFsBQAAAAdiZWFyQ29sCQAETgAAAAIJAQAAABRhY3Rpb25zV2l0aE1heWJlUG9vbAAAAAQFAAAAB2J1bGxDb2wJAABkAAAAAgUAAAAHYmVhckNvbAUAAAAPYWRkZWRDb2xsYXRlcmFsBQAAAAhidWxsQ2lyYwkAAGQAAAACBQAAAAhiZWFyQ2lyYwUAAAASYWRkZWRUb0NpcmN1bGF0aW9uCQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAADmhlYWRQb2ludGVyS2V5BQAAAARuZXh0CQAETAAAAAIJAQAAAApjb2xsZWN0RmVlAAAAAQUAAAAHZmVlU2l6ZQkABEwAAAACBQAAABFkZWNyZWFzZVF1ZXVlU2l6ZQkABEwAAAACCQEAAAAOU2NyaXB0VHJhbnNmZXIAAAADBQAAAAdpbnZva2VyBQAAABJhZGRlZFRvQ2lyY3VsYXRpb24JAAJZAAAAAQUAAAAEQkVBUgUAAAADbmlsCQAAAgAAAAECAAAADGJhZCB0b2tlbiBpZAMJAAAAAAAAAgUAAAAGYWN0aW9uBQAAAAZSRURFRU0EAAAADXJlbW92ZWRUb2tlbnMFAAAAA2FtdAMJAAAAAAAAAgUAAAAFdG9rZW4FAAAABEJVTEwEAAAAEXJlbW92ZWRDb2xsYXRlcmFsCQAAawAAAAMFAAAAB2J1bGxDb2wFAAAADXJlbW92ZWRUb2tlbnMFAAAACGJ1bGxDaXJjBAAAAAdmZWVTaXplCQAAawAAAAMFAAAAEXJlbW92ZWRDb2xsYXRlcmFsBQAAABByZWRlZW1QZXJjZW50aWxlAAAAAAAAACcQBAAAAAZwYXlvdXQDCQAAZgAAAAIFAAAAEXJlbW92ZWRDb2xsYXRlcmFsBQAAAAdmZWVTaXplCQAAZQAAAAIFAAAAEXJlbW92ZWRDb2xsYXRlcmFsBQAAAAdmZWVTaXplAAAAAAAAAAAACQAETgAAAAIJAQAAABRhY3Rpb25zV2l0aE1heWJlUG9vbAAAAAQJAABlAAAAAgUAAAAHYnVsbENvbAUAAAARcmVtb3ZlZENvbGxhdGVyYWwFAAAAB2JlYXJDb2wJAABlAAAAAgUAAAAIYnVsbENpcmMFAAAADXJlbW92ZWRUb2tlbnMFAAAACGJlYXJDaXJjCQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAADmhlYWRQb2ludGVyS2V5BQAAAARuZXh0CQAETAAAAAIJAQAAAApjb2xsZWN0RmVlAAAAAQUAAAAHZmVlU2l6ZQkABEwAAAACBQAAABFkZWNyZWFzZVF1ZXVlU2l6ZQkABEwAAAACCQEAAAAOU2NyaXB0VHJhbnNmZXIAAAADBQAAAAdpbnZva2VyBQAAAAZwYXlvdXQJAAJZAAAAAQUAAAAJbWFpblRva2VuBQAAAANuaWwDCQAAAAAAAAIFAAAABXRva2VuBQAAAARCRUFSBAAAABFyZW1vdmVkQ29sbGF0ZXJhbAkAAGsAAAADBQAAAAdiZWFyQ29sBQAAAA1yZW1vdmVkVG9rZW5zBQAAAAhiZWFyQ2lyYwQAAAAHZmVlU2l6ZQkAAGsAAAADBQAAABFyZW1vdmVkQ29sbGF0ZXJhbAUAAAAQcmVkZWVtUGVyY2VudGlsZQAAAAAAAAAnEAQAAAAGcGF5b3V0AwkAAGYAAAACBQAAABFyZW1vdmVkQ29sbGF0ZXJhbAUAAAAHZmVlU2l6ZQkAAGUAAAACBQAAABFyZW1vdmVkQ29sbGF0ZXJhbAUAAAAHZmVlU2l6ZQAAAAAAAAAAAAkABE4AAAACCQEAAAAUYWN0aW9uc1dpdGhNYXliZVBvb2wAAAAEBQAAAAdidWxsQ29sCQAAZQAAAAIFAAAAB2JlYXJDb2wFAAAAEXJlbW92ZWRDb2xsYXRlcmFsBQAAAAhidWxsQ2lyYwkAAGUAAAACBQAAAAhiZWFyQ2lyYwUAAAANcmVtb3ZlZFRva2VucwkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACBQAAAA5oZWFkUG9pbnRlcktleQUAAAAEbmV4dAkABEwAAAACCQEAAAAKY29sbGVjdEZlZQAAAAEFAAAAB2ZlZVNpemUJAARMAAAAAgUAAAARZGVjcmVhc2VRdWV1ZVNpemUJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwUAAAAHaW52b2tlcgUAAAAGcGF5b3V0CQACWQAAAAEFAAAACW1haW5Ub2tlbgUAAAADbmlsCQAAAgAAAAECAAAADGJhZCB0b2tlbiBpZAMJAAAAAAAAAgUAAAAGYWN0aW9uBQAAAARQT09MBAAAAAtpc3N1ZVRva2VucwkAAGsAAAADBQAAABRwb29sVG9rZW5DaXJjdWxhdGlvbgUAAAADYW10BQAAAAlwb29sVmFsdWUJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAAFXBvb2xNYWluVG9rZW5WYWx1ZUtleQkAAGQAAAACBQAAAAhwb29sTWFpbgUAAAADYW10CQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAABdwb29sVG9rZW5DaXJjdWxhdGlvbktleQkAAGQAAAACBQAAABRwb29sVG9rZW5DaXJjdWxhdGlvbgUAAAALaXNzdWVUb2tlbnMJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgUAAAAOaGVhZFBvaW50ZXJLZXkFAAAABG5leHQJAARMAAAAAgUAAAARZGVjcmVhc2VRdWV1ZVNpemUJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwUAAAAHaW52b2tlcgUAAAALaXNzdWVUb2tlbnMJAAJZAAAAAQUAAAAJcG9vbFRva2VuBQAAAANuaWwDCQAAAAAAAAIFAAAABmFjdGlvbgUAAAAGVU5QT09MCgEAAAAFc2hhcmUAAAABAAAAAWEJAABrAAAAAwUAAAABYQUAAAADYW10BQAAABRwb29sVG9rZW5DaXJjdWxhdGlvbgQAAAAMdW5wb29sZWRNYWluCQEAAAAFc2hhcmUAAAABBQAAAAhwb29sTWFpbgQAAAAKdW5wb29sZWRVcAkBAAAABXNoYXJlAAAAAQUAAAAGcG9vbFVwBAAAAAt1bnBvb2xlZER3bgkBAAAABXNoYXJlAAAAAQUAAAAHcG9vbER3bgQAAAAPdW5wb29sZWRVcFZhbHVlCQAAawAAAAMFAAAACnVucG9vbGVkVXAFAAAAB2J1bGxDb2wFAAAACGJ1bGxDaXJjBAAAABB1bnBvb2xlZER3blZhbHVlCQAAawAAAAMFAAAAC3VucG9vbGVkRHduBQAAAAdiZWFyQ29sBQAAAAhiZWFyQ2lyYwkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAAVcG9vbE1haW5Ub2tlblZhbHVlS2V5CQAAZQAAAAIFAAAACHBvb2xNYWluBQAAAAx1bnBvb2xlZE1haW4JAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAAF3Bvb2xUb2tlbkNpcmN1bGF0aW9uS2V5CQAAZQAAAAIFAAAAFHBvb2xUb2tlbkNpcmN1bGF0aW9uBQAAAANhbXQJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAACXBvb2xVcEtleQkAAGUAAAACBQAAAAZwb29sVXAFAAAACnVucG9vbGVkVXAJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAACnBvb2xEd25LZXkJAABlAAAAAgUAAAAHcG9vbER3bgUAAAALdW5wb29sZWREd24JAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAAEmJ1bGxDaXJjdWxhdGlvbktleQkAAGUAAAACBQAAAAhidWxsQ2lyYwUAAAAKdW5wb29sZWRVcAkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAASYmVhckNpcmN1bGF0aW9uS2V5CQAAZQAAAAIFAAAACGJlYXJDaXJjBQAAAAt1bnBvb2xlZER3bgkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAARYnVsbENvbGxhdGVyYWxLZXkJAABlAAAAAgUAAAAHYnVsbENvbAUAAAAPdW5wb29sZWRVcFZhbHVlCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAABFiZWFyQ29sbGF0ZXJhbEtleQkAAGUAAAACBQAAAAdiZWFyQ29sBQAAABB1bnBvb2xlZER3blZhbHVlCQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAADmhlYWRQb2ludGVyS2V5BQAAAARuZXh0CQAETAAAAAIFAAAAEWRlY3JlYXNlUXVldWVTaXplCQAETAAAAAIJAQAAAA5TY3JpcHRUcmFuc2ZlcgAAAAMFAAAAB2ludm9rZXIJAABkAAAAAgkAAGQAAAACBQAAAAx1bnBvb2xlZE1haW4FAAAAD3VucG9vbGVkVXBWYWx1ZQUAAAAQdW5wb29sZWREd25WYWx1ZQkAAlkAAAABBQAAAAltYWluVG9rZW4FAAAAA25pbAkAAAIAAAABCQABLAAAAAICAAAADGJhZCBhY3Rpb246IAUAAAAGYWN0aW9uAwUAAAANaXNMYXN0RWxlbWVudAkABEwAAAACBQAAAA1vdmVyd3JpdGVUYWlsBQAAAAVpdGVtcwUAAAAFaXRlbXMBAAAACXJlYmFsYW5jZQAAAAAKAQAAAAJMVgAAAAMAAAABdgAAAAJwMAAAAAJwMQQAAAAFZGVub20AAAAAAAAAAGQEAAAABHBtYXgJAABpAAAAAgMJAABmAAAAAgUAAAACcDEFAAAAAnAwBQAAAAJwMQUAAAACcDAFAAAABWRlbm9tBAAAAARwbWluCQAAaQAAAAIDCQAAZgAAAAIFAAAAAnAwBQAAAAJwMQUAAAACcDEFAAAAAnAwBQAAAAVkZW5vbQQAAAABYQkAAGgAAAACBQAAAARwbWluBQAAAARwbWluBAAAAAFiCQAAZQAAAAIJAABoAAAAAgkAAGgAAAACAAAAAAAAAAAJBQAAAARwbWF4BQAAAARwbWF4CQAAaAAAAAIJAABoAAAAAgAAAAAAAAAADwUAAAAEcG1heAUAAAAEcG1pbgkAAGsAAAADBQAAAAF2CQAAZAAAAAIJAABoAAAAAgAAAAAAAAAABgUAAAABYQUAAAABYgkAAGQAAAACCQAAaAAAAAIAAAAAAAAAAAcFAAAAAWEFAAAAAWIEAAAAEXNldHRsZWRQcmljZUluZGV4CQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQaAAAAAgUAAAAEdGhpcwUAAAAabGFzdFJlYmFsYW5jZVByaWNlSW5kZXhLZXkCAAAAEWluY29uc2lzdGVudCBkYXRhBAAAABN1bnNldHRsZWRQcmljZUluZGV4CQAAZAAAAAIFAAAAEXNldHRsZWRQcmljZUluZGV4AAAAAAAAAAABBAAAABJzZXR0bGVkUHJpY2VIZWlnaHQJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABBoAAAACBQAAAAZvcmFjbGUJAAEsAAAAAgIAAAAMcHJpY2VfaW5kZXhfCQABpAAAAAEFAAAAEXNldHRsZWRQcmljZUluZGV4AgAAAChiYWQgb3JhY2xlIGRhdGEgZm9yIHNldHRsZWQgcHJpY2UgaGVpZ2h0BAAAAAxzZXR0bGVkUHJpY2UJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABBoAAAACBQAAAAZvcmFjbGUJAAEsAAAAAgIAAAAGcHJpY2VfCQABpAAAAAEFAAAAEnNldHRsZWRQcmljZUhlaWdodAIAAAAZYmFkIG9yYWNsZSBkYXRhIGZvciBwcmljZQQAAAAPbmV4dFByaWNlSGVpZ2h0CQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQaAAAAAgUAAAAGb3JhY2xlCQABLAAAAAICAAAADHByaWNlX2luZGV4XwkAAaQAAAABBQAAABN1bnNldHRsZWRQcmljZUluZGV4AgAAABRubyBuZXh0IHByaWNlIGhlaWdodAQAAAAJbmV4dFByaWNlCQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQaAAAAAgUAAAAGb3JhY2xlCQABLAAAAAICAAAABnByaWNlXwkAAaQAAAABBQAAAA9uZXh0UHJpY2VIZWlnaHQCAAAADW5vIG5leHQgcHJpY2UEAAAABm1pblZvbAMJAABmAAAAAgUAAAAHYmVhckNvbAUAAAAHYnVsbENvbAUAAAAHYnVsbENvbAUAAAAHYmVhckNvbAQAAAAGcmVkaXN0CQEAAAACTFYAAAADBQAAAAZtaW5Wb2wFAAAADHNldHRsZWRQcmljZQUAAAAJbmV4dFByaWNlBAAAAApuZXdCdWxsQ29sAwkAAGYAAAACBQAAAAluZXh0UHJpY2UFAAAADHNldHRsZWRQcmljZQkAAGQAAAACBQAAAAdidWxsQ29sBQAAAAZyZWRpc3QJAABlAAAAAgUAAAAHYnVsbENvbAUAAAAGcmVkaXN0BAAAAApuZXdCZWFyQ29sAwkAAGYAAAACBQAAAAluZXh0UHJpY2UFAAAADHNldHRsZWRQcmljZQkAAGUAAAACBQAAAAdiZWFyQ29sBQAAAAZyZWRpc3QJAABkAAAAAgUAAAAHYmVhckNvbAUAAAAGcmVkaXN0AwUAAAALcG9vbEVuYWJsZWQEAAAADSR0MDE5MjIwMTk0MDcJAQAAAAtwb29sU3VwcG9ydAAAAAcFAAAACm5ld0J1bGxDb2wFAAAACm5ld0JlYXJDb2wFAAAACGJ1bGxDaXJjBQAAAAhiZWFyQ2lyYwUAAAAIcG9vbE1haW4FAAAABnBvb2xVcAUAAAAHcG9vbER3bgQAAAAKdXBkQnVsbENvbAgFAAAADSR0MDE5MjIwMTk0MDcAAAACXzEEAAAACnVwZEJlYXJDb2wIBQAAAA0kdDAxOTIyMDE5NDA3AAAAAl8yBAAAAAt1cGRCdWxsQ2lyYwgFAAAADSR0MDE5MjIwMTk0MDcAAAACXzMEAAAAC3VwZEJlYXJDaXJjCAUAAAANJHQwMTkyMjAxOTQwNwAAAAJfNAQAAAALdXBkUG9vbE1haW4IBQAAAA0kdDAxOTIyMDE5NDA3AAAAAl81BAAAAAl1cGRQb29sVXAIBQAAAA0kdDAxOTIyMDE5NDA3AAAAAl82BAAAAAp1cGRQb29sRHduCAUAAAANJHQwMTkyMjAxOTQwNwAAAAJfNwkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAARYnVsbENvbGxhdGVyYWxLZXkFAAAACnVwZEJ1bGxDb2wJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAAEWJlYXJDb2xsYXRlcmFsS2V5BQAAAAp1cGRCZWFyQ29sCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAABJidWxsQ2lyY3VsYXRpb25LZXkFAAAAC3VwZEJ1bGxDaXJjCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAABJiZWFyQ2lyY3VsYXRpb25LZXkFAAAAC3VwZEJlYXJDaXJjCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAABVwb29sTWFpblRva2VuVmFsdWVLZXkFAAAAC3VwZFBvb2xNYWluCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAAAlwb29sVXBLZXkFAAAACXVwZFBvb2xVcAkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAAKcG9vbER3bktleQUAAAAKdXBkUG9vbER3bgkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAAabGFzdFJlYmFsYW5jZVByaWNlSW5kZXhLZXkFAAAAE3Vuc2V0dGxlZFByaWNlSW5kZXgFAAAAA25pbAkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAARYnVsbENvbGxhdGVyYWxLZXkFAAAACm5ld0J1bGxDb2wJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAAEWJlYXJDb2xsYXRlcmFsS2V5BQAAAApuZXdCZWFyQ29sCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAABpsYXN0UmViYWxhbmNlUHJpY2VJbmRleEtleQUAAAATdW5zZXR0bGVkUHJpY2VJbmRleAUAAAADbmlsAAAADAAAAANpbnYBAAAABGluaXQAAAAFAAAABmJ1bGxJZAAAAAZiZWFySWQAAAALbWFpblRva2VuSWQAAAAIb3JhY2xlUEsAAAALd2hpdGVsaXN0ZWQDCQEAAAAJaXNEZWZpbmVkAAAAAQkABB0AAAACBQAAAAR0aGlzBQAAAAdCVUxMS2V5CQAAAgAAAAECAAAAE2FscmVhZHkgaW5pdGlhbGl6ZWQDCQEAAAACIT0AAAACCQACWAAAAAEJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAggJAAGRAAAAAggFAAAAA2ludgAAAAhwYXltZW50cwAAAAAAAAAAAAAAAAdhc3NldElkAgAAABluZXV0cmlubyBwYXltZW50IHJlcXVpcmVkBQAAAAttYWluVG9rZW5JZAkAAAIAAAABAgAAABdwYXltZW50IG5vdCBpbiBuZXV0cmlubwQAAAATdG90YWxPd25lZE1haW5Ub2tlbggJAAGRAAAAAggFAAAAA2ludgAAAAhwYXltZW50cwAAAAAAAAAAAAAAAAZhbW91bnQEAAAABWJ1bGxzCQAAaQAAAAIFAAAAE3RvdGFsT3duZWRNYWluVG9rZW4AAAAAAAAAAAIEAAAABWJlYXJzCQAAZQAAAAIFAAAAE3RvdGFsT3duZWRNYWluVG9rZW4FAAAABWJ1bGxzAwMJAAAAAAAAAgUAAAAFYmVhcnMAAAAAAAAAAAAGCQAAAAAAAAIFAAAABWJ1bGxzAAAAAAAAAAAACQAAAgAAAAECAAAAE2Nhbid0IGluaXQgYmFsYW5jZXMEAAAAF29yYWNsZUN1cnJlbnRQcmljZUluZGV4CQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQaAAAAAgkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQEAAAAUYWRkcmVzc0Zyb21QdWJsaWNLZXkAAAABCQACWQAAAAEFAAAACG9yYWNsZVBLAgAAABJiYWQgb3JhY2xlIGFkZHJlc3MFAAAAEWxhc3RQcmljZUluZGV4S2V5AgAAACJjYW4ndCBmaW5kIGxhc3Qgb3JhY2xlIHByaWNlIGluZGV4CQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAAB0JVTExLZXkFAAAABmJ1bGxJZAkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACBQAAAAdCRUFSS2V5BQAAAAZiZWFySWQJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgUAAAAMbWFpblRva2VuS2V5BQAAAAttYWluVG9rZW5JZAkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACBQAAAAtvcmFjbGVQS0tleQUAAAAIb3JhY2xlUEsJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAAEWJ1bGxDb2xsYXRlcmFsS2V5BQAAAAVidWxscwkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAARYmVhckNvbGxhdGVyYWxLZXkFAAAABWJlYXJzCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAABJidWxsQ2lyY3VsYXRpb25LZXkFAAAABWJ1bGxzCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAABJiZWFyQ2lyY3VsYXRpb25LZXkFAAAABWJlYXJzCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAABpsYXN0UmViYWxhbmNlUHJpY2VJbmRleEtleQUAAAAXb3JhY2xlQ3VycmVudFByaWNlSW5kZXgJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgUAAAAMd2hpdGVsaXN0S2V5BQAAAAt3aGl0ZWxpc3RlZAkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAASaXNzdWVQZXJj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", "chainId": 87, "height": 2269310, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: EQCpMC2MmbSLSGwsHFtDXai27wxfvpRCMgv36evxEzjA Next: H5XQMYij4pYQCbR2oGmk5yYmxhkNhSjH5Yz2XMT6xTHD Diff:
Old | New | Differences | |
---|---|---|---|
1 | - | {-# STDLIB_VERSION | |
1 | + | {-# STDLIB_VERSION 4 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | + | let ten6 = 1000000 | |
5 | + | ||
6 | + | let ten8 = 100000000 | |
7 | + | ||
4 | 8 | let BULLKey = "BULLId" | |
5 | 9 | ||
6 | 10 | let BEARKey = "BEARId" | |
7 | 11 | ||
8 | 12 | let mainTokenKey = "mainTokenId" | |
13 | + | ||
14 | + | let bullCollateralKey = "bullCollateral" | |
15 | + | ||
16 | + | let bearCollateralKey = "bearCollateral" | |
17 | + | ||
18 | + | let bullCirculationKey = "bullCirculation" | |
19 | + | ||
20 | + | let bearCirculationKey = "bearCirculation" | |
9 | 21 | ||
10 | 22 | let issuePercentileKey = "issuePercentile" | |
11 | 23 | ||
15 | 27 | ||
16 | 28 | let minRedeemKey = "minRedeem" | |
17 | 29 | ||
30 | + | let minPoolKey = "minPool" | |
31 | + | ||
32 | + | let feesAccumulatedKey = "feesAccumulated" | |
33 | + | ||
18 | 34 | let whitelistOnlyKey = "whitelistOnly" | |
35 | + | ||
36 | + | let whitelistKey = "issueWhiteList" | |
19 | 37 | ||
20 | 38 | let oraclePKKey = "oracle" | |
21 | 39 | ||
29 | 47 | ||
30 | 48 | let lastRebalancePriceIndexKey = "lastSettlementPriceId" | |
31 | 49 | ||
32 | - | let | |
50 | + | let headPointerKey = "headPointer" | |
33 | 51 | ||
34 | - | let | |
52 | + | let tailPointerKey = "tailPointer" | |
35 | 53 | ||
36 | - | let | |
54 | + | let queueSizeKey = "queueSize" | |
37 | 55 | ||
38 | - | let | |
56 | + | let poolMainTokenValueKey = "poolMainTokenValue" | |
39 | 57 | ||
40 | - | let | |
58 | + | let poolUpKey = "poolUp" | |
41 | 59 | ||
42 | - | let whitelist = valueOrErrorMessage(getString(this, whitelistKey), "no bullCollateralKey") | |
60 | + | let poolDwnKey = "poolDwn" | |
61 | + | ||
62 | + | let poolEnabledKey = "poolEnabled" | |
63 | + | ||
64 | + | let poolTokenCirculationKey = "poolTokenCirculation" | |
65 | + | ||
66 | + | let poolTokenKey = "poolToken" | |
43 | 67 | ||
44 | 68 | let bullCol = valueOrErrorMessage(getInteger(this, bullCollateralKey), "no bullCollateralKey") | |
45 | 69 | ||
63 | 87 | ||
64 | 88 | let minRedeem = valueOrErrorMessage(getInteger(this, minRedeemKey), "no minRedeemKey") | |
65 | 89 | ||
90 | + | let minPool = valueOrErrorMessage(getInteger(this, minPoolKey), "no minPoolKey") | |
91 | + | ||
66 | 92 | let whitelistOnly = valueOrErrorMessage(getBoolean(this, whitelistOnlyKey), "no whitelistOnlyKey") | |
93 | + | ||
94 | + | let whitelist = valueOrErrorMessage(getString(this, whitelistKey), "no bullCollateralKey") | |
95 | + | ||
96 | + | let poolInitialized = isDefined(getBoolean(this, poolMainTokenValueKey)) | |
97 | + | ||
98 | + | let poolEnabled = (getBoolean(this, poolEnabledKey) == true) | |
99 | + | ||
100 | + | let poolMain = valueOrErrorMessage(getInteger(this, poolMainTokenValueKey), "no poolMainTokenValueKey") | |
101 | + | ||
102 | + | let poolUp = valueOrErrorMessage(getInteger(this, poolUpKey), "no poolUpKey") | |
103 | + | ||
104 | + | let poolDwn = valueOrErrorMessage(getInteger(this, poolDwnKey), "no poolDwnKey") | |
105 | + | ||
106 | + | let poolToken = valueOrErrorMessage(getString(this, poolTokenKey), "no poolTokenKey") | |
107 | + | ||
108 | + | let poolTokenCirculation = valueOrErrorMessage(getInteger(this, poolTokenCirculationKey), "no poolTokenCirculationKey") | |
109 | + | ||
110 | + | let poolValue = ((poolMain + fraction(bullCol, poolUp, bullCirc)) + fraction(bearCol, poolDwn, bearCirc)) | |
67 | 111 | ||
68 | 112 | let oracle = valueOrErrorMessage(addressFromPublicKey(fromBase58String(valueOrErrorMessage(getString(this, oraclePKKey), "no oraclePKKey"))), "bad oracle address") | |
69 | 113 | ||
71 | 115 | ||
72 | 116 | let oraclePriceIndex = valueOrErrorMessage(getInteger(oracle, lastPriceIndexKey), ((("bad oracle data at " + toString(oracle)) + ": no integer at ") + lastPriceIndexKey)) | |
73 | 117 | ||
74 | - | let | |
118 | + | let queueSize = valueOrElse(getInteger(this, queueSizeKey), 0) | |
75 | 119 | ||
76 | - | let | |
120 | + | let headPointer = valueOrElse(getString(this, headPointerKey), "") | |
77 | 121 | ||
78 | - | let | |
122 | + | let tailPointer = valueOrElse(getString(this, tailPointerKey), "") | |
79 | 123 | ||
80 | - | let queueSize = match getInteger(this, queueSizeKey) { | |
81 | - | case i: Int => | |
82 | - | i | |
83 | - | case _ => | |
84 | - | 0 | |
85 | - | } | |
86 | - | ||
87 | - | let headPointer = match getString(this, headPointerKey) { | |
88 | - | case s: String => | |
89 | - | s | |
90 | - | case _ => | |
91 | - | "" | |
92 | - | } | |
93 | - | ||
94 | - | let tailPointer = match getString(this, tailPointerKey) { | |
95 | - | case s: String => | |
96 | - | s | |
97 | - | case _ => | |
98 | - | "" | |
99 | - | } | |
100 | - | ||
101 | - | let feesAccumulatedKey = "feesAccumulated" | |
102 | - | ||
103 | - | let feesAccumulated = match getInteger(this, feesAccumulatedKey) { | |
104 | - | case i: Int => | |
105 | - | i | |
106 | - | case _ => | |
107 | - | 0 | |
108 | - | } | |
124 | + | let feesAccumulated = valueOrElse(getInteger(this, feesAccumulatedKey), 0) | |
109 | 125 | ||
110 | 126 | let ISSUE = "ISSUE" | |
111 | 127 | ||
112 | 128 | let REDEEM = "REDEEM" | |
129 | + | ||
130 | + | let POOL = "POOL" | |
131 | + | ||
132 | + | let UNPOOL = "UNPOOL" | |
113 | 133 | ||
114 | 134 | let feeAddrKey = "feeAddress" | |
115 | 135 | ||
127 | 147 | ||
128 | 148 | let pubKeyAdminsList = ["2HHqV8W9DJayV5R6tBD2Sb8srphpoboDi7r1t1aPiumC", "5ZXe82RRASU7qshXM2J9JNYhqJ9GWYjjVq2gwUV5Naz9", "5WRXFSjwcTbNfKcJs8ZqXmSSWYsSVJUtMvMqZj5hH4Nc"] | |
129 | 149 | ||
150 | + | func safeFraction (a,b,c) = if (if ((a == 0)) | |
151 | + | then true | |
152 | + | else (b == 0)) | |
153 | + | then 0 | |
154 | + | else fraction(a, b, c) | |
155 | + | ||
156 | + | ||
130 | 157 | func buildNewItem (action,amt,token,priceIndex,invoker) = (((((((((action + "|") + toString(amt)) + "|") + token) + "|") + toString(priceIndex)) + "|") + invoker) + "|") | |
131 | 158 | ||
132 | 159 | ||
133 | - | func | |
160 | + | func validateRequestRedeem (inv) = if ((inv.caller == this)) | |
134 | 161 | then throw("can't do") | |
135 | 162 | else { | |
136 | 163 | func errorMessage (got) = throw(((((("only BULL(" + BULL) + ") or BEAR(") + BEAR) + ") tokens are accepted, received: ") + got)) | |
137 | 164 | ||
138 | - | if (!(isDefined(inv.payment))) | |
139 | - | then errorMessage("no attached payment") | |
165 | + | let assetId = toBase58String(valueOrErrorMessage(value(inv.payments[0]).assetId, "waves are not accepted here")) | |
166 | + | if (if ((assetId != BEAR)) | |
167 | + | then (assetId != BULL) | |
168 | + | else false) | |
169 | + | then errorMessage(assetId) | |
140 | 170 | else { | |
141 | - | let assetId = toBase58String(valueOrErrorMessage(value(inv.payment).assetId, "waves are not accepted here")) | |
142 | - | if (if ((assetId != BEAR)) | |
143 | - | then (assetId != BULL) | |
144 | - | else false) | |
145 | - | then errorMessage(assetId) | |
146 | - | else { | |
147 | - | let attachedAmount = value(inv.payment).amount | |
148 | - | let col = if ((assetId == BEAR)) | |
149 | - | then bearCol | |
150 | - | else bullCol | |
151 | - | let circ = if ((assetId == BEAR)) | |
152 | - | then bearCirc | |
153 | - | else bullCirc | |
154 | - | let estimated = fraction(col, attachedAmount, circ) | |
155 | - | if ((minRedeem > estimated)) | |
156 | - | then throw((((((((((("Attached payment too small. Min redeem amount is " + toString((minRedeem / 1000000))) + " USDN, ") + "attached amount: ") + toString(attachedAmount)) + ", col: ") + toString(col)) + ", circ: ") + toString(circ)) + ", estimated: ") + toString(estimated))) | |
157 | - | else unit | |
158 | - | } | |
171 | + | let attachedAmount = inv.payments[0].amount | |
172 | + | let col = if ((assetId == BEAR)) | |
173 | + | then bearCol | |
174 | + | else bullCol | |
175 | + | let circ = if ((assetId == BEAR)) | |
176 | + | then bearCirc | |
177 | + | else bullCirc | |
178 | + | let estimated = fraction(col, attachedAmount, circ) | |
179 | + | if ((minRedeem > estimated)) | |
180 | + | then throw((((((((((("Attached payment too small. Min redeem amount is " + toString((minRedeem / 1000000))) + " USDN, ") + "attached amount: ") + toString(attachedAmount)) + ", col: ") + toString(col)) + ", circ: ") + toString(circ)) + ", estimated: ") + toString(estimated))) | |
181 | + | else unit | |
159 | 182 | } | |
160 | 183 | } | |
161 | 184 | ||
162 | 185 | ||
163 | 186 | func enqueue (id,action,amt,token,priceIndex,invoker) = { | |
164 | - | let increaseQueueSize = | |
187 | + | let increaseQueueSize = IntegerEntry(queueSizeKey, (queueSize + 1)) | |
165 | 188 | let itm = buildNewItem(action, amt, token, priceIndex, invoker) | |
166 | 189 | if ((queueSize == 0)) | |
167 | - | then | |
190 | + | then [StringEntry(headPointerKey, id), StringEntry(tailPointerKey, id), StringEntry(id, itm), increaseQueueSize] | |
168 | 191 | else { | |
169 | 192 | let prevId = valueOrErrorMessage(getString(this, tailPointerKey), "can't get tail pointer") | |
170 | 193 | let prevItm = split(valueOrErrorMessage(getString(this, prevId), "can't resolve pointer"), "|") | |
171 | 194 | let updatedPrevItm = ((((((((((prevItm[0] + "|") + prevItm[1]) + "|") + prevItm[2]) + "|") + prevItm[3]) + "|") + prevItm[4]) + "|") + id) | |
172 | - | ||
195 | + | [StringEntry(prevId, updatedPrevItm), StringEntry(id, itm), StringEntry(tailPointerKey, id), increaseQueueSize] | |
173 | 196 | } | |
174 | 197 | } | |
198 | + | ||
199 | + | ||
200 | + | func poolSupport (curBullCol0,curBearCol0,curBullCirc0,curBearCirc0,curPoolMain0,curPoolUp0,curPoolDwn0) = { | |
201 | + | func closeUp (curBullCol,curBearCol,curBullCirc,curBearCirc,curPoolMain,curPoolUp,curPoolDwn) = { | |
202 | + | let diff = (curBullCol - curBearCol) | |
203 | + | let exposure = fraction(curBullCol, curPoolUp, curBullCirc) | |
204 | + | let liquidatedTokens = if ((diff > exposure)) | |
205 | + | then curPoolUp | |
206 | + | else fraction(diff, curBullCirc, curBullCol) | |
207 | + | let liquidatedValue = if ((diff > exposure)) | |
208 | + | then exposure | |
209 | + | else fraction(liquidatedTokens, curBullCol, curBullCirc) | |
210 | + | $Tuple7((curBullCol - liquidatedValue), curBearCol, (curBullCirc - liquidatedTokens), curBearCirc, (curPoolMain + liquidatedValue), (curPoolUp - liquidatedTokens), curPoolDwn) | |
211 | + | } | |
212 | + | ||
213 | + | func closeDwn (curBullCol,curBearCol,curBullCirc,curBearCirc,curPoolMain,curPoolUp,curPoolDwn) = { | |
214 | + | let diff = (curBearCol - curBullCol) | |
215 | + | let exposure = fraction(curBearCol, curPoolDwn, curBearCirc) | |
216 | + | let liquidatedTokens = if ((diff > exposure)) | |
217 | + | then curPoolDwn | |
218 | + | else fraction(diff, curBearCirc, curBearCol) | |
219 | + | let liquidatedValue = if ((diff > exposure)) | |
220 | + | then exposure | |
221 | + | else fraction(liquidatedTokens, curBearCol, curBearCirc) | |
222 | + | $Tuple7(curBullCol, (curBearCol - liquidatedValue), curBullCirc, (curBearCirc - liquidatedTokens), (curPoolMain + liquidatedValue), curPoolUp, (curPoolDwn - liquidatedTokens)) | |
223 | + | } | |
224 | + | ||
225 | + | func openDwn (curBullCol,curBearCol,curBullCirc,curBearCirc,curPoolMain,curPoolUp,curPoolDwn) = { | |
226 | + | let diff = (curBullCol - curBearCol) | |
227 | + | let spentPoolValue = if ((curPoolMain > diff)) | |
228 | + | then diff | |
229 | + | else curPoolMain | |
230 | + | let acquiredTokens = fraction(spentPoolValue, curBearCirc, curBearCol) | |
231 | + | $Tuple7(curBullCol, (curBearCol + spentPoolValue), curBullCirc, (curBearCirc + acquiredTokens), (curPoolMain - spentPoolValue), curPoolUp, (curPoolDwn + acquiredTokens)) | |
232 | + | } | |
233 | + | ||
234 | + | func openUp (curBullCol,curBearCol,curBullCirc,curBearCirc,curPoolMain,curPoolUp,curPoolDwn) = { | |
235 | + | let diff = (curBearCol - curBullCol) | |
236 | + | let spentPoolValue = if ((curPoolMain > diff)) | |
237 | + | then diff | |
238 | + | else curPoolMain | |
239 | + | let acquiredTokens = fraction(spentPoolValue, curBullCirc, curBullCol) | |
240 | + | $Tuple7((curBullCol + spentPoolValue), curBearCol, (curBullCirc + acquiredTokens), curBearCirc, (curPoolMain - spentPoolValue), (curPoolUp + acquiredTokens), curPoolDwn) | |
241 | + | } | |
242 | + | ||
243 | + | if ((curBullCol0 > curBearCol0)) | |
244 | + | then { | |
245 | + | let afterCloseUp = closeUp(curBullCol0, curBearCol0, curBullCirc0, curBearCirc0, curPoolMain0, curPoolUp0, curPoolDwn0) | |
246 | + | let $t0994610083 = afterCloseUp | |
247 | + | let a = $t0994610083._1 | |
248 | + | let b = $t0994610083._2 | |
249 | + | let c = $t0994610083._3 | |
250 | + | let d = $t0994610083._4 | |
251 | + | let e = $t0994610083._5 | |
252 | + | let f = $t0994610083._6 | |
253 | + | let g = $t0994610083._7 | |
254 | + | if ((f > 0)) | |
255 | + | then afterCloseUp | |
256 | + | else if ((f == 0)) | |
257 | + | then openDwn(a, b, c, d, e, f, g) | |
258 | + | else throw("poolUp < 0") | |
259 | + | } | |
260 | + | else { | |
261 | + | let afterCloseDwn = closeDwn(curBullCol0, curBearCol0, curBullCirc0, curBearCirc0, curPoolMain0, curPoolUp0, curPoolDwn0) | |
262 | + | let $t01043410574 = afterCloseDwn | |
263 | + | let a = $t01043410574._1 | |
264 | + | let b = $t01043410574._2 | |
265 | + | let c = $t01043410574._3 | |
266 | + | let d = $t01043410574._4 | |
267 | + | let e = $t01043410574._5 | |
268 | + | let f = $t01043410574._6 | |
269 | + | let g = $t01043410574._7 | |
270 | + | if ((g > 0)) | |
271 | + | then afterCloseDwn | |
272 | + | else if ((g == 0)) | |
273 | + | then openUp(a, b, c, d, e, f, g) | |
274 | + | else throw("poolDwn < 0") | |
275 | + | } | |
276 | + | } | |
277 | + | ||
278 | + | ||
279 | + | func actionsWithMaybePool (curBullCol0,curBearCol0,curBullCirc0,curBearCirc0) = if (poolEnabled) | |
280 | + | then { | |
281 | + | let $t01089811081 = poolSupport(curBullCol0, curBearCol0, curBullCirc0, curBearCirc0, poolMain, poolUp, poolDwn) | |
282 | + | let bullCol1 = $t01089811081._1 | |
283 | + | let bearCol1 = $t01089811081._2 | |
284 | + | let bullCic1 = $t01089811081._3 | |
285 | + | let bearCirc1 = $t01089811081._4 | |
286 | + | let poolMain1 = $t01089811081._5 | |
287 | + | let poolUp1 = $t01089811081._6 | |
288 | + | let poolDwn1 = $t01089811081._7 | |
289 | + | [IntegerEntry(bullCollateralKey, bullCol1), IntegerEntry(bullCirculationKey, bullCic1), IntegerEntry(bearCollateralKey, bearCol1), IntegerEntry(bearCirculationKey, bearCirc1), IntegerEntry(poolMainTokenValueKey, poolMain1), IntegerEntry(poolUpKey, poolUp1), IntegerEntry(poolDwnKey, poolDwn1)] | |
290 | + | } | |
291 | + | else [IntegerEntry(bullCollateralKey, curBullCol0), IntegerEntry(bullCirculationKey, curBullCirc0), IntegerEntry(bearCollateralKey, curBearCol0), IntegerEntry(bearCirculationKey, curBearCirc0)] | |
175 | 292 | ||
176 | 293 | ||
177 | 294 | func dequeue () = if ((queueSize == 0)) | |
178 | 295 | then throw("nothing to settle") | |
179 | 296 | else { | |
180 | - | func collectFee (fees) = | |
297 | + | func collectFee (fees) = IntegerEntry(feesAccumulatedKey, (feesAccumulated + fees)) | |
181 | 298 | ||
182 | - | let decreaseQueueSize = | |
299 | + | let decreaseQueueSize = IntegerEntry(queueSizeKey, (queueSize - 1)) | |
183 | 300 | let isLastElement = (headPointer == tailPointer) | |
184 | - | let overwriteTail = | |
301 | + | let overwriteTail = StringEntry(tailPointerKey, "") | |
185 | 302 | let data = split(valueOrErrorMessage(getString(this, headPointer), "bad head pointer"), "|") | |
186 | 303 | let action = data[0] | |
187 | 304 | let amt = parseIntValue(data[1]) | |
189 | 306 | let priceIndex = parseIntValue(data[3]) | |
190 | 307 | let invoker = addressFromStringValue(data[4]) | |
191 | 308 | let next = data[5] | |
192 | - | if ((rebalancedPriceIndex > priceIndex)) | |
309 | + | let items = if ((rebalancedPriceIndex > priceIndex)) | |
193 | 310 | then throw(((("corrupt state, rebalancedPriceIndex=" + toString(rebalancedPriceIndex)) + ", request price id=") + toString(priceIndex))) | |
194 | 311 | else if ((priceIndex > rebalancedPriceIndex)) | |
195 | 312 | then throw("can't dequeue, too early, rebalance first") | |
200 | 317 | if ((token == BULL)) | |
201 | 318 | then { | |
202 | 319 | let addedToCirculation = fraction(bullCirc, addedCollateral, bullCol) | |
203 | - | let items = [DataEntry(bullCollateralKey, (bullCol + addedCollateral)), DataEntry(bullCirculationKey, (bullCirc + addedToCirculation)), DataEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize] | |
204 | - | ScriptResult(WriteSet(if (isLastElement) | |
205 | - | then overwriteTail :: items | |
206 | - | else items), TransferSet([ScriptTransfer(invoker, addedToCirculation, fromBase58String(BULL))])) | |
320 | + | (actionsWithMaybePool((bullCol + addedCollateral), bearCol, (bullCirc + addedToCirculation), bearCirc) ++ [StringEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize, ScriptTransfer(invoker, addedToCirculation, fromBase58String(BULL))]) | |
207 | 321 | } | |
208 | 322 | else if ((token == BEAR)) | |
209 | 323 | then { | |
210 | 324 | let addedToCirculation = fraction(bearCirc, addedCollateral, bearCol) | |
211 | - | let items = [DataEntry(bearCollateralKey, (bearCol + addedCollateral)), DataEntry(bearCirculationKey, (bearCirc + addedToCirculation)), DataEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize] | |
212 | - | ScriptResult(WriteSet(if (isLastElement) | |
213 | - | then overwriteTail :: items | |
214 | - | else items), TransferSet([ScriptTransfer(invoker, addedToCirculation, fromBase58String(BEAR))])) | |
325 | + | (actionsWithMaybePool(bullCol, (bearCol + addedCollateral), bullCirc, (bearCirc + addedToCirculation)) ++ [StringEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize, ScriptTransfer(invoker, addedToCirculation, fromBase58String(BEAR))]) | |
215 | 326 | } | |
216 | 327 | else throw("bad token id") | |
217 | 328 | } | |
225 | 336 | let payout = if ((removedCollateral > feeSize)) | |
226 | 337 | then (removedCollateral - feeSize) | |
227 | 338 | else 0 | |
228 | - | let items = [DataEntry(bullCollateralKey, (bullCol - removedCollateral)), DataEntry(bullCirculationKey, (bullCirc - removedTokens)), DataEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize] | |
229 | - | ScriptResult(WriteSet(if (isLastElement) | |
230 | - | then overwriteTail :: items | |
231 | - | else items), TransferSet([ScriptTransfer(invoker, payout, fromBase58String(mainToken))])) | |
339 | + | (actionsWithMaybePool((bullCol - removedCollateral), bearCol, (bullCirc - removedTokens), bearCirc) ++ [StringEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize, ScriptTransfer(invoker, payout, fromBase58String(mainToken))]) | |
232 | 340 | } | |
233 | 341 | else if ((token == BEAR)) | |
234 | 342 | then { | |
237 | 345 | let payout = if ((removedCollateral > feeSize)) | |
238 | 346 | then (removedCollateral - feeSize) | |
239 | 347 | else 0 | |
240 | - | let items = [DataEntry(bearCollateralKey, (bearCol - removedCollateral)), DataEntry(bearCirculationKey, (bearCirc - removedTokens)), DataEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize] | |
241 | - | ScriptResult(WriteSet(if (isLastElement) | |
242 | - | then overwriteTail :: items | |
243 | - | else items), TransferSet([ScriptTransfer(invoker, payout, fromBase58String(mainToken))])) | |
348 | + | (actionsWithMaybePool(bullCol, (bearCol - removedCollateral), bullCirc, (bearCirc - removedTokens)) ++ [StringEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize, ScriptTransfer(invoker, payout, fromBase58String(mainToken))]) | |
244 | 349 | } | |
245 | 350 | else throw("bad token id") | |
246 | 351 | } | |
247 | - | else throw(("bad action: " + action)) | |
352 | + | else if ((action == POOL)) | |
353 | + | then { | |
354 | + | let issueTokens = fraction(poolTokenCirculation, amt, poolValue) | |
355 | + | [IntegerEntry(poolMainTokenValueKey, (poolMain + amt)), IntegerEntry(poolTokenCirculationKey, (poolTokenCirculation + issueTokens)), StringEntry(headPointerKey, next), decreaseQueueSize, ScriptTransfer(invoker, issueTokens, fromBase58String(poolToken))] | |
356 | + | } | |
357 | + | else if ((action == UNPOOL)) | |
358 | + | then { | |
359 | + | func share (a) = fraction(a, amt, poolTokenCirculation) | |
360 | + | ||
361 | + | let unpooledMain = share(poolMain) | |
362 | + | let unpooledUp = share(poolUp) | |
363 | + | let unpooledDwn = share(poolDwn) | |
364 | + | let unpooledUpValue = fraction(unpooledUp, bullCol, bullCirc) | |
365 | + | let unpooledDwnValue = fraction(unpooledDwn, bearCol, bearCirc) | |
366 | + | [IntegerEntry(poolMainTokenValueKey, (poolMain - unpooledMain)), IntegerEntry(poolTokenCirculationKey, (poolTokenCirculation - amt)), IntegerEntry(poolUpKey, (poolUp - unpooledUp)), IntegerEntry(poolDwnKey, (poolDwn - unpooledDwn)), IntegerEntry(bullCirculationKey, (bullCirc - unpooledUp)), IntegerEntry(bearCirculationKey, (bearCirc - unpooledDwn)), IntegerEntry(bullCollateralKey, (bullCol - unpooledUpValue)), IntegerEntry(bearCollateralKey, (bearCol - unpooledDwnValue)), StringEntry(headPointerKey, next), decreaseQueueSize, ScriptTransfer(invoker, ((unpooledMain + unpooledUpValue) + unpooledDwnValue), fromBase58String(mainToken))] | |
367 | + | } | |
368 | + | else throw(("bad action: " + action)) | |
369 | + | if (isLastElement) | |
370 | + | then overwriteTail :: items | |
371 | + | else items | |
248 | 372 | } | |
249 | 373 | ||
250 | 374 | ||
272 | 396 | then bullCol | |
273 | 397 | else bearCol | |
274 | 398 | let redist = LV(minVol, settledPrice, nextPrice) | |
275 | - | if ((nextPrice > settledPrice)) | |
276 | - | then WriteSet([DataEntry(bullCollateralKey, (bullCol + redist)), DataEntry(bearCollateralKey, (bearCol - redist)), DataEntry(lastRebalancePriceIndexKey, unsettledPriceIndex)]) | |
277 | - | else if ((settledPrice > nextPrice)) | |
278 | - | then WriteSet([DataEntry(bullCollateralKey, (bullCol - redist)), DataEntry(bearCollateralKey, (bearCol + redist)), DataEntry(lastRebalancePriceIndexKey, unsettledPriceIndex)]) | |
279 | - | else WriteSet([DataEntry(lastRebalancePriceIndexKey, unsettledPriceIndex)]) | |
399 | + | let newBullCol = if ((nextPrice > settledPrice)) | |
400 | + | then (bullCol + redist) | |
401 | + | else (bullCol - redist) | |
402 | + | let newBearCol = if ((nextPrice > settledPrice)) | |
403 | + | then (bearCol - redist) | |
404 | + | else (bearCol + redist) | |
405 | + | if (poolEnabled) | |
406 | + | then { | |
407 | + | let $t01922019407 = poolSupport(newBullCol, newBearCol, bullCirc, bearCirc, poolMain, poolUp, poolDwn) | |
408 | + | let updBullCol = $t01922019407._1 | |
409 | + | let updBearCol = $t01922019407._2 | |
410 | + | let updBullCirc = $t01922019407._3 | |
411 | + | let updBearCirc = $t01922019407._4 | |
412 | + | let updPoolMain = $t01922019407._5 | |
413 | + | let updPoolUp = $t01922019407._6 | |
414 | + | let updPoolDwn = $t01922019407._7 | |
415 | + | [IntegerEntry(bullCollateralKey, updBullCol), IntegerEntry(bearCollateralKey, updBearCol), IntegerEntry(bullCirculationKey, updBullCirc), IntegerEntry(bearCirculationKey, updBearCirc), IntegerEntry(poolMainTokenValueKey, updPoolMain), IntegerEntry(poolUpKey, updPoolUp), IntegerEntry(poolDwnKey, updPoolDwn), IntegerEntry(lastRebalancePriceIndexKey, unsettledPriceIndex)] | |
416 | + | } | |
417 | + | else [IntegerEntry(bullCollateralKey, newBullCol), IntegerEntry(bearCollateralKey, newBearCol), IntegerEntry(lastRebalancePriceIndexKey, unsettledPriceIndex)] | |
280 | 418 | } | |
281 | 419 | ||
282 | 420 | ||
283 | 421 | @Callable(inv) | |
284 | 422 | func init (bullId,bearId,mainTokenId,oraclePK,whitelisted) = if (isDefined(getString(this, BULLKey))) | |
285 | 423 | then throw("already initialized") | |
286 | - | else if (!(isDefined(inv.payment))) | |
287 | - | then throw("neutrino payment required") | |
288 | - | else if ((toBase58String(valueOrErrorMessage(value(inv.payment).assetId, "neutrino payment required")) != mainTokenId)) | |
289 | - | then throw("payment not in neutrino") | |
290 | - | else { | |
291 | - | let totalOwnedMainToken = value(inv.payment).amount | |
292 | - | let bulls = (totalOwnedMainToken / 2) | |
293 | - | let bears = (totalOwnedMainToken - bulls) | |
294 | - | if (if ((bears == 0)) | |
295 | - | then true | |
296 | - | else (bulls == 0)) | |
297 | - | then throw("can't init balances") | |
298 | - | else { | |
299 | - | let oracleCurrentPriceIndex = valueOrErrorMessage(getInteger(valueOrErrorMessage(addressFromPublicKey(fromBase58String(oraclePK)), "bad oracle address"), lastPriceIndexKey), "can't find last oracle price index") | |
300 | - | ScriptResult(WriteSet([DataEntry(BULLKey, bullId), DataEntry(BEARKey, bearId), DataEntry(mainTokenKey, mainTokenId), DataEntry(oraclePKKey, oraclePK), DataEntry(bullCollateralKey, bulls), DataEntry(bearCollateralKey, bears), DataEntry(bullCirculationKey, bulls), DataEntry(bearCirculationKey, bears), DataEntry(lastRebalancePriceIndexKey, oracleCurrentPriceIndex), DataEntry(whitelistKey, whitelisted), DataEntry(issuePercentileKey, 0), DataEntry(redeemPercentileKey, 0), DataEntry(minIssueKey, 0), DataEntry(minRedeemKey, 0), DataEntry(whitelistOnlyKey, true)]), TransferSet([ScriptTransfer(inv.caller, bulls, fromBase58String(bullId)), ScriptTransfer(inv.caller, bears, fromBase58String(bearId))])) | |
301 | - | } | |
302 | - | } | |
424 | + | else if ((toBase58String(valueOrErrorMessage(inv.payments[0].assetId, "neutrino payment required")) != mainTokenId)) | |
425 | + | then throw("payment not in neutrino") | |
426 | + | else { | |
427 | + | let totalOwnedMainToken = inv.payments[0].amount | |
428 | + | let bulls = (totalOwnedMainToken / 2) | |
429 | + | let bears = (totalOwnedMainToken - bulls) | |
430 | + | if (if ((bears == 0)) | |
431 | + | then true | |
432 | + | else (bulls == 0)) | |
433 | + | then throw("can't init balances") | |
434 | + | else { | |
435 | + | let oracleCurrentPriceIndex = valueOrErrorMessage(getInteger(valueOrErrorMessage(addressFromPublicKey(fromBase58String(oraclePK)), "bad oracle address"), lastPriceIndexKey), "can't find last oracle price index") | |
436 | + | [StringEntry(BULLKey, bullId), StringEntry(BEARKey, bearId), StringEntry(mainTokenKey, mainTokenId), StringEntry(oraclePKKey, oraclePK), IntegerEntry(bullCollateralKey, bulls), IntegerEntry(bearCollateralKey, bears), IntegerEntry(bullCirculationKey, bulls), IntegerEntry(bearCirculationKey, bears), IntegerEntry(lastRebalancePriceIndexKey, oracleCurrentPriceIndex), StringEntry(whitelistKey, whitelisted), IntegerEntry(issuePercentileKey, 0), IntegerEntry(redeemPercentileKey, 0), IntegerEntry(minIssueKey, 0), IntegerEntry(minRedeemKey, 0), BooleanEntry(whitelistOnlyKey, true), ScriptTransfer(inv.caller, bulls, fromBase58String(bullId)), ScriptTransfer(inv.caller, bears, fromBase58String(bearId))] | |
437 | + | } | |
438 | + | } | |
303 | 439 | ||
304 | 440 | ||
305 | 441 | ||
306 | 442 | @Callable(i) | |
307 | - | func setParams (iP,rP,mI,mR,wl) = if ((i.caller != this)) | |
443 | + | func setParams (iP,rP,mI,mR,mP,wl) = if ((i.caller != this)) | |
308 | 444 | then throw("only self can change whitelist") | |
309 | - | else | |
445 | + | else [IntegerEntry(issuePercentileKey, iP), IntegerEntry(redeemPercentileKey, rP), IntegerEntry(minIssueKey, mI), IntegerEntry(minRedeemKey, mR), IntegerEntry(minPoolKey, mP), BooleanEntry(whitelistOnlyKey, wl)] | |
310 | 446 | ||
311 | 447 | ||
312 | 448 | ||
313 | 449 | @Callable(i) | |
314 | 450 | func setWhitelist (l) = if ((i.caller != this)) | |
315 | 451 | then throw("only self can change whitelist") | |
316 | - | else | |
452 | + | else [StringEntry(whitelistKey, l)] | |
317 | 453 | ||
318 | 454 | ||
319 | 455 | ||
320 | 456 | @Callable(i) | |
321 | 457 | func setAddresses (feeAddr,stakingAddr,daemonPK) = if ((i.caller != this)) | |
322 | 458 | then throw("only self can change feeAcc addresses") | |
323 | - | else | |
459 | + | else [StringEntry(feeAddrKey, feeAddr), StringEntry(stakingAddrKey, stakingAddr), StringEntry(daemonPubKeyKey, daemonPK)] | |
324 | 460 | ||
325 | 461 | ||
326 | 462 | ||
327 | 463 | @Callable(i) | |
328 | 464 | func withdrawFee (amount) = if ((amount > feesAccumulated)) | |
329 | 465 | then throw(("too much. available: " + toString(feesAccumulated))) | |
330 | - | else | |
466 | + | else [IntegerEntry(feesAccumulatedKey, (feesAccumulated - amount)), ScriptTransfer(feeAddress, amount, fromBase58String(mainToken))] | |
331 | 467 | ||
332 | 468 | ||
333 | 469 | ||
334 | 470 | @Callable(inv) | |
335 | - | func requestRedeem () = if (( | |
471 | + | func requestRedeem () = if ((validateRequestRedeem(inv) == unit)) | |
336 | 472 | then { | |
337 | - | let assetId = toBase58String(valueOrErrorMessage( | |
338 | - | enqueue(toBase58String(inv.transactionId), REDEEM, | |
473 | + | let assetId = toBase58String(valueOrErrorMessage(inv.payments[0].assetId, "waves are not accepted here")) | |
474 | + | enqueue(toBase58String(inv.transactionId), REDEEM, inv.payments[0].amount, assetId, (oraclePriceIndex + 1), toString(inv.caller)) | |
339 | 475 | } | |
340 | 476 | else throw("doesn't happen") | |
341 | 477 | ||
354 | 490 | then (tokenId != BEAR) | |
355 | 491 | else false) | |
356 | 492 | then errorMessage | |
357 | - | else if ( | |
493 | + | else if ((inv.payments[0].assetId != fromBase58String(mainToken))) | |
358 | 494 | then errorMessage | |
359 | - | else if ((value(inv.payment).assetId != fromBase58String(mainToken))) | |
360 | - | then errorMessage | |
361 | - | else if ((minIssue > value(inv.payment).amount)) | |
362 | - | then throw((("Attached payment too small. Min required: " + toString((minIssue / 1000000))) + " USDN")) | |
363 | - | else enqueue(toBase58String(inv.transactionId), ISSUE, value(inv.payment).amount, tokenId, (oraclePriceIndex + 1), toString(inv.caller)) | |
495 | + | else if ((minIssue > inv.payments[0].amount)) | |
496 | + | then throw((("Attached payment too small. Min required: " + toString((minIssue / 1000000))) + " USDN")) | |
497 | + | else enqueue(toBase58String(inv.transactionId), ISSUE, inv.payments[0].amount, tokenId, (oraclePriceIndex + 1), toString(inv.caller)) | |
364 | 498 | } | |
365 | 499 | ||
366 | 500 | ||
387 | 521 | } | |
388 | 522 | ||
389 | 523 | ||
524 | + | ||
525 | + | @Callable(inv) | |
526 | + | func setupPool (poolTokenId) = if ((inv.caller != this)) | |
527 | + | then throw("only self can init") | |
528 | + | else if (poolInitialized) | |
529 | + | then throw("pool already initialized") | |
530 | + | else [IntegerEntry(poolDwnKey, 0), IntegerEntry(poolUpKey, 0), IntegerEntry(poolMainTokenValueKey, 0), StringEntry(poolTokenKey, poolTokenId), IntegerEntry(poolTokenCirculationKey, 0), BooleanEntry(poolEnabledKey, false), IntegerEntry(minPoolKey, ((10 * 1000) * 1000))] | |
531 | + | ||
532 | + | ||
533 | + | ||
534 | + | @Callable(inv) | |
535 | + | func startPool () = if ((poolValue != 0)) | |
536 | + | then throw("pool already started") | |
537 | + | else { | |
538 | + | let errMessage = (("please attach 10.000000 main tokens(" + mainToken) + ")") | |
539 | + | let pmt = inv.payments[0] | |
540 | + | if ((pmt.amount != (10 * ten6))) | |
541 | + | then throw(errMessage) | |
542 | + | else if ((pmt.assetId != fromBase58String(mainToken))) | |
543 | + | then throw(errMessage) | |
544 | + | else [IntegerEntry(poolDwnKey, 0), IntegerEntry(poolUpKey, 0), IntegerEntry(poolMainTokenValueKey, (10 * ten6)), BooleanEntry(poolEnabledKey, true), IntegerEntry(poolTokenCirculationKey, ten6), ScriptTransfer(inv.caller, ten6, fromBase58String(poolToken))] | |
545 | + | } | |
546 | + | ||
547 | + | ||
548 | + | ||
549 | + | @Callable(inv) | |
550 | + | func requestPool () = if (!(poolEnabled)) | |
551 | + | then throw("pooling not enabled at the moment") | |
552 | + | else if (if (whitelistOnly) | |
553 | + | then !(isDefined(indexOf(whitelist, toString(inv.caller)))) | |
554 | + | else false) | |
555 | + | then throw("only whitelisted can do") | |
556 | + | else { | |
557 | + | let errMessage = (("main token must be attached(" + mainToken) + ")") | |
558 | + | let pmt = inv.payments[0] | |
559 | + | if ((pmt.assetId != fromBase58String(mainToken))) | |
560 | + | then throw(errMessage) | |
561 | + | else if ((minPool > pmt.amount)) | |
562 | + | then throw(((("pool at least " + toString(minPool)) + " ") + mainToken)) | |
563 | + | else enqueue(toBase58String(inv.transactionId), POOL, inv.payments[0].amount, "", (oraclePriceIndex + 1), toString(inv.caller)) | |
564 | + | } | |
565 | + | ||
566 | + | ||
567 | + | ||
568 | + | @Callable(inv) | |
569 | + | func requestUnpool () = if (!(poolEnabled)) | |
570 | + | then throw("pool not enabled at the moment") | |
571 | + | else { | |
572 | + | let errMessage = (("only pool token allowed(" + poolToken) + ")") | |
573 | + | let pmt = inv.payments[0] | |
574 | + | if ((pmt.assetId != fromBase58String(poolToken))) | |
575 | + | then throw(errMessage) | |
576 | + | else { | |
577 | + | let estimate = fraction(poolValue, pmt.amount, poolTokenCirculation) | |
578 | + | if ((minPool > estimate)) | |
579 | + | then throw(((("unpool at least for" + toString(minPool)) + " ") + mainToken)) | |
580 | + | else enqueue(toBase58String(inv.transactionId), UNPOOL, inv.payments[0].amount, "", (oraclePriceIndex + 1), toString(inv.caller)) | |
581 | + | } | |
582 | + | } | |
583 | + | ||
584 | + | ||
390 | 585 | @Verifier(tx) | |
391 | 586 | func verify () = { | |
392 | 587 | let adminAction = ((((if (sigVerify(tx.bodyBytes, tx.proofs[0], fromBase58String(pubKeyAdminsList[0]))) | |
407 | 602 | let lock = if (if ((tx.function == "lockNeutrinoSP")) | |
408 | 603 | then (tx.args[0] == stakingAddress) | |
409 | 604 | else false) | |
410 | - | then (wavesBalance(this) >= | |
605 | + | then (wavesBalance(this).available >= ten8) | |
411 | 606 | else false | |
412 | 607 | let funcCorrect = if (lock) | |
413 | 608 | then true |
Old | New | Differences | |
---|---|---|---|
1 | - | {-# STDLIB_VERSION | |
1 | + | {-# STDLIB_VERSION 4 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | + | let ten6 = 1000000 | |
5 | + | ||
6 | + | let ten8 = 100000000 | |
7 | + | ||
4 | 8 | let BULLKey = "BULLId" | |
5 | 9 | ||
6 | 10 | let BEARKey = "BEARId" | |
7 | 11 | ||
8 | 12 | let mainTokenKey = "mainTokenId" | |
13 | + | ||
14 | + | let bullCollateralKey = "bullCollateral" | |
15 | + | ||
16 | + | let bearCollateralKey = "bearCollateral" | |
17 | + | ||
18 | + | let bullCirculationKey = "bullCirculation" | |
19 | + | ||
20 | + | let bearCirculationKey = "bearCirculation" | |
9 | 21 | ||
10 | 22 | let issuePercentileKey = "issuePercentile" | |
11 | 23 | ||
12 | 24 | let redeemPercentileKey = "redeemPercentile" | |
13 | 25 | ||
14 | 26 | let minIssueKey = "minIssue" | |
15 | 27 | ||
16 | 28 | let minRedeemKey = "minRedeem" | |
17 | 29 | ||
30 | + | let minPoolKey = "minPool" | |
31 | + | ||
32 | + | let feesAccumulatedKey = "feesAccumulated" | |
33 | + | ||
18 | 34 | let whitelistOnlyKey = "whitelistOnly" | |
35 | + | ||
36 | + | let whitelistKey = "issueWhiteList" | |
19 | 37 | ||
20 | 38 | let oraclePKKey = "oracle" | |
21 | 39 | ||
22 | 40 | let lastPriceIndexKey = "price_index" | |
23 | 41 | ||
24 | 42 | let priceIndexPrefix = "price_index_" | |
25 | 43 | ||
26 | 44 | let priceHeightPrefix = "price_" | |
27 | 45 | ||
28 | 46 | let oracleCurrentPriceIndexKey = "price_index" | |
29 | 47 | ||
30 | 48 | let lastRebalancePriceIndexKey = "lastSettlementPriceId" | |
31 | 49 | ||
32 | - | let | |
50 | + | let headPointerKey = "headPointer" | |
33 | 51 | ||
34 | - | let | |
52 | + | let tailPointerKey = "tailPointer" | |
35 | 53 | ||
36 | - | let | |
54 | + | let queueSizeKey = "queueSize" | |
37 | 55 | ||
38 | - | let | |
56 | + | let poolMainTokenValueKey = "poolMainTokenValue" | |
39 | 57 | ||
40 | - | let | |
58 | + | let poolUpKey = "poolUp" | |
41 | 59 | ||
42 | - | let whitelist = valueOrErrorMessage(getString(this, whitelistKey), "no bullCollateralKey") | |
60 | + | let poolDwnKey = "poolDwn" | |
61 | + | ||
62 | + | let poolEnabledKey = "poolEnabled" | |
63 | + | ||
64 | + | let poolTokenCirculationKey = "poolTokenCirculation" | |
65 | + | ||
66 | + | let poolTokenKey = "poolToken" | |
43 | 67 | ||
44 | 68 | let bullCol = valueOrErrorMessage(getInteger(this, bullCollateralKey), "no bullCollateralKey") | |
45 | 69 | ||
46 | 70 | let bearCol = valueOrErrorMessage(getInteger(this, bearCollateralKey), "no bearCollateralKey") | |
47 | 71 | ||
48 | 72 | let bullCirc = valueOrErrorMessage(getInteger(this, bullCirculationKey), "no bullCirculationKey") | |
49 | 73 | ||
50 | 74 | let bearCirc = valueOrErrorMessage(getInteger(this, bearCirculationKey), "no bearCirculationKey") | |
51 | 75 | ||
52 | 76 | let BULL = valueOrErrorMessage(getString(this, BULLKey), "no BULLKey") | |
53 | 77 | ||
54 | 78 | let BEAR = valueOrErrorMessage(getString(this, BEARKey), "no BEARKey") | |
55 | 79 | ||
56 | 80 | let mainToken = valueOrErrorMessage(getString(this, mainTokenKey), "no mainTokenKey") | |
57 | 81 | ||
58 | 82 | let issuePercentile = valueOrErrorMessage(getInteger(this, issuePercentileKey), "no issuePercentileKey") | |
59 | 83 | ||
60 | 84 | let redeemPercentile = valueOrErrorMessage(getInteger(this, redeemPercentileKey), "no redeemPercentileKey") | |
61 | 85 | ||
62 | 86 | let minIssue = valueOrErrorMessage(getInteger(this, minIssueKey), "no minIssueKey") | |
63 | 87 | ||
64 | 88 | let minRedeem = valueOrErrorMessage(getInteger(this, minRedeemKey), "no minRedeemKey") | |
65 | 89 | ||
90 | + | let minPool = valueOrErrorMessage(getInteger(this, minPoolKey), "no minPoolKey") | |
91 | + | ||
66 | 92 | let whitelistOnly = valueOrErrorMessage(getBoolean(this, whitelistOnlyKey), "no whitelistOnlyKey") | |
93 | + | ||
94 | + | let whitelist = valueOrErrorMessage(getString(this, whitelistKey), "no bullCollateralKey") | |
95 | + | ||
96 | + | let poolInitialized = isDefined(getBoolean(this, poolMainTokenValueKey)) | |
97 | + | ||
98 | + | let poolEnabled = (getBoolean(this, poolEnabledKey) == true) | |
99 | + | ||
100 | + | let poolMain = valueOrErrorMessage(getInteger(this, poolMainTokenValueKey), "no poolMainTokenValueKey") | |
101 | + | ||
102 | + | let poolUp = valueOrErrorMessage(getInteger(this, poolUpKey), "no poolUpKey") | |
103 | + | ||
104 | + | let poolDwn = valueOrErrorMessage(getInteger(this, poolDwnKey), "no poolDwnKey") | |
105 | + | ||
106 | + | let poolToken = valueOrErrorMessage(getString(this, poolTokenKey), "no poolTokenKey") | |
107 | + | ||
108 | + | let poolTokenCirculation = valueOrErrorMessage(getInteger(this, poolTokenCirculationKey), "no poolTokenCirculationKey") | |
109 | + | ||
110 | + | let poolValue = ((poolMain + fraction(bullCol, poolUp, bullCirc)) + fraction(bearCol, poolDwn, bearCirc)) | |
67 | 111 | ||
68 | 112 | let oracle = valueOrErrorMessage(addressFromPublicKey(fromBase58String(valueOrErrorMessage(getString(this, oraclePKKey), "no oraclePKKey"))), "bad oracle address") | |
69 | 113 | ||
70 | 114 | let rebalancedPriceIndex = valueOrErrorMessage(getInteger(this, lastRebalancePriceIndexKey), "no last rebalance price") | |
71 | 115 | ||
72 | 116 | let oraclePriceIndex = valueOrErrorMessage(getInteger(oracle, lastPriceIndexKey), ((("bad oracle data at " + toString(oracle)) + ": no integer at ") + lastPriceIndexKey)) | |
73 | 117 | ||
74 | - | let | |
118 | + | let queueSize = valueOrElse(getInteger(this, queueSizeKey), 0) | |
75 | 119 | ||
76 | - | let | |
120 | + | let headPointer = valueOrElse(getString(this, headPointerKey), "") | |
77 | 121 | ||
78 | - | let | |
122 | + | let tailPointer = valueOrElse(getString(this, tailPointerKey), "") | |
79 | 123 | ||
80 | - | let queueSize = match getInteger(this, queueSizeKey) { | |
81 | - | case i: Int => | |
82 | - | i | |
83 | - | case _ => | |
84 | - | 0 | |
85 | - | } | |
86 | - | ||
87 | - | let headPointer = match getString(this, headPointerKey) { | |
88 | - | case s: String => | |
89 | - | s | |
90 | - | case _ => | |
91 | - | "" | |
92 | - | } | |
93 | - | ||
94 | - | let tailPointer = match getString(this, tailPointerKey) { | |
95 | - | case s: String => | |
96 | - | s | |
97 | - | case _ => | |
98 | - | "" | |
99 | - | } | |
100 | - | ||
101 | - | let feesAccumulatedKey = "feesAccumulated" | |
102 | - | ||
103 | - | let feesAccumulated = match getInteger(this, feesAccumulatedKey) { | |
104 | - | case i: Int => | |
105 | - | i | |
106 | - | case _ => | |
107 | - | 0 | |
108 | - | } | |
124 | + | let feesAccumulated = valueOrElse(getInteger(this, feesAccumulatedKey), 0) | |
109 | 125 | ||
110 | 126 | let ISSUE = "ISSUE" | |
111 | 127 | ||
112 | 128 | let REDEEM = "REDEEM" | |
129 | + | ||
130 | + | let POOL = "POOL" | |
131 | + | ||
132 | + | let UNPOOL = "UNPOOL" | |
113 | 133 | ||
114 | 134 | let feeAddrKey = "feeAddress" | |
115 | 135 | ||
116 | 136 | let stakingAddrKey = "stakingAddress" | |
117 | 137 | ||
118 | 138 | let daemonPubKeyKey = "daemonPublicKey" | |
119 | 139 | ||
120 | 140 | let feeAddress = valueOrErrorMessage(addressFromString(valueOrErrorMessage(getString(this, feeAddrKey), "no feeAddress")), "bad feeAddress") | |
121 | 141 | ||
122 | 142 | let stakingAddress = valueOrErrorMessage(getString(this, stakingAddrKey), "no stakingAddress") | |
123 | 143 | ||
124 | 144 | let daemonPublicKey = fromBase58String(valueOrErrorMessage(getString(this, daemonPubKeyKey), "no daemonPublicKey")) | |
125 | 145 | ||
126 | 146 | let rpdAddress = addressFromString("3PNikM6yp4NqcSU8guxQtmR5onr2D4e8yTJ") | |
127 | 147 | ||
128 | 148 | let pubKeyAdminsList = ["2HHqV8W9DJayV5R6tBD2Sb8srphpoboDi7r1t1aPiumC", "5ZXe82RRASU7qshXM2J9JNYhqJ9GWYjjVq2gwUV5Naz9", "5WRXFSjwcTbNfKcJs8ZqXmSSWYsSVJUtMvMqZj5hH4Nc"] | |
129 | 149 | ||
150 | + | func safeFraction (a,b,c) = if (if ((a == 0)) | |
151 | + | then true | |
152 | + | else (b == 0)) | |
153 | + | then 0 | |
154 | + | else fraction(a, b, c) | |
155 | + | ||
156 | + | ||
130 | 157 | func buildNewItem (action,amt,token,priceIndex,invoker) = (((((((((action + "|") + toString(amt)) + "|") + token) + "|") + toString(priceIndex)) + "|") + invoker) + "|") | |
131 | 158 | ||
132 | 159 | ||
133 | - | func | |
160 | + | func validateRequestRedeem (inv) = if ((inv.caller == this)) | |
134 | 161 | then throw("can't do") | |
135 | 162 | else { | |
136 | 163 | func errorMessage (got) = throw(((((("only BULL(" + BULL) + ") or BEAR(") + BEAR) + ") tokens are accepted, received: ") + got)) | |
137 | 164 | ||
138 | - | if (!(isDefined(inv.payment))) | |
139 | - | then errorMessage("no attached payment") | |
165 | + | let assetId = toBase58String(valueOrErrorMessage(value(inv.payments[0]).assetId, "waves are not accepted here")) | |
166 | + | if (if ((assetId != BEAR)) | |
167 | + | then (assetId != BULL) | |
168 | + | else false) | |
169 | + | then errorMessage(assetId) | |
140 | 170 | else { | |
141 | - | let assetId = toBase58String(valueOrErrorMessage(value(inv.payment).assetId, "waves are not accepted here")) | |
142 | - | if (if ((assetId != BEAR)) | |
143 | - | then (assetId != BULL) | |
144 | - | else false) | |
145 | - | then errorMessage(assetId) | |
146 | - | else { | |
147 | - | let attachedAmount = value(inv.payment).amount | |
148 | - | let col = if ((assetId == BEAR)) | |
149 | - | then bearCol | |
150 | - | else bullCol | |
151 | - | let circ = if ((assetId == BEAR)) | |
152 | - | then bearCirc | |
153 | - | else bullCirc | |
154 | - | let estimated = fraction(col, attachedAmount, circ) | |
155 | - | if ((minRedeem > estimated)) | |
156 | - | then throw((((((((((("Attached payment too small. Min redeem amount is " + toString((minRedeem / 1000000))) + " USDN, ") + "attached amount: ") + toString(attachedAmount)) + ", col: ") + toString(col)) + ", circ: ") + toString(circ)) + ", estimated: ") + toString(estimated))) | |
157 | - | else unit | |
158 | - | } | |
171 | + | let attachedAmount = inv.payments[0].amount | |
172 | + | let col = if ((assetId == BEAR)) | |
173 | + | then bearCol | |
174 | + | else bullCol | |
175 | + | let circ = if ((assetId == BEAR)) | |
176 | + | then bearCirc | |
177 | + | else bullCirc | |
178 | + | let estimated = fraction(col, attachedAmount, circ) | |
179 | + | if ((minRedeem > estimated)) | |
180 | + | then throw((((((((((("Attached payment too small. Min redeem amount is " + toString((minRedeem / 1000000))) + " USDN, ") + "attached amount: ") + toString(attachedAmount)) + ", col: ") + toString(col)) + ", circ: ") + toString(circ)) + ", estimated: ") + toString(estimated))) | |
181 | + | else unit | |
159 | 182 | } | |
160 | 183 | } | |
161 | 184 | ||
162 | 185 | ||
163 | 186 | func enqueue (id,action,amt,token,priceIndex,invoker) = { | |
164 | - | let increaseQueueSize = | |
187 | + | let increaseQueueSize = IntegerEntry(queueSizeKey, (queueSize + 1)) | |
165 | 188 | let itm = buildNewItem(action, amt, token, priceIndex, invoker) | |
166 | 189 | if ((queueSize == 0)) | |
167 | - | then | |
190 | + | then [StringEntry(headPointerKey, id), StringEntry(tailPointerKey, id), StringEntry(id, itm), increaseQueueSize] | |
168 | 191 | else { | |
169 | 192 | let prevId = valueOrErrorMessage(getString(this, tailPointerKey), "can't get tail pointer") | |
170 | 193 | let prevItm = split(valueOrErrorMessage(getString(this, prevId), "can't resolve pointer"), "|") | |
171 | 194 | let updatedPrevItm = ((((((((((prevItm[0] + "|") + prevItm[1]) + "|") + prevItm[2]) + "|") + prevItm[3]) + "|") + prevItm[4]) + "|") + id) | |
172 | - | ||
195 | + | [StringEntry(prevId, updatedPrevItm), StringEntry(id, itm), StringEntry(tailPointerKey, id), increaseQueueSize] | |
173 | 196 | } | |
174 | 197 | } | |
198 | + | ||
199 | + | ||
200 | + | func poolSupport (curBullCol0,curBearCol0,curBullCirc0,curBearCirc0,curPoolMain0,curPoolUp0,curPoolDwn0) = { | |
201 | + | func closeUp (curBullCol,curBearCol,curBullCirc,curBearCirc,curPoolMain,curPoolUp,curPoolDwn) = { | |
202 | + | let diff = (curBullCol - curBearCol) | |
203 | + | let exposure = fraction(curBullCol, curPoolUp, curBullCirc) | |
204 | + | let liquidatedTokens = if ((diff > exposure)) | |
205 | + | then curPoolUp | |
206 | + | else fraction(diff, curBullCirc, curBullCol) | |
207 | + | let liquidatedValue = if ((diff > exposure)) | |
208 | + | then exposure | |
209 | + | else fraction(liquidatedTokens, curBullCol, curBullCirc) | |
210 | + | $Tuple7((curBullCol - liquidatedValue), curBearCol, (curBullCirc - liquidatedTokens), curBearCirc, (curPoolMain + liquidatedValue), (curPoolUp - liquidatedTokens), curPoolDwn) | |
211 | + | } | |
212 | + | ||
213 | + | func closeDwn (curBullCol,curBearCol,curBullCirc,curBearCirc,curPoolMain,curPoolUp,curPoolDwn) = { | |
214 | + | let diff = (curBearCol - curBullCol) | |
215 | + | let exposure = fraction(curBearCol, curPoolDwn, curBearCirc) | |
216 | + | let liquidatedTokens = if ((diff > exposure)) | |
217 | + | then curPoolDwn | |
218 | + | else fraction(diff, curBearCirc, curBearCol) | |
219 | + | let liquidatedValue = if ((diff > exposure)) | |
220 | + | then exposure | |
221 | + | else fraction(liquidatedTokens, curBearCol, curBearCirc) | |
222 | + | $Tuple7(curBullCol, (curBearCol - liquidatedValue), curBullCirc, (curBearCirc - liquidatedTokens), (curPoolMain + liquidatedValue), curPoolUp, (curPoolDwn - liquidatedTokens)) | |
223 | + | } | |
224 | + | ||
225 | + | func openDwn (curBullCol,curBearCol,curBullCirc,curBearCirc,curPoolMain,curPoolUp,curPoolDwn) = { | |
226 | + | let diff = (curBullCol - curBearCol) | |
227 | + | let spentPoolValue = if ((curPoolMain > diff)) | |
228 | + | then diff | |
229 | + | else curPoolMain | |
230 | + | let acquiredTokens = fraction(spentPoolValue, curBearCirc, curBearCol) | |
231 | + | $Tuple7(curBullCol, (curBearCol + spentPoolValue), curBullCirc, (curBearCirc + acquiredTokens), (curPoolMain - spentPoolValue), curPoolUp, (curPoolDwn + acquiredTokens)) | |
232 | + | } | |
233 | + | ||
234 | + | func openUp (curBullCol,curBearCol,curBullCirc,curBearCirc,curPoolMain,curPoolUp,curPoolDwn) = { | |
235 | + | let diff = (curBearCol - curBullCol) | |
236 | + | let spentPoolValue = if ((curPoolMain > diff)) | |
237 | + | then diff | |
238 | + | else curPoolMain | |
239 | + | let acquiredTokens = fraction(spentPoolValue, curBullCirc, curBullCol) | |
240 | + | $Tuple7((curBullCol + spentPoolValue), curBearCol, (curBullCirc + acquiredTokens), curBearCirc, (curPoolMain - spentPoolValue), (curPoolUp + acquiredTokens), curPoolDwn) | |
241 | + | } | |
242 | + | ||
243 | + | if ((curBullCol0 > curBearCol0)) | |
244 | + | then { | |
245 | + | let afterCloseUp = closeUp(curBullCol0, curBearCol0, curBullCirc0, curBearCirc0, curPoolMain0, curPoolUp0, curPoolDwn0) | |
246 | + | let $t0994610083 = afterCloseUp | |
247 | + | let a = $t0994610083._1 | |
248 | + | let b = $t0994610083._2 | |
249 | + | let c = $t0994610083._3 | |
250 | + | let d = $t0994610083._4 | |
251 | + | let e = $t0994610083._5 | |
252 | + | let f = $t0994610083._6 | |
253 | + | let g = $t0994610083._7 | |
254 | + | if ((f > 0)) | |
255 | + | then afterCloseUp | |
256 | + | else if ((f == 0)) | |
257 | + | then openDwn(a, b, c, d, e, f, g) | |
258 | + | else throw("poolUp < 0") | |
259 | + | } | |
260 | + | else { | |
261 | + | let afterCloseDwn = closeDwn(curBullCol0, curBearCol0, curBullCirc0, curBearCirc0, curPoolMain0, curPoolUp0, curPoolDwn0) | |
262 | + | let $t01043410574 = afterCloseDwn | |
263 | + | let a = $t01043410574._1 | |
264 | + | let b = $t01043410574._2 | |
265 | + | let c = $t01043410574._3 | |
266 | + | let d = $t01043410574._4 | |
267 | + | let e = $t01043410574._5 | |
268 | + | let f = $t01043410574._6 | |
269 | + | let g = $t01043410574._7 | |
270 | + | if ((g > 0)) | |
271 | + | then afterCloseDwn | |
272 | + | else if ((g == 0)) | |
273 | + | then openUp(a, b, c, d, e, f, g) | |
274 | + | else throw("poolDwn < 0") | |
275 | + | } | |
276 | + | } | |
277 | + | ||
278 | + | ||
279 | + | func actionsWithMaybePool (curBullCol0,curBearCol0,curBullCirc0,curBearCirc0) = if (poolEnabled) | |
280 | + | then { | |
281 | + | let $t01089811081 = poolSupport(curBullCol0, curBearCol0, curBullCirc0, curBearCirc0, poolMain, poolUp, poolDwn) | |
282 | + | let bullCol1 = $t01089811081._1 | |
283 | + | let bearCol1 = $t01089811081._2 | |
284 | + | let bullCic1 = $t01089811081._3 | |
285 | + | let bearCirc1 = $t01089811081._4 | |
286 | + | let poolMain1 = $t01089811081._5 | |
287 | + | let poolUp1 = $t01089811081._6 | |
288 | + | let poolDwn1 = $t01089811081._7 | |
289 | + | [IntegerEntry(bullCollateralKey, bullCol1), IntegerEntry(bullCirculationKey, bullCic1), IntegerEntry(bearCollateralKey, bearCol1), IntegerEntry(bearCirculationKey, bearCirc1), IntegerEntry(poolMainTokenValueKey, poolMain1), IntegerEntry(poolUpKey, poolUp1), IntegerEntry(poolDwnKey, poolDwn1)] | |
290 | + | } | |
291 | + | else [IntegerEntry(bullCollateralKey, curBullCol0), IntegerEntry(bullCirculationKey, curBullCirc0), IntegerEntry(bearCollateralKey, curBearCol0), IntegerEntry(bearCirculationKey, curBearCirc0)] | |
175 | 292 | ||
176 | 293 | ||
177 | 294 | func dequeue () = if ((queueSize == 0)) | |
178 | 295 | then throw("nothing to settle") | |
179 | 296 | else { | |
180 | - | func collectFee (fees) = | |
297 | + | func collectFee (fees) = IntegerEntry(feesAccumulatedKey, (feesAccumulated + fees)) | |
181 | 298 | ||
182 | - | let decreaseQueueSize = | |
299 | + | let decreaseQueueSize = IntegerEntry(queueSizeKey, (queueSize - 1)) | |
183 | 300 | let isLastElement = (headPointer == tailPointer) | |
184 | - | let overwriteTail = | |
301 | + | let overwriteTail = StringEntry(tailPointerKey, "") | |
185 | 302 | let data = split(valueOrErrorMessage(getString(this, headPointer), "bad head pointer"), "|") | |
186 | 303 | let action = data[0] | |
187 | 304 | let amt = parseIntValue(data[1]) | |
188 | 305 | let token = data[2] | |
189 | 306 | let priceIndex = parseIntValue(data[3]) | |
190 | 307 | let invoker = addressFromStringValue(data[4]) | |
191 | 308 | let next = data[5] | |
192 | - | if ((rebalancedPriceIndex > priceIndex)) | |
309 | + | let items = if ((rebalancedPriceIndex > priceIndex)) | |
193 | 310 | then throw(((("corrupt state, rebalancedPriceIndex=" + toString(rebalancedPriceIndex)) + ", request price id=") + toString(priceIndex))) | |
194 | 311 | else if ((priceIndex > rebalancedPriceIndex)) | |
195 | 312 | then throw("can't dequeue, too early, rebalance first") | |
196 | 313 | else if ((action == ISSUE)) | |
197 | 314 | then { | |
198 | 315 | let feeSize = fraction(amt, issuePercentile, 10000) | |
199 | 316 | let addedCollateral = (amt - feeSize) | |
200 | 317 | if ((token == BULL)) | |
201 | 318 | then { | |
202 | 319 | let addedToCirculation = fraction(bullCirc, addedCollateral, bullCol) | |
203 | - | let items = [DataEntry(bullCollateralKey, (bullCol + addedCollateral)), DataEntry(bullCirculationKey, (bullCirc + addedToCirculation)), DataEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize] | |
204 | - | ScriptResult(WriteSet(if (isLastElement) | |
205 | - | then overwriteTail :: items | |
206 | - | else items), TransferSet([ScriptTransfer(invoker, addedToCirculation, fromBase58String(BULL))])) | |
320 | + | (actionsWithMaybePool((bullCol + addedCollateral), bearCol, (bullCirc + addedToCirculation), bearCirc) ++ [StringEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize, ScriptTransfer(invoker, addedToCirculation, fromBase58String(BULL))]) | |
207 | 321 | } | |
208 | 322 | else if ((token == BEAR)) | |
209 | 323 | then { | |
210 | 324 | let addedToCirculation = fraction(bearCirc, addedCollateral, bearCol) | |
211 | - | let items = [DataEntry(bearCollateralKey, (bearCol + addedCollateral)), DataEntry(bearCirculationKey, (bearCirc + addedToCirculation)), DataEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize] | |
212 | - | ScriptResult(WriteSet(if (isLastElement) | |
213 | - | then overwriteTail :: items | |
214 | - | else items), TransferSet([ScriptTransfer(invoker, addedToCirculation, fromBase58String(BEAR))])) | |
325 | + | (actionsWithMaybePool(bullCol, (bearCol + addedCollateral), bullCirc, (bearCirc + addedToCirculation)) ++ [StringEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize, ScriptTransfer(invoker, addedToCirculation, fromBase58String(BEAR))]) | |
215 | 326 | } | |
216 | 327 | else throw("bad token id") | |
217 | 328 | } | |
218 | 329 | else if ((action == REDEEM)) | |
219 | 330 | then { | |
220 | 331 | let removedTokens = amt | |
221 | 332 | if ((token == BULL)) | |
222 | 333 | then { | |
223 | 334 | let removedCollateral = fraction(bullCol, removedTokens, bullCirc) | |
224 | 335 | let feeSize = fraction(removedCollateral, redeemPercentile, 10000) | |
225 | 336 | let payout = if ((removedCollateral > feeSize)) | |
226 | 337 | then (removedCollateral - feeSize) | |
227 | 338 | else 0 | |
228 | - | let items = [DataEntry(bullCollateralKey, (bullCol - removedCollateral)), DataEntry(bullCirculationKey, (bullCirc - removedTokens)), DataEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize] | |
229 | - | ScriptResult(WriteSet(if (isLastElement) | |
230 | - | then overwriteTail :: items | |
231 | - | else items), TransferSet([ScriptTransfer(invoker, payout, fromBase58String(mainToken))])) | |
339 | + | (actionsWithMaybePool((bullCol - removedCollateral), bearCol, (bullCirc - removedTokens), bearCirc) ++ [StringEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize, ScriptTransfer(invoker, payout, fromBase58String(mainToken))]) | |
232 | 340 | } | |
233 | 341 | else if ((token == BEAR)) | |
234 | 342 | then { | |
235 | 343 | let removedCollateral = fraction(bearCol, removedTokens, bearCirc) | |
236 | 344 | let feeSize = fraction(removedCollateral, redeemPercentile, 10000) | |
237 | 345 | let payout = if ((removedCollateral > feeSize)) | |
238 | 346 | then (removedCollateral - feeSize) | |
239 | 347 | else 0 | |
240 | - | let items = [DataEntry(bearCollateralKey, (bearCol - removedCollateral)), DataEntry(bearCirculationKey, (bearCirc - removedTokens)), DataEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize] | |
241 | - | ScriptResult(WriteSet(if (isLastElement) | |
242 | - | then overwriteTail :: items | |
243 | - | else items), TransferSet([ScriptTransfer(invoker, payout, fromBase58String(mainToken))])) | |
348 | + | (actionsWithMaybePool(bullCol, (bearCol - removedCollateral), bullCirc, (bearCirc - removedTokens)) ++ [StringEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize, ScriptTransfer(invoker, payout, fromBase58String(mainToken))]) | |
244 | 349 | } | |
245 | 350 | else throw("bad token id") | |
246 | 351 | } | |
247 | - | else throw(("bad action: " + action)) | |
352 | + | else if ((action == POOL)) | |
353 | + | then { | |
354 | + | let issueTokens = fraction(poolTokenCirculation, amt, poolValue) | |
355 | + | [IntegerEntry(poolMainTokenValueKey, (poolMain + amt)), IntegerEntry(poolTokenCirculationKey, (poolTokenCirculation + issueTokens)), StringEntry(headPointerKey, next), decreaseQueueSize, ScriptTransfer(invoker, issueTokens, fromBase58String(poolToken))] | |
356 | + | } | |
357 | + | else if ((action == UNPOOL)) | |
358 | + | then { | |
359 | + | func share (a) = fraction(a, amt, poolTokenCirculation) | |
360 | + | ||
361 | + | let unpooledMain = share(poolMain) | |
362 | + | let unpooledUp = share(poolUp) | |
363 | + | let unpooledDwn = share(poolDwn) | |
364 | + | let unpooledUpValue = fraction(unpooledUp, bullCol, bullCirc) | |
365 | + | let unpooledDwnValue = fraction(unpooledDwn, bearCol, bearCirc) | |
366 | + | [IntegerEntry(poolMainTokenValueKey, (poolMain - unpooledMain)), IntegerEntry(poolTokenCirculationKey, (poolTokenCirculation - amt)), IntegerEntry(poolUpKey, (poolUp - unpooledUp)), IntegerEntry(poolDwnKey, (poolDwn - unpooledDwn)), IntegerEntry(bullCirculationKey, (bullCirc - unpooledUp)), IntegerEntry(bearCirculationKey, (bearCirc - unpooledDwn)), IntegerEntry(bullCollateralKey, (bullCol - unpooledUpValue)), IntegerEntry(bearCollateralKey, (bearCol - unpooledDwnValue)), StringEntry(headPointerKey, next), decreaseQueueSize, ScriptTransfer(invoker, ((unpooledMain + unpooledUpValue) + unpooledDwnValue), fromBase58String(mainToken))] | |
367 | + | } | |
368 | + | else throw(("bad action: " + action)) | |
369 | + | if (isLastElement) | |
370 | + | then overwriteTail :: items | |
371 | + | else items | |
248 | 372 | } | |
249 | 373 | ||
250 | 374 | ||
251 | 375 | func rebalance () = { | |
252 | 376 | func LV (v,p0,p1) = { | |
253 | 377 | let denom = 100 | |
254 | 378 | let pmax = ((if ((p1 > p0)) | |
255 | 379 | then p1 | |
256 | 380 | else p0) / denom) | |
257 | 381 | let pmin = ((if ((p0 > p1)) | |
258 | 382 | then p1 | |
259 | 383 | else p0) / denom) | |
260 | 384 | let a = (pmin * pmin) | |
261 | 385 | let b = (((9 * pmax) * pmax) - ((15 * pmax) * pmin)) | |
262 | 386 | fraction(v, ((6 * a) + b), ((7 * a) + b)) | |
263 | 387 | } | |
264 | 388 | ||
265 | 389 | let settledPriceIndex = valueOrErrorMessage(getInteger(this, lastRebalancePriceIndexKey), "inconsistent data") | |
266 | 390 | let unsettledPriceIndex = (settledPriceIndex + 1) | |
267 | 391 | let settledPriceHeight = valueOrErrorMessage(getInteger(oracle, ("price_index_" + toString(settledPriceIndex))), "bad oracle data for settled price height") | |
268 | 392 | let settledPrice = valueOrErrorMessage(getInteger(oracle, ("price_" + toString(settledPriceHeight))), "bad oracle data for price") | |
269 | 393 | let nextPriceHeight = valueOrErrorMessage(getInteger(oracle, ("price_index_" + toString(unsettledPriceIndex))), "no next price height") | |
270 | 394 | let nextPrice = valueOrErrorMessage(getInteger(oracle, ("price_" + toString(nextPriceHeight))), "no next price") | |
271 | 395 | let minVol = if ((bearCol > bullCol)) | |
272 | 396 | then bullCol | |
273 | 397 | else bearCol | |
274 | 398 | let redist = LV(minVol, settledPrice, nextPrice) | |
275 | - | if ((nextPrice > settledPrice)) | |
276 | - | then WriteSet([DataEntry(bullCollateralKey, (bullCol + redist)), DataEntry(bearCollateralKey, (bearCol - redist)), DataEntry(lastRebalancePriceIndexKey, unsettledPriceIndex)]) | |
277 | - | else if ((settledPrice > nextPrice)) | |
278 | - | then WriteSet([DataEntry(bullCollateralKey, (bullCol - redist)), DataEntry(bearCollateralKey, (bearCol + redist)), DataEntry(lastRebalancePriceIndexKey, unsettledPriceIndex)]) | |
279 | - | else WriteSet([DataEntry(lastRebalancePriceIndexKey, unsettledPriceIndex)]) | |
399 | + | let newBullCol = if ((nextPrice > settledPrice)) | |
400 | + | then (bullCol + redist) | |
401 | + | else (bullCol - redist) | |
402 | + | let newBearCol = if ((nextPrice > settledPrice)) | |
403 | + | then (bearCol - redist) | |
404 | + | else (bearCol + redist) | |
405 | + | if (poolEnabled) | |
406 | + | then { | |
407 | + | let $t01922019407 = poolSupport(newBullCol, newBearCol, bullCirc, bearCirc, poolMain, poolUp, poolDwn) | |
408 | + | let updBullCol = $t01922019407._1 | |
409 | + | let updBearCol = $t01922019407._2 | |
410 | + | let updBullCirc = $t01922019407._3 | |
411 | + | let updBearCirc = $t01922019407._4 | |
412 | + | let updPoolMain = $t01922019407._5 | |
413 | + | let updPoolUp = $t01922019407._6 | |
414 | + | let updPoolDwn = $t01922019407._7 | |
415 | + | [IntegerEntry(bullCollateralKey, updBullCol), IntegerEntry(bearCollateralKey, updBearCol), IntegerEntry(bullCirculationKey, updBullCirc), IntegerEntry(bearCirculationKey, updBearCirc), IntegerEntry(poolMainTokenValueKey, updPoolMain), IntegerEntry(poolUpKey, updPoolUp), IntegerEntry(poolDwnKey, updPoolDwn), IntegerEntry(lastRebalancePriceIndexKey, unsettledPriceIndex)] | |
416 | + | } | |
417 | + | else [IntegerEntry(bullCollateralKey, newBullCol), IntegerEntry(bearCollateralKey, newBearCol), IntegerEntry(lastRebalancePriceIndexKey, unsettledPriceIndex)] | |
280 | 418 | } | |
281 | 419 | ||
282 | 420 | ||
283 | 421 | @Callable(inv) | |
284 | 422 | func init (bullId,bearId,mainTokenId,oraclePK,whitelisted) = if (isDefined(getString(this, BULLKey))) | |
285 | 423 | then throw("already initialized") | |
286 | - | else if (!(isDefined(inv.payment))) | |
287 | - | then throw("neutrino payment required") | |
288 | - | else if ((toBase58String(valueOrErrorMessage(value(inv.payment).assetId, "neutrino payment required")) != mainTokenId)) | |
289 | - | then throw("payment not in neutrino") | |
290 | - | else { | |
291 | - | let totalOwnedMainToken = value(inv.payment).amount | |
292 | - | let bulls = (totalOwnedMainToken / 2) | |
293 | - | let bears = (totalOwnedMainToken - bulls) | |
294 | - | if (if ((bears == 0)) | |
295 | - | then true | |
296 | - | else (bulls == 0)) | |
297 | - | then throw("can't init balances") | |
298 | - | else { | |
299 | - | let oracleCurrentPriceIndex = valueOrErrorMessage(getInteger(valueOrErrorMessage(addressFromPublicKey(fromBase58String(oraclePK)), "bad oracle address"), lastPriceIndexKey), "can't find last oracle price index") | |
300 | - | ScriptResult(WriteSet([DataEntry(BULLKey, bullId), DataEntry(BEARKey, bearId), DataEntry(mainTokenKey, mainTokenId), DataEntry(oraclePKKey, oraclePK), DataEntry(bullCollateralKey, bulls), DataEntry(bearCollateralKey, bears), DataEntry(bullCirculationKey, bulls), DataEntry(bearCirculationKey, bears), DataEntry(lastRebalancePriceIndexKey, oracleCurrentPriceIndex), DataEntry(whitelistKey, whitelisted), DataEntry(issuePercentileKey, 0), DataEntry(redeemPercentileKey, 0), DataEntry(minIssueKey, 0), DataEntry(minRedeemKey, 0), DataEntry(whitelistOnlyKey, true)]), TransferSet([ScriptTransfer(inv.caller, bulls, fromBase58String(bullId)), ScriptTransfer(inv.caller, bears, fromBase58String(bearId))])) | |
301 | - | } | |
302 | - | } | |
424 | + | else if ((toBase58String(valueOrErrorMessage(inv.payments[0].assetId, "neutrino payment required")) != mainTokenId)) | |
425 | + | then throw("payment not in neutrino") | |
426 | + | else { | |
427 | + | let totalOwnedMainToken = inv.payments[0].amount | |
428 | + | let bulls = (totalOwnedMainToken / 2) | |
429 | + | let bears = (totalOwnedMainToken - bulls) | |
430 | + | if (if ((bears == 0)) | |
431 | + | then true | |
432 | + | else (bulls == 0)) | |
433 | + | then throw("can't init balances") | |
434 | + | else { | |
435 | + | let oracleCurrentPriceIndex = valueOrErrorMessage(getInteger(valueOrErrorMessage(addressFromPublicKey(fromBase58String(oraclePK)), "bad oracle address"), lastPriceIndexKey), "can't find last oracle price index") | |
436 | + | [StringEntry(BULLKey, bullId), StringEntry(BEARKey, bearId), StringEntry(mainTokenKey, mainTokenId), StringEntry(oraclePKKey, oraclePK), IntegerEntry(bullCollateralKey, bulls), IntegerEntry(bearCollateralKey, bears), IntegerEntry(bullCirculationKey, bulls), IntegerEntry(bearCirculationKey, bears), IntegerEntry(lastRebalancePriceIndexKey, oracleCurrentPriceIndex), StringEntry(whitelistKey, whitelisted), IntegerEntry(issuePercentileKey, 0), IntegerEntry(redeemPercentileKey, 0), IntegerEntry(minIssueKey, 0), IntegerEntry(minRedeemKey, 0), BooleanEntry(whitelistOnlyKey, true), ScriptTransfer(inv.caller, bulls, fromBase58String(bullId)), ScriptTransfer(inv.caller, bears, fromBase58String(bearId))] | |
437 | + | } | |
438 | + | } | |
303 | 439 | ||
304 | 440 | ||
305 | 441 | ||
306 | 442 | @Callable(i) | |
307 | - | func setParams (iP,rP,mI,mR,wl) = if ((i.caller != this)) | |
443 | + | func setParams (iP,rP,mI,mR,mP,wl) = if ((i.caller != this)) | |
308 | 444 | then throw("only self can change whitelist") | |
309 | - | else | |
445 | + | else [IntegerEntry(issuePercentileKey, iP), IntegerEntry(redeemPercentileKey, rP), IntegerEntry(minIssueKey, mI), IntegerEntry(minRedeemKey, mR), IntegerEntry(minPoolKey, mP), BooleanEntry(whitelistOnlyKey, wl)] | |
310 | 446 | ||
311 | 447 | ||
312 | 448 | ||
313 | 449 | @Callable(i) | |
314 | 450 | func setWhitelist (l) = if ((i.caller != this)) | |
315 | 451 | then throw("only self can change whitelist") | |
316 | - | else | |
452 | + | else [StringEntry(whitelistKey, l)] | |
317 | 453 | ||
318 | 454 | ||
319 | 455 | ||
320 | 456 | @Callable(i) | |
321 | 457 | func setAddresses (feeAddr,stakingAddr,daemonPK) = if ((i.caller != this)) | |
322 | 458 | then throw("only self can change feeAcc addresses") | |
323 | - | else | |
459 | + | else [StringEntry(feeAddrKey, feeAddr), StringEntry(stakingAddrKey, stakingAddr), StringEntry(daemonPubKeyKey, daemonPK)] | |
324 | 460 | ||
325 | 461 | ||
326 | 462 | ||
327 | 463 | @Callable(i) | |
328 | 464 | func withdrawFee (amount) = if ((amount > feesAccumulated)) | |
329 | 465 | then throw(("too much. available: " + toString(feesAccumulated))) | |
330 | - | else | |
466 | + | else [IntegerEntry(feesAccumulatedKey, (feesAccumulated - amount)), ScriptTransfer(feeAddress, amount, fromBase58String(mainToken))] | |
331 | 467 | ||
332 | 468 | ||
333 | 469 | ||
334 | 470 | @Callable(inv) | |
335 | - | func requestRedeem () = if (( | |
471 | + | func requestRedeem () = if ((validateRequestRedeem(inv) == unit)) | |
336 | 472 | then { | |
337 | - | let assetId = toBase58String(valueOrErrorMessage( | |
338 | - | enqueue(toBase58String(inv.transactionId), REDEEM, | |
473 | + | let assetId = toBase58String(valueOrErrorMessage(inv.payments[0].assetId, "waves are not accepted here")) | |
474 | + | enqueue(toBase58String(inv.transactionId), REDEEM, inv.payments[0].amount, assetId, (oraclePriceIndex + 1), toString(inv.caller)) | |
339 | 475 | } | |
340 | 476 | else throw("doesn't happen") | |
341 | 477 | ||
342 | 478 | ||
343 | 479 | ||
344 | 480 | @Callable(inv) | |
345 | 481 | func requestIssue (tokenId) = if ((inv.caller == this)) | |
346 | 482 | then throw("can't do") | |
347 | 483 | else if (if (whitelistOnly) | |
348 | 484 | then !(isDefined(indexOf(whitelist, toString(inv.caller)))) | |
349 | 485 | else false) | |
350 | 486 | then throw("only whitelisted can do") | |
351 | 487 | else { | |
352 | 488 | let errorMessage = throw((((((("only BULL(" + BULL) + ") or BEAR(") + BEAR) + ") tokens are available in exchange for USDN(") + mainToken) + ")")) | |
353 | 489 | if (if ((tokenId != BULL)) | |
354 | 490 | then (tokenId != BEAR) | |
355 | 491 | else false) | |
356 | 492 | then errorMessage | |
357 | - | else if ( | |
493 | + | else if ((inv.payments[0].assetId != fromBase58String(mainToken))) | |
358 | 494 | then errorMessage | |
359 | - | else if ((value(inv.payment).assetId != fromBase58String(mainToken))) | |
360 | - | then errorMessage | |
361 | - | else if ((minIssue > value(inv.payment).amount)) | |
362 | - | then throw((("Attached payment too small. Min required: " + toString((minIssue / 1000000))) + " USDN")) | |
363 | - | else enqueue(toBase58String(inv.transactionId), ISSUE, value(inv.payment).amount, tokenId, (oraclePriceIndex + 1), toString(inv.caller)) | |
495 | + | else if ((minIssue > inv.payments[0].amount)) | |
496 | + | then throw((("Attached payment too small. Min required: " + toString((minIssue / 1000000))) + " USDN")) | |
497 | + | else enqueue(toBase58String(inv.transactionId), ISSUE, inv.payments[0].amount, tokenId, (oraclePriceIndex + 1), toString(inv.caller)) | |
364 | 498 | } | |
365 | 499 | ||
366 | 500 | ||
367 | 501 | ||
368 | 502 | @Callable(inv) | |
369 | 503 | func settle () = { | |
370 | 504 | let queueEmpty = (headPointer == "") | |
371 | 505 | let canRebalance = (oraclePriceIndex > rebalancedPriceIndex) | |
372 | 506 | if (queueEmpty) | |
373 | 507 | then if (canRebalance) | |
374 | 508 | then rebalance() | |
375 | 509 | else throw("[OK] all done, carry on") | |
376 | 510 | else { | |
377 | 511 | let data = split(valueOrErrorMessage(getString(this, headPointer), "bad head pointer"), "|") | |
378 | 512 | let priceIndex = parseIntValue(data[3]) | |
379 | 513 | if ((priceIndex > rebalancedPriceIndex)) | |
380 | 514 | then if (canRebalance) | |
381 | 515 | then rebalance() | |
382 | 516 | else throw("[OK] need to wait") | |
383 | 517 | else if ((priceIndex == rebalancedPriceIndex)) | |
384 | 518 | then dequeue() | |
385 | 519 | else throw("corrupt data, future price id already rebalanced") | |
386 | 520 | } | |
387 | 521 | } | |
388 | 522 | ||
389 | 523 | ||
524 | + | ||
525 | + | @Callable(inv) | |
526 | + | func setupPool (poolTokenId) = if ((inv.caller != this)) | |
527 | + | then throw("only self can init") | |
528 | + | else if (poolInitialized) | |
529 | + | then throw("pool already initialized") | |
530 | + | else [IntegerEntry(poolDwnKey, 0), IntegerEntry(poolUpKey, 0), IntegerEntry(poolMainTokenValueKey, 0), StringEntry(poolTokenKey, poolTokenId), IntegerEntry(poolTokenCirculationKey, 0), BooleanEntry(poolEnabledKey, false), IntegerEntry(minPoolKey, ((10 * 1000) * 1000))] | |
531 | + | ||
532 | + | ||
533 | + | ||
534 | + | @Callable(inv) | |
535 | + | func startPool () = if ((poolValue != 0)) | |
536 | + | then throw("pool already started") | |
537 | + | else { | |
538 | + | let errMessage = (("please attach 10.000000 main tokens(" + mainToken) + ")") | |
539 | + | let pmt = inv.payments[0] | |
540 | + | if ((pmt.amount != (10 * ten6))) | |
541 | + | then throw(errMessage) | |
542 | + | else if ((pmt.assetId != fromBase58String(mainToken))) | |
543 | + | then throw(errMessage) | |
544 | + | else [IntegerEntry(poolDwnKey, 0), IntegerEntry(poolUpKey, 0), IntegerEntry(poolMainTokenValueKey, (10 * ten6)), BooleanEntry(poolEnabledKey, true), IntegerEntry(poolTokenCirculationKey, ten6), ScriptTransfer(inv.caller, ten6, fromBase58String(poolToken))] | |
545 | + | } | |
546 | + | ||
547 | + | ||
548 | + | ||
549 | + | @Callable(inv) | |
550 | + | func requestPool () = if (!(poolEnabled)) | |
551 | + | then throw("pooling not enabled at the moment") | |
552 | + | else if (if (whitelistOnly) | |
553 | + | then !(isDefined(indexOf(whitelist, toString(inv.caller)))) | |
554 | + | else false) | |
555 | + | then throw("only whitelisted can do") | |
556 | + | else { | |
557 | + | let errMessage = (("main token must be attached(" + mainToken) + ")") | |
558 | + | let pmt = inv.payments[0] | |
559 | + | if ((pmt.assetId != fromBase58String(mainToken))) | |
560 | + | then throw(errMessage) | |
561 | + | else if ((minPool > pmt.amount)) | |
562 | + | then throw(((("pool at least " + toString(minPool)) + " ") + mainToken)) | |
563 | + | else enqueue(toBase58String(inv.transactionId), POOL, inv.payments[0].amount, "", (oraclePriceIndex + 1), toString(inv.caller)) | |
564 | + | } | |
565 | + | ||
566 | + | ||
567 | + | ||
568 | + | @Callable(inv) | |
569 | + | func requestUnpool () = if (!(poolEnabled)) | |
570 | + | then throw("pool not enabled at the moment") | |
571 | + | else { | |
572 | + | let errMessage = (("only pool token allowed(" + poolToken) + ")") | |
573 | + | let pmt = inv.payments[0] | |
574 | + | if ((pmt.assetId != fromBase58String(poolToken))) | |
575 | + | then throw(errMessage) | |
576 | + | else { | |
577 | + | let estimate = fraction(poolValue, pmt.amount, poolTokenCirculation) | |
578 | + | if ((minPool > estimate)) | |
579 | + | then throw(((("unpool at least for" + toString(minPool)) + " ") + mainToken)) | |
580 | + | else enqueue(toBase58String(inv.transactionId), UNPOOL, inv.payments[0].amount, "", (oraclePriceIndex + 1), toString(inv.caller)) | |
581 | + | } | |
582 | + | } | |
583 | + | ||
584 | + | ||
390 | 585 | @Verifier(tx) | |
391 | 586 | func verify () = { | |
392 | 587 | let adminAction = ((((if (sigVerify(tx.bodyBytes, tx.proofs[0], fromBase58String(pubKeyAdminsList[0]))) | |
393 | 588 | then 1 | |
394 | 589 | else 0) + (if (sigVerify(tx.bodyBytes, tx.proofs[1], fromBase58String(pubKeyAdminsList[1]))) | |
395 | 590 | then 1 | |
396 | 591 | else 0)) + (if (sigVerify(tx.bodyBytes, tx.proofs[2], fromBase58String(pubKeyAdminsList[2]))) | |
397 | 592 | then 1 | |
398 | 593 | else 0)) > 1) | |
399 | 594 | let stakingAction = match tx { | |
400 | 595 | case tx: InvokeScriptTransaction => | |
401 | 596 | let signedCorrectly = sigVerify(tx.bodyBytes, tx.proofs[0], daemonPublicKey) | |
402 | 597 | let feesCorrect = if ((tx.feeAssetId == unit)) | |
403 | 598 | then ((1000 * 1000) >= tx.fee) | |
404 | 599 | else false | |
405 | 600 | let dappCorrect = (tx.dApp == rpdAddress) | |
406 | 601 | let unlock = (tx.function == "unlockNeutrino") | |
407 | 602 | let lock = if (if ((tx.function == "lockNeutrinoSP")) | |
408 | 603 | then (tx.args[0] == stakingAddress) | |
409 | 604 | else false) | |
410 | - | then (wavesBalance(this) >= | |
605 | + | then (wavesBalance(this).available >= ten8) | |
411 | 606 | else false | |
412 | 607 | let funcCorrect = if (lock) | |
413 | 608 | then true | |
414 | 609 | else unlock | |
415 | 610 | if (if (if (signedCorrectly) | |
416 | 611 | then feesCorrect | |
417 | 612 | else false) | |
418 | 613 | then dappCorrect | |
419 | 614 | else false) | |
420 | 615 | then funcCorrect | |
421 | 616 | else false | |
422 | 617 | case _ => | |
423 | 618 | false | |
424 | 619 | } | |
425 | 620 | if (adminAction) | |
426 | 621 | then true | |
427 | 622 | else stakingAction | |
428 | 623 | } | |
429 | 624 |
github/deemru/w8io/786bc32 110.96 ms ◑