tx · D5dPMa5Sz2QcHQrn5piwiHR2YZkjh1MZbUJt5MG5gath 3N3irEKCdj77h97aEbfj3fa3uMXCNCXVhKt: -0.01200000 Waves 2023.12.11 09:53 [2881703] smart account 3N3irEKCdj77h97aEbfj3fa3uMXCNCXVhKt > SELF 0.00000000 Waves
{ "type": 13, "id": "D5dPMa5Sz2QcHQrn5piwiHR2YZkjh1MZbUJt5MG5gath", "fee": 1200000, "feeAssetId": null, "timestamp": 1702277624189, "version": 1, "sender": "3N3irEKCdj77h97aEbfj3fa3uMXCNCXVhKt", "senderPublicKey": "FACNGaFYnR8yFbQFg9sRBpzGVCyzMyLeVw3JMhGQT1wn", "proofs": [ "2QAC5bFUq7e2s5JbnBCNhFPWieNVfmkFkqwXP2UDd5aNNypNvp5iVhh3JSekaX8C5Y73EsJtukMYLC5hhEaAQrEk" ], "script": "base64:BgIWCAISBAoCCAESBQoDGBEBEgMKAQgSAC8ADGNvbnRyYWN0RmlsZQIRbDJtcF9zdGFraW5nLnJpZGUAA1NFUAICX18ABnNjYWxlOACAwtcvAAdzY2FsZTE4AICAkLu61q3wDQANc2NhbGUxOEJpZ0ludAkAtgIBBQdzY2FsZTE4ABJBRERSRVNTX0JZVEVTX1NJWkUAGgANQkxPQ0tTX0lOX0RBWQCgCwEIdGhyb3dFcnIBA21zZwkAAgEJAKwCAgkArAICBQxjb250cmFjdEZpbGUCAjogBQNtc2cACmtleUFzc2V0SWQJALkJAgkAzAgCAgIlcwkAzAgCAgdhc3NldElkBQNuaWwFA1NFUAATa2V5RW1pc3Npb25QZXJCbG9jawkAuQkCCQDMCAICAiVzCQDMCAICEGVtaXNzaW9uUGVyQmxvY2sFA25pbAUDU0VQABlrZXlFbWlzc2lvblBlcmlvZEluQmxvY2tzCQC5CQIJAMwIAgICJXMJAMwIAgIWZW1pc3Npb25QZXJpb2RJbkJsb2NrcwUDbmlsBQNTRVAADWtleVN0YXJ0QmxvY2sJALkJAgkAzAgCAgIlcwkAzAgCAgpzdGFydEJsb2NrBQNuaWwFA1NFUAAQa2V5VG90YWxMcEFtb3VudAkAuQkCCQDMCAICAiVzCQDMCAICDXRvdGFsTHBBbW91bnQFA25pbAUDU0VQABNrZXlUb3RhbEFzc2V0QW1vdW50CQC5CQIJAMwIAgICJXMJAMwIAgIQdG90YWxBc3NldEFtb3VudAUDbmlsBQNTRVAAFmtleVRvdGFsTG9ja2VkTHBBbW91bnQJALkJAgkAzAgCAgIlcwkAzAgCAhN0b3RhbExvY2tlZExwQW1vdW50BQNuaWwFA1NFUAEPa2V5VXNlckxwQW1vdW50AQt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBCVzJXMJAMwIAgIMdXNlckxwQW1vdW50CQDMCAIFC3VzZXJBZGRyZXNzBQNuaWwFA1NFUAEVa2V5VXNlckxvY2tlZExwQW1vdW50AQt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBCVzJXMJAMwIAgISdXNlckxvY2tlZExwQW1vdW50CQDMCAIFC3VzZXJBZGRyZXNzBQNuaWwFA1NFUAETa2V5VXNlclN0YWtpbmdOb2RlcwELdXNlckFkZHJlc3MJALkJAgkAzAgCAgQlcyVzCQDMCAICEHVzZXJTdGFraW5nTm9kZXMJAMwIAgULdXNlckFkZHJlc3MFA25pbAUDU0VQARlrZXlVc2VyU3Rha2luZ05vZGVzU2hhcmVzAQt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBCVzJXMJAMwIAgIWdXNlclN0YWtpbmdOb2Rlc1NoYXJlcwkAzAgCBQt1c2VyQWRkcmVzcwUDbmlsBQNTRVABGmtleVVzZXJUb3RhbEFzc2V0V2l0aGRyYXduAQt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBCVzJXMJAMwIAgITdG90YWxBc3NldFdpdGhkcmF3bgkAzAgCBQt1c2VyQWRkcmVzcwUDbmlsBQNTRVABF2tleVVzZXJUb3RhbEFzc2V0U3Rha2VkAQt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBCVzJXMJAMwIAgIQdG90YWxBc3NldFN0YWtlZAkAzAgCBQt1c2VyQWRkcmVzcwUDbmlsBQNTRVABCmtleUhpc3RvcnkDBHR5cGULdXNlckFkZHJlc3MEdHhJZAkAuQkCCQDMCAICBiVzJXMlcwkAzAgCBQR0eXBlCQDMCAIFC3VzZXJBZGRyZXNzCQDMCAIJANgEAQUEdHhJZAUDbmlsBQNTRVABDWZvcm1hdEhpc3RvcnkEC3RvdGFsUHJvZml0BXByaWNlEHRvdGFsQXNzZXRBbW91bnQNdG90YWxMcEFtb3VudAkAuQkCCQDMCAICCCVkJWQlZCVkCQDMCAIJAKQDAQULdG90YWxQcm9maXQJAMwIAgkApgMBBQVwcmljZQkAzAgCCQCkAwEFEHRvdGFsQXNzZXRBbW91bnQJAMwIAgkApAMBBQ10b3RhbExwQW1vdW50BQNuaWwFA1NFUAANdG90YWxMcEFtb3VudAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBRBrZXlUb3RhbExwQW1vdW50AAAAEHRvdGFsQXNzZXRBbW91bnQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwUTa2V5VG90YWxBc3NldEFtb3VudAAAABN0b3RhbExvY2tlZExwQW1vdW50CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFFmtleVRvdGFsTG9ja2VkTHBBbW91bnQAAAANYXNzZXRJZFN0cmluZwkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzBQprZXlBc3NldElkAgVXQVZFUwAMYXNzZXRJZEJ5dGVzAwkAAAIFDWFzc2V0SWRTdHJpbmcCBVdBVkVTBQR1bml0CQDZBAEFDWFzc2V0SWRTdHJpbmcAFmVtaXNzaW9uUGVyaW9kSW5CbG9ja3MJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwUZa2V5RW1pc3Npb25QZXJpb2RJbkJsb2NrcwUNQkxPQ0tTX0lOX0RBWQAQZW1pc3Npb25QZXJCbG9jawkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBRNrZXlFbWlzc2lvblBlckJsb2NrAAAAEWVtaXNzaW9uUGVyUGVyaW9kCQBoAgUQZW1pc3Npb25QZXJCbG9jawUWZW1pc3Npb25QZXJpb2RJbkJsb2NrcwEZc3RyaW5nTGlzdFRvSW50TGlzdEhlbHBlcgIDYWNjBXZhbHVlCQDNCAIFA2FjYwkBDXBhcnNlSW50VmFsdWUBBQV2YWx1ZQEYY2FsY1RvdGFsUHJvZml0Rm9ySGVpZ2h0AQFoBApzdGFydEJsb2NrCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFDWtleVN0YXJ0QmxvY2sFBmhlaWdodAQLc3RhcnRQZXJpb2QJAGsDBQpzdGFydEJsb2NrAAEFFmVtaXNzaW9uUGVyaW9kSW5CbG9ja3MEDmVsYXBzZWRQZXJpb2RzCQBlAgkAaQIFAWgFFmVtaXNzaW9uUGVyaW9kSW5CbG9ja3MFC3N0YXJ0UGVyaW9kCQCWAwEJAMwIAgAACQDMCAIJAGgCBRFlbWlzc2lvblBlclBlcmlvZAUOZWxhcHNlZFBlcmlvZHMFA25pbAEPY2FsY1RvdGFsUHJvZml0AAkBGGNhbGNUb3RhbFByb2ZpdEZvckhlaWdodAEFBmhlaWdodAEUZ2V0TWF4QXNzZXRBdmFpbGFibGUABAckbWF0Y2gwBQxhc3NldElkQnl0ZXMDCQABAgUHJG1hdGNoMAIEVW5pdAQBdQUHJG1hdGNoMAgJAO8HAQUEdGhpcwlhdmFpbGFibGUDCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQBYgUHJG1hdGNoMAkA8AcCBQR0aGlzBQFiCQACAQILTWF0Y2ggZXJyb3IBK2dldFRvdGFsQXNzZXRBbW91bnRXaXRoUHJvZml0T3JNYXhBdmFpbGFibGUBCGF0SGVpZ2h0BBp0b3RhbEFzc2V0QW1vdW50V2l0aFByb2ZpdAkAZAIFEHRvdGFsQXNzZXRBbW91bnQJARhjYWxjVG90YWxQcm9maXRGb3JIZWlnaHQBBQhhdEhlaWdodAQLdG90YWxBbW91bnQJAJcDAQkAzAgCBRp0b3RhbEFzc2V0QW1vdW50V2l0aFByb2ZpdAkAzAgCCQEUZ2V0TWF4QXNzZXRBdmFpbGFibGUABQNuaWwDCQAAAgUNdG90YWxMcEFtb3VudAAAAAAFC3RvdGFsQW1vdW50ARBnZXRQcmljZUF0SGVpZ2h0AQFoAwkBAiE9AgUNdG90YWxMcEFtb3VudAAACQC8AgMJALYCAQkBK2dldFRvdGFsQXNzZXRBbW91bnRXaXRoUHJvZml0T3JNYXhBdmFpbGFibGUBBQFoBQ1zY2FsZTE4QmlnSW50CQC2AgEFDXRvdGFsTHBBbW91bnQFDXNjYWxlMThCaWdJbnQBD2dldEN1cnJlbnRQcmljZQAJARBnZXRQcmljZUF0SGVpZ2h0AQUGaGVpZ2h0ARJnZXRSZW1haW5pbmdCbG9ja3MAAwkAAAIFEGVtaXNzaW9uUGVyQmxvY2sAAAAACQBrAwkAZQIJARRnZXRNYXhBc3NldEF2YWlsYWJsZQAJAStnZXRUb3RhbEFzc2V0QW1vdW50V2l0aFByb2ZpdE9yTWF4QXZhaWxhYmxlAQUGaGVpZ2h0AAEFEGVtaXNzaW9uUGVyQmxvY2sBF2dldFVzZXJTdGFraW5nTm9kZXNEYXRhAQt1c2VyQWRkcmVzcwQIbm9kZXNSYXcJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwkBE2tleVVzZXJTdGFraW5nTm9kZXMBBQt1c2VyQWRkcmVzcwIABAlzaGFyZXNSYXcJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwkBGWtleVVzZXJTdGFraW5nTm9kZXNTaGFyZXMBBQt1c2VyQWRkcmVzcwIABAlub2Rlc0xpc3QDCQAAAgUIbm9kZXNSYXcCAAUDbmlsCQC1CQIFCG5vZGVzUmF3BQNTRVAEEHNoYXJlc1N0cmluZ0xpc3QDCQAAAgUJc2hhcmVzUmF3AgAFA25pbAkAtQkCBQlzaGFyZXNSYXcFA1NFUAQKc2hhcmVzTGlzdAoAAiRsBRBzaGFyZXNTdHJpbmdMaXN0CgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARlzdHJpbmdMaXN0VG9JbnRMaXN0SGVscGVyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAyMAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQJAJQKAgUJbm9kZXNMaXN0BQpzaGFyZXNMaXN0AQ9jYWxjQXNzZXRGcm9tTHACCGxwQW1vdW50CGF0SGVpZ2h0CQCWAwEJAMwIAgAACQDMCAIJAKADAQkAvAIDCQC2AgEFCGxwQW1vdW50CQEQZ2V0UHJpY2VBdEhlaWdodAEFCGF0SGVpZ2h0BQ1zY2FsZTE4QmlnSW50BQNuaWwBD2NhbGNMcEZyb21Bc3NldAILYXNzZXRBbW91bnQIYXRIZWlnaHQJAJYDAQkAzAgCAAAJAMwIAgkAoAMBCQC8AgMJALYCAQULYXNzZXRBbW91bnQFDXNjYWxlMThCaWdJbnQJARBnZXRQcmljZUF0SGVpZ2h0AQUIYXRIZWlnaHQFA25pbAEPZ2V0VXNlckxwQW1vdW50AQt1c2VyQWRkcmVzcwkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEPa2V5VXNlckxwQW1vdW50AQULdXNlckFkZHJlc3MAAAEVZ2V0VXNlckxvY2tlZExwQW1vdW50AQt1c2VyQWRkcmVzcwkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEVa2V5VXNlckxvY2tlZExwQW1vdW50AQULdXNlckFkZHJlc3MAAAEgZ2V0VXNlckF2YWlsYWJsZUFzc2V0c1RvV2l0aGRyYXcBC3VzZXJBZGRyZXNzBAx1c2VyTHBBbW91bnQJAQ9nZXRVc2VyTHBBbW91bnQBBQt1c2VyQWRkcmVzcwkBD2NhbGNBc3NldEZyb21McAIFDHVzZXJMcEFtb3VudAUGaGVpZ2h0ARtnZXRDbGVhclN0YWtpbmdOb2Rlc0FjdGlvbnMBC3VzZXJBZGRyZXNzCQDMCAIJAQtEZWxldGVFbnRyeQEJARNrZXlVc2VyU3Rha2luZ05vZGVzAQULdXNlckFkZHJlc3MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBGWtleVVzZXJTdGFraW5nTm9kZXNTaGFyZXMBBQt1c2VyQWRkcmVzcwUDbmlsAQ9nZXRTdGFrZUFjdGlvbnMDAWkLdXNlckFkZHJlc3MLc3Rha2VIZWlnaHQEBmNoZWNrcwkAzAgCAwkAAAIJAJADAQgFAWkIcGF5bWVudHMAAQYJAQh0aHJvd0VycgECGHNob3VsZCBpbmNsdWRlIDEgcGF5bWVudAkAzAgCAwkAAAIICQCRAwIIBQFpCHBheW1lbnRzAAAHYXNzZXRJZAUMYXNzZXRJZEJ5dGVzBgkBCHRocm93RXJyAQkArAICAhVwYXltZW50IHNob3VsZCBiZSBpbiAFDWFzc2V0SWRTdHJpbmcJAMwIAgMJAGYCCAkAkQMCCAUBaQhwYXltZW50cwAABmFtb3VudAAABgIncGF5bWVudCBhbW91bnQgc2hvdWxkIGJlIGdyZWF0ZXIgdGhhbiAwCQDMCAIDCQAAAgkAyAEBCQDZBAEFC3VzZXJBZGRyZXNzBRJBRERSRVNTX0JZVEVTX1NJWkUGCQEIdGhyb3dFcnIBAhl1c2VyIGFkZHJlc3MgaXMgbm90IHZhbGlkBQNuaWwDCQAAAgUGY2hlY2tzBQZjaGVja3MEDXBheW1lbnRBbW91bnQICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50BA9wYXltZW50THBBbW91bnQJAQ9jYWxjTHBGcm9tQXNzZXQCBQ1wYXltZW50QW1vdW50BQtzdGFrZUhlaWdodAQMdXNlckxwQW1vdW50CQEPZ2V0VXNlckxwQW1vdW50AQULdXNlckFkZHJlc3MEFXVzZXJUb3RhbFN0YWtlZEFtb3VudAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEXa2V5VXNlclRvdGFsQXNzZXRTdGFrZWQBBQt1c2VyQWRkcmVzcwAABBBuZXdUb3RhbExwQW1vdW50CQBkAgUNdG90YWxMcEFtb3VudAUPcGF5bWVudExwQW1vdW50BBNuZXdUb3RhbEFzc2V0QW1vdW50CQEPY2FsY0Fzc2V0RnJvbUxwAgUQbmV3VG90YWxMcEFtb3VudAULc3Rha2VIZWlnaHQED25ld1VzZXJMcEFtb3VudAkAZAIFDHVzZXJMcEFtb3VudAUPcGF5bWVudExwQW1vdW50BBhuZXdVc2VyVG90YWxTdGFrZWRBbW91bnQJAGQCBRV1c2VyVG90YWxTdGFrZWRBbW91bnQFDXBheW1lbnRBbW91bnQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBCmtleUhpc3RvcnkDAgVzdGFrZQULdXNlckFkZHJlc3MIBQFpDXRyYW5zYWN0aW9uSWQJAQ1mb3JtYXRIaXN0b3J5BAkBD2NhbGNUb3RhbFByb2ZpdAAJAQ9nZXRDdXJyZW50UHJpY2UABQ10b3RhbExwQW1vdW50BRB0b3RhbEFzc2V0QW1vdW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCBRBrZXlUb3RhbExwQW1vdW50BRBuZXdUb3RhbExwQW1vdW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCBRNrZXlUb3RhbEFzc2V0QW1vdW50BRNuZXdUb3RhbEFzc2V0QW1vdW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEPa2V5VXNlckxwQW1vdW50AQULdXNlckFkZHJlc3MFD25ld1VzZXJMcEFtb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBF2tleVVzZXJUb3RhbEFzc2V0U3Rha2VkAQULdXNlckFkZHJlc3MFGG5ld1VzZXJUb3RhbFN0YWtlZEFtb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgUNa2V5U3RhcnRCbG9jawUGaGVpZ2h0BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4EAWkBDXN0YWtlRm9yQWRtaW4CC3VzZXJBZGRyZXNzC3N0YWtlSGVpZ2h0BAVjaGVjawkAzAgCAwkAAAIIBQFpBmNhbGxlcgUEdGhpcwYJAQh0aHJvd0VycgECEXBlcm1pc3Npb24gZGVuaWVkBQNuaWwDCQAAAgUFY2hlY2sFBWNoZWNrCQEPZ2V0U3Rha2VBY3Rpb25zAwUBaQULdXNlckFkZHJlc3MFC3N0YWtlSGVpZ2h0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBB2FpcmRyb3ADC2FkZHJlc3NMaXN0CmFtb3VudExpc3QNYWlyZHJvcEhlaWdodAoBA3N1bQIFYWNjdW0EbmV4dAMJAGYCAAAFBG5leHQJAQh0aHJvd0VycgECI25lZ2F0aXZlIGFtb3VudCB2YWx1ZSBpbiBhbW91bnRMaXN0CQBkAgUFYWNjdW0FBG5leHQEDWFtb3VudExpc3RTdW0KAAIkbAUKYW1vdW50TGlzdAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAAAAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEDc3VtAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyA5MAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgQFY2hlY2sJAMwIAgMJAAACCAUBaQZjYWxsZXIFBHRoaXMGCQEIdGhyb3dFcnIBAhFwZXJtaXNzaW9uIGRlbmllZAkAzAgCAwkAAAIJAJADAQgFAWkIcGF5bWVudHMAAQYJAQh0aHJvd0VycgECGHNob3VsZCBpbmNsdWRlIDEgcGF5bWVudAkAzAgCAwkAAAIICQCRAwIIBQFpCHBheW1lbnRzAAAHYXNzZXRJZAUMYXNzZXRJZEJ5dGVzBgkBCHRocm93RXJyAQkArAICAhVwYXltZW50IHNob3VsZCBiZSBpbiAFDWFzc2V0SWRTdHJpbmcJAMwIAgMJAGYCCAkAkQMCCAUBaQhwYXltZW50cwAABmFtb3VudAAABgIncGF5bWVudCBhbW91bnQgc2hvdWxkIGJlIGdyZWF0ZXIgdGhhbiAwCQDMCAIDCQAAAgkAkAMBBQthZGRyZXNzTGlzdAkAkAMBBQphbW91bnRMaXN0BgkBCHRocm93RXJyAQItYWRkcmVzc0xpc3Qgc2hvdWxkIGJlIHNhbWUgc2l6ZSBhcyBhbW91bnRMaXN0CQDMCAIDCQBnAggJAJEDAggFAWkIcGF5bWVudHMAAAZhbW91bnQFDWFtb3VudExpc3RTdW0GCQEIdGhyb3dFcnIBAi1wYXltZW50IGFtb3VudCBpcyBsZXNzIHRoYW4gc3VtIG9mIGFtb3VudExpc3QFA25pbAMJAAACBQVjaGVjawUFY2hlY2sKARZnZXRBaXJkcm9wU3RhdGVDaGFuZ2VzAgVhY2N1bQthc3NldEFtb3VudAQLJHQwODE3MDgyMjEFBWFjY3VtBAZyZXN1bHQIBQskdDA4MTcwODIyMQJfMQQFaW5kZXgIBQskdDA4MTcwODIyMQJfMgQHdG90YWxMcAgFCyR0MDgxNzA4MjIxAl8zBA1wcm9jZXNzZWRMaXN0CAULJHQwODE3MDgyMjECXzQEDWFkZHJlc3NTdHJpbmcJAJEDAgULYWRkcmVzc0xpc3QFBWluZGV4BAdhZGRyZXNzBAckbWF0Y2gwCQCmCAEFDWFkZHJlc3NTdHJpbmcDCQABAgUHJG1hdGNoMAIHQWRkcmVzcwQDYWRyBQckbWF0Y2gwBQNhZHIJAQh0aHJvd0VycgECHmludmFsaWQgYWRkcmVzcyBpbiBhZGRyZXNzTGlzdAQCY2gJAMwIAgMJAQEhAQkBD2NvbnRhaW5zRWxlbWVudAIFDXByb2Nlc3NlZExpc3QFB2FkZHJlc3MGCQEIdGhyb3dFcnIBAiBkdXBsaWNhdGUgYWRkcmVzcyBpcyBhZGRyZXNzTGlzdAUDbmlsAwkAAAIFAmNoBQJjaAQNYWRkZWRMcEFtb3VudAkBD2NhbGNMcEZyb21Bc3NldAIFC2Fzc2V0QW1vdW50BQ1haXJkcm9wSGVpZ2h0BA91c2VyTG9ja2VkTHBLZXkJARVrZXlVc2VyTG9ja2VkTHBBbW91bnQBBQ1hZGRyZXNzU3RyaW5nBAtvbGRMcEFtb3VudAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQ91c2VyTG9ja2VkTHBLZXkAAAkAlgoECQDNCAIFBnJlc3VsdAkBDEludGVnZXJFbnRyeQIFD3VzZXJMb2NrZWRMcEtleQkAZAIFC29sZExwQW1vdW50BQ1hZGRlZExwQW1vdW50CQBkAgUFaW5kZXgAAQkAZAIFB3RvdGFsTHAFDWFkZGVkTHBBbW91bnQJAM0IAgUNcHJvY2Vzc2VkTGlzdAUHYWRkcmVzcwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgQLJHQwOTAwMDkxMTcKAAIkbAUKYW1vdW50TGlzdAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAJAJYKBAUDbmlsAAAAAAUDbmlsCgEFJGYxXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARZnZXRBaXJkcm9wU3RhdGVDaGFuZ2VzAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYxXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyA5MAkBBSRmMV8yAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgkBBSRmMV8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgQOYWlyZHJvcEVudHJpZXMIBQskdDA5MDAwOTExNwJfMQQCX2EIBQskdDA5MDAwOTExNwJfMgQYYWRkZWRUb3RhbExvY2tlZExwQW1vdW50CAULJHQwOTAwMDkxMTcCXzMEAl9iCAULJHQwOTAwMDkxMTcCXzQEDW5ld1RvdGFsQXNzZXQJAQ9jYWxjQXNzZXRGcm9tTHACCQBkAgUNdG90YWxMcEFtb3VudAUYYWRkZWRUb3RhbExvY2tlZExwQW1vdW50BQ1haXJkcm9wSGVpZ2h0CQDOCAIJAMwIAgkBDEludGVnZXJFbnRyeQIFFmtleVRvdGFsTG9ja2VkTHBBbW91bnQJAGQCBRN0b3RhbExvY2tlZExwQW1vdW50BRhhZGRlZFRvdGFsTG9ja2VkTHBBbW91bnQJAMwIAgkBDEludGVnZXJFbnRyeQIFEGtleVRvdGFsTHBBbW91bnQJAGQCBQ10b3RhbExwQW1vdW50BRhhZGRlZFRvdGFsTG9ja2VkTHBBbW91bnQJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tleVRvdGFsQXNzZXRBbW91bnQFDW5ld1RvdGFsQXNzZXQJAMwIAgkBDEludGVnZXJFbnRyeQIFDWtleVN0YXJ0QmxvY2sFBmhlaWdodAUDbmlsBQ5haXJkcm9wRW50cmllcwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARVnZXRVc2VyQXNzZXRzUkVBRE9OTFkBC3VzZXJBZGRyZXNzBAx1c2VyTHBBbW91bnQJAQ9nZXRVc2VyTHBBbW91bnQBBQt1c2VyQWRkcmVzcwQSdXNlckxvY2tlZExwQW1vdW50CQEVZ2V0VXNlckxvY2tlZExwQW1vdW50AQULdXNlckFkZHJlc3MEFXVzZXJMb2NrZWRBc3NldEFtb3VudAkBD2NhbGNBc3NldEZyb21McAIFEnVzZXJMb2NrZWRMcEFtb3VudAUGaGVpZ2h0BBx1c2VyQXZhaWxhYmxlQXNzZXRUb1dpdGhkcmF3CQEgZ2V0VXNlckF2YWlsYWJsZUFzc2V0c1RvV2l0aGRyYXcBBQt1c2VyQWRkcmVzcwQVdXNlclRvdGFsU3Rha2VkQW1vdW50CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJARdrZXlVc2VyVG90YWxBc3NldFN0YWtlZAEFC3VzZXJBZGRyZXNzAAAEF3VzZXJUb3RhbEFzc2V0V2l0aGRyYXduCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJARprZXlVc2VyVG90YWxBc3NldFdpdGhkcmF3bgEFC3VzZXJBZGRyZXNzAAAEDSR0MDEwNDkwMTA1ODIJARdnZXRVc2VyU3Rha2luZ05vZGVzRGF0YQEFC3VzZXJBZGRyZXNzBBR1c2VyU3Rha2luZ05vZGVzTGlzdAgFDSR0MDEwNDkwMTA1ODICXzEEGXVzZXJTdGFraW5nTm9kZVNoYXJlc0xpc3QIBQ0kdDAxMDQ5MDEwNTgyAl8yCQCUCgIFA25pbAkAnAoKBQx1c2VyTHBBbW91bnQFHHVzZXJBdmFpbGFibGVBc3NldFRvV2l0aGRyYXcJAQ9nZXRDdXJyZW50UHJpY2UABRV1c2VyVG90YWxTdGFrZWRBbW91bnQFF3VzZXJUb3RhbEFzc2V0V2l0aGRyYXduBRJ1c2VyTG9ja2VkTHBBbW91bnQFFXVzZXJMb2NrZWRBc3NldEFtb3VudAUUdXNlclN0YWtpbmdOb2Rlc0xpc3QFGXVzZXJTdGFraW5nTm9kZVNoYXJlc0xpc3QJARJnZXRSZW1haW5pbmdCbG9ja3MAAWkBFmdldFRvdGFsQXNzZXRzUkVBRE9OTFkACQCUCgIFA25pbAkAmAoGBQ10b3RhbExwQW1vdW50CQErZ2V0VG90YWxBc3NldEFtb3VudFdpdGhQcm9maXRPck1heEF2YWlsYWJsZQEFBmhlaWdodAkBD2dldEN1cnJlbnRQcmljZQAFE3RvdGFsTG9ja2VkTHBBbW91bnQJAQ9jYWxjQXNzZXRGcm9tTHACBRN0b3RhbExvY2tlZExwQW1vdW50BQZoZWlnaHQJARJnZXRSZW1haW5pbmdCbG9ja3MAAOVYDts=", "chainId": 84, "height": 2881703, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: FNXT4xp1TdUQa5rtbNEocEEGXN1NDnkj5fSXyhD2zUk5 Next: Hq2jw7mQaM9AKWTJ8tdbXiGETFKmrbGH7GJNMr3cuhiX Diff:
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 6 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | - | let contractFile = " | |
4 | + | let contractFile = "l2mp_staking.ride" | |
5 | 5 | ||
6 | - | let | |
6 | + | let SEP = "__" | |
7 | 7 | ||
8 | - | let | |
8 | + | let scale8 = 100000000 | |
9 | 9 | ||
10 | - | func getStringOrFail (key) = valueOrErrorMessage(getString(this, key), ("No data for this.key=" + key)) | |
10 | + | let scale18 = 1000000000000000000 | |
11 | + | ||
12 | + | let scale18BigInt = toBigInt(scale18) | |
13 | + | ||
14 | + | let ADDRESS_BYTES_SIZE = 26 | |
15 | + | ||
16 | + | let BLOCKS_IN_DAY = 1440 | |
17 | + | ||
18 | + | func throwErr (msg) = throw(((contractFile + ": ") + msg)) | |
11 | 19 | ||
12 | 20 | ||
13 | - | func pepeContractAddress () = getStringOrFail(keysWavesContract) | |
21 | + | let keyAssetId = makeString(["%s", "assetId"], SEP) | |
22 | + | ||
23 | + | let keyEmissionPerBlock = makeString(["%s", "emissionPerBlock"], SEP) | |
24 | + | ||
25 | + | let keyEmissionPeriodInBlocks = makeString(["%s", "emissionPeriodInBlocks"], SEP) | |
26 | + | ||
27 | + | let keyStartBlock = makeString(["%s", "startBlock"], SEP) | |
28 | + | ||
29 | + | let keyTotalLpAmount = makeString(["%s", "totalLpAmount"], SEP) | |
30 | + | ||
31 | + | let keyTotalAssetAmount = makeString(["%s", "totalAssetAmount"], SEP) | |
32 | + | ||
33 | + | let keyTotalLockedLpAmount = makeString(["%s", "totalLockedLpAmount"], SEP) | |
34 | + | ||
35 | + | func keyUserLpAmount (userAddress) = makeString(["%s%s", "userLpAmount", userAddress], SEP) | |
14 | 36 | ||
15 | 37 | ||
16 | - | func | |
38 | + | func keyUserLockedLpAmount (userAddress) = makeString(["%s%s", "userLockedLpAmount", userAddress], SEP) | |
17 | 39 | ||
18 | 40 | ||
19 | - | let pepeContract = addressFromStringValue(pepeContractAddress()) | |
20 | - | ||
21 | - | let sWaves = fromBase58String(sWavesIdString()) | |
22 | - | ||
23 | - | func keyManagerPublicKey () = "%s__managerPublicKey" | |
41 | + | func keyUserStakingNodes (userAddress) = makeString(["%s%s", "userStakingNodes", userAddress], SEP) | |
24 | 42 | ||
25 | 43 | ||
26 | - | func | |
44 | + | func keyUserStakingNodesShares (userAddress) = makeString(["%s%s", "userStakingNodesShares", userAddress], SEP) | |
27 | 45 | ||
28 | 46 | ||
29 | - | func | |
47 | + | func keyUserTotalAssetWithdrawn (userAddress) = makeString(["%s%s", "totalAssetWithdrawn", userAddress], SEP) | |
30 | 48 | ||
31 | 49 | ||
32 | - | func managerPublicKeyOrUnit () = match getString(keyManagerPublicKey()) { | |
33 | - | case s: String => | |
34 | - | fromBase58String(s) | |
35 | - | case _: Unit => | |
36 | - | unit | |
50 | + | func keyUserTotalAssetStaked (userAddress) = makeString(["%s%s", "totalAssetStaked", userAddress], SEP) | |
51 | + | ||
52 | + | ||
53 | + | func keyHistory (type,userAddress,txId) = makeString(["%s%s%s", type, userAddress, toBase58String(txId)], SEP) | |
54 | + | ||
55 | + | ||
56 | + | func formatHistory (totalProfit,price,totalAssetAmount,totalLpAmount) = makeString(["%d%d%d%d", toString(totalProfit), toString(price), toString(totalAssetAmount), toString(totalLpAmount)], SEP) | |
57 | + | ||
58 | + | ||
59 | + | let totalLpAmount = valueOrElse(getInteger(this, keyTotalLpAmount), 0) | |
60 | + | ||
61 | + | let totalAssetAmount = valueOrElse(getInteger(this, keyTotalAssetAmount), 0) | |
62 | + | ||
63 | + | let totalLockedLpAmount = valueOrElse(getInteger(this, keyTotalLockedLpAmount), 0) | |
64 | + | ||
65 | + | let assetIdString = valueOrElse(getString(this, keyAssetId), "WAVES") | |
66 | + | ||
67 | + | let assetIdBytes = if ((assetIdString == "WAVES")) | |
68 | + | then unit | |
69 | + | else fromBase58String(assetIdString) | |
70 | + | ||
71 | + | let emissionPeriodInBlocks = valueOrElse(getInteger(this, keyEmissionPeriodInBlocks), BLOCKS_IN_DAY) | |
72 | + | ||
73 | + | let emissionPerBlock = valueOrElse(getInteger(this, keyEmissionPerBlock), 0) | |
74 | + | ||
75 | + | let emissionPerPeriod = (emissionPerBlock * emissionPeriodInBlocks) | |
76 | + | ||
77 | + | func stringListToIntListHelper (acc,value) = (acc :+ parseIntValue(value)) | |
78 | + | ||
79 | + | ||
80 | + | func calcTotalProfitForHeight (h) = { | |
81 | + | let startBlock = valueOrElse(getInteger(this, keyStartBlock), height) | |
82 | + | let startPeriod = fraction(startBlock, 1, emissionPeriodInBlocks) | |
83 | + | let elapsedPeriods = ((h / emissionPeriodInBlocks) - startPeriod) | |
84 | + | max([0, (emissionPerPeriod * elapsedPeriods)]) | |
85 | + | } | |
86 | + | ||
87 | + | ||
88 | + | func calcTotalProfit () = calcTotalProfitForHeight(height) | |
89 | + | ||
90 | + | ||
91 | + | func getMaxAssetAvailable () = match assetIdBytes { | |
92 | + | case u: Unit => | |
93 | + | wavesBalance(this).available | |
94 | + | case b: ByteVector => | |
95 | + | assetBalance(this, b) | |
37 | 96 | case _ => | |
38 | 97 | throw("Match error") | |
39 | 98 | } | |
40 | 99 | ||
41 | 100 | ||
42 | - | func pendingManagerPublicKeyOrUnit () = match getString(keyPendingManagerPublicKey()) { | |
43 | - | case s: String => | |
44 | - | fromBase58String(s) | |
45 | - | case _: Unit => | |
46 | - | unit | |
47 | - | case _ => | |
48 | - | throw("Match error") | |
49 | - | } | |
101 | + | func getTotalAssetAmountWithProfitOrMaxAvailable (atHeight) = { | |
102 | + | let totalAssetAmountWithProfit = (totalAssetAmount + calcTotalProfitForHeight(atHeight)) | |
103 | + | let totalAmount = min([totalAssetAmountWithProfit, getMaxAssetAvailable()]) | |
104 | + | if ((totalLpAmount == 0)) | |
105 | + | then 0 | |
106 | + | else totalAmount | |
107 | + | } | |
50 | 108 | ||
51 | 109 | ||
52 | - | func isManager (i) = match managerPublicKeyOrUnit() { | |
53 | - | case pk: ByteVector => | |
54 | - | (i.callerPublicKey == pk) | |
55 | - | case _: Unit => | |
56 | - | (i.caller == this) | |
57 | - | case _ => | |
58 | - | throw("Match error") | |
59 | - | } | |
110 | + | func getPriceAtHeight (h) = if ((totalLpAmount != 0)) | |
111 | + | then fraction(toBigInt(getTotalAssetAmountWithProfitOrMaxAvailable(h)), scale18BigInt, toBigInt(totalLpAmount)) | |
112 | + | else scale18BigInt | |
60 | 113 | ||
61 | 114 | ||
62 | - | func mustManager (i) = if (isManager(i)) | |
63 | - | then true | |
64 | - | else throw("permission denied") | |
115 | + | func getCurrentPrice () = getPriceAtHeight(height) | |
116 | + | ||
117 | + | ||
118 | + | func getRemainingBlocks () = if ((emissionPerBlock == 0)) | |
119 | + | then 0 | |
120 | + | else fraction((getMaxAssetAvailable() - getTotalAssetAmountWithProfitOrMaxAvailable(height)), 1, emissionPerBlock) | |
121 | + | ||
122 | + | ||
123 | + | func getUserStakingNodesData (userAddress) = { | |
124 | + | let nodesRaw = valueOrElse(getString(this, keyUserStakingNodes(userAddress)), "") | |
125 | + | let sharesRaw = valueOrElse(getString(this, keyUserStakingNodesShares(userAddress)), "") | |
126 | + | let nodesList = if ((nodesRaw == "")) | |
127 | + | then nil | |
128 | + | else split(nodesRaw, SEP) | |
129 | + | let sharesStringList = if ((sharesRaw == "")) | |
130 | + | then nil | |
131 | + | else split(sharesRaw, SEP) | |
132 | + | let sharesList = { | |
133 | + | let $l = sharesStringList | |
134 | + | let $s = size($l) | |
135 | + | let $acc0 = nil | |
136 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
137 | + | then $a | |
138 | + | else stringListToIntListHelper($a, $l[$i]) | |
139 | + | ||
140 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
141 | + | then $a | |
142 | + | else throw("List size exceeds 20") | |
143 | + | ||
144 | + | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20) | |
145 | + | } | |
146 | + | $Tuple2(nodesList, sharesList) | |
147 | + | } | |
148 | + | ||
149 | + | ||
150 | + | func calcAssetFromLp (lpAmount,atHeight) = max([0, toInt(fraction(toBigInt(lpAmount), getPriceAtHeight(atHeight), scale18BigInt))]) | |
151 | + | ||
152 | + | ||
153 | + | func calcLpFromAsset (assetAmount,atHeight) = max([0, toInt(fraction(toBigInt(assetAmount), scale18BigInt, getPriceAtHeight(atHeight)))]) | |
154 | + | ||
155 | + | ||
156 | + | func getUserLpAmount (userAddress) = valueOrElse(getInteger(this, keyUserLpAmount(userAddress)), 0) | |
157 | + | ||
158 | + | ||
159 | + | func getUserLockedLpAmount (userAddress) = valueOrElse(getInteger(this, keyUserLockedLpAmount(userAddress)), 0) | |
160 | + | ||
161 | + | ||
162 | + | func getUserAvailableAssetsToWithdraw (userAddress) = { | |
163 | + | let userLpAmount = getUserLpAmount(userAddress) | |
164 | + | calcAssetFromLp(userLpAmount, height) | |
165 | + | } | |
166 | + | ||
167 | + | ||
168 | + | func getClearStakingNodesActions (userAddress) = [DeleteEntry(keyUserStakingNodes(userAddress)), DeleteEntry(keyUserStakingNodesShares(userAddress))] | |
169 | + | ||
170 | + | ||
171 | + | func getStakeActions (i,userAddress,stakeHeight) = { | |
172 | + | let checks = [if ((size(i.payments) == 1)) | |
173 | + | then true | |
174 | + | else throwErr("should include 1 payment"), if ((i.payments[0].assetId == assetIdBytes)) | |
175 | + | then true | |
176 | + | else throwErr(("payment should be in " + assetIdString)), if ((i.payments[0].amount > 0)) | |
177 | + | then true | |
178 | + | else "payment amount should be greater than 0", if ((size(fromBase58String(userAddress)) == ADDRESS_BYTES_SIZE)) | |
179 | + | then true | |
180 | + | else throwErr("user address is not valid")] | |
181 | + | if ((checks == checks)) | |
182 | + | then { | |
183 | + | let paymentAmount = i.payments[0].amount | |
184 | + | let paymentLpAmount = calcLpFromAsset(paymentAmount, stakeHeight) | |
185 | + | let userLpAmount = getUserLpAmount(userAddress) | |
186 | + | let userTotalStakedAmount = valueOrElse(getInteger(this, keyUserTotalAssetStaked(userAddress)), 0) | |
187 | + | let newTotalLpAmount = (totalLpAmount + paymentLpAmount) | |
188 | + | let newTotalAssetAmount = calcAssetFromLp(newTotalLpAmount, stakeHeight) | |
189 | + | let newUserLpAmount = (userLpAmount + paymentLpAmount) | |
190 | + | let newUserTotalStakedAmount = (userTotalStakedAmount + paymentAmount) | |
191 | + | [StringEntry(keyHistory("stake", userAddress, i.transactionId), formatHistory(calcTotalProfit(), getCurrentPrice(), totalLpAmount, totalAssetAmount)), IntegerEntry(keyTotalLpAmount, newTotalLpAmount), IntegerEntry(keyTotalAssetAmount, newTotalAssetAmount), IntegerEntry(keyUserLpAmount(userAddress), newUserLpAmount), IntegerEntry(keyUserTotalAssetStaked(userAddress), newUserTotalStakedAmount), IntegerEntry(keyStartBlock, height)] | |
192 | + | } | |
193 | + | else throw("Strict value is not equal to itself.") | |
194 | + | } | |
65 | 195 | ||
66 | 196 | ||
67 | 197 | @Callable(i) | |
68 | - | func getRate () = { | |
69 | - | let results = invoke(pepeContract, "getRate", nil, nil) | |
70 | - | match results { | |
71 | - | case t: String => | |
72 | - | $Tuple2(nil, parseIntValue(t)) | |
73 | - | case _ => | |
74 | - | error("getRate(): unexpected return") | |
75 | - | } | |
198 | + | func stakeForAdmin (userAddress,stakeHeight) = { | |
199 | + | let check = [if ((i.caller == this)) | |
200 | + | then true | |
201 | + | else throwErr("permission denied")] | |
202 | + | if ((check == check)) | |
203 | + | then getStakeActions(i, userAddress, stakeHeight) | |
204 | + | else throw("Strict value is not equal to itself.") | |
76 | 205 | } | |
77 | 206 | ||
78 | 207 | ||
79 | 208 | ||
80 | 209 | @Callable(i) | |
81 | - | func deposit () = { | |
82 | - | let startBalance = assetBalance(this, sWaves) | |
83 | - | if ((startBalance == startBalance)) | |
210 | + | func airdrop (addressList,amountList,airdropHeight) = { | |
211 | + | func sum (accum,next) = if ((0 > next)) | |
212 | + | then throwErr("negative amount value in amountList") | |
213 | + | else (accum + next) | |
214 | + | ||
215 | + | let amountListSum = { | |
216 | + | let $l = amountList | |
217 | + | let $s = size($l) | |
218 | + | let $acc0 = 0 | |
219 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
220 | + | then $a | |
221 | + | else sum($a, $l[$i]) | |
222 | + | ||
223 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
224 | + | then $a | |
225 | + | else throw("List size exceeds 90") | |
226 | + | ||
227 | + | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50), 51), 52), 53), 54), 55), 56), 57), 58), 59), 60), 61), 62), 63), 64), 65), 66), 67), 68), 69), 70), 71), 72), 73), 74), 75), 76), 77), 78), 79), 80), 81), 82), 83), 84), 85), 86), 87), 88), 89), 90) | |
228 | + | } | |
229 | + | let check = [if ((i.caller == this)) | |
230 | + | then true | |
231 | + | else throwErr("permission denied"), if ((size(i.payments) == 1)) | |
232 | + | then true | |
233 | + | else throwErr("should include 1 payment"), if ((i.payments[0].assetId == assetIdBytes)) | |
234 | + | then true | |
235 | + | else throwErr(("payment should be in " + assetIdString)), if ((i.payments[0].amount > 0)) | |
236 | + | then true | |
237 | + | else "payment amount should be greater than 0", if ((size(addressList) == size(amountList))) | |
238 | + | then true | |
239 | + | else throwErr("addressList should be same size as amountList"), if ((i.payments[0].amount >= amountListSum)) | |
240 | + | then true | |
241 | + | else throwErr("payment amount is less than sum of amountList")] | |
242 | + | if ((check == check)) | |
84 | 243 | then { | |
85 | - | let results = invoke(pepeContract, "deposit", nil, i.payments) | |
86 | - | if ((results == results)) | |
87 | - | then { | |
88 | - | let newBalance = assetBalance(this, sWaves) | |
89 | - | let sendAmount = (newBalance - startBalance) | |
90 | - | $Tuple2([ScriptTransfer(i.caller, sendAmount, sWaves)], sendAmount) | |
91 | - | } | |
92 | - | else throw("Strict value is not equal to itself.") | |
244 | + | func getAirdropStateChanges (accum,assetAmount) = { | |
245 | + | let $t081708221 = accum | |
246 | + | let result = $t081708221._1 | |
247 | + | let index = $t081708221._2 | |
248 | + | let totalLp = $t081708221._3 | |
249 | + | let processedList = $t081708221._4 | |
250 | + | let addressString = addressList[index] | |
251 | + | let address = match addressFromString(addressString) { | |
252 | + | case adr: Address => | |
253 | + | adr | |
254 | + | case _ => | |
255 | + | throwErr("invalid address in addressList") | |
256 | + | } | |
257 | + | let ch = [if (!(containsElement(processedList, address))) | |
258 | + | then true | |
259 | + | else throwErr("duplicate address is addressList")] | |
260 | + | if ((ch == ch)) | |
261 | + | then { | |
262 | + | let addedLpAmount = calcLpFromAsset(assetAmount, airdropHeight) | |
263 | + | let userLockedLpKey = keyUserLockedLpAmount(addressString) | |
264 | + | let oldLpAmount = valueOrElse(getInteger(this, userLockedLpKey), 0) | |
265 | + | $Tuple4((result :+ IntegerEntry(userLockedLpKey, (oldLpAmount + addedLpAmount))), (index + 1), (totalLp + addedLpAmount), (processedList :+ address)) | |
266 | + | } | |
267 | + | else throw("Strict value is not equal to itself.") | |
268 | + | } | |
269 | + | ||
270 | + | let $t090009117 = { | |
271 | + | let $l = amountList | |
272 | + | let $s = size($l) | |
273 | + | let $acc0 = $Tuple4(nil, 0, 0, nil) | |
274 | + | func $f1_1 ($a,$i) = if (($i >= $s)) | |
275 | + | then $a | |
276 | + | else getAirdropStateChanges($a, $l[$i]) | |
277 | + | ||
278 | + | func $f1_2 ($a,$i) = if (($i >= $s)) | |
279 | + | then $a | |
280 | + | else throw("List size exceeds 90") | |
281 | + | ||
282 | + | $f1_2($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50), 51), 52), 53), 54), 55), 56), 57), 58), 59), 60), 61), 62), 63), 64), 65), 66), 67), 68), 69), 70), 71), 72), 73), 74), 75), 76), 77), 78), 79), 80), 81), 82), 83), 84), 85), 86), 87), 88), 89), 90) | |
283 | + | } | |
284 | + | let airdropEntries = $t090009117._1 | |
285 | + | let _a = $t090009117._2 | |
286 | + | let addedTotalLockedLpAmount = $t090009117._3 | |
287 | + | let _b = $t090009117._4 | |
288 | + | let newTotalAsset = calcAssetFromLp((totalLpAmount + addedTotalLockedLpAmount), airdropHeight) | |
289 | + | ([IntegerEntry(keyTotalLockedLpAmount, (totalLockedLpAmount + addedTotalLockedLpAmount)), IntegerEntry(keyTotalLpAmount, (totalLpAmount + addedTotalLockedLpAmount)), IntegerEntry(keyTotalAssetAmount, newTotalAsset), IntegerEntry(keyStartBlock, height)] ++ airdropEntries) | |
93 | 290 | } | |
94 | 291 | else throw("Strict value is not equal to itself.") | |
95 | 292 | } | |
97 | 294 | ||
98 | 295 | ||
99 | 296 | @Callable(i) | |
100 | - | func withdraw () = { | |
101 | - | let startBalance = wavesBalance(this).available | |
102 | - | if ((startBalance == startBalance)) | |
103 | - | then { | |
104 | - | let results = invoke(pepeContract, "withdraw", nil, i.payments) | |
105 | - | if ((results == results)) | |
106 | - | then { | |
107 | - | let newBalance = wavesBalance(this).available | |
108 | - | let sendAmount = (newBalance - startBalance) | |
109 | - | $Tuple2([ScriptTransfer(i.caller, sendAmount, unit)], sendAmount) | |
110 | - | } | |
111 | - | else throw("Strict value is not equal to itself.") | |
112 | - | } | |
113 | - | else throw("Strict value is not equal to itself.") | |
297 | + | func getUserAssetsREADONLY (userAddress) = { | |
298 | + | let userLpAmount = getUserLpAmount(userAddress) | |
299 | + | let userLockedLpAmount = getUserLockedLpAmount(userAddress) | |
300 | + | let userLockedAssetAmount = calcAssetFromLp(userLockedLpAmount, height) | |
301 | + | let userAvailableAssetToWithdraw = getUserAvailableAssetsToWithdraw(userAddress) | |
302 | + | let userTotalStakedAmount = valueOrElse(getInteger(this, keyUserTotalAssetStaked(userAddress)), 0) | |
303 | + | let userTotalAssetWithdrawn = valueOrElse(getInteger(this, keyUserTotalAssetWithdrawn(userAddress)), 0) | |
304 | + | let $t01049010582 = getUserStakingNodesData(userAddress) | |
305 | + | let userStakingNodesList = $t01049010582._1 | |
306 | + | let userStakingNodeSharesList = $t01049010582._2 | |
307 | + | $Tuple2(nil, $Tuple10(userLpAmount, userAvailableAssetToWithdraw, getCurrentPrice(), userTotalStakedAmount, userTotalAssetWithdrawn, userLockedLpAmount, userLockedAssetAmount, userStakingNodesList, userStakingNodeSharesList, getRemainingBlocks())) | |
114 | 308 | } | |
115 | 309 | ||
116 | 310 | ||
117 | 311 | ||
118 | 312 | @Callable(i) | |
119 | - | func setManager (pendingManagerPublicKey) = { | |
120 | - | let checkCaller = mustManager(i) | |
121 | - | if ((checkCaller == checkCaller)) | |
122 | - | then { | |
123 | - | let checkManagerPublicKey = fromBase58String(pendingManagerPublicKey) | |
124 | - | if ((checkManagerPublicKey == checkManagerPublicKey)) | |
125 | - | then [StringEntry(keyPendingManagerPublicKey(), pendingManagerPublicKey)] | |
126 | - | else throw("Strict value is not equal to itself.") | |
127 | - | } | |
128 | - | else throw("Strict value is not equal to itself.") | |
129 | - | } | |
313 | + | func getTotalAssetsREADONLY () = $Tuple2(nil, $Tuple6(totalLpAmount, getTotalAssetAmountWithProfitOrMaxAvailable(height), getCurrentPrice(), totalLockedLpAmount, calcAssetFromLp(totalLockedLpAmount, height), getRemainingBlocks())) | |
130 | 314 | ||
131 | - | ||
132 | - | ||
133 | - | @Callable(i) | |
134 | - | func confirmManager () = { | |
135 | - | let pm = pendingManagerPublicKeyOrUnit() | |
136 | - | let hasPM = if (isDefined(pm)) | |
137 | - | then true | |
138 | - | else throw("no pending manager") | |
139 | - | if ((hasPM == hasPM)) | |
140 | - | then { | |
141 | - | let checkPM = if ((i.callerPublicKey == value(pm))) | |
142 | - | then true | |
143 | - | else throw("you are not pending manager") | |
144 | - | if ((checkPM == checkPM)) | |
145 | - | then [StringEntry(keyManagerPublicKey(), toBase58String(value(pm))), DeleteEntry(keyPendingManagerPublicKey())] | |
146 | - | else throw("Strict value is not equal to itself.") | |
147 | - | } | |
148 | - | else throw("Strict value is not equal to itself.") | |
149 | - | } | |
150 | - | ||
151 | - | ||
152 | - | @Verifier(tx) | |
153 | - | func verify () = { | |
154 | - | let targetPublicKey = match managerPublicKeyOrUnit() { | |
155 | - | case pk: ByteVector => | |
156 | - | pk | |
157 | - | case _: Unit => | |
158 | - | tx.senderPublicKey | |
159 | - | case _ => | |
160 | - | throw("Match error") | |
161 | - | } | |
162 | - | sigVerify(tx.bodyBytes, tx.proofs[0], targetPublicKey) | |
163 | - | } | |
164 | 315 |
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 6 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | - | let contractFile = " | |
4 | + | let contractFile = "l2mp_staking.ride" | |
5 | 5 | ||
6 | - | let | |
6 | + | let SEP = "__" | |
7 | 7 | ||
8 | - | let | |
8 | + | let scale8 = 100000000 | |
9 | 9 | ||
10 | - | func getStringOrFail (key) = valueOrErrorMessage(getString(this, key), ("No data for this.key=" + key)) | |
10 | + | let scale18 = 1000000000000000000 | |
11 | + | ||
12 | + | let scale18BigInt = toBigInt(scale18) | |
13 | + | ||
14 | + | let ADDRESS_BYTES_SIZE = 26 | |
15 | + | ||
16 | + | let BLOCKS_IN_DAY = 1440 | |
17 | + | ||
18 | + | func throwErr (msg) = throw(((contractFile + ": ") + msg)) | |
11 | 19 | ||
12 | 20 | ||
13 | - | func pepeContractAddress () = getStringOrFail(keysWavesContract) | |
21 | + | let keyAssetId = makeString(["%s", "assetId"], SEP) | |
22 | + | ||
23 | + | let keyEmissionPerBlock = makeString(["%s", "emissionPerBlock"], SEP) | |
24 | + | ||
25 | + | let keyEmissionPeriodInBlocks = makeString(["%s", "emissionPeriodInBlocks"], SEP) | |
26 | + | ||
27 | + | let keyStartBlock = makeString(["%s", "startBlock"], SEP) | |
28 | + | ||
29 | + | let keyTotalLpAmount = makeString(["%s", "totalLpAmount"], SEP) | |
30 | + | ||
31 | + | let keyTotalAssetAmount = makeString(["%s", "totalAssetAmount"], SEP) | |
32 | + | ||
33 | + | let keyTotalLockedLpAmount = makeString(["%s", "totalLockedLpAmount"], SEP) | |
34 | + | ||
35 | + | func keyUserLpAmount (userAddress) = makeString(["%s%s", "userLpAmount", userAddress], SEP) | |
14 | 36 | ||
15 | 37 | ||
16 | - | func | |
38 | + | func keyUserLockedLpAmount (userAddress) = makeString(["%s%s", "userLockedLpAmount", userAddress], SEP) | |
17 | 39 | ||
18 | 40 | ||
19 | - | let pepeContract = addressFromStringValue(pepeContractAddress()) | |
20 | - | ||
21 | - | let sWaves = fromBase58String(sWavesIdString()) | |
22 | - | ||
23 | - | func keyManagerPublicKey () = "%s__managerPublicKey" | |
41 | + | func keyUserStakingNodes (userAddress) = makeString(["%s%s", "userStakingNodes", userAddress], SEP) | |
24 | 42 | ||
25 | 43 | ||
26 | - | func | |
44 | + | func keyUserStakingNodesShares (userAddress) = makeString(["%s%s", "userStakingNodesShares", userAddress], SEP) | |
27 | 45 | ||
28 | 46 | ||
29 | - | func | |
47 | + | func keyUserTotalAssetWithdrawn (userAddress) = makeString(["%s%s", "totalAssetWithdrawn", userAddress], SEP) | |
30 | 48 | ||
31 | 49 | ||
32 | - | func managerPublicKeyOrUnit () = match getString(keyManagerPublicKey()) { | |
33 | - | case s: String => | |
34 | - | fromBase58String(s) | |
35 | - | case _: Unit => | |
36 | - | unit | |
50 | + | func keyUserTotalAssetStaked (userAddress) = makeString(["%s%s", "totalAssetStaked", userAddress], SEP) | |
51 | + | ||
52 | + | ||
53 | + | func keyHistory (type,userAddress,txId) = makeString(["%s%s%s", type, userAddress, toBase58String(txId)], SEP) | |
54 | + | ||
55 | + | ||
56 | + | func formatHistory (totalProfit,price,totalAssetAmount,totalLpAmount) = makeString(["%d%d%d%d", toString(totalProfit), toString(price), toString(totalAssetAmount), toString(totalLpAmount)], SEP) | |
57 | + | ||
58 | + | ||
59 | + | let totalLpAmount = valueOrElse(getInteger(this, keyTotalLpAmount), 0) | |
60 | + | ||
61 | + | let totalAssetAmount = valueOrElse(getInteger(this, keyTotalAssetAmount), 0) | |
62 | + | ||
63 | + | let totalLockedLpAmount = valueOrElse(getInteger(this, keyTotalLockedLpAmount), 0) | |
64 | + | ||
65 | + | let assetIdString = valueOrElse(getString(this, keyAssetId), "WAVES") | |
66 | + | ||
67 | + | let assetIdBytes = if ((assetIdString == "WAVES")) | |
68 | + | then unit | |
69 | + | else fromBase58String(assetIdString) | |
70 | + | ||
71 | + | let emissionPeriodInBlocks = valueOrElse(getInteger(this, keyEmissionPeriodInBlocks), BLOCKS_IN_DAY) | |
72 | + | ||
73 | + | let emissionPerBlock = valueOrElse(getInteger(this, keyEmissionPerBlock), 0) | |
74 | + | ||
75 | + | let emissionPerPeriod = (emissionPerBlock * emissionPeriodInBlocks) | |
76 | + | ||
77 | + | func stringListToIntListHelper (acc,value) = (acc :+ parseIntValue(value)) | |
78 | + | ||
79 | + | ||
80 | + | func calcTotalProfitForHeight (h) = { | |
81 | + | let startBlock = valueOrElse(getInteger(this, keyStartBlock), height) | |
82 | + | let startPeriod = fraction(startBlock, 1, emissionPeriodInBlocks) | |
83 | + | let elapsedPeriods = ((h / emissionPeriodInBlocks) - startPeriod) | |
84 | + | max([0, (emissionPerPeriod * elapsedPeriods)]) | |
85 | + | } | |
86 | + | ||
87 | + | ||
88 | + | func calcTotalProfit () = calcTotalProfitForHeight(height) | |
89 | + | ||
90 | + | ||
91 | + | func getMaxAssetAvailable () = match assetIdBytes { | |
92 | + | case u: Unit => | |
93 | + | wavesBalance(this).available | |
94 | + | case b: ByteVector => | |
95 | + | assetBalance(this, b) | |
37 | 96 | case _ => | |
38 | 97 | throw("Match error") | |
39 | 98 | } | |
40 | 99 | ||
41 | 100 | ||
42 | - | func pendingManagerPublicKeyOrUnit () = match getString(keyPendingManagerPublicKey()) { | |
43 | - | case s: String => | |
44 | - | fromBase58String(s) | |
45 | - | case _: Unit => | |
46 | - | unit | |
47 | - | case _ => | |
48 | - | throw("Match error") | |
49 | - | } | |
101 | + | func getTotalAssetAmountWithProfitOrMaxAvailable (atHeight) = { | |
102 | + | let totalAssetAmountWithProfit = (totalAssetAmount + calcTotalProfitForHeight(atHeight)) | |
103 | + | let totalAmount = min([totalAssetAmountWithProfit, getMaxAssetAvailable()]) | |
104 | + | if ((totalLpAmount == 0)) | |
105 | + | then 0 | |
106 | + | else totalAmount | |
107 | + | } | |
50 | 108 | ||
51 | 109 | ||
52 | - | func isManager (i) = match managerPublicKeyOrUnit() { | |
53 | - | case pk: ByteVector => | |
54 | - | (i.callerPublicKey == pk) | |
55 | - | case _: Unit => | |
56 | - | (i.caller == this) | |
57 | - | case _ => | |
58 | - | throw("Match error") | |
59 | - | } | |
110 | + | func getPriceAtHeight (h) = if ((totalLpAmount != 0)) | |
111 | + | then fraction(toBigInt(getTotalAssetAmountWithProfitOrMaxAvailable(h)), scale18BigInt, toBigInt(totalLpAmount)) | |
112 | + | else scale18BigInt | |
60 | 113 | ||
61 | 114 | ||
62 | - | func mustManager (i) = if (isManager(i)) | |
63 | - | then true | |
64 | - | else throw("permission denied") | |
115 | + | func getCurrentPrice () = getPriceAtHeight(height) | |
116 | + | ||
117 | + | ||
118 | + | func getRemainingBlocks () = if ((emissionPerBlock == 0)) | |
119 | + | then 0 | |
120 | + | else fraction((getMaxAssetAvailable() - getTotalAssetAmountWithProfitOrMaxAvailable(height)), 1, emissionPerBlock) | |
121 | + | ||
122 | + | ||
123 | + | func getUserStakingNodesData (userAddress) = { | |
124 | + | let nodesRaw = valueOrElse(getString(this, keyUserStakingNodes(userAddress)), "") | |
125 | + | let sharesRaw = valueOrElse(getString(this, keyUserStakingNodesShares(userAddress)), "") | |
126 | + | let nodesList = if ((nodesRaw == "")) | |
127 | + | then nil | |
128 | + | else split(nodesRaw, SEP) | |
129 | + | let sharesStringList = if ((sharesRaw == "")) | |
130 | + | then nil | |
131 | + | else split(sharesRaw, SEP) | |
132 | + | let sharesList = { | |
133 | + | let $l = sharesStringList | |
134 | + | let $s = size($l) | |
135 | + | let $acc0 = nil | |
136 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
137 | + | then $a | |
138 | + | else stringListToIntListHelper($a, $l[$i]) | |
139 | + | ||
140 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
141 | + | then $a | |
142 | + | else throw("List size exceeds 20") | |
143 | + | ||
144 | + | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20) | |
145 | + | } | |
146 | + | $Tuple2(nodesList, sharesList) | |
147 | + | } | |
148 | + | ||
149 | + | ||
150 | + | func calcAssetFromLp (lpAmount,atHeight) = max([0, toInt(fraction(toBigInt(lpAmount), getPriceAtHeight(atHeight), scale18BigInt))]) | |
151 | + | ||
152 | + | ||
153 | + | func calcLpFromAsset (assetAmount,atHeight) = max([0, toInt(fraction(toBigInt(assetAmount), scale18BigInt, getPriceAtHeight(atHeight)))]) | |
154 | + | ||
155 | + | ||
156 | + | func getUserLpAmount (userAddress) = valueOrElse(getInteger(this, keyUserLpAmount(userAddress)), 0) | |
157 | + | ||
158 | + | ||
159 | + | func getUserLockedLpAmount (userAddress) = valueOrElse(getInteger(this, keyUserLockedLpAmount(userAddress)), 0) | |
160 | + | ||
161 | + | ||
162 | + | func getUserAvailableAssetsToWithdraw (userAddress) = { | |
163 | + | let userLpAmount = getUserLpAmount(userAddress) | |
164 | + | calcAssetFromLp(userLpAmount, height) | |
165 | + | } | |
166 | + | ||
167 | + | ||
168 | + | func getClearStakingNodesActions (userAddress) = [DeleteEntry(keyUserStakingNodes(userAddress)), DeleteEntry(keyUserStakingNodesShares(userAddress))] | |
169 | + | ||
170 | + | ||
171 | + | func getStakeActions (i,userAddress,stakeHeight) = { | |
172 | + | let checks = [if ((size(i.payments) == 1)) | |
173 | + | then true | |
174 | + | else throwErr("should include 1 payment"), if ((i.payments[0].assetId == assetIdBytes)) | |
175 | + | then true | |
176 | + | else throwErr(("payment should be in " + assetIdString)), if ((i.payments[0].amount > 0)) | |
177 | + | then true | |
178 | + | else "payment amount should be greater than 0", if ((size(fromBase58String(userAddress)) == ADDRESS_BYTES_SIZE)) | |
179 | + | then true | |
180 | + | else throwErr("user address is not valid")] | |
181 | + | if ((checks == checks)) | |
182 | + | then { | |
183 | + | let paymentAmount = i.payments[0].amount | |
184 | + | let paymentLpAmount = calcLpFromAsset(paymentAmount, stakeHeight) | |
185 | + | let userLpAmount = getUserLpAmount(userAddress) | |
186 | + | let userTotalStakedAmount = valueOrElse(getInteger(this, keyUserTotalAssetStaked(userAddress)), 0) | |
187 | + | let newTotalLpAmount = (totalLpAmount + paymentLpAmount) | |
188 | + | let newTotalAssetAmount = calcAssetFromLp(newTotalLpAmount, stakeHeight) | |
189 | + | let newUserLpAmount = (userLpAmount + paymentLpAmount) | |
190 | + | let newUserTotalStakedAmount = (userTotalStakedAmount + paymentAmount) | |
191 | + | [StringEntry(keyHistory("stake", userAddress, i.transactionId), formatHistory(calcTotalProfit(), getCurrentPrice(), totalLpAmount, totalAssetAmount)), IntegerEntry(keyTotalLpAmount, newTotalLpAmount), IntegerEntry(keyTotalAssetAmount, newTotalAssetAmount), IntegerEntry(keyUserLpAmount(userAddress), newUserLpAmount), IntegerEntry(keyUserTotalAssetStaked(userAddress), newUserTotalStakedAmount), IntegerEntry(keyStartBlock, height)] | |
192 | + | } | |
193 | + | else throw("Strict value is not equal to itself.") | |
194 | + | } | |
65 | 195 | ||
66 | 196 | ||
67 | 197 | @Callable(i) | |
68 | - | func getRate () = { | |
69 | - | let results = invoke(pepeContract, "getRate", nil, nil) | |
70 | - | match results { | |
71 | - | case t: String => | |
72 | - | $Tuple2(nil, parseIntValue(t)) | |
73 | - | case _ => | |
74 | - | error("getRate(): unexpected return") | |
75 | - | } | |
198 | + | func stakeForAdmin (userAddress,stakeHeight) = { | |
199 | + | let check = [if ((i.caller == this)) | |
200 | + | then true | |
201 | + | else throwErr("permission denied")] | |
202 | + | if ((check == check)) | |
203 | + | then getStakeActions(i, userAddress, stakeHeight) | |
204 | + | else throw("Strict value is not equal to itself.") | |
76 | 205 | } | |
77 | 206 | ||
78 | 207 | ||
79 | 208 | ||
80 | 209 | @Callable(i) | |
81 | - | func deposit () = { | |
82 | - | let startBalance = assetBalance(this, sWaves) | |
83 | - | if ((startBalance == startBalance)) | |
210 | + | func airdrop (addressList,amountList,airdropHeight) = { | |
211 | + | func sum (accum,next) = if ((0 > next)) | |
212 | + | then throwErr("negative amount value in amountList") | |
213 | + | else (accum + next) | |
214 | + | ||
215 | + | let amountListSum = { | |
216 | + | let $l = amountList | |
217 | + | let $s = size($l) | |
218 | + | let $acc0 = 0 | |
219 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
220 | + | then $a | |
221 | + | else sum($a, $l[$i]) | |
222 | + | ||
223 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
224 | + | then $a | |
225 | + | else throw("List size exceeds 90") | |
226 | + | ||
227 | + | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50), 51), 52), 53), 54), 55), 56), 57), 58), 59), 60), 61), 62), 63), 64), 65), 66), 67), 68), 69), 70), 71), 72), 73), 74), 75), 76), 77), 78), 79), 80), 81), 82), 83), 84), 85), 86), 87), 88), 89), 90) | |
228 | + | } | |
229 | + | let check = [if ((i.caller == this)) | |
230 | + | then true | |
231 | + | else throwErr("permission denied"), if ((size(i.payments) == 1)) | |
232 | + | then true | |
233 | + | else throwErr("should include 1 payment"), if ((i.payments[0].assetId == assetIdBytes)) | |
234 | + | then true | |
235 | + | else throwErr(("payment should be in " + assetIdString)), if ((i.payments[0].amount > 0)) | |
236 | + | then true | |
237 | + | else "payment amount should be greater than 0", if ((size(addressList) == size(amountList))) | |
238 | + | then true | |
239 | + | else throwErr("addressList should be same size as amountList"), if ((i.payments[0].amount >= amountListSum)) | |
240 | + | then true | |
241 | + | else throwErr("payment amount is less than sum of amountList")] | |
242 | + | if ((check == check)) | |
84 | 243 | then { | |
85 | - | let results = invoke(pepeContract, "deposit", nil, i.payments) | |
86 | - | if ((results == results)) | |
87 | - | then { | |
88 | - | let newBalance = assetBalance(this, sWaves) | |
89 | - | let sendAmount = (newBalance - startBalance) | |
90 | - | $Tuple2([ScriptTransfer(i.caller, sendAmount, sWaves)], sendAmount) | |
91 | - | } | |
92 | - | else throw("Strict value is not equal to itself.") | |
244 | + | func getAirdropStateChanges (accum,assetAmount) = { | |
245 | + | let $t081708221 = accum | |
246 | + | let result = $t081708221._1 | |
247 | + | let index = $t081708221._2 | |
248 | + | let totalLp = $t081708221._3 | |
249 | + | let processedList = $t081708221._4 | |
250 | + | let addressString = addressList[index] | |
251 | + | let address = match addressFromString(addressString) { | |
252 | + | case adr: Address => | |
253 | + | adr | |
254 | + | case _ => | |
255 | + | throwErr("invalid address in addressList") | |
256 | + | } | |
257 | + | let ch = [if (!(containsElement(processedList, address))) | |
258 | + | then true | |
259 | + | else throwErr("duplicate address is addressList")] | |
260 | + | if ((ch == ch)) | |
261 | + | then { | |
262 | + | let addedLpAmount = calcLpFromAsset(assetAmount, airdropHeight) | |
263 | + | let userLockedLpKey = keyUserLockedLpAmount(addressString) | |
264 | + | let oldLpAmount = valueOrElse(getInteger(this, userLockedLpKey), 0) | |
265 | + | $Tuple4((result :+ IntegerEntry(userLockedLpKey, (oldLpAmount + addedLpAmount))), (index + 1), (totalLp + addedLpAmount), (processedList :+ address)) | |
266 | + | } | |
267 | + | else throw("Strict value is not equal to itself.") | |
268 | + | } | |
269 | + | ||
270 | + | let $t090009117 = { | |
271 | + | let $l = amountList | |
272 | + | let $s = size($l) | |
273 | + | let $acc0 = $Tuple4(nil, 0, 0, nil) | |
274 | + | func $f1_1 ($a,$i) = if (($i >= $s)) | |
275 | + | then $a | |
276 | + | else getAirdropStateChanges($a, $l[$i]) | |
277 | + | ||
278 | + | func $f1_2 ($a,$i) = if (($i >= $s)) | |
279 | + | then $a | |
280 | + | else throw("List size exceeds 90") | |
281 | + | ||
282 | + | $f1_2($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50), 51), 52), 53), 54), 55), 56), 57), 58), 59), 60), 61), 62), 63), 64), 65), 66), 67), 68), 69), 70), 71), 72), 73), 74), 75), 76), 77), 78), 79), 80), 81), 82), 83), 84), 85), 86), 87), 88), 89), 90) | |
283 | + | } | |
284 | + | let airdropEntries = $t090009117._1 | |
285 | + | let _a = $t090009117._2 | |
286 | + | let addedTotalLockedLpAmount = $t090009117._3 | |
287 | + | let _b = $t090009117._4 | |
288 | + | let newTotalAsset = calcAssetFromLp((totalLpAmount + addedTotalLockedLpAmount), airdropHeight) | |
289 | + | ([IntegerEntry(keyTotalLockedLpAmount, (totalLockedLpAmount + addedTotalLockedLpAmount)), IntegerEntry(keyTotalLpAmount, (totalLpAmount + addedTotalLockedLpAmount)), IntegerEntry(keyTotalAssetAmount, newTotalAsset), IntegerEntry(keyStartBlock, height)] ++ airdropEntries) | |
93 | 290 | } | |
94 | 291 | else throw("Strict value is not equal to itself.") | |
95 | 292 | } | |
96 | 293 | ||
97 | 294 | ||
98 | 295 | ||
99 | 296 | @Callable(i) | |
100 | - | func withdraw () = { | |
101 | - | let startBalance = wavesBalance(this).available | |
102 | - | if ((startBalance == startBalance)) | |
103 | - | then { | |
104 | - | let results = invoke(pepeContract, "withdraw", nil, i.payments) | |
105 | - | if ((results == results)) | |
106 | - | then { | |
107 | - | let newBalance = wavesBalance(this).available | |
108 | - | let sendAmount = (newBalance - startBalance) | |
109 | - | $Tuple2([ScriptTransfer(i.caller, sendAmount, unit)], sendAmount) | |
110 | - | } | |
111 | - | else throw("Strict value is not equal to itself.") | |
112 | - | } | |
113 | - | else throw("Strict value is not equal to itself.") | |
297 | + | func getUserAssetsREADONLY (userAddress) = { | |
298 | + | let userLpAmount = getUserLpAmount(userAddress) | |
299 | + | let userLockedLpAmount = getUserLockedLpAmount(userAddress) | |
300 | + | let userLockedAssetAmount = calcAssetFromLp(userLockedLpAmount, height) | |
301 | + | let userAvailableAssetToWithdraw = getUserAvailableAssetsToWithdraw(userAddress) | |
302 | + | let userTotalStakedAmount = valueOrElse(getInteger(this, keyUserTotalAssetStaked(userAddress)), 0) | |
303 | + | let userTotalAssetWithdrawn = valueOrElse(getInteger(this, keyUserTotalAssetWithdrawn(userAddress)), 0) | |
304 | + | let $t01049010582 = getUserStakingNodesData(userAddress) | |
305 | + | let userStakingNodesList = $t01049010582._1 | |
306 | + | let userStakingNodeSharesList = $t01049010582._2 | |
307 | + | $Tuple2(nil, $Tuple10(userLpAmount, userAvailableAssetToWithdraw, getCurrentPrice(), userTotalStakedAmount, userTotalAssetWithdrawn, userLockedLpAmount, userLockedAssetAmount, userStakingNodesList, userStakingNodeSharesList, getRemainingBlocks())) | |
114 | 308 | } | |
115 | 309 | ||
116 | 310 | ||
117 | 311 | ||
118 | 312 | @Callable(i) | |
119 | - | func setManager (pendingManagerPublicKey) = { | |
120 | - | let checkCaller = mustManager(i) | |
121 | - | if ((checkCaller == checkCaller)) | |
122 | - | then { | |
123 | - | let checkManagerPublicKey = fromBase58String(pendingManagerPublicKey) | |
124 | - | if ((checkManagerPublicKey == checkManagerPublicKey)) | |
125 | - | then [StringEntry(keyPendingManagerPublicKey(), pendingManagerPublicKey)] | |
126 | - | else throw("Strict value is not equal to itself.") | |
127 | - | } | |
128 | - | else throw("Strict value is not equal to itself.") | |
129 | - | } | |
313 | + | func getTotalAssetsREADONLY () = $Tuple2(nil, $Tuple6(totalLpAmount, getTotalAssetAmountWithProfitOrMaxAvailable(height), getCurrentPrice(), totalLockedLpAmount, calcAssetFromLp(totalLockedLpAmount, height), getRemainingBlocks())) | |
130 | 314 | ||
131 | - | ||
132 | - | ||
133 | - | @Callable(i) | |
134 | - | func confirmManager () = { | |
135 | - | let pm = pendingManagerPublicKeyOrUnit() | |
136 | - | let hasPM = if (isDefined(pm)) | |
137 | - | then true | |
138 | - | else throw("no pending manager") | |
139 | - | if ((hasPM == hasPM)) | |
140 | - | then { | |
141 | - | let checkPM = if ((i.callerPublicKey == value(pm))) | |
142 | - | then true | |
143 | - | else throw("you are not pending manager") | |
144 | - | if ((checkPM == checkPM)) | |
145 | - | then [StringEntry(keyManagerPublicKey(), toBase58String(value(pm))), DeleteEntry(keyPendingManagerPublicKey())] | |
146 | - | else throw("Strict value is not equal to itself.") | |
147 | - | } | |
148 | - | else throw("Strict value is not equal to itself.") | |
149 | - | } | |
150 | - | ||
151 | - | ||
152 | - | @Verifier(tx) | |
153 | - | func verify () = { | |
154 | - | let targetPublicKey = match managerPublicKeyOrUnit() { | |
155 | - | case pk: ByteVector => | |
156 | - | pk | |
157 | - | case _: Unit => | |
158 | - | tx.senderPublicKey | |
159 | - | case _ => | |
160 | - | throw("Match error") | |
161 | - | } | |
162 | - | sigVerify(tx.bodyBytes, tx.proofs[0], targetPublicKey) | |
163 | - | } | |
164 | 315 |
github/deemru/w8io/169f3d6 54.61 ms ◑