tx · A3kQoQSnGrcqFFfi8DFpr1ZLxcfqckRYfmdsacgFEWWH

3NCWFHDzdPHZC6636ZkMLNDup9mjpbTLs7h:  -0.02700000 Waves

2024.10.21 15:43 [3336621] smart account 3NCWFHDzdPHZC6636ZkMLNDup9mjpbTLs7h > SELF 0.00000000 Waves

{ "type": 13, "id": "A3kQoQSnGrcqFFfi8DFpr1ZLxcfqckRYfmdsacgFEWWH", "fee": 2700000, "feeAssetId": null, "timestamp": 1729514616761, "version": 1, "sender": "3NCWFHDzdPHZC6636ZkMLNDup9mjpbTLs7h", "senderPublicKey": "3z8Q6Zu3KppVmn6fJJvrLc1Wo3krVHSvfaNcerm82md2", "proofs": [ "44U5BdCRsH9GUgYL3xk21119mVfazfCv6BrjtAcopC29fCojCbqP9KtXUvZ4S8qPNNTdp66GEdsLRkp2dhmkwETp" ], "script": "base64:BgJNCAISAwoBARIAEgMKAQQSAwoBBBIDCgEIEgQKAggIEgMKAQgSBAoCCAgSAwoBCBIECgIIARIECgIIARIDCgEBEgASAwoBCBIAEgMKAQhNAAxjb250cmFjdEZpbGUCEWwybXBfbGVhc2luZy5yaWRlAANTRVACAl9fABJCTE9DS1NfSU5fSU5URVJWQUwA6AcABnNjYWxlOACAwtcvABJ1bml0c0NsYWltSW50ZXJ2YWwJAGgCCQBoAgDtAgAYADwBCHRocm93RXJyAQNtc2cJAAIBCQCsAgIJAKwCAgUMY29udHJhY3RGaWxlAgI6IAUDbXNnAAxrZXlMMkFzc2V0SWQJALkJAgkAzAgCAgIlcwkAzAgCAgdhc3NldElkBQNuaWwFA1NFUAAMa2V5Rm9yY2VTdG9wCQC5CQIJAMwIAgICJXMJAMwIAgIJZm9yY2VTdG9wBQNuaWwFA1NFUAAPa2V5Rm9yY2VPdXRTdG9wCQC5CQIJAMwIAgICJXMJAMwIAgIMZm9yY2VPdXRTdG9wBQNuaWwFA1NFUAAPa2V5VW5pdHNBc3NldElkCQC5CQIJAMwIAgICJXMJAMwIAgIMdW5pdHNBc3NldElkBQNuaWwFA1NFUAAWa2V5VW5pdHNQZXJCbG9ja1NjYWxlOAkAuQkCCQDMCAICAiVzCQDMCAICDXVuaXRzUGVyQmxvY2sFA25pbAUDU0VQABFrZXlQZXJpb2RPZmZzZXRJZAkAuQkCCQDMCAICAiVzCQDMCAICCG9mZnNldElkBQNuaWwFA1NFUAAVa2V5UGVyaW9kT2Zmc2V0SGVpZ2h0CQC5CQIJAMwIAgICJXMJAMwIAgIMb2Zmc2V0SGVpZ2h0BQNuaWwFA1NFUAAPa2V5UGVyaW9kTGVuZ3RoCQC5CQIJAMwIAgICJXMJAMwIAgIMcGVyaW9kTGVuZ3RoBQNuaWwFA1NFUAAYa2V5VW5pdHNDbGFpbVN0YXJ0SGVpZ2h0CQC5CQIJAMwIAgICJXMJAMwIAgIVdW5pdHNDbGFpbVN0YXJ0SGVpZ2h0BQNuaWwFA1NFUAAOcGVyaW9kT2Zmc2V0SWQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwURa2V5UGVyaW9kT2Zmc2V0SWQAAAAMcGVyaW9kTGVuZ3RoCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFD2tleVBlcmlvZExlbmd0aACQTgAScGVyaW9kT2Zmc2V0SGVpZ2h0CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFFWtleVBlcmlvZE9mZnNldEhlaWdodAD///////////8BAA9jdXJyZW50UGVyaW9kSWQDAwkAZgIFBmhlaWdodAUScGVyaW9kT2Zmc2V0SGVpZ2h0CQECIT0CBRJwZXJpb2RPZmZzZXRIZWlnaHQA////////////AQcJAGQCCQBpAgkAZQIFBmhlaWdodAUScGVyaW9kT2Zmc2V0SGVpZ2h0BQxwZXJpb2RMZW5ndGgFDnBlcmlvZE9mZnNldElkCQCWAwEJAMwIAgAACQDMCAIJAGUCBQ5wZXJpb2RPZmZzZXRJZAABBQNuaWwAE2N1cnJlbnRQZXJpb2RIZWlnaHQDAwkAAAIFEnBlcmlvZE9mZnNldEhlaWdodAD///////////8BBgMJAAACBQ9jdXJyZW50UGVyaW9kSWQAAAkAZgIFEnBlcmlvZE9mZnNldEhlaWdodAUGaGVpZ2h0BwAACQBkAgUScGVyaW9kT2Zmc2V0SGVpZ2h0CQBoAgkAZQIFD2N1cnJlbnRQZXJpb2RJZAUOcGVyaW9kT2Zmc2V0SWQFDHBlcmlvZExlbmd0aAAQbmV4dFBlcmlvZEhlaWdodAMDCQAAAgUScGVyaW9kT2Zmc2V0SGVpZ2h0AP///////////wEGAwkAAAIFD2N1cnJlbnRQZXJpb2RJZAAACQBmAgUScGVyaW9kT2Zmc2V0SGVpZ2h0BQZoZWlnaHQHAAAJAGQCBRNjdXJyZW50UGVyaW9kSGVpZ2h0BQxwZXJpb2RMZW5ndGgAFXVuaXRzQ2xhaW1TdGFydEhlaWdodAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBRhrZXlVbml0c0NsYWltU3RhcnRIZWlnaHQFBmhlaWdodAESa2V5TGVhc2luZ05vZGVEYXRhAQtub2RlQWRkcmVzcwkAuQkCCQDMCAICAiVzCQDMCAIFC25vZGVBZGRyZXNzBQNuaWwFA1NFUAEWa2V5VXNlckxlYXNpbmdOb2RlRGF0YQILdXNlckFkZHJlc3MLbm9kZUFkZHJlc3MJALkJAgkAzAgCAgQlcyVzCQDMCAIFC25vZGVBZGRyZXNzCQDMCAIFC3VzZXJBZGRyZXNzBQNuaWwFA1NFUAEOa2V5VXNlclRvQ2xhaW0BC3VzZXJBZGRyZXNzCQC5CQIJAMwIAgIEJXMlcwkAzAgCAgd0b0NsYWltCQDMCAIFC3VzZXJBZGRyZXNzBQNuaWwFA1NFUAESa2V5VXNlclRvdGFsTG9ja2VkAQt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBCVzJXMJAMwIAgIPdXNlclRvdGFsTG9ja2VkCQDMCAIFC3VzZXJBZGRyZXNzBQNuaWwFA1NFUAEUa2V5VW5pdHNDbGFpbWVkQmxvY2sBC3VzZXJBZGRyZXNzCQC5CQIJAMwIAgIEJXMlcwkAzAgCAhF1bml0c0NsYWltZWRCbG9jawkAzAgCBQt1c2VyQWRkcmVzcwUDbmlsBQNTRVABEGtleVVubG9ja2VkVW5pdHMBC3VzZXJBZGRyZXNzCQC5CQIJAMwIAgIEJXMlcwkAzAgCAg11bmxvY2tlZFVuaXRzCQDMCAIFC3VzZXJBZGRyZXNzBQNuaWwFA1NFUAEUa2V5VG90YWxVbml0c0NsYWltZWQBC3VzZXJBZGRyZXNzCQC5CQIJAMwIAgIEJXMlcwkAzAgCAhF0b3RhbFVuaXRzQ2xhaW1lZAkAzAgCBQt1c2VyQWRkcmVzcwUDbmlsBQNTRVABC2tleUwyVG9CdXJuAQt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBCVzJXMJAMwIAgIIbDJUb0J1cm4JAMwIAgULdXNlckFkZHJlc3MFA25pbAUDU0VQARBrZXlMMkJ1cm5lZFRvdGFsAQt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBCVzJXMJAMwIAgINbDJCdXJuZWRUb3RhbAkAzAgCBQt1c2VyQWRkcmVzcwUDbmlsBQNTRVABFmtleU5vZGVMZWFzaW5nQnlIZWlnaHQBC25vZGVBZGRyZXNzBAFoAwkAAAIFEnBlcmlvZE9mZnNldEhlaWdodAD///////////8BAAAFBmhlaWdodAkAuQkCCQDMCAICBCVzJWQJAMwIAgULbm9kZUFkZHJlc3MJAMwIAgkApAMBBQFoBQNuaWwFA1NFUAEWa2V5VXNlckxlYXNpbmdCeUhlaWdodAILbm9kZUFkZHJlc3MLdXNlckFkZHJlc3MEAWgDCQAAAgUScGVyaW9kT2Zmc2V0SGVpZ2h0AP///////////wEAAAUGaGVpZ2h0CQC5CQIJAMwIAgIGJXMlcyVkCQDMCAIFC25vZGVBZGRyZXNzCQDMCAIFC3VzZXJBZGRyZXNzCQDMCAIJAKQDAQUBaAUDbmlsBQNTRVABEmFzc2V0U3RyaW5nVG9CeXRlcwENYXNzZXRJZFN0cmluZwMJAAACBQ1hc3NldElkU3RyaW5nAgVXQVZFUwUEdW5pdAkA2QQBBQ1hc3NldElkU3RyaW5nARJhc3NldEJ5dGVzVG9TdHJpbmcBB2Fzc2V0SWQEByRtYXRjaDAFB2Fzc2V0SWQDCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQBYQUHJG1hdGNoMAkA2AQBBQFhAgVXQVZFUwAPbDJBc3NldElkU3RyaW5nCQELdmFsdWVPckVsc2UCCQCdCAIFBHRoaXMFDGtleUwyQXNzZXRJZAIFV0FWRVMAEnVuaXRzQXNzZXRJZFN0cmluZwkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzBQ9rZXlVbml0c0Fzc2V0SWQCBVdBVkVTAA5sMkFzc2V0SWRCeXRlcwkBEmFzc2V0U3RyaW5nVG9CeXRlcwEFD2wyQXNzZXRJZFN0cmluZwARdW5pdHNBc3NldElkQnl0ZXMJARJhc3NldFN0cmluZ1RvQnl0ZXMBBRJ1bml0c0Fzc2V0SWRTdHJpbmcAC2lzRm9yY2VTdG9wCQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMFDGtleUZvcmNlU3RvcAcADmlzRm9yY2VPdXRTdG9wCQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMFD2tleUZvcmNlT3V0U3RvcAcBDmlzVmFsaWRBZGRyZXNzAQdhZGRyZXNzBAckbWF0Y2gwCQCmCAEFB2FkZHJlc3MDCQABAgUHJG1hdGNoMAIHQWRkcmVzcwQBYQUHJG1hdGNoMAYHAA9BRE1JTl9MSVNUX1NJWkUABQAGUVVPUlVNAAMAEVRYSURfQllURVNfTEVOR1RIACABGGtleUFsbG93ZWRUeElkVm90ZVByZWZpeAEEdHhJZAkAuQkCCQDMCAICBiVzJXMlcwkAzAgCAglhbGxvd1R4SWQJAMwIAgUEdHhJZAUDbmlsBQNTRVABEGtleUZ1bGxBZG1pblZvdGUCBnByZWZpeAxhZG1pbkFkZHJlc3MJALkJAgkAzAgCBQZwcmVmaXgJAMwIAgUMYWRtaW5BZGRyZXNzBQNuaWwFA1NFUAETa2V5QWRtaW5BZGRyZXNzTGlzdAAJALkJAgkAzAgCAgIlcwkAzAgCAhBhZG1pbkFkZHJlc3NMaXN0BQNuaWwFA1NFUAEOa2V5QWxsb3dlZFR4SWQACQC5CQIJAMwIAgICJXMJAMwIAgIEdHhJZAUDbmlsBQNTRVABDGdldEFkbWluVm90ZQIGcHJlZml4BWFkbWluBAd2b3RlS2V5CQEQa2V5RnVsbEFkbWluVm90ZQIFBnByZWZpeAUFYWRtaW4JAQt2YWx1ZU9yRWxzZQIJAJ8IAQUHdm90ZUtleQAAAQ1nZXRBZG1pbnNMaXN0AAQHJG1hdGNoMAkAnQgCBQR0aGlzCQETa2V5QWRtaW5BZGRyZXNzTGlzdAADCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFzBQckbWF0Y2gwCQC1CQIFAXMFA1NFUAUDbmlsAQ1pc0luQWRtaW5MaXN0AQdhZGRyZXNzCQEPY29udGFpbnNFbGVtZW50AgkBDWdldEFkbWluc0xpc3QABQdhZGRyZXNzARJnZW5Wb3Rlc0tleXNIZWxwZXICAWEMYWRtaW5BZGRyZXNzBAskdDA1MDIxNTA0NQUBYQQGcmVzdWx0CAULJHQwNTAyMTUwNDUCXzEEBnByZWZpeAgFCyR0MDUwMjE1MDQ1Al8yCQCUCgIJAM0IAgUGcmVzdWx0CQEQa2V5RnVsbEFkbWluVm90ZQIFBnByZWZpeAUMYWRtaW5BZGRyZXNzBQZwcmVmaXgBDGdlblZvdGVzS2V5cwEJa2V5UHJlZml4BAlhZG1pbkxpc3QJARNrZXlBZG1pbkFkZHJlc3NMaXN0AAQLJHQwNTE5MjUyNzYKAAIkbAkBDWdldEFkbWluc0xpc3QACgACJHMJAJADAQUCJGwKAAUkYWNjMAkAlAoCBQNuaWwFCWtleVByZWZpeAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQESZ2VuVm90ZXNLZXlzSGVscGVyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhNMaXN0IHNpemUgZXhjZWVkcyA1CQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQQGcmVzdWx0CAULJHQwNTE5MjUyNzYCXzEEBnByZWZpeAgFCyR0MDUxOTI1Mjc2Al8yBQZyZXN1bHQBEGNvdW50Vm90ZXNIZWxwZXICBnJlc3VsdAd2b3RlS2V5CQBkAgUGcmVzdWx0CQELdmFsdWVPckVsc2UCCQCfCAEFB3ZvdGVLZXkAAAEKY291bnRWb3RlcwEGcHJlZml4BAV2b3RlcwkBDGdlblZvdGVzS2V5cwEFBnByZWZpeAoAAiRsBQV2b3RlcwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAAAAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEQY291bnRWb3Rlc0hlbHBlcgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQITTGlzdCBzaXplIGV4Y2VlZHMgNQkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUBEGNsZWFyVm90ZXNIZWxwZXICBnJlc3VsdANrZXkJAM0IAgUGcmVzdWx0CQELRGVsZXRlRW50cnkBBQNrZXkBE2dldENsZWFyVm90ZUVudHJpZXMBBnByZWZpeAQFdm90ZXMJAQxnZW5Wb3Rlc0tleXMBBQZwcmVmaXgKAAIkbAUFdm90ZXMKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBEGNsZWFyVm90ZXNIZWxwZXICBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECE0xpc3Qgc2l6ZSBleGNlZWRzIDUJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAQx2b3RlSU5URVJOQUwEE2NhbGxlckFkZHJlc3NTdHJpbmcJa2V5UHJlZml4CG1pblZvdGVzCnZvdGVSZXN1bHQEB3ZvdGVLZXkJARBrZXlGdWxsQWRtaW5Wb3RlAgUJa2V5UHJlZml4BRNjYWxsZXJBZGRyZXNzU3RyaW5nBBBhZG1pbkN1cnJlbnRWb3RlCQEMZ2V0QWRtaW5Wb3RlAgUJa2V5UHJlZml4BRNjYWxsZXJBZGRyZXNzU3RyaW5nBANlcnIDCQEBIQEJAQ1pc0luQWRtaW5MaXN0AQUTY2FsbGVyQWRkcmVzc1N0cmluZwkBCHRocm93RXJyAQkArAICCQCsAgICCUFkZHJlc3M6IAUTY2FsbGVyQWRkcmVzc1N0cmluZwISIG5vdCBpbiBBZG1pbiBsaXN0AwkAAAIFEGFkbWluQ3VycmVudFZvdGUAAQkBCHRocm93RXJyAQkArAICBQd2b3RlS2V5AhIgeW91IGFscmVhZHkgdm90ZWQFBHVuaXQDCQAAAgUDZXJyBQNlcnIEBXZvdGVzCQEKY291bnRWb3RlcwEFCWtleVByZWZpeAMJAGcCCQBkAgUFdm90ZXMAAQUIbWluVm90ZXMEEGNsZWFyVm90ZUVudHJpZXMJARNnZXRDbGVhclZvdGVFbnRyaWVzAQUJa2V5UHJlZml4CQDOCAIFEGNsZWFyVm90ZUVudHJpZXMFCnZvdGVSZXN1bHQJAMwIAgkBDEludGVnZXJFbnRyeQIFB3ZvdGVLZXkAAQUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuARNnZXRMZWFzaW5nTm9kZUVudHJ5Awtub2RlQWRkcmVzcw1jdXJyZW50TGVhc2VkCm5leHRMZWFzZWQEC3ZhbHVlU3RyaW5nCQC5CQIJAMwIAgIIJWQlZCVkJWQJAMwIAgkApAMBBRNjdXJyZW50UGVyaW9kSGVpZ2h0CQDMCAIJAKQDAQUNY3VycmVudExlYXNlZAkAzAgCCQCkAwEFEG5leHRQZXJpb2RIZWlnaHQJAMwIAgkApAMBBQpuZXh0TGVhc2VkBQNuaWwFA1NFUAkBC1N0cmluZ0VudHJ5AgkBEmtleUxlYXNpbmdOb2RlRGF0YQEFC25vZGVBZGRyZXNzBQt2YWx1ZVN0cmluZwESZ2V0TGVhc2luZ05vZGVEYXRhAQtub2RlQWRkcmVzcwQYbGVhc2luZ05vZGVEYXRhU3RyaW5nUmF3CQCdCAIFBHRoaXMJARJrZXlMZWFzaW5nTm9kZURhdGEBBQtub2RlQWRkcmVzcwQHJG1hdGNoMAUYbGVhc2luZ05vZGVEYXRhU3RyaW5nUmF3AwkAAQIFByRtYXRjaDACBlN0cmluZwQCZHMFByRtYXRjaDAECGRhdGFMaXN0CQC1CQIFAmRzBQNTRVAEEW5vZGVDdXJyZW50UGVyaW9kCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUIZGF0YUxpc3QAAQQRbm9kZUN1cnJlbnRMZWFzZWQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQhkYXRhTGlzdAACBA5ub2RlTmV4dFBlcmlvZAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCGRhdGFMaXN0AAMEDm5vZGVOZXh0TGVhc2VkCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUIZGF0YUxpc3QABAMDCQBmAgUObm9kZU5leHRQZXJpb2QFBmhlaWdodAYJAAACBRJwZXJpb2RPZmZzZXRIZWlnaHQA////////////AQkAlAoCBRFub2RlQ3VycmVudExlYXNlZAUObm9kZU5leHRMZWFzZWQJAJQKAgUObm9kZU5leHRMZWFzZWQFDm5vZGVOZXh0TGVhc2VkCQCUCgIAAAAAARNnZXRVc2VyTGVhc2luZ0VudHJ5BAtub2RlQWRkcmVzcwt1c2VyQWRkcmVzcxF1c2VyQ3VycmVudExlYXNlZA51c2VyTmV4dExlYXNlZAQLdmFsdWVTdHJpbmcJALkJAgkAzAgCAgglZCVkJWQlZAkAzAgCCQCkAwEFE2N1cnJlbnRQZXJpb2RIZWlnaHQJAMwIAgkApAMBBRF1c2VyQ3VycmVudExlYXNlZAkAzAgCCQCkAwEFEG5leHRQZXJpb2RIZWlnaHQJAMwIAgkApAMBBQ51c2VyTmV4dExlYXNlZAUDbmlsBQNTRVAJAQtTdHJpbmdFbnRyeQIJARZrZXlVc2VyTGVhc2luZ05vZGVEYXRhAgULdXNlckFkZHJlc3MFC25vZGVBZGRyZXNzBQt2YWx1ZVN0cmluZwESZ2V0VXNlckxlYXNpbmdEYXRhAgtub2RlQWRkcmVzcwt1c2VyQWRkcmVzcwQYbGVhc2luZ1VzZXJEYXRhU3RyaW5nUmF3CQCdCAIFBHRoaXMJARZrZXlVc2VyTGVhc2luZ05vZGVEYXRhAgULdXNlckFkZHJlc3MFC25vZGVBZGRyZXNzBAckbWF0Y2gwBRhsZWFzaW5nVXNlckRhdGFTdHJpbmdSYXcDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAJkcwUHJG1hdGNoMAQIZGF0YUxpc3QJALUJAgUCZHMFA1NFUAQRdXNlckN1cnJlbnRQZXJpb2QJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQhkYXRhTGlzdAABBBF1c2VyQ3VycmVudExlYXNlZAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCGRhdGFMaXN0AAIEDnVzZXJOZXh0UGVyaW9kCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUIZGF0YUxpc3QAAwQOdXNlck5leHRMZWFzZWQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQhkYXRhTGlzdAAEAwMJAGYCBQ51c2VyTmV4dFBlcmlvZAUGaGVpZ2h0BgkAAAIFEnBlcmlvZE9mZnNldEhlaWdodAD///////////8BCQCUCgIFEXVzZXJDdXJyZW50TGVhc2VkBQ51c2VyTmV4dExlYXNlZAkAlAoCBQ51c2VyTmV4dExlYXNlZAUOdXNlck5leHRMZWFzZWQJAJQKAgAAAAABE2dldFVzZXJUb0NsYWltRW50cnkDC3VzZXJBZGRyZXNzB3RvQ2xhaW0IdG9VbmxvY2sEC3ZhbHVlU3RyaW5nCQC5CQIJAMwIAgIIJWQlZCVkJWQJAMwIAgkApAMBBRNjdXJyZW50UGVyaW9kSGVpZ2h0CQDMCAIJAKQDAQUHdG9DbGFpbQkAzAgCCQCkAwEFEG5leHRQZXJpb2RIZWlnaHQJAMwIAgkApAMBBQh0b1VubG9jawUDbmlsBQNTRVAJAQtTdHJpbmdFbnRyeQIJAQ5rZXlVc2VyVG9DbGFpbQEFC3VzZXJBZGRyZXNzBQt2YWx1ZVN0cmluZwEVZ2V0VXNlclRvQ2xhaW1CYWxhbmNlAQt1c2VyQWRkcmVzcwQYdXNlclRvQ2xhaW1EYXRhU3RyaW5nUmF3CQCdCAIFBHRoaXMJAQ5rZXlVc2VyVG9DbGFpbQEFC3VzZXJBZGRyZXNzBAckbWF0Y2gwBRh1c2VyVG9DbGFpbURhdGFTdHJpbmdSYXcDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAJkcwUHJG1hdGNoMAQIZGF0YUxpc3QJALUJAgUCZHMFA1NFUAQNY3VycmVudFBlcmlvZAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCGRhdGFMaXN0AAEEB3RvQ2xhaW0JAQ1wYXJzZUludFZhbHVlAQkAkQMCBQhkYXRhTGlzdAACBApuZXh0UGVyaW9kCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUIZGF0YUxpc3QAAwQIdG9VbmxvY2sJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQhkYXRhTGlzdAAEAwMJAGYCBQpuZXh0UGVyaW9kBQZoZWlnaHQGCQAAAgUPY3VycmVudFBlcmlvZElkAAAJAJQKAgUHdG9DbGFpbQUIdG9VbmxvY2sJAJQKAgkAZAIFB3RvQ2xhaW0FCHRvVW5sb2NrAAAJAJQKAgAAAAABF2dldFVzZXJUb3RhbExvY2tlZEVudHJ5Agt1c2VyQWRkcmVzcw91c2VyVG90YWxMb2NrZWQJAQxJbnRlZ2VyRW50cnkCCQESa2V5VXNlclRvdGFsTG9ja2VkAQULdXNlckFkZHJlc3MFD3VzZXJUb3RhbExvY2tlZAESZ2V0VXNlclRvdGFsTG9ja2VkAQt1c2VyQWRkcmVzcwkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQESa2V5VXNlclRvdGFsTG9ja2VkAQULdXNlckFkZHJlc3MAAAEVY2FsY3VsYXRlVW5pdHNUb0NsYWltAQt1c2VyQWRkcmVzcwQPY2xhaW1lZEJsb2NrS2V5CQEUa2V5VW5pdHNDbGFpbWVkQmxvY2sBBQt1c2VyQWRkcmVzcwQMY2xhaW1lZEJsb2NrCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFD2NsYWltZWRCbG9ja0tleQUVdW5pdHNDbGFpbVN0YXJ0SGVpZ2h0BBN1bml0c1BlckJsb2NrU2NhbGU4CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFFmtleVVuaXRzUGVyQmxvY2tTY2FsZTgAAAQMY3VycmVudEJsb2NrCQCXAwEJAMwIAgkAZAIFFXVuaXRzQ2xhaW1TdGFydEhlaWdodAUSdW5pdHNDbGFpbUludGVydmFsCQDMCAIFBmhlaWdodAUDbmlsBAxibG9ja3NQYXNzZWQJAGUCBQxjdXJyZW50QmxvY2sFDGNsYWltZWRCbG9jawQMYW1vdW50U3Rha2VkCQESZ2V0VXNlclRvdGFsTG9ja2VkAQULdXNlckFkZHJlc3MED3VuaXRzVG9DbGFpbU5vdwkAawMJAGgCBRN1bml0c1BlckJsb2NrU2NhbGU4BQxibG9ja3NQYXNzZWQFDGFtb3VudFN0YWtlZAUGc2NhbGU4BAhsMlRvQnVybgkAawMFDGFtb3VudFN0YWtlZAUMYmxvY2tzUGFzc2VkBRJ1bml0c0NsYWltSW50ZXJ2YWwJAJUKAwUPdW5pdHNUb0NsYWltTm93BQhsMlRvQnVybgUMY2xhaW1lZEJsb2NrARRnZXRVbmxvY2tVbml0c0FjdGlvbgELdXNlckFkZHJlc3MEDmtVbmxvY2tlZFVuaXRzCQEQa2V5VW5sb2NrZWRVbml0cwEFC3VzZXJBZGRyZXNzBA11bmxvY2tlZFVuaXRzCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFDmtVbmxvY2tlZFVuaXRzAAAECWtMMlRvQnVybgkBC2tleUwyVG9CdXJuAQULdXNlckFkZHJlc3MECGwyVG9CdXJuCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFCWtMMlRvQnVybgAABA0kdDAxMTIxNzExMzAyCQEVY2FsY3VsYXRlVW5pdHNUb0NsYWltAQULdXNlckFkZHJlc3MED3VuaXRzVG9DbGFpbU5vdwgFDSR0MDExMjE3MTEzMDICXzEEC2wyVG9CdXJuTm93CAUNJHQwMTEyMTcxMTMwMgJfMgQMY2xhaW1lZEJsb2NrCAUNJHQwMTEyMTcxMTMwMgJfMwMJAGcCAAAFD3VuaXRzVG9DbGFpbU5vdwUDbmlsCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEUa2V5VW5pdHNDbGFpbWVkQmxvY2sBBQt1c2VyQWRkcmVzcwUMY2xhaW1lZEJsb2NrCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQlrTDJUb0J1cm4JAGQCBQhsMlRvQnVybgULbDJUb0J1cm5Ob3cJAMwIAgkBDEludGVnZXJFbnRyeQIFDmtVbmxvY2tlZFVuaXRzCQBkAgUNdW5sb2NrZWRVbml0cwUPdW5pdHNUb0NsYWltTm93BQNuaWwBEWdldFVuc3Rha2VBY3Rpb25zAwtub2RlQWRkcmVzcwt1c2VyQWRkcmVzcw11bnN0YWtlQW1vdW50BA0kdDAxMTY5NzExNzcwCQESZ2V0TGVhc2luZ05vZGVEYXRhAQULbm9kZUFkZHJlc3MEEW5vZGVDdXJyZW50TGVhc2VkCAUNJHQwMTE2OTcxMTc3MAJfMQQObm9kZU5leHRMZWFzZWQIBQ0kdDAxMTY5NzExNzcwAl8yBA0kdDAxMTc3NTExODYxCQESZ2V0VXNlckxlYXNpbmdEYXRhAgULbm9kZUFkZHJlc3MFC3VzZXJBZGRyZXNzBBF1c2VyQ3VycmVudExlYXNlZAgFDSR0MDExNzc1MTE4NjECXzEEDnVzZXJOZXh0TGVhc2VkCAUNJHQwMTE3NzUxMTg2MQJfMgQGY2hlY2tzCQDMCAIDCQEBIQEFC2lzRm9yY2VTdG9wBgkBCHRocm93RXJyAQIdY29udHJhY3QgaXMgdGVtcG9yYXJ5IHN0b3BwZWQJAMwIAgMJAQEhAQUOaXNGb3JjZU91dFN0b3AGCQEIdGhyb3dFcnIBAh11bnN0YWtlIGlzIHRlbXBvcmFyeSBkaXNhYmxlZAkAzAgCAwkAZgIFDXVuc3Rha2VBbW91bnQAAAYJAQh0aHJvd0VycgECJ3Vuc3Rha2UgYW1vdW50IHNob3VsZCBiZSBncmVhdGVyIHRoYW4gMAkAzAgCAwkAZwIFDnVzZXJOZXh0TGVhc2VkBQ11bnN0YWtlQW1vdW50BgkBCHRocm93RXJyAQI5dW5zdGFrZSBhbW91bnQgc2hvdWxkIGJlIGxlc3Mgb3IgZXF1YWwgdXNlciBzdGFrZWQgYW1vdW50CQDMCAIDCQBnAgUObm9kZU5leHRMZWFzZWQFDXVuc3Rha2VBbW91bnQGCQEIdGhyb3dFcnIBAjl1bnN0YWtlIGFtb3VudCBzaG91bGQgYmUgbGVzcyBvciBlcXVhbCBub2RlIHN0YWtlZCBhbW91bnQJAMwIAgMJAQ5pc1ZhbGlkQWRkcmVzcwEFC25vZGVBZGRyZXNzBgkBCHRocm93RXJyAQkAuQkCCQDMCAICGm5vZGUgYWRkcmVzcyBpcyBub3QgdmFsaWQ6CQDMCAIFC25vZGVBZGRyZXNzBQNuaWwCASAJAMwIAgMJAQ5pc1ZhbGlkQWRkcmVzcwEFC3VzZXJBZGRyZXNzBgkBCHRocm93RXJyAQkAuQkCCQDMCAICGnVzZXIgYWRkcmVzcyBpcyBub3QgdmFsaWQ6CQDMCAIFC3VzZXJBZGRyZXNzBQNuaWwCASAFA25pbAMJAAACBQZjaGVja3MFBmNoZWNrcwQQbmV3Tm9kZU5leHRMZWFzZQkAZQIFDm5vZGVOZXh0TGVhc2VkBQ11bnN0YWtlQW1vdW50BBFuZXdVc2VyTmV4dExlYXNlZAkAZQIFDnVzZXJOZXh0TGVhc2VkBQ11bnN0YWtlQW1vdW50BA0kdDAxMjc0NTEyODA1CQEVZ2V0VXNlclRvQ2xhaW1CYWxhbmNlAQULdXNlckFkZHJlc3MEB3RvQ2xhaW0IBQ0kdDAxMjc0NTEyODA1Al8xBAh0b1VubG9jawgFDSR0MDEyNzQ1MTI4MDUCXzIEC25ld1RvVW5sb2NrCQBkAgUIdG9VbmxvY2sFDXVuc3Rha2VBbW91bnQED3VzZXJUb3RhbExvY2tlZAkBEmdldFVzZXJUb3RhbExvY2tlZAEFC3VzZXJBZGRyZXNzBBJuZXdVc2VyVG90YWxMb2NrZWQJAGUCBQ91c2VyVG90YWxMb2NrZWQFDXVuc3Rha2VBbW91bnQEFHVuaXRzVW5sb2NrZWRBY3Rpb25zCQEUZ2V0VW5sb2NrVW5pdHNBY3Rpb24BBQt1c2VyQWRkcmVzcwkAzggCCQDMCAIJARNnZXRMZWFzaW5nTm9kZUVudHJ5AwULbm9kZUFkZHJlc3MFEW5vZGVDdXJyZW50TGVhc2VkBRBuZXdOb2RlTmV4dExlYXNlCQDMCAIJARNnZXRVc2VyTGVhc2luZ0VudHJ5BAULbm9kZUFkZHJlc3MFC3VzZXJBZGRyZXNzBRF1c2VyQ3VycmVudExlYXNlZAURbmV3VXNlck5leHRMZWFzZWQJAMwIAgkBE2dldFVzZXJUb0NsYWltRW50cnkDBQt1c2VyQWRkcmVzcwUHdG9DbGFpbQULbmV3VG9VbmxvY2sJAMwIAgkBF2dldFVzZXJUb3RhbExvY2tlZEVudHJ5AgULdXNlckFkZHJlc3MFEm5ld1VzZXJUb3RhbExvY2tlZAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBFmtleU5vZGVMZWFzaW5nQnlIZWlnaHQBBQtub2RlQWRkcmVzcwUQbmV3Tm9kZU5leHRMZWFzZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBFmtleVVzZXJMZWFzaW5nQnlIZWlnaHQCBQtub2RlQWRkcmVzcwULdXNlckFkZHJlc3MFEW5ld1VzZXJOZXh0TGVhc2VkBQNuaWwFFHVuaXRzVW5sb2NrZWRBY3Rpb25zCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuARdnZXRDbGFpbVVubG9ja2VkQWN0aW9ucwILdXNlckFkZHJlc3MLY2xhaW1BbW91bnQEDSR0MDEzNjI0MTM2ODQJARVnZXRVc2VyVG9DbGFpbUJhbGFuY2UBBQt1c2VyQWRkcmVzcwQHdG9DbGFpbQgFDSR0MDEzNjI0MTM2ODQCXzEECHRvVW5sb2NrCAUNJHQwMTM2MjQxMzY4NAJfMgQGY2hlY2tzCQDMCAIDCQEBIQEFC2lzRm9yY2VTdG9wBgkBCHRocm93RXJyAQIdY29udHJhY3QgaXMgdGVtcG9yYXJ5IHN0b3BwZWQJAMwIAgMJAQEhAQUOaXNGb3JjZU91dFN0b3AGCQEIdGhyb3dFcnIBAhtjbGFpbSBpcyB0ZW1wb3JhcnkgZGlzYWJsZWQJAMwIAgMJAGYCBQtjbGFpbUFtb3VudAAABgkBCHRocm93RXJyAQIlY2xhaW0gYW1vdW50IHNob3VsZCBiZSBncmVhdGVyIHRoYW4gMAkAzAgCAwkAZwIFB3RvQ2xhaW0FC2NsYWltQW1vdW50BgkBCHRocm93RXJyAQI0Y2xhaW0gYW1vdW50IHNob3VsZCBiZSBsZXNzIG9yIGVxdWFsIHVubG9ja2VkIGFtb3VudAkAzAgCAwkBDmlzVmFsaWRBZGRyZXNzAQULdXNlckFkZHJlc3MGCQEIdGhyb3dFcnIBCQC5CQIJAMwIAgIadXNlciBhZGRyZXNzIGlzIG5vdCB2YWxpZDoJAMwIAgULdXNlckFkZHJlc3MFA25pbAIBIAUDbmlsAwkAAAIFBmNoZWNrcwUGY2hlY2tzBApuZXdUb0NsYWltCQBlAgUHdG9DbGFpbQULY2xhaW1BbW91bnQJAMwIAgkBE2dldFVzZXJUb0NsYWltRW50cnkDBQt1c2VyQWRkcmVzcwUKbmV3VG9DbGFpbQUIdG9VbmxvY2sJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwkBEUBleHRyTmF0aXZlKDEwNjIpAQULdXNlckFkZHJlc3MFC2NsYWltQW1vdW50BQ5sMkFzc2V0SWRCeXRlcwUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuARJnZXRTdGFrZUZvckFjdGlvbnMCC3VzZXJBZGRyZXNzAWkEDSR0MDE0NDUwMTQ1MTAJARVnZXRVc2VyVG9DbGFpbUJhbGFuY2UBBQt1c2VyQWRkcmVzcwQHdG9DbGFpbQgFDSR0MDE0NDUwMTQ1MTACXzEECHRvVW5sb2NrCAUNJHQwMTQ0NTAxNDUxMAJfMgQGY2hlY2tzCQDMCAIDCQEBIQEFC2lzRm9yY2VTdG9wBgkBCHRocm93RXJyAQIdY29udHJhY3QgaXMgdGVtcG9yYXJ5IHN0b3BwZWQJAMwIAgMJAGcCAAEJAJADAQgFAWkIcGF5bWVudHMGCQEIdGhyb3dFcnIBAhFtYXhpbXVtIDEgcGF5bWVudAkAzAgCAwMJAAACCQCQAwEIBQFpCHBheW1lbnRzAAAGCQAAAggJAJEDAggFAWkIcGF5bWVudHMAAAdhc3NldElkBQ5sMkFzc2V0SWRCeXRlcwYJAQh0aHJvd0VycgEJALkJAgkAzAgCAhpwYXltZW50IGFzc2V0SWQgc2hvdWxkIGJlOgkAzAgCBQ9sMkFzc2V0SWRTdHJpbmcFA25pbAIBIAkAzAgCAwkBDmlzVmFsaWRBZGRyZXNzAQULdXNlckFkZHJlc3MGCQEIdGhyb3dFcnIBCQC5CQIJAMwIAgIadXNlciBhZGRyZXNzIGlzIG5vdCB2YWxpZDoJAMwIAgULdXNlckFkZHJlc3MFA25pbAIBIAUDbmlsAwkAAAIFBmNoZWNrcwUGY2hlY2tzBApuZXdUb0NsYWltCQBkAgUHdG9DbGFpbQgJAJEDAggFAWkIcGF5bWVudHMAAAZhbW91bnQJAMwIAgkBE2dldFVzZXJUb0NsYWltRW50cnkDBQt1c2VyQWRkcmVzcwUKbmV3VG9DbGFpbQUIdG9VbmxvY2sFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgEPZ2V0U3Rha2VBY3Rpb25zBAtub2RlQWRkcmVzcwt1c2VyQWRkcmVzcxF1c2VyTGVhc2luZ0Ftb3VudAFpBA0kdDAxNTI0MjE1MzAyCQEVZ2V0VXNlclRvQ2xhaW1CYWxhbmNlAQULdXNlckFkZHJlc3MEB3RvQ2xhaW0IBQ0kdDAxNTI0MjE1MzAyAl8xBAh0b1VubG9jawgFDSR0MDE1MjQyMTUzMDICXzIEDXBheW1lbnRBbW91bnQDCQAAAgkAkAMBCAUBaQhwYXltZW50cwAAAAAICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50BAlhdmFpbGFibGUJAGQCCQBkAgUIdG9VbmxvY2sFB3RvQ2xhaW0FDXBheW1lbnRBbW91bnQEBmNoZWNrcwkAzAgCAwkBASEBBQtpc0ZvcmNlU3RvcAYJAQh0aHJvd0VycgECHWNvbnRyYWN0IGlzIHRlbXBvcmFyeSBzdG9wcGVkCQDMCAIDCQBnAgABCQCQAwEIBQFpCHBheW1lbnRzBgkBCHRocm93RXJyAQIRbWF4aW11bSAxIHBheW1lbnQJAMwIAgMDCQAAAgkAkAMBCAUBaQhwYXltZW50cwAABgkAAAIICQCRAwIIBQFpCHBheW1lbnRzAAAHYXNzZXRJZAUObDJBc3NldElkQnl0ZXMGCQEIdGhyb3dFcnIBCQC5CQIJAMwIAgIacGF5bWVudCBhc3NldElkIHNob3VsZCBiZToJAMwIAgUPbDJBc3NldElkU3RyaW5nBQNuaWwCASAJAMwIAgMJAGYCBRF1c2VyTGVhc2luZ0Ftb3VudAAABgkBCHRocm93RXJyAQIfYW1vdW50IHNob3VsZCBiZSBncmVhdGVyIHRoYW4gMAkAzAgCAwkAZwIFCWF2YWlsYWJsZQURdXNlckxlYXNpbmdBbW91bnQGCQEIdGhyb3dFcnIBAjthbW91bnQgc2hvdWxkIGJlIGxlc3Mgb3IgZXF1YWwgKHBheW1lbnQgKyBhdmFpbGFibGUpIGFtb3VudAkAzAgCAwkAZwIFEXVzZXJMZWFzaW5nQW1vdW50BQ1wYXltZW50QW1vdW50BgkAAgECMGFtb3VudCBzaG91bGQgYmUgZ3JlYXRlciBvciBlcXVhbCBwYXltZW50IGFtb3VudAkAzAgCAwkBDmlzVmFsaWRBZGRyZXNzAQULbm9kZUFkZHJlc3MGCQEIdGhyb3dFcnIBCQC5CQIJAMwIAgIabm9kZSBhZGRyZXNzIGlzIG5vdCB2YWxpZDoJAMwIAgULbm9kZUFkZHJlc3MFA25pbAIBIAkAzAgCAwkBDmlzVmFsaWRBZGRyZXNzAQULdXNlckFkZHJlc3MGCQEIdGhyb3dFcnIBCQC5CQIJAMwIAgIadXNlciBhZGRyZXNzIGlzIG5vdCB2YWxpZDoJAMwIAgULdXNlckFkZHJlc3MFA25pbAIBIAUDbmlsAwkAAAIFBmNoZWNrcwUGY2hlY2tzBA0kdDAxNjM3NzE2NDUwCQESZ2V0TGVhc2luZ05vZGVEYXRhAQULbm9kZUFkZHJlc3MEEW5vZGVDdXJyZW50TGVhc2VkCAUNJHQwMTYzNzcxNjQ1MAJfMQQObm9kZU5leHRMZWFzZWQIBQ0kdDAxNjM3NzE2NDUwAl8yBBBuZXdOb2RlTmV4dExlYXNlCQBkAgUObm9kZU5leHRMZWFzZWQFEXVzZXJMZWFzaW5nQW1vdW50BA0kdDAxNjUxODE2NjA0CQESZ2V0VXNlckxlYXNpbmdEYXRhAgULbm9kZUFkZHJlc3MFC3VzZXJBZGRyZXNzBBF1c2VyQ3VycmVudExlYXNlZAgFDSR0MDE2NTE4MTY2MDQCXzEEDnVzZXJOZXh0TGVhc2VkCAUNJHQwMTY1MTgxNjYwNAJfMgQRbmV3VXNlck5leHRMZWFzZWQJAGQCBQ51c2VyTmV4dExlYXNlZAURdXNlckxlYXNpbmdBbW91bnQEEmZyb21VbmxvY2tlZEFtb3VudAkAZQIFEXVzZXJMZWFzaW5nQW1vdW50BQ1wYXltZW50QW1vdW50BAtuZXdUb1VubG9jawkAlgMBCQDMCAIAAAkAzAgCCQBlAgUIdG9VbmxvY2sFEmZyb21VbmxvY2tlZEFtb3VudAUDbmlsBApuZXdUb0NsYWltCQCXAwEJAMwIAgUHdG9DbGFpbQkAzAgCCQBkAgUHdG9DbGFpbQkAZQIFCHRvVW5sb2NrBRJmcm9tVW5sb2NrZWRBbW91bnQFA25pbAQPdXNlclRvdGFsTG9ja2VkCQESZ2V0VXNlclRvdGFsTG9ja2VkAQULdXNlckFkZHJlc3MEEm5ld1VzZXJUb3RhbExvY2tlZAkAZAIFD3VzZXJUb3RhbExvY2tlZAURdXNlckxlYXNpbmdBbW91bnQEFHVuaXRzVW5sb2NrZWRBY3Rpb25zCQEUZ2V0VW5sb2NrVW5pdHNBY3Rpb24BBQt1c2VyQWRkcmVzcwkAzggCCQDMCAIJARNnZXRMZWFzaW5nTm9kZUVudHJ5AwULbm9kZUFkZHJlc3MFEW5vZGVDdXJyZW50TGVhc2VkBRBuZXdOb2RlTmV4dExlYXNlCQDMCAIJARNnZXRVc2VyTGVhc2luZ0VudHJ5BAULbm9kZUFkZHJlc3MFC3VzZXJBZGRyZXNzBRF1c2VyQ3VycmVudExlYXNlZAURbmV3VXNlck5leHRMZWFzZWQJAMwIAgkBE2dldFVzZXJUb0NsYWltRW50cnkDBQt1c2VyQWRkcmVzcwUKbmV3VG9DbGFpbQULbmV3VG9VbmxvY2sJAMwIAgkBF2dldFVzZXJUb3RhbExvY2tlZEVudHJ5AgULdXNlckFkZHJlc3MFEm5ld1VzZXJUb3RhbExvY2tlZAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBFmtleU5vZGVMZWFzaW5nQnlIZWlnaHQBBQtub2RlQWRkcmVzcwUQbmV3Tm9kZU5leHRMZWFzZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBFmtleVVzZXJMZWFzaW5nQnlIZWlnaHQCBQtub2RlQWRkcmVzcwULdXNlckFkZHJlc3MFEW5ld1VzZXJOZXh0TGVhc2VkBQNuaWwFFHVuaXRzVW5sb2NrZWRBY3Rpb25zCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuARpnZXRTdGFrZUZyb21QYXltZW50QWN0aW9ucwMLbm9kZUFkZHJlc3MLdXNlckFkZHJlc3MBaQQGY2hlY2tzCQDMCAIDCQAAAgkAkAMBCAUBaQhwYXltZW50cwABBgkBCHRocm93RXJyAQIgcGF5bWVudCBzaXplIHNob3VsZCBiZSBleGFjdGx5IDEFA25pbAMJAAACBQZjaGVja3MFBmNoZWNrcwkBD2dldFN0YWtlQWN0aW9ucwQFC25vZGVBZGRyZXNzBQt1c2VyQWRkcmVzcwgJAJEDAggFAWkIcGF5bWVudHMAAAZhbW91bnQFAWkJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BHGdldFNldE5ld1BlcmlvZExlbmd0aEFjdGlvbnMBD25ld1BlcmlvZExlbmd0aAQFY2hlY2sJAMwIAgMJAGYCBQ9uZXdQZXJpb2RMZW5ndGgAAAYJAQh0aHJvd0VycgECJnBlcmlvZCBsZW5ndGggc2hvdWxkIGJlIGdyZWF0ZXIgdGhhbiAwBQNuaWwDCQAAAgUFY2hlY2sFBWNoZWNrAwkAAAIFEnBlcmlvZE9mZnNldEhlaWdodAD///////////8BCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ9rZXlQZXJpb2RMZW5ndGgFD25ld1BlcmlvZExlbmd0aAkAzAgCCQEMSW50ZWdlckVudHJ5AgUVa2V5UGVyaW9kT2Zmc2V0SGVpZ2h0BQZoZWlnaHQFA25pbAkAzAgCCQEMSW50ZWdlckVudHJ5AgURa2V5UGVyaW9kT2Zmc2V0SWQJAGQCBQ9jdXJyZW50UGVyaW9kSWQAAQkAzAgCCQEMSW50ZWdlckVudHJ5AgUVa2V5UGVyaW9kT2Zmc2V0SGVpZ2h0BRBuZXh0UGVyaW9kSGVpZ2h0CQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ9rZXlQZXJpb2RMZW5ndGgFD25ld1BlcmlvZExlbmd0aAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuARFnZXRVbml0c0NsYWltRGF0YQELdXNlckFkZHJlc3MEDSR0MDE4NDg5MTg1NzQJARVjYWxjdWxhdGVVbml0c1RvQ2xhaW0BBQt1c2VyQWRkcmVzcwQPdW5sb2NrZWRVbml0Tm93CAUNJHQwMTg0ODkxODU3NAJfMQQLbDJUb0J1cm5Ob3cIBQ0kdDAxODQ4OTE4NTc0Al8yBAxjbGFpbWVkQmxvY2sIBQ0kdDAxODQ4OTE4NTc0Al8zBBF1bmxvY2tlZFVuaXRzUHJldgkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEQa2V5VW5sb2NrZWRVbml0cwEFC3VzZXJBZGRyZXNzAAAEC3VuaXRzVG9TZW5kCQBkAgUPdW5sb2NrZWRVbml0Tm93BRF1bmxvY2tlZFVuaXRzUHJldgQMbDJUb0J1cm5QcmV2CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQtrZXlMMlRvQnVybgEFC3VzZXJBZGRyZXNzAAAECGwyVG9CdXJuCQBkAgUMbDJUb0J1cm5QcmV2BQtsMlRvQnVybk5vdwQRdG90YWxVbml0c0NsYWltZWQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBFGtleVRvdGFsVW5pdHNDbGFpbWVkAQULdXNlckFkZHJlc3MAAAQNdG90YWxMMkJ1cm5lZAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEQa2V5TDJCdXJuZWRUb3RhbAEFC3VzZXJBZGRyZXNzAAAJAJcKBQULdW5pdHNUb1NlbmQFEXRvdGFsVW5pdHNDbGFpbWVkBQhsMlRvQnVybgUNdG90YWxMMkJ1cm5lZAUMY2xhaW1lZEJsb2NrARRnZXRDbGFpbVVuaXRzQWN0aW9ucwELdXNlckFkZHJlc3MEDSR0MDE5MTY2MTkyNzQJARFnZXRVbml0c0NsYWltRGF0YQEFC3VzZXJBZGRyZXNzBAt1bml0c1RvU2VuZAgFDSR0MDE5MTY2MTkyNzQCXzEEEXRvdGFsVW5pdHNDbGFpbWVkCAUNJHQwMTkxNjYxOTI3NAJfMgQIbDJUb0J1cm4IBQ0kdDAxOTE2NjE5Mjc0Al8zBA10b3RhbEwyQnVybmVkCAUNJHQwMTkxNjYxOTI3NAJfNAQMY2xhaW1lZEJsb2NrCAUNJHQwMTkxNjYxOTI3NAJfNQQFY2hlY2sJAMwIAgMJAGcCAAAFC3VuaXRzVG9TZW5kBgkBCHRocm93RXJyAQIQbm90aGluZyB0byBjbGFpbQUDbmlsAwkAAAIFBWNoZWNrBQVjaGVjawQKYnVybkFjdGlvbgQHJG1hdGNoMAUObDJBc3NldElkQnl0ZXMDCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQCaWQFByRtYXRjaDAJAMwIAgkBBEJ1cm4CBQJpZAUIbDJUb0J1cm4FA25pbAUDbmlsCQDOCAIJAMwIAgkBDEludGVnZXJFbnRyeQIJARRrZXlVbml0c0NsYWltZWRCbG9jawEFC3VzZXJBZGRyZXNzBQxjbGFpbWVkQmxvY2sJAMwIAgkBDEludGVnZXJFbnRyeQIJARRrZXlUb3RhbFVuaXRzQ2xhaW1lZAEFC3VzZXJBZGRyZXNzCQBkAgURdG90YWxVbml0c0NsYWltZWQFC3VuaXRzVG9TZW5kCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEQa2V5TDJCdXJuZWRUb3RhbAEFC3VzZXJBZGRyZXNzCQBkAgUNdG90YWxMMkJ1cm5lZAUIbDJUb0J1cm4JAMwIAgkBDEludGVnZXJFbnRyeQIJARBrZXlVbmxvY2tlZFVuaXRzAQULdXNlckFkZHJlc3MAAAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBC2tleUwyVG9CdXJuAQULdXNlckFkZHJlc3MAAAkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCQERQGV4dHJOYXRpdmUoMTA2MikBBQt1c2VyQWRkcmVzcwULdW5pdHNUb1NlbmQFEXVuaXRzQXNzZXRJZEJ5dGVzBQNuaWwFCmJ1cm5BY3Rpb24JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4QAWkBEnNldE5ld1BlcmlvZExlbmd0aAEPbmV3UGVyaW9kTGVuZ3RoBAZjaGVja3MJAMwIAgMJAQ1pc0luQWRtaW5MaXN0AQkApQgBCAUBaQZjYWxsZXIGCQEIdGhyb3dFcnIBAhpjYWxsZXIgaXMgbm90IGluIGFkbWluTGlzdAUDbmlsAwkAAAIFBmNoZWNrcwUGY2hlY2tzCQEcZ2V0U2V0TmV3UGVyaW9kTGVuZ3RoQWN0aW9ucwEFD25ld1BlcmlvZExlbmd0aAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQpjbGFpbVVuaXRzAAQLdXNlckFkZHJlc3MJAKUIAQgFAWkGY2FsbGVyCQEUZ2V0Q2xhaW1Vbml0c0FjdGlvbnMBBQt1c2VyQWRkcmVzcwFpARBzZXRGb3JjZVN0b3BGbGFnAQRzdG9wBAVjaGVjawkAzAgCAwkBDWlzSW5BZG1pbkxpc3QBCQClCAEIBQFpBmNhbGxlcgYJAQh0aHJvd0VycgECGmNhbGxlciBpcyBub3QgaW4gYWRtaW5MaXN0BQNuaWwDCQAAAgUFY2hlY2sFBWNoZWNrCQDMCAIJAQxCb29sZWFuRW50cnkCBQxrZXlGb3JjZVN0b3AFBHN0b3AFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARNzZXRGb3JjZU91dFN0b3BGbGFnAQRzdG9wBAVjaGVjawkAzAgCAwkBDWlzSW5BZG1pbkxpc3QBCQClCAEIBQFpBmNhbGxlcgYJAQh0aHJvd0VycgECGmNhbGxlciBpcyBub3QgaW4gYWRtaW5MaXN0BQNuaWwDCQAAAgUFY2hlY2sFBWNoZWNrCQDMCAIJAQxCb29sZWFuRW50cnkCBQ9rZXlGb3JjZU91dFN0b3AFBHN0b3AFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARNnZXROb2RlRGF0YVJFQURPTkxZAQtub2RlQWRkcmVzcwQNJHQwMjEwMDcyMTA3MQkBEmdldExlYXNpbmdOb2RlRGF0YQEFC25vZGVBZGRyZXNzBAxjdXJyZW50TGVhc2UIBQ0kdDAyMTAwNzIxMDcxAl8xBApuZXh0TGVhc2VkCAUNJHQwMjEwMDcyMTA3MQJfMgkAlAoCBQNuaWwJAJcKBQUTY3VycmVudFBlcmlvZEhlaWdodAUMY3VycmVudExlYXNlBRBuZXh0UGVyaW9kSGVpZ2h0BQpuZXh0TGVhc2VkBQZoZWlnaHQBaQEaZ2V0VXNlckxlYXNpbmdEYXRhUkVBRE9OTFkCC25vZGVBZGRyZXNzC3VzZXJBZGRyZXNzBA0kdDAyMTQ0MTIxNTE4CQESZ2V0VXNlckxlYXNpbmdEYXRhAgULbm9kZUFkZHJlc3MFC3VzZXJBZGRyZXNzBAxjdXJyZW50TGVhc2UIBQ0kdDAyMTQ0MTIxNTE4Al8xBApuZXh0TGVhc2VkCAUNJHQwMjE0NDEyMTUxOAJfMgkAlAoCBQNuaWwJAJcKBQUTY3VycmVudFBlcmlvZEhlaWdodAUMY3VycmVudExlYXNlBRBuZXh0UGVyaW9kSGVpZ2h0BQpuZXh0TGVhc2VkBQZoZWlnaHQBaQETZ2V0VXNlckRhdGFSRUFET05MWQELdXNlckFkZHJlc3MEDSR0MDIyMDM0MjIwOTQJARVnZXRVc2VyVG9DbGFpbUJhbGFuY2UBBQt1c2VyQWRkcmVzcwQHdG9DbGFpbQgFDSR0MDIyMDM0MjIwOTQCXzEECHRvVW5sb2NrCAUNJHQwMjIwMzQyMjA5NAJfMgQPdXNlclRvdGFsTG9ja2VkCQESZ2V0VXNlclRvdGFsTG9ja2VkAQULdXNlckFkZHJlc3MEDSR0MDIyMTU3MjIyNjUJARFnZXRVbml0c0NsYWltRGF0YQEFC3VzZXJBZGRyZXNzBAt1bml0c1RvU2VuZAgFDSR0MDIyMTU3MjIyNjUCXzEEEXRvdGFsVW5pdHNDbGFpbWVkCAUNJHQwMjIxNTcyMjI2NQJfMgQIbDJUb0J1cm4IBQ0kdDAyMjE1NzIyMjY1Al8zBA10b3RhbEwyQnVybmVkCAUNJHQwMjIxNTcyMjI2NQJfNAQMY2xhaW1lZEJsb2NrCAUNJHQwMjIxNTcyMjI2NQJfNQkAlAoCBQNuaWwJAJ0KCwUTY3VycmVudFBlcmlvZEhlaWdodAUHdG9DbGFpbQUQbmV4dFBlcmlvZEhlaWdodAUIdG9VbmxvY2sFD3VzZXJUb3RhbExvY2tlZAUGaGVpZ2h0BQt1bml0c1RvU2VuZAURdG90YWxVbml0c0NsYWltZWQFCGwyVG9CdXJuBQ10b3RhbEwyQnVybmVkBQxjbGFpbWVkQmxvY2sBaQEObGVhc2VCeUFkZHJlc3MCC25vZGVBZGRyZXNzC3VzZXJBZGRyZXNzCQEaZ2V0U3Rha2VGcm9tUGF5bWVudEFjdGlvbnMDBQtub2RlQWRkcmVzcwULdXNlckFkZHJlc3MFAWkBaQEFbGVhc2UBC25vZGVBZGRyZXNzBAt1c2VyQWRkcmVzcwkApQgBCAUBaQZjYWxsZXIJARpnZXRTdGFrZUZyb21QYXltZW50QWN0aW9ucwMFC25vZGVBZGRyZXNzBQt1c2VyQWRkcmVzcwUBaQFpAQ9sZWFzZUZyb21Mb2NrZWQCC25vZGVBZGRyZXNzBmFtb3VudAQLdXNlckFkZHJlc3MJAKUIAQgFAWkGY2FsbGVyCQEPZ2V0U3Rha2VBY3Rpb25zBAULbm9kZUFkZHJlc3MFC3VzZXJBZGRyZXNzBQZhbW91bnQFAWkBaQELY2FuY2VsTGVhc2UCC25vZGVBZGRyZXNzBmFtb3VudAQLdXNlckFkZHJlc3MJAKUIAQgFAWkGY2FsbGVyCQERZ2V0VW5zdGFrZUFjdGlvbnMDBQtub2RlQWRkcmVzcwULdXNlckFkZHJlc3MFBmFtb3VudAFpAQVjbGFpbQEGYW1vdW50BAt1c2VyQWRkcmVzcwkApQgBCAUBaQZjYWxsZXIJARdnZXRDbGFpbVVubG9ja2VkQWN0aW9ucwIFC3VzZXJBZGRyZXNzBQZhbW91bnQBaQEIY2xhaW1BbGwABAt1c2VyQWRkcmVzcwkApQgBCAUBaQZjYWxsZXIEDSR0MDIzNDU3MjM1MTcJARVnZXRVc2VyVG9DbGFpbUJhbGFuY2UBBQt1c2VyQWRkcmVzcwQHdG9DbGFpbQgFDSR0MDIzNDU3MjM1MTcCXzEECHRvVW5sb2NrCAUNJHQwMjM0NTcyMzUxNwJfMgQGY2hlY2tzCQDMCAIDCQBmAgUHdG9DbGFpbQAABgkBCHRocm93RXJyAQIQbm90aGluZyB0byBjbGFpbQUDbmlsAwkAAAIFBmNoZWNrcwUGY2hlY2tzCQEXZ2V0Q2xhaW1VbmxvY2tlZEFjdGlvbnMCBQt1c2VyQWRkcmVzcwUHdG9DbGFpbQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQhzdGFrZUZvcgELdXNlckFkZHJlc3MJARJnZXRTdGFrZUZvckFjdGlvbnMCBQt1c2VyQWRkcmVzcwUBaQFpARFzdGFydFVuaXRzVmVzdGluZwAEB3RvdGFsTDIAgICo7IWv0bEBBAp0b3RhbFVuaXRzCAkAkQMCCAUBaQhwYXltZW50cwAABmFtb3VudAQTdW5pdHNQZXJCbG9ja1NjYWxlOAkAaQIJAGsDBQd0b3RhbEwyBQZzY2FsZTgFCnRvdGFsVW5pdHMFEnVuaXRzQ2xhaW1JbnRlcnZhbAQFY2hlY2sJAMwIAgMJAQ1pc0luQWRtaW5MaXN0AQkApQgBCAUBaQZjYWxsZXIGCQEIdGhyb3dFcnIBAhpjYWxsZXIgaXMgbm90IGluIGFkbWluTGlzdAkAzAgCAwkAAAIJAJADAQgFAWkIcGF5bWVudHMAAQYJAQh0aHJvd0VycgECE3Nob3VsZCBiZSAxIHBheW1lbnQJAMwIAgMJAGYCBRN1bml0c1BlckJsb2NrU2NhbGU4AAAGCQEIdGhyb3dFcnIBAih1bml0cyBwZXIgYmxvY2sgc2hvdWxkIGJlIGdyZWF0ZWQgdGhhbiAwBQNuaWwDCQAAAgUFY2hlY2sFBWNoZWNrCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRZrZXlVbml0c1BlckJsb2NrU2NhbGU4BRN1bml0c1BlckJsb2NrU2NhbGU4CQDMCAIJAQxJbnRlZ2VyRW50cnkCBRhrZXlVbml0c0NsYWltU3RhcnRIZWlnaHQFBmhlaWdodAkAzAgCCQELU3RyaW5nRW50cnkCBQ9rZXlVbml0c0Fzc2V0SWQJARJhc3NldEJ5dGVzVG9TdHJpbmcBCAkAkQMCCAUBaQhwYXltZW50cwAAB2Fzc2V0SWQFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQt2b3RlRm9yVHhJZAEEdHhJZAQTY2FsbGVyQWRkcmVzc1N0cmluZwkA2AQBCAgFAWkGY2FsbGVyBWJ5dGVzBAlrZXlQcmVmaXgJARhrZXlBbGxvd2VkVHhJZFZvdGVQcmVmaXgBBQR0eElkBAZyZXN1bHQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDmtleUFsbG93ZWRUeElkAAUEdHhJZAUDbmlsBBFhbGxvd2VkVHhJZE9wdGlvbgkAnQgCBQR0aGlzCQEOa2V5QWxsb3dlZFR4SWQABANlcnIJAMwIAgMJAAACCQDIAQEJANkEAQUEdHhJZAURVFhJRF9CWVRFU19MRU5HVEgGCQEIdGhyb3dFcnIBCQCsAgIFBHR4SWQCEiBpcyBub3QgdmFsaWQgdHhJZAkAzAgCAwMJAAACBRFhbGxvd2VkVHhJZE9wdGlvbgUEdW5pdAYJAQIhPQIJAQV2YWx1ZQEFEWFsbG93ZWRUeElkT3B0aW9uBQR0eElkBgkBCHRocm93RXJyAQkArAICBQR0eElkAhMgaXMgYWxyZWFkeSBhbGxvd2VkBQNuaWwDCQAAAgUDZXJyBQNlcnIJAQx2b3RlSU5URVJOQUwEBRNjYWxsZXJBZGRyZXNzU3RyaW5nBQlrZXlQcmVmaXgFBlFVT1JVTQUGcmVzdWx0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAQJ0eAEGdmVyaWZ5AAQIYnlBZG1pbnMJAAACCAUCdHgCaWQJANkEAQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzCQEOa2V5QWxsb3dlZFR4SWQAAgAEB2J5T3duZXIDCQBnAgkAkAMBCQENZ2V0QWRtaW5zTGlzdAAFBlFVT1JVTQcJAPQDAwgFAnR4CWJvZHlCeXRlcwkAkQMCCAUCdHgGcHJvb2ZzAAAIBQJ0eA9zZW5kZXJQdWJsaWNLZXkDBQhieUFkbWlucwYFB2J5T3duZXKu+QK+", "chainId": 84, "height": 3336621, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 24A1mSKMLAyoGHWK9aRJsRp8HChXJF9GBtsXyxM61QGr Next: 5kig3UQyBqXAuNNrokWxkS13UtjRKtYo9Wb1kxx7NotR Diff:
OldNewDifferences
99
1010 let scale8 = 100000000
1111
12+let unitsClaimInterval = ((365 * 24) * 60)
13+
1214 func throwErr (msg) = throw(((contractFile + ": ") + msg))
1315
1416
15-let keyAssetId = makeString(["%s", "assetId"], SEP)
17+let keyL2AssetId = makeString(["%s", "assetId"], SEP)
1618
1719 let keyForceStop = makeString(["%s", "forceStop"], SEP)
1820
1921 let keyForceOutStop = makeString(["%s", "forceOutStop"], SEP)
22+
23+let keyUnitsAssetId = makeString(["%s", "unitsAssetId"], SEP)
24+
25+let keyUnitsPerBlockScale8 = makeString(["%s", "unitsPerBlock"], SEP)
2026
2127 let keyPeriodOffsetId = makeString(["%s", "offsetId"], SEP)
2228
2329 let keyPeriodOffsetHeight = makeString(["%s", "offsetHeight"], SEP)
2430
2531 let keyPeriodLength = makeString(["%s", "periodLength"], SEP)
32+
33+let keyUnitsClaimStartHeight = makeString(["%s", "unitsClaimStartHeight"], SEP)
2634
2735 let periodOffsetId = valueOrElse(getInteger(this, keyPeriodOffsetId), 0)
2836
5260 then 0
5361 else (currentPeriodHeight + periodLength)
5462
63+let unitsClaimStartHeight = valueOrElse(getInteger(this, keyUnitsClaimStartHeight), height)
64+
5565 func keyLeasingNodeData (nodeAddress) = makeString(["%s", nodeAddress], SEP)
5666
5767
6474 func keyUserTotalLocked (userAddress) = makeString(["%s%s", "userTotalLocked", userAddress], SEP)
6575
6676
67-func keyClaimedBlock (userAddress) = makeString(["%s%s", userAddress, "claimedBlock"], SEP)
77+func keyUnitsClaimedBlock (userAddress) = makeString(["%s%s", "unitsClaimedBlock", userAddress], SEP)
6878
6979
70-func keyTotalUnitsClaimed (userAddress) = makeString(["%s%s", userAddress, "totalUnitsClaimed"], SEP)
80+func keyUnlockedUnits (userAddress) = makeString(["%s%s", "unlockedUnits", userAddress], SEP)
81+
82+
83+func keyTotalUnitsClaimed (userAddress) = makeString(["%s%s", "totalUnitsClaimed", userAddress], SEP)
84+
85+
86+func keyL2ToBurn (userAddress) = makeString(["%s%s", "l2ToBurn", userAddress], SEP)
87+
88+
89+func keyL2BurnedTotal (userAddress) = makeString(["%s%s", "l2BurnedTotal", userAddress], SEP)
7190
7291
7392 func keyNodeLeasingByHeight (nodeAddress) = {
86105 }
87106
88107
89-let assetIdString = valueOrElse(getString(this, keyAssetId), "WAVES")
90-
91-let assetIdBytes = if ((assetIdString == "WAVES"))
108+func assetStringToBytes (assetIdString) = if ((assetIdString == "WAVES"))
92109 then unit
93110 else fromBase58String(assetIdString)
111+
112+
113+func assetBytesToString (assetId) = match assetId {
114+ case a: ByteVector =>
115+ toBase58String(a)
116+ case _ =>
117+ "WAVES"
118+}
119+
120+
121+let l2AssetIdString = valueOrElse(getString(this, keyL2AssetId), "WAVES")
122+
123+let unitsAssetIdString = valueOrElse(getString(this, keyUnitsAssetId), "WAVES")
124+
125+let l2AssetIdBytes = assetStringToBytes(l2AssetIdString)
126+
127+let unitsAssetIdBytes = assetStringToBytes(unitsAssetIdString)
94128
95129 let isForceStop = valueOrElse(getBoolean(this, keyForceStop), false)
96130
140174
141175
142176 func genVotesKeysHelper (a,adminAddress) = {
143- let $t039683992 = a
144- let result = $t039683992._1
145- let prefix = $t039683992._2
177+ let $t050215045 = a
178+ let result = $t050215045._1
179+ let prefix = $t050215045._2
146180 $Tuple2((result :+ keyFullAdminVote(prefix, adminAddress)), prefix)
147181 }
148182
149183
150184 func genVotesKeys (keyPrefix) = {
151185 let adminList = keyAdminAddressList()
152- let $t041394223 = {
186+ let $t051925276 = {
153187 let $l = getAdminsList()
154188 let $s = size($l)
155189 let $acc0 = $Tuple2(nil, keyPrefix)
163197
164198 $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5)
165199 }
166- let result = $t041394223._1
167- let prefix = $t041394223._2
200+ let result = $t051925276._1
201+ let prefix = $t051925276._2
168202 result
169203 }
170204
315349 func getUserTotalLocked (userAddress) = valueOrElse(getInteger(this, keyUserTotalLocked(userAddress)), 0)
316350
317351
352+func calculateUnitsToClaim (userAddress) = {
353+ let claimedBlockKey = keyUnitsClaimedBlock(userAddress)
354+ let claimedBlock = valueOrElse(getInteger(this, claimedBlockKey), unitsClaimStartHeight)
355+ let unitsPerBlockScale8 = valueOrElse(getInteger(this, keyUnitsPerBlockScale8), 0)
356+ let currentBlock = min([(unitsClaimStartHeight + unitsClaimInterval), height])
357+ let blocksPassed = (currentBlock - claimedBlock)
358+ let amountStaked = getUserTotalLocked(userAddress)
359+ let unitsToClaimNow = fraction((unitsPerBlockScale8 * blocksPassed), amountStaked, scale8)
360+ let l2ToBurn = fraction(amountStaked, blocksPassed, unitsClaimInterval)
361+ $Tuple3(unitsToClaimNow, l2ToBurn, claimedBlock)
362+ }
363+
364+
365+func getUnlockUnitsAction (userAddress) = {
366+ let kUnlockedUnits = keyUnlockedUnits(userAddress)
367+ let unlockedUnits = valueOrElse(getInteger(this, kUnlockedUnits), 0)
368+ let kL2ToBurn = keyL2ToBurn(userAddress)
369+ let l2ToBurn = valueOrElse(getInteger(this, kL2ToBurn), 0)
370+ let $t01121711302 = calculateUnitsToClaim(userAddress)
371+ let unitsToClaimNow = $t01121711302._1
372+ let l2ToBurnNow = $t01121711302._2
373+ let claimedBlock = $t01121711302._3
374+ if ((0 >= unitsToClaimNow))
375+ then nil
376+ else [IntegerEntry(keyUnitsClaimedBlock(userAddress), claimedBlock), IntegerEntry(kL2ToBurn, (l2ToBurn + l2ToBurnNow)), IntegerEntry(kUnlockedUnits, (unlockedUnits + unitsToClaimNow))]
377+ }
378+
379+
318380 func getUnstakeActions (nodeAddress,userAddress,unstakeAmount) = {
319- let $t092639336 = getLeasingNodeData(nodeAddress)
320- let nodeCurrentLeased = $t092639336._1
321- let nodeNextLeased = $t092639336._2
322- let $t093419427 = getUserLeasingData(nodeAddress, userAddress)
323- let userCurrentLeased = $t093419427._1
324- let userNextLeased = $t093419427._2
381+ let $t01169711770 = getLeasingNodeData(nodeAddress)
382+ let nodeCurrentLeased = $t01169711770._1
383+ let nodeNextLeased = $t01169711770._2
384+ let $t01177511861 = getUserLeasingData(nodeAddress, userAddress)
385+ let userCurrentLeased = $t01177511861._1
386+ let userNextLeased = $t01177511861._2
325387 let checks = [if (!(isForceStop))
326388 then true
327389 else throwErr("contract is temporary stopped"), if (!(isForceOutStop))
341403 then {
342404 let newNodeNextLease = (nodeNextLeased - unstakeAmount)
343405 let newUserNextLeased = (userNextLeased - unstakeAmount)
344- let $t01031110371 = getUserToClaimBalance(userAddress)
345- let toClaim = $t01031110371._1
346- let toUnlock = $t01031110371._2
406+ let $t01274512805 = getUserToClaimBalance(userAddress)
407+ let toClaim = $t01274512805._1
408+ let toUnlock = $t01274512805._2
347409 let newToUnlock = (toUnlock + unstakeAmount)
348410 let userTotalLocked = getUserTotalLocked(userAddress)
349411 let newUserTotalLocked = (userTotalLocked - unstakeAmount)
350-[getLeasingNodeEntry(nodeAddress, nodeCurrentLeased, newNodeNextLease), getUserLeasingEntry(nodeAddress, userAddress, userCurrentLeased, newUserNextLeased), getUserToClaimEntry(userAddress, toClaim, newToUnlock), getUserTotalLockedEntry(userAddress, newUserTotalLocked), IntegerEntry(keyNodeLeasingByHeight(nodeAddress), newNodeNextLease), IntegerEntry(keyUserLeasingByHeight(nodeAddress, userAddress), newUserNextLeased)]
412+ let unitsUnlockedActions = getUnlockUnitsAction(userAddress)
413+ ([getLeasingNodeEntry(nodeAddress, nodeCurrentLeased, newNodeNextLease), getUserLeasingEntry(nodeAddress, userAddress, userCurrentLeased, newUserNextLeased), getUserToClaimEntry(userAddress, toClaim, newToUnlock), getUserTotalLockedEntry(userAddress, newUserTotalLocked), IntegerEntry(keyNodeLeasingByHeight(nodeAddress), newNodeNextLease), IntegerEntry(keyUserLeasingByHeight(nodeAddress, userAddress), newUserNextLeased)] ++ unitsUnlockedActions)
351414 }
352415 else throw("Strict value is not equal to itself.")
353416 }
354417
355418
356419 func getClaimUnlockedActions (userAddress,claimAmount) = {
357- let $t01110011160 = getUserToClaimBalance(userAddress)
358- let toClaim = $t01110011160._1
359- let toUnlock = $t01110011160._2
420+ let $t01362413684 = getUserToClaimBalance(userAddress)
421+ let toClaim = $t01362413684._1
422+ let toUnlock = $t01362413684._2
360423 let checks = [if (!(isForceStop))
361424 then true
362425 else throwErr("contract is temporary stopped"), if (!(isForceOutStop))
371434 if ((checks == checks))
372435 then {
373436 let newToClaim = (toClaim - claimAmount)
374-[getUserToClaimEntry(userAddress, newToClaim, toUnlock), ScriptTransfer(addressFromStringValue(userAddress), claimAmount, assetIdBytes)]
437+[getUserToClaimEntry(userAddress, newToClaim, toUnlock), ScriptTransfer(addressFromStringValue(userAddress), claimAmount, l2AssetIdBytes)]
375438 }
376439 else throw("Strict value is not equal to itself.")
377440 }
378441
379442
380443 func getStakeForActions (userAddress,i) = {
381- let $t01192411984 = getUserToClaimBalance(userAddress)
382- let toClaim = $t01192411984._1
383- let toUnlock = $t01192411984._2
444+ let $t01445014510 = getUserToClaimBalance(userAddress)
445+ let toClaim = $t01445014510._1
446+ let toUnlock = $t01445014510._2
384447 let checks = [if (!(isForceStop))
385448 then true
386449 else throwErr("contract is temporary stopped"), if ((1 >= size(i.payments)))
387450 then true
388451 else throwErr("maximum 1 payment"), if (if ((size(i.payments) == 0))
389452 then true
390- else (i.payments[0].assetId == assetIdBytes))
453+ else (i.payments[0].assetId == l2AssetIdBytes))
391454 then true
392- else throwErr(makeString(["payment assetId should be:", assetIdString], " ")), if (isValidAddress(userAddress))
455+ else throwErr(makeString(["payment assetId should be:", l2AssetIdString], " ")), if (isValidAddress(userAddress))
393456 then true
394457 else throwErr(makeString(["user address is not valid:", userAddress], " "))]
395458 if ((checks == checks))
401464 }
402465
403466
404-func calculateClaim (userAddress) = {
405- let claimedBlockKey = keyClaimedBlock(userAddress)
406- let claimedBlock = valueOrElse(getInteger(this, claimedBlockKey), height)
407- let blocksPassed = (height - claimedBlock)
408- let amountStaked = getUserTotalLocked(userAddress)
409- let toClaimNow = ((blocksPassed * (amountStaked * scale8)) / BLOCKS_IN_INTERVAL)
410- toClaimNow
411- }
412-
413-
414-func setUser (userAddress,claimedBlock) = {
415- let claimedBlockKey = keyClaimedBlock(userAddress)
416-[IntegerEntry(claimedBlockKey, claimedBlock)]
417- }
418-
419-
420467 func getStakeActions (nodeAddress,userAddress,userLeasingAmount,i) = {
421- let $t01328313343 = getUserToClaimBalance(userAddress)
422- let toClaim = $t01328313343._1
423- let toUnlock = $t01328313343._2
468+ let $t01524215302 = getUserToClaimBalance(userAddress)
469+ let toClaim = $t01524215302._1
470+ let toUnlock = $t01524215302._2
424471 let paymentAmount = if ((size(i.payments) == 0))
425472 then 0
426473 else i.payments[0].amount
431478 then true
432479 else throwErr("maximum 1 payment"), if (if ((size(i.payments) == 0))
433480 then true
434- else (i.payments[0].assetId == assetIdBytes))
481+ else (i.payments[0].assetId == l2AssetIdBytes))
435482 then true
436- else throwErr(makeString(["payment assetId should be:", assetIdString], " ")), if ((userLeasingAmount > 0))
483+ else throwErr(makeString(["payment assetId should be:", l2AssetIdString], " ")), if ((userLeasingAmount > 0))
437484 then true
438485 else throwErr("amount should be greater than 0"), if ((available >= userLeasingAmount))
439486 then true
446493 else throwErr(makeString(["user address is not valid:", userAddress], " "))]
447494 if ((checks == checks))
448495 then {
449- let $t01441414487 = getLeasingNodeData(nodeAddress)
450- let nodeCurrentLeased = $t01441414487._1
451- let nodeNextLeased = $t01441414487._2
496+ let $t01637716450 = getLeasingNodeData(nodeAddress)
497+ let nodeCurrentLeased = $t01637716450._1
498+ let nodeNextLeased = $t01637716450._2
452499 let newNodeNextLease = (nodeNextLeased + userLeasingAmount)
453- let $t01455514641 = getUserLeasingData(nodeAddress, userAddress)
454- let userCurrentLeased = $t01455514641._1
455- let userNextLeased = $t01455514641._2
500+ let $t01651816604 = getUserLeasingData(nodeAddress, userAddress)
501+ let userCurrentLeased = $t01651816604._1
502+ let userNextLeased = $t01651816604._2
456503 let newUserNextLeased = (userNextLeased + userLeasingAmount)
457504 let fromUnlockedAmount = (userLeasingAmount - paymentAmount)
458505 let newToUnlock = max([0, (toUnlock - fromUnlockedAmount)])
459506 let newToClaim = min([toClaim, (toClaim + (toUnlock - fromUnlockedAmount))])
460507 let userTotalLocked = getUserTotalLocked(userAddress)
461508 let newUserTotalLocked = (userTotalLocked + userLeasingAmount)
462-[getLeasingNodeEntry(nodeAddress, nodeCurrentLeased, newNodeNextLease), getUserLeasingEntry(nodeAddress, userAddress, userCurrentLeased, newUserNextLeased), getUserToClaimEntry(userAddress, newToClaim, newToUnlock), getUserTotalLockedEntry(userAddress, newUserTotalLocked), IntegerEntry(keyNodeLeasingByHeight(nodeAddress), newNodeNextLease), IntegerEntry(keyUserLeasingByHeight(nodeAddress, userAddress), newUserNextLeased)]
509+ let unitsUnlockedActions = getUnlockUnitsAction(userAddress)
510+ ([getLeasingNodeEntry(nodeAddress, nodeCurrentLeased, newNodeNextLease), getUserLeasingEntry(nodeAddress, userAddress, userCurrentLeased, newUserNextLeased), getUserToClaimEntry(userAddress, newToClaim, newToUnlock), getUserTotalLockedEntry(userAddress, newUserTotalLocked), IntegerEntry(keyNodeLeasingByHeight(nodeAddress), newNodeNextLease), IntegerEntry(keyUserLeasingByHeight(nodeAddress, userAddress), newUserNextLeased)] ++ unitsUnlockedActions)
463511 }
464512 else throw("Strict value is not equal to itself.")
465513 }
487535 }
488536
489537
538+func getUnitsClaimData (userAddress) = {
539+ let $t01848918574 = calculateUnitsToClaim(userAddress)
540+ let unlockedUnitNow = $t01848918574._1
541+ let l2ToBurnNow = $t01848918574._2
542+ let claimedBlock = $t01848918574._3
543+ let unlockedUnitsPrev = valueOrElse(getInteger(this, keyUnlockedUnits(userAddress)), 0)
544+ let unitsToSend = (unlockedUnitNow + unlockedUnitsPrev)
545+ let l2ToBurnPrev = valueOrElse(getInteger(this, keyL2ToBurn(userAddress)), 0)
546+ let l2ToBurn = (l2ToBurnPrev + l2ToBurnNow)
547+ let totalUnitsClaimed = valueOrElse(getInteger(this, keyTotalUnitsClaimed(userAddress)), 0)
548+ let totalL2Burned = valueOrElse(getInteger(this, keyL2BurnedTotal(userAddress)), 0)
549+ $Tuple5(unitsToSend, totalUnitsClaimed, l2ToBurn, totalL2Burned, claimedBlock)
550+ }
551+
552+
553+func getClaimUnitsActions (userAddress) = {
554+ let $t01916619274 = getUnitsClaimData(userAddress)
555+ let unitsToSend = $t01916619274._1
556+ let totalUnitsClaimed = $t01916619274._2
557+ let l2ToBurn = $t01916619274._3
558+ let totalL2Burned = $t01916619274._4
559+ let claimedBlock = $t01916619274._5
560+ let check = [if ((0 >= unitsToSend))
561+ then true
562+ else throwErr("nothing to claim")]
563+ if ((check == check))
564+ then {
565+ let burnAction = match l2AssetIdBytes {
566+ case id: ByteVector =>
567+[Burn(id, l2ToBurn)]
568+ case _ =>
569+ nil
570+ }
571+ ([IntegerEntry(keyUnitsClaimedBlock(userAddress), claimedBlock), IntegerEntry(keyTotalUnitsClaimed(userAddress), (totalUnitsClaimed + unitsToSend)), IntegerEntry(keyL2BurnedTotal(userAddress), (totalL2Burned + l2ToBurn)), IntegerEntry(keyUnlockedUnits(userAddress), 0), IntegerEntry(keyL2ToBurn(userAddress), 0), ScriptTransfer(addressFromStringValue(userAddress), unitsToSend, unitsAssetIdBytes)] ++ burnAction)
572+ }
573+ else throw("Strict value is not equal to itself.")
574+ }
575+
576+
490577 @Callable(i)
491578 func setNewPeriodLength (newPeriodLength) = {
492579 let checks = [if (isInAdminList(toString(i.caller)))
500587
501588
502589 @Callable(i)
503-func claimUnit () = {
590+func claimUnits () = {
504591 let userAddress = toString(i.caller)
505- let toClaimNow = calculateClaim(userAddress)
506- let totalUnitClaimed = valueOrElse(getInteger(this, keyTotalUnitsClaimed(userAddress)), 0)
507- let totalL2Staked = getUserTotalLocked(userAddress)
508- let check = [if ((totalL2Staked >= (totalUnitClaimed + toClaimNow)))
509- then true
510- else throwErr("Can't claim more than staked")]
511- if ((check == check))
512- then {
513- let claimedBlockKey = keyClaimedBlock(userAddress)
514- let actions = [IntegerEntry(claimedBlockKey, height), IntegerEntry(keyTotalUnitsClaimed(userAddress), (totalUnitClaimed + toClaimNow))]
515- let transferUnits = ScriptTransfer(i.caller, toClaimNow, unit)
516- (actions ++ [transferUnits])
517- }
518- else throw("Strict value is not equal to itself.")
592+ getClaimUnitsActions(userAddress)
519593 }
520594
521595
546620
547621 @Callable(i)
548622 func getNodeDataREADONLY (nodeAddress) = {
549- let $t01803818102 = getLeasingNodeData(nodeAddress)
550- let currentLease = $t01803818102._1
551- let nextLeased = $t01803818102._2
623+ let $t02100721071 = getLeasingNodeData(nodeAddress)
624+ let currentLease = $t02100721071._1
625+ let nextLeased = $t02100721071._2
552626 $Tuple2(nil, $Tuple5(currentPeriodHeight, currentLease, nextPeriodHeight, nextLeased, height))
553627 }
554628
556630
557631 @Callable(i)
558632 func getUserLeasingDataREADONLY (nodeAddress,userAddress) = {
559- let $t01847218549 = getUserLeasingData(nodeAddress, userAddress)
560- let currentLease = $t01847218549._1
561- let nextLeased = $t01847218549._2
633+ let $t02144121518 = getUserLeasingData(nodeAddress, userAddress)
634+ let currentLease = $t02144121518._1
635+ let nextLeased = $t02144121518._2
562636 $Tuple2(nil, $Tuple5(currentPeriodHeight, currentLease, nextPeriodHeight, nextLeased, height))
563637 }
564638
566640
567641 @Callable(i)
568642 func getUserDataREADONLY (userAddress) = {
569- let $t01891218972 = getUserToClaimBalance(userAddress)
570- let toClaim = $t01891218972._1
571- let toUnlock = $t01891218972._2
643+ let $t02203422094 = getUserToClaimBalance(userAddress)
644+ let toClaim = $t02203422094._1
645+ let toUnlock = $t02203422094._2
572646 let userTotalLocked = getUserTotalLocked(userAddress)
573- $Tuple2(nil, $Tuple6(currentPeriodHeight, toClaim, nextPeriodHeight, toUnlock, userTotalLocked, height))
647+ let $t02215722265 = getUnitsClaimData(userAddress)
648+ let unitsToSend = $t02215722265._1
649+ let totalUnitsClaimed = $t02215722265._2
650+ let l2ToBurn = $t02215722265._3
651+ let totalL2Burned = $t02215722265._4
652+ let claimedBlock = $t02215722265._5
653+ $Tuple2(nil, $Tuple11(currentPeriodHeight, toClaim, nextPeriodHeight, toUnlock, userTotalLocked, height, unitsToSend, totalUnitsClaimed, l2ToBurn, totalL2Burned, claimedBlock))
574654 }
575655
576656
615695 @Callable(i)
616696 func claimAll () = {
617697 let userAddress = toString(i.caller)
618- let $t01998620046 = getUserToClaimBalance(userAddress)
619- let toClaim = $t01998620046._1
620- let toUnlock = $t01998620046._2
698+ let $t02345723517 = getUserToClaimBalance(userAddress)
699+ let toClaim = $t02345723517._1
700+ let toUnlock = $t02345723517._2
621701 let checks = [if ((toClaim > 0))
622702 then true
623703 else throwErr("nothing to claim")]
630710
631711 @Callable(i)
632712 func stakeFor (userAddress) = getStakeForActions(userAddress, i)
713+
714+
715+
716+@Callable(i)
717+func startUnitsVesting () = {
718+ let totalL2 = 100000000000000000
719+ let totalUnits = i.payments[0].amount
720+ let unitsPerBlockScale8 = (fraction(totalL2, scale8, totalUnits) / unitsClaimInterval)
721+ let check = [if (isInAdminList(toString(i.caller)))
722+ then true
723+ else throwErr("caller is not in adminList"), if ((size(i.payments) == 1))
724+ then true
725+ else throwErr("should be 1 payment"), if ((unitsPerBlockScale8 > 0))
726+ then true
727+ else throwErr("units per block should be greated than 0")]
728+ if ((check == check))
729+ then [IntegerEntry(keyUnitsPerBlockScale8, unitsPerBlockScale8), IntegerEntry(keyUnitsClaimStartHeight, height), StringEntry(keyUnitsAssetId, assetBytesToString(i.payments[0].assetId))]
730+ else throw("Strict value is not equal to itself.")
731+ }
633732
634733
635734
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let contractFile = "l2mp_leasing.ride"
55
66 let SEP = "__"
77
88 let BLOCKS_IN_INTERVAL = 1000
99
1010 let scale8 = 100000000
1111
12+let unitsClaimInterval = ((365 * 24) * 60)
13+
1214 func throwErr (msg) = throw(((contractFile + ": ") + msg))
1315
1416
15-let keyAssetId = makeString(["%s", "assetId"], SEP)
17+let keyL2AssetId = makeString(["%s", "assetId"], SEP)
1618
1719 let keyForceStop = makeString(["%s", "forceStop"], SEP)
1820
1921 let keyForceOutStop = makeString(["%s", "forceOutStop"], SEP)
22+
23+let keyUnitsAssetId = makeString(["%s", "unitsAssetId"], SEP)
24+
25+let keyUnitsPerBlockScale8 = makeString(["%s", "unitsPerBlock"], SEP)
2026
2127 let keyPeriodOffsetId = makeString(["%s", "offsetId"], SEP)
2228
2329 let keyPeriodOffsetHeight = makeString(["%s", "offsetHeight"], SEP)
2430
2531 let keyPeriodLength = makeString(["%s", "periodLength"], SEP)
32+
33+let keyUnitsClaimStartHeight = makeString(["%s", "unitsClaimStartHeight"], SEP)
2634
2735 let periodOffsetId = valueOrElse(getInteger(this, keyPeriodOffsetId), 0)
2836
2937 let periodLength = valueOrElse(getInteger(this, keyPeriodLength), 10000)
3038
3139 let periodOffsetHeight = valueOrElse(getInteger(this, keyPeriodOffsetHeight), -1)
3240
3341 let currentPeriodId = if (if ((height > periodOffsetHeight))
3442 then (periodOffsetHeight != -1)
3543 else false)
3644 then (((height - periodOffsetHeight) / periodLength) + periodOffsetId)
3745 else max([0, (periodOffsetId - 1)])
3846
3947 let currentPeriodHeight = if (if ((periodOffsetHeight == -1))
4048 then true
4149 else if ((currentPeriodId == 0))
4250 then (periodOffsetHeight > height)
4351 else false)
4452 then 0
4553 else (periodOffsetHeight + ((currentPeriodId - periodOffsetId) * periodLength))
4654
4755 let nextPeriodHeight = if (if ((periodOffsetHeight == -1))
4856 then true
4957 else if ((currentPeriodId == 0))
5058 then (periodOffsetHeight > height)
5159 else false)
5260 then 0
5361 else (currentPeriodHeight + periodLength)
5462
63+let unitsClaimStartHeight = valueOrElse(getInteger(this, keyUnitsClaimStartHeight), height)
64+
5565 func keyLeasingNodeData (nodeAddress) = makeString(["%s", nodeAddress], SEP)
5666
5767
5868 func keyUserLeasingNodeData (userAddress,nodeAddress) = makeString(["%s%s", nodeAddress, userAddress], SEP)
5969
6070
6171 func keyUserToClaim (userAddress) = makeString(["%s%s", "toClaim", userAddress], SEP)
6272
6373
6474 func keyUserTotalLocked (userAddress) = makeString(["%s%s", "userTotalLocked", userAddress], SEP)
6575
6676
67-func keyClaimedBlock (userAddress) = makeString(["%s%s", userAddress, "claimedBlock"], SEP)
77+func keyUnitsClaimedBlock (userAddress) = makeString(["%s%s", "unitsClaimedBlock", userAddress], SEP)
6878
6979
70-func keyTotalUnitsClaimed (userAddress) = makeString(["%s%s", userAddress, "totalUnitsClaimed"], SEP)
80+func keyUnlockedUnits (userAddress) = makeString(["%s%s", "unlockedUnits", userAddress], SEP)
81+
82+
83+func keyTotalUnitsClaimed (userAddress) = makeString(["%s%s", "totalUnitsClaimed", userAddress], SEP)
84+
85+
86+func keyL2ToBurn (userAddress) = makeString(["%s%s", "l2ToBurn", userAddress], SEP)
87+
88+
89+func keyL2BurnedTotal (userAddress) = makeString(["%s%s", "l2BurnedTotal", userAddress], SEP)
7190
7291
7392 func keyNodeLeasingByHeight (nodeAddress) = {
7493 let h = if ((periodOffsetHeight == -1))
7594 then 0
7695 else height
7796 makeString(["%s%d", nodeAddress, toString(h)], SEP)
7897 }
7998
8099
81100 func keyUserLeasingByHeight (nodeAddress,userAddress) = {
82101 let h = if ((periodOffsetHeight == -1))
83102 then 0
84103 else height
85104 makeString(["%s%s%d", nodeAddress, userAddress, toString(h)], SEP)
86105 }
87106
88107
89-let assetIdString = valueOrElse(getString(this, keyAssetId), "WAVES")
90-
91-let assetIdBytes = if ((assetIdString == "WAVES"))
108+func assetStringToBytes (assetIdString) = if ((assetIdString == "WAVES"))
92109 then unit
93110 else fromBase58String(assetIdString)
111+
112+
113+func assetBytesToString (assetId) = match assetId {
114+ case a: ByteVector =>
115+ toBase58String(a)
116+ case _ =>
117+ "WAVES"
118+}
119+
120+
121+let l2AssetIdString = valueOrElse(getString(this, keyL2AssetId), "WAVES")
122+
123+let unitsAssetIdString = valueOrElse(getString(this, keyUnitsAssetId), "WAVES")
124+
125+let l2AssetIdBytes = assetStringToBytes(l2AssetIdString)
126+
127+let unitsAssetIdBytes = assetStringToBytes(unitsAssetIdString)
94128
95129 let isForceStop = valueOrElse(getBoolean(this, keyForceStop), false)
96130
97131 let isForceOutStop = valueOrElse(getBoolean(this, keyForceOutStop), false)
98132
99133 func isValidAddress (address) = match addressFromString(address) {
100134 case a: Address =>
101135 true
102136 case _ =>
103137 false
104138 }
105139
106140
107141 let ADMIN_LIST_SIZE = 5
108142
109143 let QUORUM = 3
110144
111145 let TXID_BYTES_LENGTH = 32
112146
113147 func keyAllowedTxIdVotePrefix (txId) = makeString(["%s%s%s", "allowTxId", txId], SEP)
114148
115149
116150 func keyFullAdminVote (prefix,adminAddress) = makeString([prefix, adminAddress], SEP)
117151
118152
119153 func keyAdminAddressList () = makeString(["%s", "adminAddressList"], SEP)
120154
121155
122156 func keyAllowedTxId () = makeString(["%s", "txId"], SEP)
123157
124158
125159 func getAdminVote (prefix,admin) = {
126160 let voteKey = keyFullAdminVote(prefix, admin)
127161 valueOrElse(getInteger(voteKey), 0)
128162 }
129163
130164
131165 func getAdminsList () = match getString(this, keyAdminAddressList()) {
132166 case s: String =>
133167 split(s, SEP)
134168 case _ =>
135169 nil
136170 }
137171
138172
139173 func isInAdminList (address) = containsElement(getAdminsList(), address)
140174
141175
142176 func genVotesKeysHelper (a,adminAddress) = {
143- let $t039683992 = a
144- let result = $t039683992._1
145- let prefix = $t039683992._2
177+ let $t050215045 = a
178+ let result = $t050215045._1
179+ let prefix = $t050215045._2
146180 $Tuple2((result :+ keyFullAdminVote(prefix, adminAddress)), prefix)
147181 }
148182
149183
150184 func genVotesKeys (keyPrefix) = {
151185 let adminList = keyAdminAddressList()
152- let $t041394223 = {
186+ let $t051925276 = {
153187 let $l = getAdminsList()
154188 let $s = size($l)
155189 let $acc0 = $Tuple2(nil, keyPrefix)
156190 func $f0_1 ($a,$i) = if (($i >= $s))
157191 then $a
158192 else genVotesKeysHelper($a, $l[$i])
159193
160194 func $f0_2 ($a,$i) = if (($i >= $s))
161195 then $a
162196 else throw("List size exceeds 5")
163197
164198 $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5)
165199 }
166- let result = $t041394223._1
167- let prefix = $t041394223._2
200+ let result = $t051925276._1
201+ let prefix = $t051925276._2
168202 result
169203 }
170204
171205
172206 func countVotesHelper (result,voteKey) = (result + valueOrElse(getInteger(voteKey), 0))
173207
174208
175209 func countVotes (prefix) = {
176210 let votes = genVotesKeys(prefix)
177211 let $l = votes
178212 let $s = size($l)
179213 let $acc0 = 0
180214 func $f0_1 ($a,$i) = if (($i >= $s))
181215 then $a
182216 else countVotesHelper($a, $l[$i])
183217
184218 func $f0_2 ($a,$i) = if (($i >= $s))
185219 then $a
186220 else throw("List size exceeds 5")
187221
188222 $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5)
189223 }
190224
191225
192226 func clearVotesHelper (result,key) = (result :+ DeleteEntry(key))
193227
194228
195229 func getClearVoteEntries (prefix) = {
196230 let votes = genVotesKeys(prefix)
197231 let $l = votes
198232 let $s = size($l)
199233 let $acc0 = nil
200234 func $f0_1 ($a,$i) = if (($i >= $s))
201235 then $a
202236 else clearVotesHelper($a, $l[$i])
203237
204238 func $f0_2 ($a,$i) = if (($i >= $s))
205239 then $a
206240 else throw("List size exceeds 5")
207241
208242 $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5)
209243 }
210244
211245
212246 func voteINTERNAL (callerAddressString,keyPrefix,minVotes,voteResult) = {
213247 let voteKey = keyFullAdminVote(keyPrefix, callerAddressString)
214248 let adminCurrentVote = getAdminVote(keyPrefix, callerAddressString)
215249 let err = if (!(isInAdminList(callerAddressString)))
216250 then throwErr((("Address: " + callerAddressString) + " not in Admin list"))
217251 else if ((adminCurrentVote == 1))
218252 then throwErr((voteKey + " you already voted"))
219253 else unit
220254 if ((err == err))
221255 then {
222256 let votes = countVotes(keyPrefix)
223257 if (((votes + 1) >= minVotes))
224258 then {
225259 let clearVoteEntries = getClearVoteEntries(keyPrefix)
226260 (clearVoteEntries ++ voteResult)
227261 }
228262 else [IntegerEntry(voteKey, 1)]
229263 }
230264 else throw("Strict value is not equal to itself.")
231265 }
232266
233267
234268 func getLeasingNodeEntry (nodeAddress,currentLeased,nextLeased) = {
235269 let valueString = makeString(["%d%d%d%d", toString(currentPeriodHeight), toString(currentLeased), toString(nextPeriodHeight), toString(nextLeased)], SEP)
236270 StringEntry(keyLeasingNodeData(nodeAddress), valueString)
237271 }
238272
239273
240274 func getLeasingNodeData (nodeAddress) = {
241275 let leasingNodeDataStringRaw = getString(this, keyLeasingNodeData(nodeAddress))
242276 match leasingNodeDataStringRaw {
243277 case ds: String =>
244278 let dataList = split(ds, SEP)
245279 let nodeCurrentPeriod = parseIntValue(dataList[1])
246280 let nodeCurrentLeased = parseIntValue(dataList[2])
247281 let nodeNextPeriod = parseIntValue(dataList[3])
248282 let nodeNextLeased = parseIntValue(dataList[4])
249283 if (if ((nodeNextPeriod > height))
250284 then true
251285 else (periodOffsetHeight == -1))
252286 then $Tuple2(nodeCurrentLeased, nodeNextLeased)
253287 else $Tuple2(nodeNextLeased, nodeNextLeased)
254288 case _ =>
255289 $Tuple2(0, 0)
256290 }
257291 }
258292
259293
260294 func getUserLeasingEntry (nodeAddress,userAddress,userCurrentLeased,userNextLeased) = {
261295 let valueString = makeString(["%d%d%d%d", toString(currentPeriodHeight), toString(userCurrentLeased), toString(nextPeriodHeight), toString(userNextLeased)], SEP)
262296 StringEntry(keyUserLeasingNodeData(userAddress, nodeAddress), valueString)
263297 }
264298
265299
266300 func getUserLeasingData (nodeAddress,userAddress) = {
267301 let leasingUserDataStringRaw = getString(this, keyUserLeasingNodeData(userAddress, nodeAddress))
268302 match leasingUserDataStringRaw {
269303 case ds: String =>
270304 let dataList = split(ds, SEP)
271305 let userCurrentPeriod = parseIntValue(dataList[1])
272306 let userCurrentLeased = parseIntValue(dataList[2])
273307 let userNextPeriod = parseIntValue(dataList[3])
274308 let userNextLeased = parseIntValue(dataList[4])
275309 if (if ((userNextPeriod > height))
276310 then true
277311 else (periodOffsetHeight == -1))
278312 then $Tuple2(userCurrentLeased, userNextLeased)
279313 else $Tuple2(userNextLeased, userNextLeased)
280314 case _ =>
281315 $Tuple2(0, 0)
282316 }
283317 }
284318
285319
286320 func getUserToClaimEntry (userAddress,toClaim,toUnlock) = {
287321 let valueString = makeString(["%d%d%d%d", toString(currentPeriodHeight), toString(toClaim), toString(nextPeriodHeight), toString(toUnlock)], SEP)
288322 StringEntry(keyUserToClaim(userAddress), valueString)
289323 }
290324
291325
292326 func getUserToClaimBalance (userAddress) = {
293327 let userToClaimDataStringRaw = getString(this, keyUserToClaim(userAddress))
294328 match userToClaimDataStringRaw {
295329 case ds: String =>
296330 let dataList = split(ds, SEP)
297331 let currentPeriod = parseIntValue(dataList[1])
298332 let toClaim = parseIntValue(dataList[2])
299333 let nextPeriod = parseIntValue(dataList[3])
300334 let toUnlock = parseIntValue(dataList[4])
301335 if (if ((nextPeriod > height))
302336 then true
303337 else (currentPeriodId == 0))
304338 then $Tuple2(toClaim, toUnlock)
305339 else $Tuple2((toClaim + toUnlock), 0)
306340 case _ =>
307341 $Tuple2(0, 0)
308342 }
309343 }
310344
311345
312346 func getUserTotalLockedEntry (userAddress,userTotalLocked) = IntegerEntry(keyUserTotalLocked(userAddress), userTotalLocked)
313347
314348
315349 func getUserTotalLocked (userAddress) = valueOrElse(getInteger(this, keyUserTotalLocked(userAddress)), 0)
316350
317351
352+func calculateUnitsToClaim (userAddress) = {
353+ let claimedBlockKey = keyUnitsClaimedBlock(userAddress)
354+ let claimedBlock = valueOrElse(getInteger(this, claimedBlockKey), unitsClaimStartHeight)
355+ let unitsPerBlockScale8 = valueOrElse(getInteger(this, keyUnitsPerBlockScale8), 0)
356+ let currentBlock = min([(unitsClaimStartHeight + unitsClaimInterval), height])
357+ let blocksPassed = (currentBlock - claimedBlock)
358+ let amountStaked = getUserTotalLocked(userAddress)
359+ let unitsToClaimNow = fraction((unitsPerBlockScale8 * blocksPassed), amountStaked, scale8)
360+ let l2ToBurn = fraction(amountStaked, blocksPassed, unitsClaimInterval)
361+ $Tuple3(unitsToClaimNow, l2ToBurn, claimedBlock)
362+ }
363+
364+
365+func getUnlockUnitsAction (userAddress) = {
366+ let kUnlockedUnits = keyUnlockedUnits(userAddress)
367+ let unlockedUnits = valueOrElse(getInteger(this, kUnlockedUnits), 0)
368+ let kL2ToBurn = keyL2ToBurn(userAddress)
369+ let l2ToBurn = valueOrElse(getInteger(this, kL2ToBurn), 0)
370+ let $t01121711302 = calculateUnitsToClaim(userAddress)
371+ let unitsToClaimNow = $t01121711302._1
372+ let l2ToBurnNow = $t01121711302._2
373+ let claimedBlock = $t01121711302._3
374+ if ((0 >= unitsToClaimNow))
375+ then nil
376+ else [IntegerEntry(keyUnitsClaimedBlock(userAddress), claimedBlock), IntegerEntry(kL2ToBurn, (l2ToBurn + l2ToBurnNow)), IntegerEntry(kUnlockedUnits, (unlockedUnits + unitsToClaimNow))]
377+ }
378+
379+
318380 func getUnstakeActions (nodeAddress,userAddress,unstakeAmount) = {
319- let $t092639336 = getLeasingNodeData(nodeAddress)
320- let nodeCurrentLeased = $t092639336._1
321- let nodeNextLeased = $t092639336._2
322- let $t093419427 = getUserLeasingData(nodeAddress, userAddress)
323- let userCurrentLeased = $t093419427._1
324- let userNextLeased = $t093419427._2
381+ let $t01169711770 = getLeasingNodeData(nodeAddress)
382+ let nodeCurrentLeased = $t01169711770._1
383+ let nodeNextLeased = $t01169711770._2
384+ let $t01177511861 = getUserLeasingData(nodeAddress, userAddress)
385+ let userCurrentLeased = $t01177511861._1
386+ let userNextLeased = $t01177511861._2
325387 let checks = [if (!(isForceStop))
326388 then true
327389 else throwErr("contract is temporary stopped"), if (!(isForceOutStop))
328390 then true
329391 else throwErr("unstake is temporary disabled"), if ((unstakeAmount > 0))
330392 then true
331393 else throwErr("unstake amount should be greater than 0"), if ((userNextLeased >= unstakeAmount))
332394 then true
333395 else throwErr("unstake amount should be less or equal user staked amount"), if ((nodeNextLeased >= unstakeAmount))
334396 then true
335397 else throwErr("unstake amount should be less or equal node staked amount"), if (isValidAddress(nodeAddress))
336398 then true
337399 else throwErr(makeString(["node address is not valid:", nodeAddress], " ")), if (isValidAddress(userAddress))
338400 then true
339401 else throwErr(makeString(["user address is not valid:", userAddress], " "))]
340402 if ((checks == checks))
341403 then {
342404 let newNodeNextLease = (nodeNextLeased - unstakeAmount)
343405 let newUserNextLeased = (userNextLeased - unstakeAmount)
344- let $t01031110371 = getUserToClaimBalance(userAddress)
345- let toClaim = $t01031110371._1
346- let toUnlock = $t01031110371._2
406+ let $t01274512805 = getUserToClaimBalance(userAddress)
407+ let toClaim = $t01274512805._1
408+ let toUnlock = $t01274512805._2
347409 let newToUnlock = (toUnlock + unstakeAmount)
348410 let userTotalLocked = getUserTotalLocked(userAddress)
349411 let newUserTotalLocked = (userTotalLocked - unstakeAmount)
350-[getLeasingNodeEntry(nodeAddress, nodeCurrentLeased, newNodeNextLease), getUserLeasingEntry(nodeAddress, userAddress, userCurrentLeased, newUserNextLeased), getUserToClaimEntry(userAddress, toClaim, newToUnlock), getUserTotalLockedEntry(userAddress, newUserTotalLocked), IntegerEntry(keyNodeLeasingByHeight(nodeAddress), newNodeNextLease), IntegerEntry(keyUserLeasingByHeight(nodeAddress, userAddress), newUserNextLeased)]
412+ let unitsUnlockedActions = getUnlockUnitsAction(userAddress)
413+ ([getLeasingNodeEntry(nodeAddress, nodeCurrentLeased, newNodeNextLease), getUserLeasingEntry(nodeAddress, userAddress, userCurrentLeased, newUserNextLeased), getUserToClaimEntry(userAddress, toClaim, newToUnlock), getUserTotalLockedEntry(userAddress, newUserTotalLocked), IntegerEntry(keyNodeLeasingByHeight(nodeAddress), newNodeNextLease), IntegerEntry(keyUserLeasingByHeight(nodeAddress, userAddress), newUserNextLeased)] ++ unitsUnlockedActions)
351414 }
352415 else throw("Strict value is not equal to itself.")
353416 }
354417
355418
356419 func getClaimUnlockedActions (userAddress,claimAmount) = {
357- let $t01110011160 = getUserToClaimBalance(userAddress)
358- let toClaim = $t01110011160._1
359- let toUnlock = $t01110011160._2
420+ let $t01362413684 = getUserToClaimBalance(userAddress)
421+ let toClaim = $t01362413684._1
422+ let toUnlock = $t01362413684._2
360423 let checks = [if (!(isForceStop))
361424 then true
362425 else throwErr("contract is temporary stopped"), if (!(isForceOutStop))
363426 then true
364427 else throwErr("claim is temporary disabled"), if ((claimAmount > 0))
365428 then true
366429 else throwErr("claim amount should be greater than 0"), if ((toClaim >= claimAmount))
367430 then true
368431 else throwErr("claim amount should be less or equal unlocked amount"), if (isValidAddress(userAddress))
369432 then true
370433 else throwErr(makeString(["user address is not valid:", userAddress], " "))]
371434 if ((checks == checks))
372435 then {
373436 let newToClaim = (toClaim - claimAmount)
374-[getUserToClaimEntry(userAddress, newToClaim, toUnlock), ScriptTransfer(addressFromStringValue(userAddress), claimAmount, assetIdBytes)]
437+[getUserToClaimEntry(userAddress, newToClaim, toUnlock), ScriptTransfer(addressFromStringValue(userAddress), claimAmount, l2AssetIdBytes)]
375438 }
376439 else throw("Strict value is not equal to itself.")
377440 }
378441
379442
380443 func getStakeForActions (userAddress,i) = {
381- let $t01192411984 = getUserToClaimBalance(userAddress)
382- let toClaim = $t01192411984._1
383- let toUnlock = $t01192411984._2
444+ let $t01445014510 = getUserToClaimBalance(userAddress)
445+ let toClaim = $t01445014510._1
446+ let toUnlock = $t01445014510._2
384447 let checks = [if (!(isForceStop))
385448 then true
386449 else throwErr("contract is temporary stopped"), if ((1 >= size(i.payments)))
387450 then true
388451 else throwErr("maximum 1 payment"), if (if ((size(i.payments) == 0))
389452 then true
390- else (i.payments[0].assetId == assetIdBytes))
453+ else (i.payments[0].assetId == l2AssetIdBytes))
391454 then true
392- else throwErr(makeString(["payment assetId should be:", assetIdString], " ")), if (isValidAddress(userAddress))
455+ else throwErr(makeString(["payment assetId should be:", l2AssetIdString], " ")), if (isValidAddress(userAddress))
393456 then true
394457 else throwErr(makeString(["user address is not valid:", userAddress], " "))]
395458 if ((checks == checks))
396459 then {
397460 let newToClaim = (toClaim + i.payments[0].amount)
398461 [getUserToClaimEntry(userAddress, newToClaim, toUnlock)]
399462 }
400463 else throw("Strict value is not equal to itself.")
401464 }
402465
403466
404-func calculateClaim (userAddress) = {
405- let claimedBlockKey = keyClaimedBlock(userAddress)
406- let claimedBlock = valueOrElse(getInteger(this, claimedBlockKey), height)
407- let blocksPassed = (height - claimedBlock)
408- let amountStaked = getUserTotalLocked(userAddress)
409- let toClaimNow = ((blocksPassed * (amountStaked * scale8)) / BLOCKS_IN_INTERVAL)
410- toClaimNow
411- }
412-
413-
414-func setUser (userAddress,claimedBlock) = {
415- let claimedBlockKey = keyClaimedBlock(userAddress)
416-[IntegerEntry(claimedBlockKey, claimedBlock)]
417- }
418-
419-
420467 func getStakeActions (nodeAddress,userAddress,userLeasingAmount,i) = {
421- let $t01328313343 = getUserToClaimBalance(userAddress)
422- let toClaim = $t01328313343._1
423- let toUnlock = $t01328313343._2
468+ let $t01524215302 = getUserToClaimBalance(userAddress)
469+ let toClaim = $t01524215302._1
470+ let toUnlock = $t01524215302._2
424471 let paymentAmount = if ((size(i.payments) == 0))
425472 then 0
426473 else i.payments[0].amount
427474 let available = ((toUnlock + toClaim) + paymentAmount)
428475 let checks = [if (!(isForceStop))
429476 then true
430477 else throwErr("contract is temporary stopped"), if ((1 >= size(i.payments)))
431478 then true
432479 else throwErr("maximum 1 payment"), if (if ((size(i.payments) == 0))
433480 then true
434- else (i.payments[0].assetId == assetIdBytes))
481+ else (i.payments[0].assetId == l2AssetIdBytes))
435482 then true
436- else throwErr(makeString(["payment assetId should be:", assetIdString], " ")), if ((userLeasingAmount > 0))
483+ else throwErr(makeString(["payment assetId should be:", l2AssetIdString], " ")), if ((userLeasingAmount > 0))
437484 then true
438485 else throwErr("amount should be greater than 0"), if ((available >= userLeasingAmount))
439486 then true
440487 else throwErr("amount should be less or equal (payment + available) amount"), if ((userLeasingAmount >= paymentAmount))
441488 then true
442489 else throw("amount should be greater or equal payment amount"), if (isValidAddress(nodeAddress))
443490 then true
444491 else throwErr(makeString(["node address is not valid:", nodeAddress], " ")), if (isValidAddress(userAddress))
445492 then true
446493 else throwErr(makeString(["user address is not valid:", userAddress], " "))]
447494 if ((checks == checks))
448495 then {
449- let $t01441414487 = getLeasingNodeData(nodeAddress)
450- let nodeCurrentLeased = $t01441414487._1
451- let nodeNextLeased = $t01441414487._2
496+ let $t01637716450 = getLeasingNodeData(nodeAddress)
497+ let nodeCurrentLeased = $t01637716450._1
498+ let nodeNextLeased = $t01637716450._2
452499 let newNodeNextLease = (nodeNextLeased + userLeasingAmount)
453- let $t01455514641 = getUserLeasingData(nodeAddress, userAddress)
454- let userCurrentLeased = $t01455514641._1
455- let userNextLeased = $t01455514641._2
500+ let $t01651816604 = getUserLeasingData(nodeAddress, userAddress)
501+ let userCurrentLeased = $t01651816604._1
502+ let userNextLeased = $t01651816604._2
456503 let newUserNextLeased = (userNextLeased + userLeasingAmount)
457504 let fromUnlockedAmount = (userLeasingAmount - paymentAmount)
458505 let newToUnlock = max([0, (toUnlock - fromUnlockedAmount)])
459506 let newToClaim = min([toClaim, (toClaim + (toUnlock - fromUnlockedAmount))])
460507 let userTotalLocked = getUserTotalLocked(userAddress)
461508 let newUserTotalLocked = (userTotalLocked + userLeasingAmount)
462-[getLeasingNodeEntry(nodeAddress, nodeCurrentLeased, newNodeNextLease), getUserLeasingEntry(nodeAddress, userAddress, userCurrentLeased, newUserNextLeased), getUserToClaimEntry(userAddress, newToClaim, newToUnlock), getUserTotalLockedEntry(userAddress, newUserTotalLocked), IntegerEntry(keyNodeLeasingByHeight(nodeAddress), newNodeNextLease), IntegerEntry(keyUserLeasingByHeight(nodeAddress, userAddress), newUserNextLeased)]
509+ let unitsUnlockedActions = getUnlockUnitsAction(userAddress)
510+ ([getLeasingNodeEntry(nodeAddress, nodeCurrentLeased, newNodeNextLease), getUserLeasingEntry(nodeAddress, userAddress, userCurrentLeased, newUserNextLeased), getUserToClaimEntry(userAddress, newToClaim, newToUnlock), getUserTotalLockedEntry(userAddress, newUserTotalLocked), IntegerEntry(keyNodeLeasingByHeight(nodeAddress), newNodeNextLease), IntegerEntry(keyUserLeasingByHeight(nodeAddress, userAddress), newUserNextLeased)] ++ unitsUnlockedActions)
463511 }
464512 else throw("Strict value is not equal to itself.")
465513 }
466514
467515
468516 func getStakeFromPaymentActions (nodeAddress,userAddress,i) = {
469517 let checks = [if ((size(i.payments) == 1))
470518 then true
471519 else throwErr("payment size should be exactly 1")]
472520 if ((checks == checks))
473521 then getStakeActions(nodeAddress, userAddress, i.payments[0].amount, i)
474522 else throw("Strict value is not equal to itself.")
475523 }
476524
477525
478526 func getSetNewPeriodLengthActions (newPeriodLength) = {
479527 let check = [if ((newPeriodLength > 0))
480528 then true
481529 else throwErr("period length should be greater than 0")]
482530 if ((check == check))
483531 then if ((periodOffsetHeight == -1))
484532 then [IntegerEntry(keyPeriodLength, newPeriodLength), IntegerEntry(keyPeriodOffsetHeight, height)]
485533 else [IntegerEntry(keyPeriodOffsetId, (currentPeriodId + 1)), IntegerEntry(keyPeriodOffsetHeight, nextPeriodHeight), IntegerEntry(keyPeriodLength, newPeriodLength)]
486534 else throw("Strict value is not equal to itself.")
487535 }
488536
489537
538+func getUnitsClaimData (userAddress) = {
539+ let $t01848918574 = calculateUnitsToClaim(userAddress)
540+ let unlockedUnitNow = $t01848918574._1
541+ let l2ToBurnNow = $t01848918574._2
542+ let claimedBlock = $t01848918574._3
543+ let unlockedUnitsPrev = valueOrElse(getInteger(this, keyUnlockedUnits(userAddress)), 0)
544+ let unitsToSend = (unlockedUnitNow + unlockedUnitsPrev)
545+ let l2ToBurnPrev = valueOrElse(getInteger(this, keyL2ToBurn(userAddress)), 0)
546+ let l2ToBurn = (l2ToBurnPrev + l2ToBurnNow)
547+ let totalUnitsClaimed = valueOrElse(getInteger(this, keyTotalUnitsClaimed(userAddress)), 0)
548+ let totalL2Burned = valueOrElse(getInteger(this, keyL2BurnedTotal(userAddress)), 0)
549+ $Tuple5(unitsToSend, totalUnitsClaimed, l2ToBurn, totalL2Burned, claimedBlock)
550+ }
551+
552+
553+func getClaimUnitsActions (userAddress) = {
554+ let $t01916619274 = getUnitsClaimData(userAddress)
555+ let unitsToSend = $t01916619274._1
556+ let totalUnitsClaimed = $t01916619274._2
557+ let l2ToBurn = $t01916619274._3
558+ let totalL2Burned = $t01916619274._4
559+ let claimedBlock = $t01916619274._5
560+ let check = [if ((0 >= unitsToSend))
561+ then true
562+ else throwErr("nothing to claim")]
563+ if ((check == check))
564+ then {
565+ let burnAction = match l2AssetIdBytes {
566+ case id: ByteVector =>
567+[Burn(id, l2ToBurn)]
568+ case _ =>
569+ nil
570+ }
571+ ([IntegerEntry(keyUnitsClaimedBlock(userAddress), claimedBlock), IntegerEntry(keyTotalUnitsClaimed(userAddress), (totalUnitsClaimed + unitsToSend)), IntegerEntry(keyL2BurnedTotal(userAddress), (totalL2Burned + l2ToBurn)), IntegerEntry(keyUnlockedUnits(userAddress), 0), IntegerEntry(keyL2ToBurn(userAddress), 0), ScriptTransfer(addressFromStringValue(userAddress), unitsToSend, unitsAssetIdBytes)] ++ burnAction)
572+ }
573+ else throw("Strict value is not equal to itself.")
574+ }
575+
576+
490577 @Callable(i)
491578 func setNewPeriodLength (newPeriodLength) = {
492579 let checks = [if (isInAdminList(toString(i.caller)))
493580 then true
494581 else throwErr("caller is not in adminList")]
495582 if ((checks == checks))
496583 then getSetNewPeriodLengthActions(newPeriodLength)
497584 else throw("Strict value is not equal to itself.")
498585 }
499586
500587
501588
502589 @Callable(i)
503-func claimUnit () = {
590+func claimUnits () = {
504591 let userAddress = toString(i.caller)
505- let toClaimNow = calculateClaim(userAddress)
506- let totalUnitClaimed = valueOrElse(getInteger(this, keyTotalUnitsClaimed(userAddress)), 0)
507- let totalL2Staked = getUserTotalLocked(userAddress)
508- let check = [if ((totalL2Staked >= (totalUnitClaimed + toClaimNow)))
509- then true
510- else throwErr("Can't claim more than staked")]
511- if ((check == check))
512- then {
513- let claimedBlockKey = keyClaimedBlock(userAddress)
514- let actions = [IntegerEntry(claimedBlockKey, height), IntegerEntry(keyTotalUnitsClaimed(userAddress), (totalUnitClaimed + toClaimNow))]
515- let transferUnits = ScriptTransfer(i.caller, toClaimNow, unit)
516- (actions ++ [transferUnits])
517- }
518- else throw("Strict value is not equal to itself.")
592+ getClaimUnitsActions(userAddress)
519593 }
520594
521595
522596
523597 @Callable(i)
524598 func setForceStopFlag (stop) = {
525599 let check = [if (isInAdminList(toString(i.caller)))
526600 then true
527601 else throwErr("caller is not in adminList")]
528602 if ((check == check))
529603 then [BooleanEntry(keyForceStop, stop)]
530604 else throw("Strict value is not equal to itself.")
531605 }
532606
533607
534608
535609 @Callable(i)
536610 func setForceOutStopFlag (stop) = {
537611 let check = [if (isInAdminList(toString(i.caller)))
538612 then true
539613 else throwErr("caller is not in adminList")]
540614 if ((check == check))
541615 then [BooleanEntry(keyForceOutStop, stop)]
542616 else throw("Strict value is not equal to itself.")
543617 }
544618
545619
546620
547621 @Callable(i)
548622 func getNodeDataREADONLY (nodeAddress) = {
549- let $t01803818102 = getLeasingNodeData(nodeAddress)
550- let currentLease = $t01803818102._1
551- let nextLeased = $t01803818102._2
623+ let $t02100721071 = getLeasingNodeData(nodeAddress)
624+ let currentLease = $t02100721071._1
625+ let nextLeased = $t02100721071._2
552626 $Tuple2(nil, $Tuple5(currentPeriodHeight, currentLease, nextPeriodHeight, nextLeased, height))
553627 }
554628
555629
556630
557631 @Callable(i)
558632 func getUserLeasingDataREADONLY (nodeAddress,userAddress) = {
559- let $t01847218549 = getUserLeasingData(nodeAddress, userAddress)
560- let currentLease = $t01847218549._1
561- let nextLeased = $t01847218549._2
633+ let $t02144121518 = getUserLeasingData(nodeAddress, userAddress)
634+ let currentLease = $t02144121518._1
635+ let nextLeased = $t02144121518._2
562636 $Tuple2(nil, $Tuple5(currentPeriodHeight, currentLease, nextPeriodHeight, nextLeased, height))
563637 }
564638
565639
566640
567641 @Callable(i)
568642 func getUserDataREADONLY (userAddress) = {
569- let $t01891218972 = getUserToClaimBalance(userAddress)
570- let toClaim = $t01891218972._1
571- let toUnlock = $t01891218972._2
643+ let $t02203422094 = getUserToClaimBalance(userAddress)
644+ let toClaim = $t02203422094._1
645+ let toUnlock = $t02203422094._2
572646 let userTotalLocked = getUserTotalLocked(userAddress)
573- $Tuple2(nil, $Tuple6(currentPeriodHeight, toClaim, nextPeriodHeight, toUnlock, userTotalLocked, height))
647+ let $t02215722265 = getUnitsClaimData(userAddress)
648+ let unitsToSend = $t02215722265._1
649+ let totalUnitsClaimed = $t02215722265._2
650+ let l2ToBurn = $t02215722265._3
651+ let totalL2Burned = $t02215722265._4
652+ let claimedBlock = $t02215722265._5
653+ $Tuple2(nil, $Tuple11(currentPeriodHeight, toClaim, nextPeriodHeight, toUnlock, userTotalLocked, height, unitsToSend, totalUnitsClaimed, l2ToBurn, totalL2Burned, claimedBlock))
574654 }
575655
576656
577657
578658 @Callable(i)
579659 func leaseByAddress (nodeAddress,userAddress) = getStakeFromPaymentActions(nodeAddress, userAddress, i)
580660
581661
582662
583663 @Callable(i)
584664 func lease (nodeAddress) = {
585665 let userAddress = toString(i.caller)
586666 getStakeFromPaymentActions(nodeAddress, userAddress, i)
587667 }
588668
589669
590670
591671 @Callable(i)
592672 func leaseFromLocked (nodeAddress,amount) = {
593673 let userAddress = toString(i.caller)
594674 getStakeActions(nodeAddress, userAddress, amount, i)
595675 }
596676
597677
598678
599679 @Callable(i)
600680 func cancelLease (nodeAddress,amount) = {
601681 let userAddress = toString(i.caller)
602682 getUnstakeActions(nodeAddress, userAddress, amount)
603683 }
604684
605685
606686
607687 @Callable(i)
608688 func claim (amount) = {
609689 let userAddress = toString(i.caller)
610690 getClaimUnlockedActions(userAddress, amount)
611691 }
612692
613693
614694
615695 @Callable(i)
616696 func claimAll () = {
617697 let userAddress = toString(i.caller)
618- let $t01998620046 = getUserToClaimBalance(userAddress)
619- let toClaim = $t01998620046._1
620- let toUnlock = $t01998620046._2
698+ let $t02345723517 = getUserToClaimBalance(userAddress)
699+ let toClaim = $t02345723517._1
700+ let toUnlock = $t02345723517._2
621701 let checks = [if ((toClaim > 0))
622702 then true
623703 else throwErr("nothing to claim")]
624704 if ((checks == checks))
625705 then getClaimUnlockedActions(userAddress, toClaim)
626706 else throw("Strict value is not equal to itself.")
627707 }
628708
629709
630710
631711 @Callable(i)
632712 func stakeFor (userAddress) = getStakeForActions(userAddress, i)
713+
714+
715+
716+@Callable(i)
717+func startUnitsVesting () = {
718+ let totalL2 = 100000000000000000
719+ let totalUnits = i.payments[0].amount
720+ let unitsPerBlockScale8 = (fraction(totalL2, scale8, totalUnits) / unitsClaimInterval)
721+ let check = [if (isInAdminList(toString(i.caller)))
722+ then true
723+ else throwErr("caller is not in adminList"), if ((size(i.payments) == 1))
724+ then true
725+ else throwErr("should be 1 payment"), if ((unitsPerBlockScale8 > 0))
726+ then true
727+ else throwErr("units per block should be greated than 0")]
728+ if ((check == check))
729+ then [IntegerEntry(keyUnitsPerBlockScale8, unitsPerBlockScale8), IntegerEntry(keyUnitsClaimStartHeight, height), StringEntry(keyUnitsAssetId, assetBytesToString(i.payments[0].assetId))]
730+ else throw("Strict value is not equal to itself.")
731+ }
633732
634733
635734
636735 @Callable(i)
637736 func voteForTxId (txId) = {
638737 let callerAddressString = toBase58String(i.caller.bytes)
639738 let keyPrefix = keyAllowedTxIdVotePrefix(txId)
640739 let result = [StringEntry(keyAllowedTxId(), txId)]
641740 let allowedTxIdOption = getString(this, keyAllowedTxId())
642741 let err = [if ((size(fromBase58String(txId)) == TXID_BYTES_LENGTH))
643742 then true
644743 else throwErr((txId + " is not valid txId")), if (if ((allowedTxIdOption == unit))
645744 then true
646745 else (value(allowedTxIdOption) != txId))
647746 then true
648747 else throwErr((txId + " is already allowed"))]
649748 if ((err == err))
650749 then voteINTERNAL(callerAddressString, keyPrefix, QUORUM, result)
651750 else throw("Strict value is not equal to itself.")
652751 }
653752
654753
655754 @Verifier(tx)
656755 func verify () = {
657756 let byAdmins = (tx.id == fromBase58String(valueOrElse(getString(this, keyAllowedTxId()), "")))
658757 let byOwner = if ((size(getAdminsList()) >= QUORUM))
659758 then false
660759 else sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
661760 if (byAdmins)
662761 then true
663762 else byOwner
664763 }
665764

github/deemru/w8io/026f985 
96.03 ms