tx · 12fwpVRbQWHR5SK2n69N2w7uASeGUsMqxMHAUhRGWKZA 3N3PoX8z2Mvu5YbaqZmtyF3dRFjqvhRkB3M: -0.01400000 Waves 2022.03.11 12:07 [1959082] smart account 3N3PoX8z2Mvu5YbaqZmtyF3dRFjqvhRkB3M > SELF 0.00000000 Waves
{ "type": 13, "id": "12fwpVRbQWHR5SK2n69N2w7uASeGUsMqxMHAUhRGWKZA", "fee": 1400000, "feeAssetId": null, "timestamp": 1646989633491, "version": 2, "chainId": 84, "sender": "3N3PoX8z2Mvu5YbaqZmtyF3dRFjqvhRkB3M", "senderPublicKey": "FWZMxrtn6KRrWMPXmQPqDg5eRzwB2YvHhMjMJpwnLmBi", "proofs": [ "532S2fnPgyWehhm9mG4RxA5jKQritRgRkaweRDQJ81vpqfVdQgpy1SENUHVpcCDsQMbfJDBxkbDPyQzQHnVw5Fi1" ], "script": "base64:AAIFAAAAAAAAABIIAhIFCgMBAQgSABIDCgEIEgAAAAAbAQAAABNrZXlNYW5hZ2VyUHVibGljS2V5AAAAAAIAAAAUJXNfX21hbmFnZXJQdWJsaWNLZXkBAAAAGmtleVBlbmRpbmdNYW5hZ2VyUHVibGljS2V5AAAAAAIAAAAbJXNfX3BlbmRpbmdNYW5hZ2VyUHVibGljS2V5AAAAAANTRVACAAAAAl9fAAAAABVJZHhDZmdDbGFpbVN0YXJ0QmxvY2sAAAAAAAAAAAEAAAAAGElkeENmZ0NsYWltVmVzdGluZ1BlcmlvZAAAAAAAAAAAAgAAAAASSWR4Q2ZnQ2xhaW1Bc3NldElkAAAAAAAAAAADAAAAABRJZHhDZmdDbGFpbUFzc2V0TXVsdAAAAAAAAAAABAAAAAAVSWR4Q2ZnQ2xhaW1Bc3NldE93bmVyAAAAAAAAAAAFAAAAABtJZHhDZmdDbGFpbUFzc2V0VG90YWxBbW91bnQAAAAAAAAAAAYAAAAAG0lkeFRvdGFsc1RvdGFsQ2xhaW1lZEFtb3VudAAAAAAAAAAAAQAAAAAYSWR4VG90YWxzUmVtYWluaW5nQW1vdW50AAAAAAAAAAACAAAAABpJZHhUb3RhbHNMYXN0Q2xhaW1lZEhlaWdodAAAAAAAAAAAAwEAAAAPZ2V0U3RyaW5nT3JGYWlsAAAAAQAAAANrZXkJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABCIAAAABBQAAAANrZXkJAAEsAAAAAgkAASwAAAACAgAAAA9tYW5kYXRvcnkgdGhpcy4FAAAAA2tleQIAAAAPIGlzIG5vdCBkZWZpbmVkAQAAABJmb3JtYXRDb25maWdTdHJpbmcAAAAGAAAAD2NsYWltU3RhcnRCbG9jawAAAA12ZXN0aW5nUGVyaW9kAAAADWFzc2V0SWRCYXNlNTgAAAAJYXNzZXRNdWx0AAAACmFzc2V0T3duZXIAAAANYXNzZXRUb3RhbEFtdAkABLkAAAACCQAETAAAAAICAAAADSVkJWQlcyVkJXMlZCUJAARMAAAAAgUAAAAPY2xhaW1TdGFydEJsb2NrCQAETAAAAAIFAAAADXZlc3RpbmdQZXJpb2QJAARMAAAAAgUAAAANYXNzZXRJZEJhc2U1OAkABEwAAAACBQAAAAlhc3NldE11bHQJAARMAAAAAgUAAAAKYXNzZXRPd25lcgkABEwAAAACBQAAAA1hc3NldFRvdGFsQW10BQAAAANuaWwFAAAAA1NFUAEAAAAMZm9ybWF0Q29uZmlnAAAABgAAAA9jbGFpbVN0YXJ0QmxvY2sAAAANdmVzdGluZ1BlcmlvZAAAAA1hc3NldElkQmFzZTU4AAAACWFzc2V0TXVsdAAAAA9jbGFpbUFzc2V0T3duZXIAAAAVY2xhaW1Bc3NldFRvdGFsQW1vdW50CQEAAAASZm9ybWF0Q29uZmlnU3RyaW5nAAAABgkAAaQAAAABBQAAAA9jbGFpbVN0YXJ0QmxvY2sJAAGkAAAAAQUAAAANdmVzdGluZ1BlcmlvZAUAAAANYXNzZXRJZEJhc2U1OAkAAaQAAAABBQAAAAlhc3NldE11bHQFAAAAD2NsYWltQXNzZXRPd25lcgkAAaQAAAABBQAAABVjbGFpbUFzc2V0VG90YWxBbW91bnQBAAAAEmZvcm1hdFRvdGFsc1N0cmluZwAAAAMAAAASdG90YWxDbGFpbWVkQW1vdW50AAAAF3JlbWFpbmluZ0Ftb3VudEZvckNsYWltAAAAEWxhc3RDbGFpbWVkSGVpZ2h0CQAEuQAAAAIJAARMAAAAAgIAAAAGJWQlZCVkCQAETAAAAAIFAAAAEnRvdGFsQ2xhaW1lZEFtb3VudAkABEwAAAACBQAAABdyZW1haW5pbmdBbW91bnRGb3JDbGFpbQkABEwAAAACBQAAABFsYXN0Q2xhaW1lZEhlaWdodAUAAAADbmlsBQAAAANTRVABAAAAE2Zvcm1hdEhpc3RvcnlSZWNvcmQAAAAEAAAAEmNsYWltZWRBc3NldEFtb3VudAAAAA5jbGFpbWluZ0Jsb2NrcwAAABRmaXJzdENhbHVsYXRpb25CbG9jawAAABNsYXN0Q2FsdWxhdGlvbkJsb2NrCQAEuQAAAAIJAARMAAAAAgIAAAAMJWQlZCVkJWQlZCVkCQAETAAAAAIJAAGkAAAAAQUAAAAGaGVpZ2h0CQAETAAAAAIJAAGkAAAAAQgFAAAACWxhc3RCbG9jawAAAAl0aW1lc3RhbXAJAARMAAAAAgkAAaQAAAABBQAAABJjbGFpbWVkQXNzZXRBbW91bnQJAARMAAAAAgkAAaQAAAABBQAAAA5jbGFpbWluZ0Jsb2NrcwkABEwAAAACCQABpAAAAAEFAAAAFGZpcnN0Q2FsdWxhdGlvbkJsb2NrCQAETAAAAAIJAAGkAAAAAQUAAAATbGFzdENhbHVsYXRpb25CbG9jawUAAAADbmlsBQAAAANTRVABAAAACWtleUNvbmZpZwAAAAACAAAACiVzX19jb25maWcBAAAACWtleVRvdGFscwAAAAACAAAACiVzX190b3RhbHMBAAAAGWtleU9wZXJhdGlvbkhpc3RvcnlSZWNvcmQAAAADAAAABHR5cGUAAAALdXNlckFkZHJlc3MAAAAGdHhJZDU4CQAEuQAAAAIJAARMAAAAAgIAAAARJXMlcyVzJXNfX2hpc3RvcnkJAARMAAAAAgUAAAAEdHlwZQkABEwAAAACBQAAAAt1c2VyQWRkcmVzcwkABEwAAAACBQAAAAZ0eElkNTgFAAAAA25pbAUAAAADU0VQAQAAAA9yZWFkQ29uZmlnQXJyYXkAAAAACQAEtQAAAAIJAQAAAA9nZXRTdHJpbmdPckZhaWwAAAABCQEAAAAJa2V5Q29uZmlnAAAAAAUAAAADU0VQAQAAAA9yZWFkVG90YWxzQXJyYXkAAAAACQAEtQAAAAIJAQAAAA9nZXRTdHJpbmdPckZhaWwAAAABCQEAAAAJa2V5VG90YWxzAAAAAAUAAAADU0VQAQAAAAtUb3RhbHNFbnRyeQAAAAQAAAADa2V5AAAACW9yaWdBcnJheQAAAApjbGFpbWVkQW10AAAAFG5ld0xhc3RDbGFpbWVkSGVpZ2h0BAAAABJ0b3RhbENsYWltZWRBbW91bnQJAQAAAA1wYXJzZUludFZhbHVlAAAAAQkAAZEAAAACBQAAAAlvcmlnQXJyYXkFAAAAG0lkeFRvdGFsc1RvdGFsQ2xhaW1lZEFtb3VudAQAAAAPcmVtYWluaW5nQW1vdW50CQEAAAANcGFyc2VJbnRWYWx1ZQAAAAEJAAGRAAAAAgUAAAAJb3JpZ0FycmF5BQAAABhJZHhUb3RhbHNSZW1haW5pbmdBbW91bnQEAAAAEWxhc3RDbGFpbWVkSGVpZ2h0CQEAAAANcGFyc2VJbnRWYWx1ZQAAAAEJAAGRAAAAAgUAAAAJb3JpZ0FycmF5BQAAABpJZHhUb3RhbHNMYXN0Q2xhaW1lZEhlaWdodAQAAAAVbmV3VG90YWxDbGFpbWVkQW1vdW50CQAAZAAAAAIFAAAAEnRvdGFsQ2xhaW1lZEFtb3VudAUAAAAKY2xhaW1lZEFtdAQAAAASbmV3UmVtYWluaW5nQW1vdW50CQAAZQAAAAIFAAAAD3JlbWFpbmluZ0Ftb3VudAUAAAAKY2xhaW1lZEFtdAMJAABmAAAAAgAAAAAAAAAAAAUAAAASbmV3UmVtYWluaW5nQW1vdW50CQAAAgAAAAECAAAADGludmFsaWQgbWF0aAkBAAAAC1N0cmluZ0VudHJ5AAAAAgUAAAADa2V5CQEAAAASZm9ybWF0VG90YWxzU3RyaW5nAAAAAwkAAaQAAAABBQAAABVuZXdUb3RhbENsYWltZWRBbW91bnQJAAGkAAAAAQUAAAASbmV3UmVtYWluaW5nQW1vdW50CQABpAAAAAEFAAAAFG5ld0xhc3RDbGFpbWVkSGVpZ2h0AQAAABpDbGFpbU9wZXJhdGlvbkhpc3RvcnlFbnRyeQAAAAYAAAALdXNlckFkZHJlc3MAAAASY2xhaW1lZEFzc2V0QW1vdW50AAAADmNsYWltaW5nQmxvY2tzAAAAFWZpcnN0Q2FsY3VsYXRpb25CbG9jawAAABRsYXN0Q2FsY3VsYXRpb25CbG9jawAAAAR0eElkCQEAAAALU3RyaW5nRW50cnkAAAACCQEAAAAZa2V5T3BlcmF0aW9uSGlzdG9yeVJlY29yZAAAAAMCAAAABWNsYWltBQAAAAt1c2VyQWRkcmVzcwkAAlgAAAABBQAAAAR0eElkCQEAAAATZm9ybWF0SGlzdG9yeVJlY29yZAAAAAQFAAAAEmNsYWltZWRBc3NldEFtb3VudAUAAAAOY2xhaW1pbmdCbG9ja3MFAAAAFWZpcnN0Q2FsY3VsYXRpb25CbG9jawUAAAAUbGFzdENhbGN1bGF0aW9uQmxvY2sBAAAAFm1hbmFnZXJQdWJsaWNLZXlPclVuaXQAAAAABAAAAAckbWF0Y2gwCQAEIgAAAAEJAQAAABNrZXlNYW5hZ2VyUHVibGljS2V5AAAAAAMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAGU3RyaW5nBAAAAAFzBQAAAAckbWF0Y2gwCQACWQAAAAEFAAAAAXMDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQFAAAABHVuaXQJAAACAAAAAQIAAAALTWF0Y2ggZXJyb3IBAAAAHXBlbmRpbmdNYW5hZ2VyUHVibGljS2V5T3JVbml0AAAAAAQAAAAHJG1hdGNoMAkABCIAAAABCQEAAAAaa2V5UGVuZGluZ01hbmFnZXJQdWJsaWNLZXkAAAAAAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAAZTdHJpbmcEAAAAAXMFAAAAByRtYXRjaDAJAAJZAAAAAQUAAAABcwMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAEVW5pdAUAAAAEdW5pdAkAAAIAAAABAgAAAAtNYXRjaCBlcnJvcgEAAAALbXVzdE1hbmFnZXIAAAABAAAAAWkEAAAAAnBkCQAAAgAAAAECAAAAEVBlcm1pc3Npb24gZGVuaWVkBAAAAAckbWF0Y2gwCQEAAAAWbWFuYWdlclB1YmxpY0tleU9yVW5pdAAAAAADCQAAAQAAAAIFAAAAByRtYXRjaDACAAAACkJ5dGVWZWN0b3IEAAAAAnBrBQAAAAckbWF0Y2gwAwkAAAAAAAACCAUAAAABaQAAAA9jYWxsZXJQdWJsaWNLZXkFAAAAAnBrBgUAAAACcGQDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQDCQAAAAAAAAIIBQAAAAFpAAAABmNhbGxlcgUAAAAEdGhpcwYFAAAAAnBkCQAAAgAAAAECAAAAC01hdGNoIGVycm9yAAAABAAAAAFpAQAAAAtjb25zdHJ1Y3RvcgAAAAMAAAAPY2xhaW1TdGFydEJsb2NrAAAAE3Zlc3RpbmdQZXJpb2RCbG9ja3MAAAASYmVuZWZpY2lhcnlBZGRyZXNzBAAAAAp2ZXN0aW5nRW5kCQAAZAAAAAIFAAAAD2NsYWltU3RhcnRCbG9jawUAAAATdmVzdGluZ1BlcmlvZEJsb2NrcwMJAQAAAAlpc0RlZmluZWQAAAABCQAEIgAAAAEJAQAAAAlrZXlDb25maWcAAAAACQAAAgAAAAECAAAAE2FscmVhZHkgaW5pdGlhbGl6ZWQDCQEAAAACIT0AAAACCQABkAAAAAEIBQAAAAFpAAAACHBheW1lbnRzAAAAAAAAAAABCQAAAgAAAAECAAAAImV4YWN0bHkgMSBwYXltZW50IG11c3QgYmUgYXR0YWNoZWQDCQEAAAACIT0AAAACAgAAACMzTjRBaWI1aXViV2lHTXpkVGg2d1dpVkRWYm8zMm9lVlVtSAkABCUAAAABCAUAAAABaQAAAAZjYWxsZXIJAAACAAAAAQIAAAAObm90IGF1dGhvcml6ZWQEAAAAGGJlbmVmaWNpYXJ5QWRkcmVzc1BhcnNlZAkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEJgAAAAEFAAAAEmJlbmVmaWNpYXJ5QWRkcmVzcwIAAAAgSW52YWxpZCBiZW5lZmljaWFyQWRkcmVzcyBwYXNzZWQEAAAAA3BtdAkBAAAABXZhbHVlAAAAAQkAAZEAAAACCAUAAAABaQAAAAhwYXltZW50cwAAAAAAAAAAAAQAAAAMY2xhaW1Bc3NldElkCQEAAAAFdmFsdWUAAAABCAUAAAADcG10AAAAB2Fzc2V0SWQEAAAADmNsYWltQXNzZXRJbmZvCQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAPsAAAAAQUAAAAMY2xhaW1Bc3NldElkAgAAABtmYWlsIHRvIGxvYWQgaWRvIGFzc2V0IGluZm8EAAAADmNsYWltQXNzZXRJZDU4CQACWAAAAAEFAAAADGNsYWltQXNzZXRJZAQAAAAOY2xhaW1Bc3NldE11bHQJAABsAAAABgAAAAAAAAAACgAAAAAAAAAAAAgFAAAADmNsYWltQXNzZXRJbmZvAAAACGRlY2ltYWxzAAAAAAAAAAAAAAAAAAAAAAAABQAAAARET1dOBAAAABBjbGFpbUFzc2V0QW1vdW50CAUAAAADcG10AAAABmFtb3VudAkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACCQEAAAAJa2V5Q29uZmlnAAAAAAkBAAAADGZvcm1hdENvbmZpZwAAAAYFAAAAD2NsYWltU3RhcnRCbG9jawUAAAATdmVzdGluZ1BlcmlvZEJsb2NrcwUAAAAOY2xhaW1Bc3NldElkNTgFAAAADmNsYWltQXNzZXRNdWx0CQAEJQAAAAEFAAAAGGJlbmVmaWNpYXJ5QWRkcmVzc1BhcnNlZAUAAAAQY2xhaW1Bc3NldEFtb3VudAkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACCQEAAAAJa2V5VG90YWxzAAAAAAkBAAAAEmZvcm1hdFRvdGFsc1N0cmluZwAAAAMCAAAAATAJAAGkAAAAAQUAAAAQY2xhaW1Bc3NldEFtb3VudAIAAAABMAUAAAADbmlsAAAAAWkBAAAABWNsYWltAAAAAAQAAAAIY2ZnQXJyYXkJAQAAAA9yZWFkQ29uZmlnQXJyYXkAAAAABAAAABNjZmdDbGFpbVN0YXJ0SGVpZ2h0CQEAAAANcGFyc2VJbnRWYWx1ZQAAAAEJAAGRAAAAAgUAAAAIY2ZnQXJyYXkFAAAAFUlkeENmZ0NsYWltU3RhcnRCbG9jawQAAAAQY2ZnQ2xhaW1EdXJhdGlvbgkBAAAADXBhcnNlSW50VmFsdWUAAAABCQABkQAAAAIFAAAACGNmZ0FycmF5BQAAABhJZHhDZmdDbGFpbVZlc3RpbmdQZXJpb2QEAAAAC2NmZ0NsYWltRW5kCQAAZAAAAAIFAAAAE2NmZ0NsYWltU3RhcnRIZWlnaHQFAAAAEGNmZ0NsYWltRHVyYXRpb24EAAAAEWNmZ0NsYWltQXNzZXRJZDU4CQABkQAAAAIFAAAACGNmZ0FycmF5BQAAABJJZHhDZmdDbGFpbUFzc2V0SWQEAAAAEmNmZ0NsYWltQXNzZXRPd25lcgkAAZEAAAACBQAAAAhjZmdBcnJheQUAAAAVSWR4Q2ZnQ2xhaW1Bc3NldE93bmVyBAAAABhjZmdDbGFpbUFzc2V0VG90YWxBbW91bnQJAQAAAA1wYXJzZUludFZhbHVlAAAAAQkAAZEAAAACBQAAAAhjZmdBcnJheQUAAAAbSWR4Q2ZnQ2xhaW1Bc3NldFRvdGFsQW1vdW50BAAAAAt1c2VyQWRkcmVzcwgFAAAAAWkAAAAGY2FsbGVyBAAAAA11c2VyQWRkcmVzczU4CQAEJQAAAAEFAAAAC3VzZXJBZGRyZXNzBAAAAA9vcmlnVG90YWxzQXJyYXkJAQAAAA9yZWFkVG90YWxzQXJyYXkAAAAABAAAABJ0b3RhbENsYWltZWRBbW91bnQJAQAAAA1wYXJzZUludFZhbHVlAAAAAQkAAZEAAAACBQAAAA9vcmlnVG90YWxzQXJyYXkFAAAAG0lkeFRvdGFsc1RvdGFsQ2xhaW1lZEFtb3VudAQAAAAUdG90YWxSZW1haW5pbmdBbW91bnQJAQAAAA1wYXJzZUludFZhbHVlAAAAAQkAAZEAAAACBQAAAA9vcmlnVG90YWxzQXJyYXkFAAAAGElkeFRvdGFsc1JlbWFpbmluZ0Ftb3VudAQAAAARbGFzdENsYWltZWRIZWlnaHQJAQAAAA1wYXJzZUludFZhbHVlAAAAAQkAAZEAAAACBQAAAA9vcmlnVG90YWxzQXJyYXkFAAAAGklkeFRvdGFsc0xhc3RDbGFpbWVkSGVpZ2h0AwkBAAAAAiE9AAAAAgUAAAANdXNlckFkZHJlc3M1OAUAAAASY2ZnQ2xhaW1Bc3NldE93bmVyCQAAAgAAAAECAAAAEnBlcm1pc3Npb25zIGRlbmllZAMJAABmAAAAAgUAAAATY2ZnQ2xhaW1TdGFydEhlaWdodAUAAAAGaGVpZ2h0CQAAAgAAAAEJAAEsAAAAAgIAAAAYV2FpdCBjbGFpbSBzdGFydCBibG9jazogCQABpAAAAAEFAAAAE2NmZ0NsYWltU3RhcnRIZWlnaHQEAAAAE2xhc3RDYWx1bGF0aW9uQmxvY2sDCQAAZgAAAAIFAAAABmhlaWdodAUAAAALY2ZnQ2xhaW1FbmQFAAAAC2NmZ0NsYWltRW5kBQAAAAZoZWlnaHQEAAAAFGZpcnN0Q2FsdWxhdGlvbkJsb2NrAwkAAAAAAAACBQAAABFsYXN0Q2xhaW1lZEhlaWdodAAAAAAAAAAAAAUAAAATY2ZnQ2xhaW1TdGFydEhlaWdodAUAAAARbGFzdENsYWltZWRIZWlnaHQEAAAADmNsYWltaW5nQmxvY2tzCQAAZQAAAAIFAAAAE2xhc3RDYWx1bGF0aW9uQmxvY2sFAAAAFGZpcnN0Q2FsdWxhdGlvbkJsb2NrBAAAABNjbGFpbWluZ0Fzc2V0QW1vdW50CQAAawAAAAMFAAAAGGNmZ0NsYWltQXNzZXRUb3RhbEFtb3VudAUAAAAOY2xhaW1pbmdCbG9ja3MFAAAAEGNmZ0NsYWltRHVyYXRpb24JAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwUAAAALdXNlckFkZHJlc3MFAAAAE2NsYWltaW5nQXNzZXRBbW91bnQJAAJZAAAAAQUAAAARY2ZnQ2xhaW1Bc3NldElkNTgJAARMAAAAAgkBAAAAC1RvdGFsc0VudHJ5AAAABAkBAAAACWtleVRvdGFscwAAAAAJAQAAAA9yZWFkVG90YWxzQXJyYXkAAAAABQAAABNjbGFpbWluZ0Fzc2V0QW1vdW50BQAAABNsYXN0Q2FsdWxhdGlvbkJsb2NrCQAETAAAAAIJAQAAABpDbGFpbU9wZXJhdGlvbkhpc3RvcnlFbnRyeQAAAAYFAAAADXVzZXJBZGRyZXNzNTgFAAAAE2NsYWltaW5nQXNzZXRBbW91bnQFAAAADmNsYWltaW5nQmxvY2tzBQAAABRmaXJzdENhbHVsYXRpb25CbG9jawUAAAATbGFzdENhbHVsYXRpb25CbG9jawgFAAAAAWkAAAANdHJhbnNhY3Rpb25JZAUAAAADbmlsAAAAAWkBAAAACnNldE1hbmFnZXIAAAABAAAAF3BlbmRpbmdNYW5hZ2VyUHVibGljS2V5BAAAAAtjaGVja0NhbGxlcgkBAAAAC211c3RNYW5hZ2VyAAAAAQUAAAABaQMJAAAAAAAAAgUAAAALY2hlY2tDYWxsZXIFAAAAC2NoZWNrQ2FsbGVyBAAAABVjaGVja01hbmFnZXJQdWJsaWNLZXkJAAJZAAAAAQUAAAAXcGVuZGluZ01hbmFnZXJQdWJsaWNLZXkDCQAAAAAAAAIFAAAAFWNoZWNrTWFuYWdlclB1YmxpY0tleQUAAAAVY2hlY2tNYW5hZ2VyUHVibGljS2V5CQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIJAQAAABprZXlQZW5kaW5nTWFuYWdlclB1YmxpY0tleQAAAAAFAAAAF3BlbmRpbmdNYW5hZ2VyUHVibGljS2V5BQAAAANuaWwJAAACAAAAAQIAAAAkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQAAAgAAAAECAAAAJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgAAAAFpAQAAAA5jb25maXJtTWFuYWdlcgAAAAAEAAAAAnBtCQEAAAAdcGVuZGluZ01hbmFnZXJQdWJsaWNLZXlPclVuaXQAAAAABAAAAAVoYXNQTQMJAQAAAAlpc0RlZmluZWQAAAABBQAAAAJwbQYJAAACAAAAAQIAAAASTm8gcGVuZGluZyBtYW5hZ2VyAwkAAAAAAAACBQAAAAVoYXNQTQUAAAAFaGFzUE0EAAAAB2NoZWNrUE0DCQAAAAAAAAIIBQAAAAFpAAAAD2NhbGxlclB1YmxpY0tleQkBAAAABXZhbHVlAAAAAQUAAAACcG0GCQAAAgAAAAECAAAAG1lvdSBhcmUgbm90IHBlbmRpbmcgbWFuYWdlcgMJAAAAAAAAAgUAAAAHY2hlY2tQTQUAAAAHY2hlY2tQTQkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACCQEAAAATa2V5TWFuYWdlclB1YmxpY0tleQAAAAAJAAJYAAAAAQkBAAAABXZhbHVlAAAAAQUAAAACcG0JAARMAAAAAgkBAAAAC0RlbGV0ZUVudHJ5AAAAAQkBAAAAGmtleVBlbmRpbmdNYW5hZ2VyUHVibGljS2V5AAAAAAUAAAADbmlsCQAAAgAAAAECAAAAJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAAIAAAABAgAAACRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4AAAABAAAAAnR4AQAAAAZ2ZXJpZnkAAAAABAAAAA90YXJnZXRQdWJsaWNLZXkEAAAAByRtYXRjaDAJAQAAABZtYW5hZ2VyUHVibGljS2V5T3JVbml0AAAAAAMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAKQnl0ZVZlY3RvcgQAAAACcGsFAAAAByRtYXRjaDAFAAAAAnBrAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAARVbml0CAUAAAACdHgAAAAPc2VuZGVyUHVibGljS2V5CQAAAgAAAAECAAAAC01hdGNoIGVycm9yCQAB9AAAAAMIBQAAAAJ0eAAAAAlib2R5Qnl0ZXMJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAUAAAAPdGFyZ2V0UHVibGljS2V5AYzC+A==", "height": 1959082, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: Dw5HPqqhBvepzspaCV3PuvhK4BHpbVxt84H7oiRYqVi8 Next: AjNaNjUcdHNiZL1L5xUPyHMWQFyNkZUC92DJ2drQi1yL Diff:
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 5 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | - | let SEP = "__" | |
5 | - | ||
6 | - | let scale8 = 100000000 | |
7 | - | ||
8 | - | let poolStatsPriceKey = 4 | |
9 | - | ||
10 | - | let idxPoolAddress = 1 | |
11 | - | ||
12 | - | let idxPoolStatus = 2 | |
13 | - | ||
14 | - | let idxPoolLPAssetId = 3 | |
15 | - | ||
16 | - | let idxAmtAssetId = 4 | |
17 | - | ||
18 | - | let idxPriceAssetId = 5 | |
19 | - | ||
20 | - | let idxAmtAssetDcm = 6 | |
21 | - | ||
22 | - | let idxPriceAssetDcm = 7 | |
23 | - | ||
24 | - | let idxIAmtAssetId = 8 | |
25 | - | ||
26 | - | let idxIPriceAssetId = 9 | |
27 | - | ||
28 | - | let idxLPAssetDcm = 10 | |
29 | - | ||
30 | - | let idxMatcherPublicKey = 11 | |
31 | - | ||
32 | - | func keyRegisterPut (poolAddress,txId) = ((("%s%s%s__P__" + poolAddress) + "__") + txId) | |
33 | - | ||
34 | - | ||
35 | - | func keyRegisterInvest (poolAddress,txId) = ((("%s%s%s__invest__" + poolAddress) + "__") + txId) | |
36 | - | ||
37 | - | ||
38 | - | func keyPoolTotalAmtByAsset (poolAddress,assetId) = ((("%s%s%s__total__" + poolAddress) + "__") + assetId) | |
39 | - | ||
40 | - | ||
41 | - | func keyFactoryContract () = "%s__factoryContract" | |
42 | - | ||
43 | - | ||
44 | - | func keySlippageAmtPerAssetCumulative (poolAddress,assetId) = (((("%s%s%s__" + poolAddress) + "__") + assetId) + "__slippageCumulative") | |
45 | - | ||
46 | - | ||
47 | - | func keyFactoryConfig () = "%s__factoryConfig" | |
48 | - | ||
49 | - | ||
50 | - | func keyMappingPoolContractAddressToPoolAssets (poolContractAddress) = (("%s%s%s__" + poolContractAddress) + "__mappings__poolContract2PoolAssets") | |
51 | - | ||
52 | - | ||
53 | - | func keyMappingsInternal2baseAssetId (internalBaseAsset) = ("%s%s%d__mappings__internal2baseAssetId__" + toString(internalBaseAsset)) | |
54 | - | ||
55 | - | ||
56 | - | func keyPoolConfig (iAmtAsset,iPriceAsset) = (((("%d%d%s__" + iAmtAsset) + "__") + iPriceAsset) + "__config") | |
57 | - | ||
58 | - | ||
59 | - | func keyAllPoolsShutdown () = "%s__shutdown" | |
60 | - | ||
61 | - | ||
62 | - | func keyPoolWeight (contractAddress) = ("%s%s__poolWeight__" + contractAddress) | |
63 | - | ||
64 | - | ||
65 | 4 | func keyManagerPublicKey () = "%s__managerPublicKey" | |
66 | 5 | ||
67 | 6 | ||
68 | 7 | func keyPendingManagerPublicKey () = "%s__pendingManagerPublicKey" | |
69 | 8 | ||
70 | 9 | ||
71 | - | let | |
10 | + | let SEP = "__" | |
72 | 11 | ||
73 | - | func convertAssetId (assetId) = if (!(isDefined(assetId))) | |
74 | - | then "WAVES" | |
75 | - | else assetId | |
12 | + | let IdxCfgClaimStartBlock = 1 | |
13 | + | ||
14 | + | let IdxCfgClaimVestingPeriod = 2 | |
15 | + | ||
16 | + | let IdxCfgClaimAssetId = 3 | |
17 | + | ||
18 | + | let IdxCfgClaimAssetMult = 4 | |
19 | + | ||
20 | + | let IdxCfgClaimAssetOwner = 5 | |
21 | + | ||
22 | + | let IdxCfgClaimAssetTotalAmount = 6 | |
23 | + | ||
24 | + | let IdxTotalsTotalClaimedAmount = 1 | |
25 | + | ||
26 | + | let IdxTotalsRemainingAmount = 2 | |
27 | + | ||
28 | + | let IdxTotalsLastClaimedHeight = 3 | |
29 | + | ||
30 | + | func getStringOrFail (key) = valueOrErrorMessage(getString(key), (("mandatory this." + key) + " is not defined")) | |
76 | 31 | ||
77 | 32 | ||
78 | - | func | |
33 | + | func formatConfigString (claimStartBlock,vestingPeriod,assetIdBase58,assetMult,assetOwner,assetTotalAmt) = makeString(["%d%d%s%d%s%d%", claimStartBlock, vestingPeriod, assetIdBase58, assetMult, assetOwner, assetTotalAmt], SEP) | |
79 | 34 | ||
80 | 35 | ||
81 | - | func | |
36 | + | func formatConfig (claimStartBlock,vestingPeriod,assetIdBase58,assetMult,claimAssetOwner,claimAssetTotalAmount) = formatConfigString(toString(claimStartBlock), toString(vestingPeriod), assetIdBase58, toString(assetMult), claimAssetOwner, toString(claimAssetTotalAmount)) | |
82 | 37 | ||
83 | 38 | ||
84 | - | func asString (val) = match val { | |
85 | - | case valStr: String => | |
86 | - | valStr | |
87 | - | case _ => | |
88 | - | throw("fail to cast into String") | |
89 | - | } | |
39 | + | func formatTotalsString (totalClaimedAmount,remainingAmountForClaim,lastClaimedHeight) = makeString(["%d%d%d", totalClaimedAmount, remainingAmountForClaim, lastClaimedHeight], SEP) | |
90 | 40 | ||
91 | 41 | ||
92 | - | func toScale (amt,resScale,curScale) = fraction(amt, resScale, curScale) | |
42 | + | func formatHistoryRecord (claimedAssetAmount,claimingBlocks,firstCalulationBlock,lastCalulationBlock) = makeString(["%d%d%d%d%d%d", toString(height), toString(lastBlock.timestamp), toString(claimedAssetAmount), toString(claimingBlocks), toString(firstCalulationBlock), toString(lastCalulationBlock)], SEP) | |
43 | + | ||
44 | + | ||
45 | + | func keyConfig () = "%s__config" | |
46 | + | ||
47 | + | ||
48 | + | func keyTotals () = "%s__totals" | |
49 | + | ||
50 | + | ||
51 | + | func keyOperationHistoryRecord (type,userAddress,txId58) = makeString(["%s%s%s%s__history", type, userAddress, txId58], SEP) | |
52 | + | ||
53 | + | ||
54 | + | func readConfigArray () = split(getStringOrFail(keyConfig()), SEP) | |
55 | + | ||
56 | + | ||
57 | + | func readTotalsArray () = split(getStringOrFail(keyTotals()), SEP) | |
58 | + | ||
59 | + | ||
60 | + | func TotalsEntry (key,origArray,claimedAmt,newLastClaimedHeight) = { | |
61 | + | let totalClaimedAmount = parseIntValue(origArray[IdxTotalsTotalClaimedAmount]) | |
62 | + | let remainingAmount = parseIntValue(origArray[IdxTotalsRemainingAmount]) | |
63 | + | let lastClaimedHeight = parseIntValue(origArray[IdxTotalsLastClaimedHeight]) | |
64 | + | let newTotalClaimedAmount = (totalClaimedAmount + claimedAmt) | |
65 | + | let newRemainingAmount = (remainingAmount - claimedAmt) | |
66 | + | if ((0 > newRemainingAmount)) | |
67 | + | then throw("invalid math") | |
68 | + | else StringEntry(key, formatTotalsString(toString(newTotalClaimedAmount), toString(newRemainingAmount), toString(newLastClaimedHeight))) | |
69 | + | } | |
70 | + | ||
71 | + | ||
72 | + | func ClaimOperationHistoryEntry (userAddress,claimedAssetAmount,claimingBlocks,firstCalculationBlock,lastCalculationBlock,txId) = StringEntry(keyOperationHistoryRecord("claim", userAddress, toBase58String(txId)), formatHistoryRecord(claimedAssetAmount, claimingBlocks, firstCalculationBlock, lastCalculationBlock)) | |
93 | 73 | ||
94 | 74 | ||
95 | 75 | func managerPublicKeyOrUnit () = match getString(keyManagerPublicKey()) { | |
130 | 110 | ||
131 | 111 | ||
132 | 112 | @Callable(i) | |
133 | - | func constructor (factoryContract) = { | |
134 | - | let checkCaller = mustManager(i) | |
135 | - | if ((checkCaller == checkCaller)) | |
136 | - | then [StringEntry(keyFactoryContract(), factoryContract)] | |
137 | - | else throw("Strict value is not equal to itself.") | |
113 | + | func constructor (claimStartBlock,vestingPeriodBlocks,beneficiaryAddress) = { | |
114 | + | let vestingEnd = (claimStartBlock + vestingPeriodBlocks) | |
115 | + | if (isDefined(getString(keyConfig()))) | |
116 | + | then throw("already initialized") | |
117 | + | else if ((size(i.payments) != 1)) | |
118 | + | then throw("exactly 1 payment must be attached") | |
119 | + | else if (("3N4Aib5iubWiGMzdTh6wWiVDVbo32oeVUmH" != toString(i.caller))) | |
120 | + | then throw("not authorized") | |
121 | + | else { | |
122 | + | let beneficiaryAddressParsed = valueOrErrorMessage(addressFromString(beneficiaryAddress), "Invalid beneficiarAddress passed") | |
123 | + | let pmt = value(i.payments[0]) | |
124 | + | let claimAssetId = value(pmt.assetId) | |
125 | + | let claimAssetInfo = valueOrErrorMessage(assetInfo(claimAssetId), "fail to load ido asset info") | |
126 | + | let claimAssetId58 = toBase58String(claimAssetId) | |
127 | + | let claimAssetMult = pow(10, 0, claimAssetInfo.decimals, 0, 0, DOWN) | |
128 | + | let claimAssetAmount = pmt.amount | |
129 | + | [StringEntry(keyConfig(), formatConfig(claimStartBlock, vestingPeriodBlocks, claimAssetId58, claimAssetMult, toString(beneficiaryAddressParsed), claimAssetAmount)), StringEntry(keyTotals(), formatTotalsString("0", toString(claimAssetAmount), "0"))] | |
130 | + | } | |
138 | 131 | } | |
139 | 132 | ||
140 | 133 | ||
141 | 134 | ||
142 | 135 | @Callable(i) | |
143 | - | func put () = { | |
144 | - | let pool = toString(i.caller) | |
145 | - | let pmtAmtAsset = value(i.payments[0]) | |
146 | - | let pmtAssetId = if (!(isDefined(pmtAmtAsset.assetId))) | |
147 | - | then "WAVES" | |
148 | - | else toBase58String(value(pmtAmtAsset.assetId)) | |
149 | - | let pmtAssetAmt = pmtAmtAsset.amount | |
150 | - | let poolAssets = split(valueOrErrorMessage(getString(factoryContract, keyMappingPoolContractAddressToPoolAssets(pool)), "Invalid caller"), SEP) | |
151 | - | let amountAssetId = parseIntValue(poolAssets[1]) | |
152 | - | let priceAssetId = parseIntValue(poolAssets[2]) | |
153 | - | let amountAsset = valueOrErrorMessage(getString(factoryContract, keyMappingsInternal2baseAssetId(amountAssetId)), "Cannot find asset") | |
154 | - | let priceAsset = valueOrErrorMessage(getString(factoryContract, keyMappingsInternal2baseAssetId(priceAssetId)), "Cannot find asset") | |
155 | - | let totalAmt = valueOrElse(getInteger(this, keyPoolTotalAmtByAsset(pool, pmtAssetId)), 0) | |
156 | - | let cumulativeSlippageAmt = valueOrElse(getInteger(this, keySlippageAmtPerAssetCumulative(pool, pmtAssetId)), 0) | |
157 | - | [StringEntry(keyRegisterPut(pool, toBase58String(i.transactionId)), dataPutActionInfo(pmtAssetId, pmtAssetAmt, height, lastBlock.timestamp)), IntegerEntry(keyPoolTotalAmtByAsset(pool, pmtAssetId), (totalAmt + pmtAssetAmt)), IntegerEntry(keySlippageAmtPerAssetCumulative(pool, pmtAssetId), (cumulativeSlippageAmt + pmtAssetAmt))] | |
158 | - | } | |
159 | - | ||
160 | - | ||
161 | - | ||
162 | - | @Callable(i) | |
163 | - | func invest (poolAddressStr) = { | |
164 | - | let poolAddress = valueOrErrorMessage(addressFromString(poolAddressStr), "invalid pool address") | |
165 | - | let poolAssets = split(valueOrErrorMessage(getString(factoryContract, keyMappingPoolContractAddressToPoolAssets(poolAddressStr)), "Invalid pool passed."), SEP) | |
166 | - | let amId = valueOrErrorMessage(getString(factoryContract, keyMappingsInternal2baseAssetId(parseIntValue(poolAssets[1]))), "No asset mapping found") | |
167 | - | let prId = valueOrErrorMessage(getString(factoryContract, keyMappingsInternal2baseAssetId(parseIntValue(poolAssets[2]))), "No asset mapping found") | |
168 | - | let amBalance = valueOrElse(getInteger(this, keyPoolTotalAmtByAsset(poolAddressStr, amId)), 0) | |
169 | - | let prBalance = valueOrElse(getInteger(this, keyPoolTotalAmtByAsset(poolAddressStr, prId)), 0) | |
170 | - | let estByPrResult = invoke(poolAddress, "evaluatePutByPriceAssetREADONLY", [prBalance], nil) | |
171 | - | let estByAmResult = invoke(poolAddress, "evaluatePutByAmountAssetREADONLY", [amBalance], nil) | |
172 | - | let IdxEstAmAmount = 7 | |
173 | - | let IdxEstPrAmount = 8 | |
174 | - | let estAmAmt = valueOrErrorMessage(parseIntValue(split(asString(estByPrResult), SEP)[IdxEstAmAmount]), "fail to parse estimated amAsset amount") | |
175 | - | let estPrAmt = valueOrErrorMessage(parseIntValue(split(asString(estByAmResult), SEP)[IdxEstPrAmount]), "fail to parse estimated prAsset amount") | |
176 | - | let $t066436744 = if ((amBalance >= estAmAmt)) | |
177 | - | then $Tuple2(estAmAmt, prBalance) | |
178 | - | else $Tuple2(amBalance, estPrAmt) | |
179 | - | let amAmt = $t066436744._1 | |
180 | - | let prAmt = $t066436744._2 | |
181 | - | let amAssetId = if ((amId == "WAVES")) | |
182 | - | then unit | |
183 | - | else fromBase58String(amId) | |
184 | - | let prAssetId = if ((prId == "WAVES")) | |
185 | - | then unit | |
186 | - | else fromBase58String(prId) | |
187 | - | let lpPut = invoke(poolAddress, "putForFree", [1000], [AttachedPayment(amAssetId, amAmt), AttachedPayment(prAssetId, prAmt)]) | |
188 | - | if ((lpPut == lpPut)) | |
189 | - | then [StringEntry(keyRegisterInvest(poolAddressStr, toBase58String(i.transactionId)), dataInvestActionInfo(amAmt, prAmt, height, lastBlock.timestamp)), IntegerEntry(keyPoolTotalAmtByAsset(poolAddressStr, amId), (amBalance - amAmt)), IntegerEntry(keyPoolTotalAmtByAsset(poolAddressStr, prId), (prBalance - prAmt))] | |
190 | - | else throw("Strict value is not equal to itself.") | |
136 | + | func claim () = { | |
137 | + | let cfgArray = readConfigArray() | |
138 | + | let cfgClaimStartHeight = parseIntValue(cfgArray[IdxCfgClaimStartBlock]) | |
139 | + | let cfgClaimDuration = parseIntValue(cfgArray[IdxCfgClaimVestingPeriod]) | |
140 | + | let cfgClaimEnd = (cfgClaimStartHeight + cfgClaimDuration) | |
141 | + | let cfgClaimAssetId58 = cfgArray[IdxCfgClaimAssetId] | |
142 | + | let cfgClaimAssetOwner = cfgArray[IdxCfgClaimAssetOwner] | |
143 | + | let cfgClaimAssetTotalAmount = parseIntValue(cfgArray[IdxCfgClaimAssetTotalAmount]) | |
144 | + | let userAddress = i.caller | |
145 | + | let userAddress58 = toString(userAddress) | |
146 | + | let origTotalsArray = readTotalsArray() | |
147 | + | let totalClaimedAmount = parseIntValue(origTotalsArray[IdxTotalsTotalClaimedAmount]) | |
148 | + | let totalRemainingAmount = parseIntValue(origTotalsArray[IdxTotalsRemainingAmount]) | |
149 | + | let lastClaimedHeight = parseIntValue(origTotalsArray[IdxTotalsLastClaimedHeight]) | |
150 | + | if ((userAddress58 != cfgClaimAssetOwner)) | |
151 | + | then throw("permissions denied") | |
152 | + | else if ((cfgClaimStartHeight > height)) | |
153 | + | then throw(("Wait claim start block: " + toString(cfgClaimStartHeight))) | |
154 | + | else { | |
155 | + | let lastCalulationBlock = if ((height > cfgClaimEnd)) | |
156 | + | then cfgClaimEnd | |
157 | + | else height | |
158 | + | let firstCalulationBlock = if ((lastClaimedHeight == 0)) | |
159 | + | then cfgClaimStartHeight | |
160 | + | else lastClaimedHeight | |
161 | + | let claimingBlocks = (lastCalulationBlock - firstCalulationBlock) | |
162 | + | let claimingAssetAmount = fraction(cfgClaimAssetTotalAmount, claimingBlocks, cfgClaimDuration) | |
163 | + | [ScriptTransfer(userAddress, claimingAssetAmount, fromBase58String(cfgClaimAssetId58)), TotalsEntry(keyTotals(), readTotalsArray(), claimingAssetAmount, lastCalulationBlock), ClaimOperationHistoryEntry(userAddress58, claimingAssetAmount, claimingBlocks, firstCalulationBlock, lastCalulationBlock, i.transactionId)] | |
164 | + | } | |
191 | 165 | } | |
192 | 166 | ||
193 | 167 |
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 5 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | - | let SEP = "__" | |
5 | - | ||
6 | - | let scale8 = 100000000 | |
7 | - | ||
8 | - | let poolStatsPriceKey = 4 | |
9 | - | ||
10 | - | let idxPoolAddress = 1 | |
11 | - | ||
12 | - | let idxPoolStatus = 2 | |
13 | - | ||
14 | - | let idxPoolLPAssetId = 3 | |
15 | - | ||
16 | - | let idxAmtAssetId = 4 | |
17 | - | ||
18 | - | let idxPriceAssetId = 5 | |
19 | - | ||
20 | - | let idxAmtAssetDcm = 6 | |
21 | - | ||
22 | - | let idxPriceAssetDcm = 7 | |
23 | - | ||
24 | - | let idxIAmtAssetId = 8 | |
25 | - | ||
26 | - | let idxIPriceAssetId = 9 | |
27 | - | ||
28 | - | let idxLPAssetDcm = 10 | |
29 | - | ||
30 | - | let idxMatcherPublicKey = 11 | |
31 | - | ||
32 | - | func keyRegisterPut (poolAddress,txId) = ((("%s%s%s__P__" + poolAddress) + "__") + txId) | |
33 | - | ||
34 | - | ||
35 | - | func keyRegisterInvest (poolAddress,txId) = ((("%s%s%s__invest__" + poolAddress) + "__") + txId) | |
36 | - | ||
37 | - | ||
38 | - | func keyPoolTotalAmtByAsset (poolAddress,assetId) = ((("%s%s%s__total__" + poolAddress) + "__") + assetId) | |
39 | - | ||
40 | - | ||
41 | - | func keyFactoryContract () = "%s__factoryContract" | |
42 | - | ||
43 | - | ||
44 | - | func keySlippageAmtPerAssetCumulative (poolAddress,assetId) = (((("%s%s%s__" + poolAddress) + "__") + assetId) + "__slippageCumulative") | |
45 | - | ||
46 | - | ||
47 | - | func keyFactoryConfig () = "%s__factoryConfig" | |
48 | - | ||
49 | - | ||
50 | - | func keyMappingPoolContractAddressToPoolAssets (poolContractAddress) = (("%s%s%s__" + poolContractAddress) + "__mappings__poolContract2PoolAssets") | |
51 | - | ||
52 | - | ||
53 | - | func keyMappingsInternal2baseAssetId (internalBaseAsset) = ("%s%s%d__mappings__internal2baseAssetId__" + toString(internalBaseAsset)) | |
54 | - | ||
55 | - | ||
56 | - | func keyPoolConfig (iAmtAsset,iPriceAsset) = (((("%d%d%s__" + iAmtAsset) + "__") + iPriceAsset) + "__config") | |
57 | - | ||
58 | - | ||
59 | - | func keyAllPoolsShutdown () = "%s__shutdown" | |
60 | - | ||
61 | - | ||
62 | - | func keyPoolWeight (contractAddress) = ("%s%s__poolWeight__" + contractAddress) | |
63 | - | ||
64 | - | ||
65 | 4 | func keyManagerPublicKey () = "%s__managerPublicKey" | |
66 | 5 | ||
67 | 6 | ||
68 | 7 | func keyPendingManagerPublicKey () = "%s__pendingManagerPublicKey" | |
69 | 8 | ||
70 | 9 | ||
71 | - | let | |
10 | + | let SEP = "__" | |
72 | 11 | ||
73 | - | func convertAssetId (assetId) = if (!(isDefined(assetId))) | |
74 | - | then "WAVES" | |
75 | - | else assetId | |
12 | + | let IdxCfgClaimStartBlock = 1 | |
13 | + | ||
14 | + | let IdxCfgClaimVestingPeriod = 2 | |
15 | + | ||
16 | + | let IdxCfgClaimAssetId = 3 | |
17 | + | ||
18 | + | let IdxCfgClaimAssetMult = 4 | |
19 | + | ||
20 | + | let IdxCfgClaimAssetOwner = 5 | |
21 | + | ||
22 | + | let IdxCfgClaimAssetTotalAmount = 6 | |
23 | + | ||
24 | + | let IdxTotalsTotalClaimedAmount = 1 | |
25 | + | ||
26 | + | let IdxTotalsRemainingAmount = 2 | |
27 | + | ||
28 | + | let IdxTotalsLastClaimedHeight = 3 | |
29 | + | ||
30 | + | func getStringOrFail (key) = valueOrErrorMessage(getString(key), (("mandatory this." + key) + " is not defined")) | |
76 | 31 | ||
77 | 32 | ||
78 | - | func | |
33 | + | func formatConfigString (claimStartBlock,vestingPeriod,assetIdBase58,assetMult,assetOwner,assetTotalAmt) = makeString(["%d%d%s%d%s%d%", claimStartBlock, vestingPeriod, assetIdBase58, assetMult, assetOwner, assetTotalAmt], SEP) | |
79 | 34 | ||
80 | 35 | ||
81 | - | func | |
36 | + | func formatConfig (claimStartBlock,vestingPeriod,assetIdBase58,assetMult,claimAssetOwner,claimAssetTotalAmount) = formatConfigString(toString(claimStartBlock), toString(vestingPeriod), assetIdBase58, toString(assetMult), claimAssetOwner, toString(claimAssetTotalAmount)) | |
82 | 37 | ||
83 | 38 | ||
84 | - | func asString (val) = match val { | |
85 | - | case valStr: String => | |
86 | - | valStr | |
87 | - | case _ => | |
88 | - | throw("fail to cast into String") | |
89 | - | } | |
39 | + | func formatTotalsString (totalClaimedAmount,remainingAmountForClaim,lastClaimedHeight) = makeString(["%d%d%d", totalClaimedAmount, remainingAmountForClaim, lastClaimedHeight], SEP) | |
90 | 40 | ||
91 | 41 | ||
92 | - | func toScale (amt,resScale,curScale) = fraction(amt, resScale, curScale) | |
42 | + | func formatHistoryRecord (claimedAssetAmount,claimingBlocks,firstCalulationBlock,lastCalulationBlock) = makeString(["%d%d%d%d%d%d", toString(height), toString(lastBlock.timestamp), toString(claimedAssetAmount), toString(claimingBlocks), toString(firstCalulationBlock), toString(lastCalulationBlock)], SEP) | |
43 | + | ||
44 | + | ||
45 | + | func keyConfig () = "%s__config" | |
46 | + | ||
47 | + | ||
48 | + | func keyTotals () = "%s__totals" | |
49 | + | ||
50 | + | ||
51 | + | func keyOperationHistoryRecord (type,userAddress,txId58) = makeString(["%s%s%s%s__history", type, userAddress, txId58], SEP) | |
52 | + | ||
53 | + | ||
54 | + | func readConfigArray () = split(getStringOrFail(keyConfig()), SEP) | |
55 | + | ||
56 | + | ||
57 | + | func readTotalsArray () = split(getStringOrFail(keyTotals()), SEP) | |
58 | + | ||
59 | + | ||
60 | + | func TotalsEntry (key,origArray,claimedAmt,newLastClaimedHeight) = { | |
61 | + | let totalClaimedAmount = parseIntValue(origArray[IdxTotalsTotalClaimedAmount]) | |
62 | + | let remainingAmount = parseIntValue(origArray[IdxTotalsRemainingAmount]) | |
63 | + | let lastClaimedHeight = parseIntValue(origArray[IdxTotalsLastClaimedHeight]) | |
64 | + | let newTotalClaimedAmount = (totalClaimedAmount + claimedAmt) | |
65 | + | let newRemainingAmount = (remainingAmount - claimedAmt) | |
66 | + | if ((0 > newRemainingAmount)) | |
67 | + | then throw("invalid math") | |
68 | + | else StringEntry(key, formatTotalsString(toString(newTotalClaimedAmount), toString(newRemainingAmount), toString(newLastClaimedHeight))) | |
69 | + | } | |
70 | + | ||
71 | + | ||
72 | + | func ClaimOperationHistoryEntry (userAddress,claimedAssetAmount,claimingBlocks,firstCalculationBlock,lastCalculationBlock,txId) = StringEntry(keyOperationHistoryRecord("claim", userAddress, toBase58String(txId)), formatHistoryRecord(claimedAssetAmount, claimingBlocks, firstCalculationBlock, lastCalculationBlock)) | |
93 | 73 | ||
94 | 74 | ||
95 | 75 | func managerPublicKeyOrUnit () = match getString(keyManagerPublicKey()) { | |
96 | 76 | case s: String => | |
97 | 77 | fromBase58String(s) | |
98 | 78 | case _: Unit => | |
99 | 79 | unit | |
100 | 80 | case _ => | |
101 | 81 | throw("Match error") | |
102 | 82 | } | |
103 | 83 | ||
104 | 84 | ||
105 | 85 | func pendingManagerPublicKeyOrUnit () = match getString(keyPendingManagerPublicKey()) { | |
106 | 86 | case s: String => | |
107 | 87 | fromBase58String(s) | |
108 | 88 | case _: Unit => | |
109 | 89 | unit | |
110 | 90 | case _ => | |
111 | 91 | throw("Match error") | |
112 | 92 | } | |
113 | 93 | ||
114 | 94 | ||
115 | 95 | func mustManager (i) = { | |
116 | 96 | let pd = throw("Permission denied") | |
117 | 97 | match managerPublicKeyOrUnit() { | |
118 | 98 | case pk: ByteVector => | |
119 | 99 | if ((i.callerPublicKey == pk)) | |
120 | 100 | then true | |
121 | 101 | else pd | |
122 | 102 | case _: Unit => | |
123 | 103 | if ((i.caller == this)) | |
124 | 104 | then true | |
125 | 105 | else pd | |
126 | 106 | case _ => | |
127 | 107 | throw("Match error") | |
128 | 108 | } | |
129 | 109 | } | |
130 | 110 | ||
131 | 111 | ||
132 | 112 | @Callable(i) | |
133 | - | func constructor (factoryContract) = { | |
134 | - | let checkCaller = mustManager(i) | |
135 | - | if ((checkCaller == checkCaller)) | |
136 | - | then [StringEntry(keyFactoryContract(), factoryContract)] | |
137 | - | else throw("Strict value is not equal to itself.") | |
113 | + | func constructor (claimStartBlock,vestingPeriodBlocks,beneficiaryAddress) = { | |
114 | + | let vestingEnd = (claimStartBlock + vestingPeriodBlocks) | |
115 | + | if (isDefined(getString(keyConfig()))) | |
116 | + | then throw("already initialized") | |
117 | + | else if ((size(i.payments) != 1)) | |
118 | + | then throw("exactly 1 payment must be attached") | |
119 | + | else if (("3N4Aib5iubWiGMzdTh6wWiVDVbo32oeVUmH" != toString(i.caller))) | |
120 | + | then throw("not authorized") | |
121 | + | else { | |
122 | + | let beneficiaryAddressParsed = valueOrErrorMessage(addressFromString(beneficiaryAddress), "Invalid beneficiarAddress passed") | |
123 | + | let pmt = value(i.payments[0]) | |
124 | + | let claimAssetId = value(pmt.assetId) | |
125 | + | let claimAssetInfo = valueOrErrorMessage(assetInfo(claimAssetId), "fail to load ido asset info") | |
126 | + | let claimAssetId58 = toBase58String(claimAssetId) | |
127 | + | let claimAssetMult = pow(10, 0, claimAssetInfo.decimals, 0, 0, DOWN) | |
128 | + | let claimAssetAmount = pmt.amount | |
129 | + | [StringEntry(keyConfig(), formatConfig(claimStartBlock, vestingPeriodBlocks, claimAssetId58, claimAssetMult, toString(beneficiaryAddressParsed), claimAssetAmount)), StringEntry(keyTotals(), formatTotalsString("0", toString(claimAssetAmount), "0"))] | |
130 | + | } | |
138 | 131 | } | |
139 | 132 | ||
140 | 133 | ||
141 | 134 | ||
142 | 135 | @Callable(i) | |
143 | - | func put () = { | |
144 | - | let pool = toString(i.caller) | |
145 | - | let pmtAmtAsset = value(i.payments[0]) | |
146 | - | let pmtAssetId = if (!(isDefined(pmtAmtAsset.assetId))) | |
147 | - | then "WAVES" | |
148 | - | else toBase58String(value(pmtAmtAsset.assetId)) | |
149 | - | let pmtAssetAmt = pmtAmtAsset.amount | |
150 | - | let poolAssets = split(valueOrErrorMessage(getString(factoryContract, keyMappingPoolContractAddressToPoolAssets(pool)), "Invalid caller"), SEP) | |
151 | - | let amountAssetId = parseIntValue(poolAssets[1]) | |
152 | - | let priceAssetId = parseIntValue(poolAssets[2]) | |
153 | - | let amountAsset = valueOrErrorMessage(getString(factoryContract, keyMappingsInternal2baseAssetId(amountAssetId)), "Cannot find asset") | |
154 | - | let priceAsset = valueOrErrorMessage(getString(factoryContract, keyMappingsInternal2baseAssetId(priceAssetId)), "Cannot find asset") | |
155 | - | let totalAmt = valueOrElse(getInteger(this, keyPoolTotalAmtByAsset(pool, pmtAssetId)), 0) | |
156 | - | let cumulativeSlippageAmt = valueOrElse(getInteger(this, keySlippageAmtPerAssetCumulative(pool, pmtAssetId)), 0) | |
157 | - | [StringEntry(keyRegisterPut(pool, toBase58String(i.transactionId)), dataPutActionInfo(pmtAssetId, pmtAssetAmt, height, lastBlock.timestamp)), IntegerEntry(keyPoolTotalAmtByAsset(pool, pmtAssetId), (totalAmt + pmtAssetAmt)), IntegerEntry(keySlippageAmtPerAssetCumulative(pool, pmtAssetId), (cumulativeSlippageAmt + pmtAssetAmt))] | |
158 | - | } | |
159 | - | ||
160 | - | ||
161 | - | ||
162 | - | @Callable(i) | |
163 | - | func invest (poolAddressStr) = { | |
164 | - | let poolAddress = valueOrErrorMessage(addressFromString(poolAddressStr), "invalid pool address") | |
165 | - | let poolAssets = split(valueOrErrorMessage(getString(factoryContract, keyMappingPoolContractAddressToPoolAssets(poolAddressStr)), "Invalid pool passed."), SEP) | |
166 | - | let amId = valueOrErrorMessage(getString(factoryContract, keyMappingsInternal2baseAssetId(parseIntValue(poolAssets[1]))), "No asset mapping found") | |
167 | - | let prId = valueOrErrorMessage(getString(factoryContract, keyMappingsInternal2baseAssetId(parseIntValue(poolAssets[2]))), "No asset mapping found") | |
168 | - | let amBalance = valueOrElse(getInteger(this, keyPoolTotalAmtByAsset(poolAddressStr, amId)), 0) | |
169 | - | let prBalance = valueOrElse(getInteger(this, keyPoolTotalAmtByAsset(poolAddressStr, prId)), 0) | |
170 | - | let estByPrResult = invoke(poolAddress, "evaluatePutByPriceAssetREADONLY", [prBalance], nil) | |
171 | - | let estByAmResult = invoke(poolAddress, "evaluatePutByAmountAssetREADONLY", [amBalance], nil) | |
172 | - | let IdxEstAmAmount = 7 | |
173 | - | let IdxEstPrAmount = 8 | |
174 | - | let estAmAmt = valueOrErrorMessage(parseIntValue(split(asString(estByPrResult), SEP)[IdxEstAmAmount]), "fail to parse estimated amAsset amount") | |
175 | - | let estPrAmt = valueOrErrorMessage(parseIntValue(split(asString(estByAmResult), SEP)[IdxEstPrAmount]), "fail to parse estimated prAsset amount") | |
176 | - | let $t066436744 = if ((amBalance >= estAmAmt)) | |
177 | - | then $Tuple2(estAmAmt, prBalance) | |
178 | - | else $Tuple2(amBalance, estPrAmt) | |
179 | - | let amAmt = $t066436744._1 | |
180 | - | let prAmt = $t066436744._2 | |
181 | - | let amAssetId = if ((amId == "WAVES")) | |
182 | - | then unit | |
183 | - | else fromBase58String(amId) | |
184 | - | let prAssetId = if ((prId == "WAVES")) | |
185 | - | then unit | |
186 | - | else fromBase58String(prId) | |
187 | - | let lpPut = invoke(poolAddress, "putForFree", [1000], [AttachedPayment(amAssetId, amAmt), AttachedPayment(prAssetId, prAmt)]) | |
188 | - | if ((lpPut == lpPut)) | |
189 | - | then [StringEntry(keyRegisterInvest(poolAddressStr, toBase58String(i.transactionId)), dataInvestActionInfo(amAmt, prAmt, height, lastBlock.timestamp)), IntegerEntry(keyPoolTotalAmtByAsset(poolAddressStr, amId), (amBalance - amAmt)), IntegerEntry(keyPoolTotalAmtByAsset(poolAddressStr, prId), (prBalance - prAmt))] | |
190 | - | else throw("Strict value is not equal to itself.") | |
136 | + | func claim () = { | |
137 | + | let cfgArray = readConfigArray() | |
138 | + | let cfgClaimStartHeight = parseIntValue(cfgArray[IdxCfgClaimStartBlock]) | |
139 | + | let cfgClaimDuration = parseIntValue(cfgArray[IdxCfgClaimVestingPeriod]) | |
140 | + | let cfgClaimEnd = (cfgClaimStartHeight + cfgClaimDuration) | |
141 | + | let cfgClaimAssetId58 = cfgArray[IdxCfgClaimAssetId] | |
142 | + | let cfgClaimAssetOwner = cfgArray[IdxCfgClaimAssetOwner] | |
143 | + | let cfgClaimAssetTotalAmount = parseIntValue(cfgArray[IdxCfgClaimAssetTotalAmount]) | |
144 | + | let userAddress = i.caller | |
145 | + | let userAddress58 = toString(userAddress) | |
146 | + | let origTotalsArray = readTotalsArray() | |
147 | + | let totalClaimedAmount = parseIntValue(origTotalsArray[IdxTotalsTotalClaimedAmount]) | |
148 | + | let totalRemainingAmount = parseIntValue(origTotalsArray[IdxTotalsRemainingAmount]) | |
149 | + | let lastClaimedHeight = parseIntValue(origTotalsArray[IdxTotalsLastClaimedHeight]) | |
150 | + | if ((userAddress58 != cfgClaimAssetOwner)) | |
151 | + | then throw("permissions denied") | |
152 | + | else if ((cfgClaimStartHeight > height)) | |
153 | + | then throw(("Wait claim start block: " + toString(cfgClaimStartHeight))) | |
154 | + | else { | |
155 | + | let lastCalulationBlock = if ((height > cfgClaimEnd)) | |
156 | + | then cfgClaimEnd | |
157 | + | else height | |
158 | + | let firstCalulationBlock = if ((lastClaimedHeight == 0)) | |
159 | + | then cfgClaimStartHeight | |
160 | + | else lastClaimedHeight | |
161 | + | let claimingBlocks = (lastCalulationBlock - firstCalulationBlock) | |
162 | + | let claimingAssetAmount = fraction(cfgClaimAssetTotalAmount, claimingBlocks, cfgClaimDuration) | |
163 | + | [ScriptTransfer(userAddress, claimingAssetAmount, fromBase58String(cfgClaimAssetId58)), TotalsEntry(keyTotals(), readTotalsArray(), claimingAssetAmount, lastCalulationBlock), ClaimOperationHistoryEntry(userAddress58, claimingAssetAmount, claimingBlocks, firstCalulationBlock, lastCalulationBlock, i.transactionId)] | |
164 | + | } | |
191 | 165 | } | |
192 | 166 | ||
193 | 167 | ||
194 | 168 | ||
195 | 169 | @Callable(i) | |
196 | 170 | func setManager (pendingManagerPublicKey) = { | |
197 | 171 | let checkCaller = mustManager(i) | |
198 | 172 | if ((checkCaller == checkCaller)) | |
199 | 173 | then { | |
200 | 174 | let checkManagerPublicKey = fromBase58String(pendingManagerPublicKey) | |
201 | 175 | if ((checkManagerPublicKey == checkManagerPublicKey)) | |
202 | 176 | then [StringEntry(keyPendingManagerPublicKey(), pendingManagerPublicKey)] | |
203 | 177 | else throw("Strict value is not equal to itself.") | |
204 | 178 | } | |
205 | 179 | else throw("Strict value is not equal to itself.") | |
206 | 180 | } | |
207 | 181 | ||
208 | 182 | ||
209 | 183 | ||
210 | 184 | @Callable(i) | |
211 | 185 | func confirmManager () = { | |
212 | 186 | let pm = pendingManagerPublicKeyOrUnit() | |
213 | 187 | let hasPM = if (isDefined(pm)) | |
214 | 188 | then true | |
215 | 189 | else throw("No pending manager") | |
216 | 190 | if ((hasPM == hasPM)) | |
217 | 191 | then { | |
218 | 192 | let checkPM = if ((i.callerPublicKey == value(pm))) | |
219 | 193 | then true | |
220 | 194 | else throw("You are not pending manager") | |
221 | 195 | if ((checkPM == checkPM)) | |
222 | 196 | then [StringEntry(keyManagerPublicKey(), toBase58String(value(pm))), DeleteEntry(keyPendingManagerPublicKey())] | |
223 | 197 | else throw("Strict value is not equal to itself.") | |
224 | 198 | } | |
225 | 199 | else throw("Strict value is not equal to itself.") | |
226 | 200 | } | |
227 | 201 | ||
228 | 202 | ||
229 | 203 | @Verifier(tx) | |
230 | 204 | func verify () = { | |
231 | 205 | let targetPublicKey = match managerPublicKeyOrUnit() { | |
232 | 206 | case pk: ByteVector => | |
233 | 207 | pk | |
234 | 208 | case _: Unit => | |
235 | 209 | tx.senderPublicKey | |
236 | 210 | case _ => | |
237 | 211 | throw("Match error") | |
238 | 212 | } | |
239 | 213 | sigVerify(tx.bodyBytes, tx.proofs[0], targetPublicKey) | |
240 | 214 | } | |
241 | 215 |
github/deemru/w8io/026f985 53.69 ms ◑