tx · 4E3w3Cq34z7CAWJyB9ffwyoAb1RKVmgL88T6q4dubgzV 3N5GdQtkca26RjfqCjZySc6xKVLy3ak2neK: -0.02000000 Waves 2025.02.04 16:12 [3489018] smart account 3N5GdQtkca26RjfqCjZySc6xKVLy3ak2neK > SELF 0.00000000 Waves
{ "type": 13, "id": "4E3w3Cq34z7CAWJyB9ffwyoAb1RKVmgL88T6q4dubgzV", "fee": 2000000, "feeAssetId": null, "timestamp": 1738674742648, "version": 2, "chainId": 84, "sender": "3N5GdQtkca26RjfqCjZySc6xKVLy3ak2neK", "senderPublicKey": "74hB8d2UATLmzddfh4KTpRuMhnVNAHSGirdFByhNSTW5", "proofs": [ "SpA8r5fCgwz4EmuhcD1DK2BMTBc3F5bBChH9kfqPWysVpnNJY5DZP1HzY28MKBCvTJppJxJtkkw7N5SdDJZWnoe" ], "script": "base64:BwI8CAISAwoBAhIAEgQKAggBEgASBAoCCAESBAoCCAgSAwoBCBIECgIIARIDCgEBEgMKAQgSAwoBCBIDCgEIEQARcmVxdWlyZWRXWFhBbW91bnQAgMivoCUAFWN5Y2xlRHVyYXRpb25JbkJsb2NrcwDoBwAYZW1lcmdlbmN5Vm90aW5nVGhyZXNob2xkAAoADXRvdGFsVm90ZXNrZXkCCnRvdGFsVm90ZXMACnd4eEFzc2V0SWQJARFAZXh0ck5hdGl2ZSgxMDU3KQECDnByb2plY3RBc3NldElkAA14V2F2ZXNBc3NldElkCQERQGV4dHJOYXRpdmUoMTA1NykBAg14V2F2ZXNBc3NldElkAAxjdXJyZW50Q3ljbGUJAGkCCQBlAggFCWxhc3RCbG9jawZoZWlnaHQJARFAZXh0ck5hdGl2ZSgxMDU1KQECCnN0YXJ0QmxvY2sFFWN5Y2xlRHVyYXRpb25JbkJsb2NrcwAgY3VycmVudEN5Y2xlUmVxdWVzdGVkV2l0aGRyYXdhbHMJAQt2YWx1ZU9yRWxzZQIJAJ8IAQkArAICAhdjeWNsZVJlcXVlc3RlZFdpdGhkcmF3OgkApAMBBQxjdXJyZW50Q3ljbGUAAAAdY3VycmVudEN5Y2xlUmVxdWVzdGVkRGVwb3NpdHMJAQt2YWx1ZU9yRWxzZQIJAJ8IAQkArAICAhZjeWNsZVJlcXVlc3RlZERlcG9zaXQ6CQCkAwEFDGN1cnJlbnRDeWNsZQAAAAp0b3RhbFZvdGVzCQERQGV4dHJOYXRpdmUoMTA1NSkBBQ10b3RhbFZvdGVza2V5ARZhc3NlcnRWYWxpZGF0b3JBZGRyZXNzARB2YWxpZGF0b3JBZGRyZXNzAwkBCWlzRGVmaW5lZAEJAJ0IAgUEdGhpcwkArAICAgp2YWxpZGF0b3I6CQClCAEFEHZhbGlkYXRvckFkZHJlc3MFBHVuaXQJAAIBAhFVbmtub3duIHZhbGlkYXRvcgEQYXNzZXJ0T25lUGF5bWVudAEKaW52b2NhdGlvbgMJAQIhPQIJAJADAQgFCmludm9jYXRpb24IcGF5bWVudHMAAQkAAgECD05vdCBvbmUgcGF5bWVudAUEdW5pdAESYXNzZXJ0UGF5bWVudEFzc2V0AgppbnZvY2F0aW9uDWV4cGVjdGVkVG9rZW4DCQECIT0CCAkAkQMCCAUKaW52b2NhdGlvbghwYXltZW50cwAAB2Fzc2V0SWQFDWV4cGVjdGVkVG9rZW4JAAIBAhNVbmV4cGVjdGVkIGFzc2V0IGlkBQR1bml0AQphc3NlcnRVaW50AQF2AwkAZgIAAAUBdgkAAgECDEludmFsaWQgdWludAUEdW5pdAEbYXNzZXJ0QWN0aXZlVmFsaWRhdG9yU3RhdHVzARB2YWxpZGF0b3JBZGRyZXNzBBJ2YWxpZGF0b3JTdGF0dXNLZXkJAKwCAgIQdmFsaWRhdG9yU3RhdHVzOgkApQgBBRB2YWxpZGF0b3JBZGRyZXNzAwkBASEBCQERQGV4dHJOYXRpdmUoMTA1NikBBRJ2YWxpZGF0b3JTdGF0dXNLZXkJAAIBAhJVbmFjdGl2ZSB2YWxpZGF0b3IFBHVuaXQBG2Fzc2VydEN5Y2xlTG93ZXJUaGF0Q3VycmVudAEFY3ljbGUDCQBmAgUMY3VycmVudEN5Y2xlBQVjeWNsZQUEdW5pdAkAAgECDUludmFsaWQgY3ljbGUBFmFzc2VydENhbGxlcklzQ29udHJhY3QBCmludm9jYXRpb24DCQECIT0CBQR0aGlzCAUKaW52b2NhdGlvbgZjYWxsZXIJAAIBAgxVbmF1dGhvcml6ZWQFBHVuaXQMCmludm9jYXRpb24BBGluaXQBCnd4eFRva2VuSWQEC2NhbGxlckNoZWNrCQEWYXNzZXJ0Q2FsbGVySXNDb250cmFjdAEFCmludm9jYXRpb24DCQAAAgULY2FsbGVyQ2hlY2sFC2NhbGxlckNoZWNrAwkBCWlzRGVmaW5lZAEJAKEIAQIOcHJvamVjdEFzc2V0SWQJAAIBAgtJbml0aWFsaXplZAQFaXNzdWUJAMIIBQIGeFdhdmVzAgZ4V2F2ZXMAAAAIBgQPeFdhdmVzQXNzZXRJZElkCQC4CAEFBWlzc3VlCQDMCAIFBWlzc3VlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ10b3RhbFZvdGVza2V5AAAJAMwIAgkBC0JpbmFyeUVudHJ5AgIOcHJvamVjdEFzc2V0SWQFCnd4eFRva2VuSWQJAMwIAgkBC0JpbmFyeUVudHJ5AgINeFdhdmVzQXNzZXRJZAUPeFdhdmVzQXNzZXRJZElkCQDMCAIJAQxJbnRlZ2VyRW50cnkCAgpzdGFydEJsb2NrCAUJbGFzdEJsb2NrBmhlaWdodAkAzAgCCQEMSW50ZWdlckVudHJ5AgIWdG90YWxSZXF1ZXN0ZWRXaXRoZHJhdwAACQDMCAIJAQxJbnRlZ2VyRW50cnkCAhFyZXF1aXJlZFdYWEFtb3VudAURcmVxdWlyZWRXWFhBbW91bnQJAMwIAgkBDEludGVnZXJFbnRyeQICGGVtZXJnZW5jeVZvdGluZ1RocmVzaG9sZAUYZW1lcmdlbmN5Vm90aW5nVGhyZXNob2xkBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4KaW52b2NhdGlvbgEOcmVxdWVzdERlcG9zaXQABBFfYXNzZXJ0T25lUGF5bWVudAkBEGFzc2VydE9uZVBheW1lbnQBBQppbnZvY2F0aW9uAwkAAAIFEV9hc3NlcnRPbmVQYXltZW50BRFfYXNzZXJ0T25lUGF5bWVudAQTX2Fzc2VydFBheW1lbnRBc3NldAkBEmFzc2VydFBheW1lbnRBc3NldAIFCmludm9jYXRpb24FBHVuaXQDCQAAAgUTX2Fzc2VydFBheW1lbnRBc3NldAUTX2Fzc2VydFBheW1lbnRBc3NldAQLd2F2ZXNBbW91bnQICQCRAwIIBQppbnZvY2F0aW9uCHBheW1lbnRzAAAGYW1vdW50BAljYWxsZXJLZXkJAKUIAQgFCmludm9jYXRpb24GY2FsbGVyBBNyZXF1ZXN0ZWREZXBvc2l0S2V5CQCsAgIJAKwCAgkArAICAhFyZXF1ZXN0ZWREZXBvc2l0OgUJY2FsbGVyS2V5AgF8CQCkAwEFDGN1cnJlbnRDeWNsZQQRcmVxdWVzdGVkRGVwb3NpdHMJAQt2YWx1ZU9yRWxzZQIJAJ8IAQUTcmVxdWVzdGVkRGVwb3NpdEtleQAABBZ0b3RhbFJlcXVlc3RlZERlcG9zaXRzCQELdmFsdWVPckVsc2UCCQCfCAEJAKwCAgIWY3ljbGVSZXF1ZXN0ZWREZXBvc2l0OgkApAMBBQxjdXJyZW50Q3ljbGUAAAkAzAgCCQEMSW50ZWdlckVudHJ5AgUTcmVxdWVzdGVkRGVwb3NpdEtleQkAZAIFEXJlcXVlc3RlZERlcG9zaXRzBQt3YXZlc0Ftb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICAhZjeWNsZVJlcXVlc3RlZERlcG9zaXQ6CQCkAwEFDGN1cnJlbnRDeWNsZQkAZAIFFnRvdGFsUmVxdWVzdGVkRGVwb3NpdHMFC3dhdmVzQW1vdW50BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4KaW52b2NhdGlvbgEOcHJvY2Vzc0RlcG9zaXQCCXJlY2lwaWVudAVjeWNsZQQMX2Fzc2VydEN5Y2xlCQEbYXNzZXJ0Q3ljbGVMb3dlclRoYXRDdXJyZW50AQUFY3ljbGUDCQAAAgUMX2Fzc2VydEN5Y2xlBQxfYXNzZXJ0Q3ljbGUEEHJlY2lwaWVudEFkZHJlc3MJARFAZXh0ck5hdGl2ZSgxMDYyKQEFCXJlY2lwaWVudAQTcmVxdWVzdGVkRGVwb3NpdEtleQkArAICCQCsAgIJAKwCAgIRcmVxdWVzdGVkRGVwb3NpdDoFCXJlY2lwaWVudAIBfAkApAMBBQVjeWNsZQQWY3ljbGVSZXF1ZXN0ZWREZXBvc2l0cwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCfCAEJAKwCAgIWY3ljbGVSZXF1ZXN0ZWREZXBvc2l0OgkApAMBBQVjeWNsZQIfTm8gcmVxdWVzdGVkIGRlcG9zaXRzIGZvciBjeWNsZQQQcmVxdWVzdGVkRGVwb3NpdAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCfCAEFE3JlcXVlc3RlZERlcG9zaXRLZXkCFE5vIHJlcXVlc3RlZCBkZXBvc2l0BA1scFRva2VuSXNzdWVkCAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQDsBwEFDXhXYXZlc0Fzc2V0SWQCD1Vrbm93biBhc3NldCBpZAhxdWFudGl0eQQJcG9vbFZhbHVlCQBlAggJAO8HAQUEdGhpcwdyZWd1bGFyBRZjeWNsZVJlcXVlc3RlZERlcG9zaXRzBAx4V2F2ZXNBbW91bnQDCQAAAgUNbHBUb2tlbklzc3VlZAAABRByZXF1ZXN0ZWREZXBvc2l0CQBrAwUQcmVxdWVzdGVkRGVwb3NpdAUNbHBUb2tlbklzc3VlZAUJcG9vbFZhbHVlBA1uZXdDeWNsZVZhbHVlCQBlAgUWY3ljbGVSZXF1ZXN0ZWREZXBvc2l0cwUQcmVxdWVzdGVkRGVwb3NpdAQTY3ljbGVXaXRoZHJhd0NoYW5nZQMJAGcCAAEFDW5ld0N5Y2xlVmFsdWUJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICAhZjeWNsZVJlcXVlc3RlZERlcG9zaXQ6CQCkAwEFBWN5Y2xlBQNuaWwJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgIWY3ljbGVSZXF1ZXN0ZWREZXBvc2l0OgkApAMBBQVjeWNsZQUNbmV3Q3ljbGVWYWx1ZQUDbmlsCQDOCAIFE2N5Y2xlV2l0aGRyYXdDaGFuZ2UJAMwIAgkBC0RlbGV0ZUVudHJ5AQUTcmVxdWVzdGVkRGVwb3NpdEtleQkAzAgCCQEHUmVpc3N1ZQMFDXhXYXZlc0Fzc2V0SWQFDHhXYXZlc0Ftb3VudAYJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwUQcmVjaXBpZW50QWRkcmVzcwUMeFdhdmVzQW1vdW50BQ14V2F2ZXNBc3NldElkBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4KaW52b2NhdGlvbgEPcmVxdWVzdFdpdGhkcmF3AAQRX2Fzc2VydE9uZVBheW1lbnQJARBhc3NlcnRPbmVQYXltZW50AQUKaW52b2NhdGlvbgMJAAACBRFfYXNzZXJ0T25lUGF5bWVudAURX2Fzc2VydE9uZVBheW1lbnQEE19hc3NlcnRQYXltZW50QXNzZXQJARJhc3NlcnRQYXltZW50QXNzZXQCBQppbnZvY2F0aW9uBQ14V2F2ZXNBc3NldElkAwkAAAIFE19hc3NlcnRQYXltZW50QXNzZXQFE19hc3NlcnRQYXltZW50QXNzZXQEDHhXYXZlc0Ftb3VudAgJAJEDAggFCmludm9jYXRpb24IcGF5bWVudHMAAAZhbW91bnQECWNhbGxlcktleQkApQgBCAUKaW52b2NhdGlvbgZjYWxsZXIEHXJlcXVlc3RlZFdpdGhkcmF3Rm9yQ2FsbGVyS2V5CQCsAgIJAKwCAgkArAICAhJyZXF1ZXN0ZWRXaXRoZHJhdzoFCWNhbGxlcktleQIBfAkApAMBBQxjdXJyZW50Q3ljbGUEGnJlcXVlc3RlZFdpdGhkcmF3Rm9yQ2FsbGVyCQELdmFsdWVPckVsc2UCCQCfCAEFHXJlcXVlc3RlZFdpdGhkcmF3Rm9yQ2FsbGVyS2V5AAAEFnRvdGFsUmVxdWVzdGVkV2l0aGRyYXcJAQt2YWx1ZU9yRWxzZQIJAJ8IAQIWdG90YWxSZXF1ZXN0ZWRXaXRoZHJhdwAABB1jdXJyZW50Q3ljbGVSZXF1ZXN0ZWRXaXRoZHJhdwUgY3VycmVudEN5Y2xlUmVxdWVzdGVkV2l0aGRyYXdhbHMJAMwIAgkBDEludGVnZXJFbnRyeQIFHXJlcXVlc3RlZFdpdGhkcmF3Rm9yQ2FsbGVyS2V5CQBkAgUacmVxdWVzdGVkV2l0aGRyYXdGb3JDYWxsZXIFDHhXYXZlc0Ftb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICAhdjeWNsZVJlcXVlc3RlZFdpdGhkcmF3OgkApAMBBQxjdXJyZW50Q3ljbGUJAGQCBR1jdXJyZW50Q3ljbGVSZXF1ZXN0ZWRXaXRoZHJhdwUMeFdhdmVzQW1vdW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCAhZ0b3RhbFJlcXVlc3RlZFdpdGhkcmF3CQBkAgUWdG90YWxSZXF1ZXN0ZWRXaXRoZHJhdwUMeFdhdmVzQW1vdW50BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4KaW52b2NhdGlvbgEPcHJvY2Vzc1dpdGhkcmF3AglyZWNpcGllbnQFY3ljbGUEDF9hc3NlcnRDeWNsZQkBG2Fzc2VydEN5Y2xlTG93ZXJUaGF0Q3VycmVudAEFBWN5Y2xlAwkAAAIFDF9hc3NlcnRDeWNsZQUMX2Fzc2VydEN5Y2xlBBByZWNpcGllbnRBZGRyZXNzCQERQGV4dHJOYXRpdmUoMTA2MikBBQlyZWNpcGllbnQEFHJlcXVlc3RlZFdpdGhkcmF3S2V5CQCsAgIJAKwCAgkArAICAhJyZXF1ZXN0ZWRXaXRoZHJhdzoFCXJlY2lwaWVudAIBfAkApAMBBQVjeWNsZQQTcmVxdWVzdGVkV2l0aGRyYXdhbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCfCAEFFHJlcXVlc3RlZFdpdGhkcmF3S2V5AhVObyByZXF1ZXN0ZWQgd2l0aGRyYXcEFmN5Y2xlUmVxdWVzdGVkV2l0aGRyYXcJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnwgBCQCsAgICF2N5Y2xlUmVxdWVzdGVkV2l0aGRyYXc6CQCkAwEFBWN5Y2xlAiJObyByZXF1ZXN0ZWQgd2l0aGRyYXdhbHMgZm9yIGN5Y2xlBAlwb29sVmFsdWUICQDvBwEFBHRoaXMHcmVndWxhcgQNbHBUb2tlbklzc3VlZAgJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkA7AcBBQ14V2F2ZXNBc3NldElkAg9Va25vd24gYXNzZXQgaWQIcXVhbnRpdHkEFnRvdGFsUmVxdWVzdGVkV2l0aGRyYXcJAQt2YWx1ZU9yRWxzZQIJAJ8IAQIWdG90YWxSZXF1ZXN0ZWRXaXRoZHJhdwAABAt3YXZlc0Ftb3VudAkAawMFE3JlcXVlc3RlZFdpdGhkcmF3YWwFCXBvb2xWYWx1ZQUNbHBUb2tlbklzc3VlZAQNbmV3Q3ljbGVWYWx1ZQkAZQIFFmN5Y2xlUmVxdWVzdGVkV2l0aGRyYXcFE3JlcXVlc3RlZFdpdGhkcmF3YWwEE2N5Y2xlV2l0aGRyYXdDaGFuZ2UDCQAAAgUNbmV3Q3ljbGVWYWx1ZQAACQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgIXY3ljbGVSZXF1ZXN0ZWRXaXRoZHJhdzoJAKQDAQUFY3ljbGUFA25pbAkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICAhdjeWNsZVJlcXVlc3RlZFdpdGhkcmF3OgkApAMBBQVjeWNsZQUNbmV3Q3ljbGVWYWx1ZQUDbmlsCQDOCAIFE2N5Y2xlV2l0aGRyYXdDaGFuZ2UJAMwIAgkBDEludGVnZXJFbnRyeQICFnRvdGFsUmVxdWVzdGVkV2l0aGRyYXcJAGUCBRZ0b3RhbFJlcXVlc3RlZFdpdGhkcmF3BRNyZXF1ZXN0ZWRXaXRoZHJhd2FsCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMFEHJlY2lwaWVudEFkZHJlc3MFC3dhdmVzQW1vdW50BQR1bml0CQDMCAIJAQRCdXJuAgUNeFdhdmVzQXNzZXRJZAUTcmVxdWVzdGVkV2l0aGRyYXdhbAkAzAgCCQELRGVsZXRlRW50cnkBBRRyZXF1ZXN0ZWRXaXRoZHJhd0tleQUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCmludm9jYXRpb24BCHJlZ2lzdGVyAgl2YWxpZGF0b3ILbWV0YWRhdGFVcmwEEV9hc3NlcnRPbmVQYXltZW50CQEQYXNzZXJ0T25lUGF5bWVudAEFCmludm9jYXRpb24DCQAAAgURX2Fzc2VydE9uZVBheW1lbnQFEV9hc3NlcnRPbmVQYXltZW50BBNfYXNzZXJ0UGF5bWVudEFzc2V0CQESYXNzZXJ0UGF5bWVudEFzc2V0AgUKaW52b2NhdGlvbgUKd3h4QXNzZXRJZAMJAAACBRNfYXNzZXJ0UGF5bWVudEFzc2V0BRNfYXNzZXJ0UGF5bWVudEFzc2V0BBNfYXNzZXJ0VmFsaWRBZGRyZXNzCQERQGV4dHJOYXRpdmUoMTA2MikBBQl2YWxpZGF0b3IDCQAAAgUTX2Fzc2VydFZhbGlkQWRkcmVzcwUTX2Fzc2VydFZhbGlkQWRkcmVzcwQJd3h4QW1vdW50CAkAkQMCCAUKaW52b2NhdGlvbghwYXltZW50cwAABmFtb3VudAQMdmFsaWRhdG9yS2V5CQCsAgICCnZhbGlkYXRvcjoFCXZhbGlkYXRvcgQSdmFsaWRhdG9yU3RhdHVzS2V5CQCsAgICEHZhbGlkYXRvclN0YXR1czoFCXZhbGlkYXRvcgQXdmFsaWRhdG9yUmVnaXN0cmF0b3JLZXkJAKwCAgIVdmFsaWRhdG9yUmVnaXN0cmF0b3I6BQl2YWxpZGF0b3IDCQEJaXNEZWZpbmVkAQkAnQgCBQR0aGlzBQx2YWxpZGF0b3JLZXkJAAIBAhJBbHJlYWR5IHJlZ2lzdGVyZWQDCQECIT0CBRFyZXF1aXJlZFdYWEFtb3VudAUJd3h4QW1vdW50CQACAQISSW52YWxpZCBXWFggYW1vdW50CQDMCAIJAQtTdHJpbmdFbnRyeQIFDHZhbGlkYXRvcktleQULbWV0YWRhdGFVcmwJAMwIAgkBDEJvb2xlYW5FbnRyeQIFEnZhbGlkYXRvclN0YXR1c0tleQYJAMwIAgkBC0JpbmFyeUVudHJ5AgUXdmFsaWRhdG9yUmVnaXN0cmF0b3JLZXkICAUKaW52b2NhdGlvbgZjYWxsZXIFYnl0ZXMFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgppbnZvY2F0aW9uAQpkZXJlZ2lzdGVyAQl2YWxpZGF0b3IEEHZhbGlkYXRvckFkZHJlc3MJARFAZXh0ck5hdGl2ZSgxMDYyKQEFCXZhbGlkYXRvcgQXdmFsaWRhdG9yUmVnaXN0cmF0b3JLZXkJAKwCAgIVdmFsaWRhdG9yUmVnaXN0cmF0b3I6BQl2YWxpZGF0b3IEEnZhbGlkYXRvclN0YXR1c0tleQkArAICAhB2YWxpZGF0b3JTdGF0dXM6BQl2YWxpZGF0b3IEEXZhbGlkYXRvclZvdGVzS2V5CQCsAgICBnZvdGVzOgUJdmFsaWRhdG9yBBdfYXNzZXJ0VmFsaWRhdG9yQWRkcmVzcwkBFmFzc2VydFZhbGlkYXRvckFkZHJlc3MBBRB2YWxpZGF0b3JBZGRyZXNzAwkAAAIFF19hc3NlcnRWYWxpZGF0b3JBZGRyZXNzBRdfYXNzZXJ0VmFsaWRhdG9yQWRkcmVzcwQZX2Fzc2V0Q2FsbGVySXNSZWdpc3RyYXRvcgMJAQIhPQIJARFAZXh0ck5hdGl2ZSgxMDU3KQEFF3ZhbGlkYXRvclJlZ2lzdHJhdG9yS2V5CAgFCmludm9jYXRpb24GY2FsbGVyBWJ5dGVzCQACAQITV3JvbmcgZGVyZWdpc3RyYXRvcgUEdW5pdAMJAAACBRlfYXNzZXRDYWxsZXJJc1JlZ2lzdHJhdG9yBRlfYXNzZXRDYWxsZXJJc1JlZ2lzdHJhdG9yBBN2YWxpZGF0b3JMZWFzZUlkS2V5CQCsAgICCGxlYXNlSWQ6BQl2YWxpZGF0b3IEBmNhbmNlbAQHJG1hdGNoMAkAoQgBBRN2YWxpZGF0b3JMZWFzZUlkS2V5AwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEAmlkBQckbWF0Y2gwCQDMCAIJAQtMZWFzZUNhbmNlbAEFAmlkBQNuaWwDCQABAgUHJG1hdGNoMAIEVW5pdAUDbmlsCQACAQILTWF0Y2ggZXJyb3IJAM4IAgkAzggCAwkBEUBleHRyTmF0aXZlKDEwNTYpAQUSdmFsaWRhdG9yU3RhdHVzS2V5BA52YWxpZGF0b3JWb3RlcwkBC3ZhbHVlT3JFbHNlAgkAnwgBBRF2YWxpZGF0b3JWb3Rlc0tleQAACQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ10b3RhbFZvdGVza2V5CQBlAgUKdG90YWxWb3RlcwUOdmFsaWRhdG9yVm90ZXMJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwgFCmludm9jYXRpb24GY2FsbGVyBRFyZXF1aXJlZFdYWEFtb3VudAUKd3h4QXNzZXRJZAUDbmlsBQNuaWwFBmNhbmNlbAkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgICBnZvdGVzOgUJdmFsaWRhdG9yCQDMCAIJAQtEZWxldGVFbnRyeQEFEnZhbGlkYXRvclN0YXR1c0tleQkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgICCnZhbGlkYXRvcjoFCXZhbGlkYXRvcgkAzAgCCQELRGVsZXRlRW50cnkBBRF2YWxpZGF0b3JWb3Rlc0tleQkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgICEHZhbGlkYXRvckxlYXNlczoFCXZhbGlkYXRvcgkAzAgCCQELRGVsZXRlRW50cnkBBRN2YWxpZGF0b3JMZWFzZUlkS2V5CQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgITbGF0ZXN0TGVhc2luZ0N5Y2xlOgUJdmFsaWRhdG9yBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4KaW52b2NhdGlvbgEEdm90ZQIJdmFsaWRhdG9yCGludGVydmFsBBB2YWxpZGF0b3JBZGRyZXNzCQERQGV4dHJOYXRpdmUoMTA2MikBBQl2YWxpZGF0b3IEF19hc3NlcnRWYWxpZGF0b3JBZGRyZXNzCQEWYXNzZXJ0VmFsaWRhdG9yQWRkcmVzcwEFEHZhbGlkYXRvckFkZHJlc3MDCQAAAgUXX2Fzc2VydFZhbGlkYXRvckFkZHJlc3MFF19hc3NlcnRWYWxpZGF0b3JBZGRyZXNzBBVfYXNzZXRWYWxpZGF0b3JTdGF0dXMJARthc3NlcnRBY3RpdmVWYWxpZGF0b3JTdGF0dXMBBRB2YWxpZGF0b3JBZGRyZXNzAwkAAAIFFV9hc3NldFZhbGlkYXRvclN0YXR1cwUVX2Fzc2V0VmFsaWRhdG9yU3RhdHVzBBFfYXNzZXJ0T25lUGF5bWVudAkBEGFzc2VydE9uZVBheW1lbnQBBQppbnZvY2F0aW9uAwkAAAIFEV9hc3NlcnRPbmVQYXltZW50BRFfYXNzZXJ0T25lUGF5bWVudAQTX2Fzc2VydFBheW1lbnRBc3NldAkBEmFzc2VydFBheW1lbnRBc3NldAIFCmludm9jYXRpb24FCnd4eEFzc2V0SWQDCQAAAgUTX2Fzc2VydFBheW1lbnRBc3NldAUTX2Fzc2VydFBheW1lbnRBc3NldAQLX2Fzc2VydFVpbnQJAQphc3NlcnRVaW50AQUIaW50ZXJ2YWwDCQAAAgULX2Fzc2VydFVpbnQFC19hc3NlcnRVaW50BAt1bmxvY2tCbG9jawkAZAIIBQlsYXN0QmxvY2sGaGVpZ2h0BQhpbnRlcnZhbAQJdXNlclZvdGVzCAkAkQMCCAUKaW52b2NhdGlvbghwYXltZW50cwAABmFtb3VudAQIdXNlckxvY2sICQCRAwIIBQppbnZvY2F0aW9uCHBheW1lbnRzAAAGYW1vdW50BAljYWxsZXJLZXkJAKUIAQgFCmludm9jYXRpb24GY2FsbGVyBA51bmxvY2tCbG9ja0tleQkArAICCQCsAgIJAKwCAgIMdW5sb2NrQmxvY2s6BQljYWxsZXJLZXkCAXwJAKQDAQULdW5sb2NrQmxvY2sEFnRvdGFsVmFsaWRhdG9yVm90ZXNLZXkJAKwCAgIGdm90ZXM6BQl2YWxpZGF0b3IEC3VzZXJWb3RlS2V5CQCsAgIJAKwCAgkArAICAgl1c2VyVm90ZToFCWNhbGxlcktleQIBfAkApAMBBQt1bmxvY2tCbG9jawQLdXNlckxvY2tLZXkJAKwCAgkArAICCQCsAgICCXVzZXJMb2NrOgUJY2FsbGVyS2V5AgF8CQCkAwEFC3VubG9ja0Jsb2NrBBN0b3RhbFZhbGlkYXRvclZvdGVzCQELdmFsdWVPckVsc2UCCQCfCAEFFnRvdGFsVmFsaWRhdG9yVm90ZXNLZXkAAAkAzAgCCQEMSW50ZWdlckVudHJ5AgULdXNlclZvdGVLZXkFCXVzZXJWb3RlcwkAzAgCCQEMSW50ZWdlckVudHJ5AgULdXNlckxvY2tLZXkFCHVzZXJMb2NrCQDMCAIJAQtCaW5hcnlFbnRyeQIFDnVubG9ja0Jsb2NrS2V5CAUQdmFsaWRhdG9yQWRkcmVzcwVieXRlcwkAzAgCCQEMSW50ZWdlckVudHJ5AgUWdG90YWxWYWxpZGF0b3JWb3Rlc0tleQkAZAIFE3RvdGFsVmFsaWRhdG9yVm90ZXMFCXVzZXJWb3RlcwkAzAgCCQEMSW50ZWdlckVudHJ5AgUNdG90YWxWb3Rlc2tleQkAZAIFCnRvdGFsVm90ZXMFCXVzZXJWb3RlcwUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCmludm9jYXRpb24BBnJlZGVlbQELdW5sb2NrQmxvY2sEEl9hc3NlcnRVbmxvY2tCbG9jawMJAGYCBQt1bmxvY2tCbG9jawgFCWxhc3RCbG9jawZoZWlnaHQJAAIBAglUb28gZWFybHkFBHVuaXQDCQAAAgUSX2Fzc2VydFVubG9ja0Jsb2NrBRJfYXNzZXJ0VW5sb2NrQmxvY2sECWNhbGxlcktleQkApQgBCAUKaW52b2NhdGlvbgZjYWxsZXIEDnVubG9ja0Jsb2NrS2V5CQCsAgIJAKwCAgkArAICAgx1bmxvY2tCbG9jazoFCWNhbGxlcktleQIBfAkApAMBBQt1bmxvY2tCbG9jawQLdXNlclZvdGVLZXkJAKwCAgkArAICCQCsAgICCXVzZXJWb3RlOgUJY2FsbGVyS2V5AgF8CQCkAwEFC3VubG9ja0Jsb2NrBAt1c2VyTG9ja0tleQkArAICCQCsAgIJAKwCAgIJdXNlckxvY2s6BQljYWxsZXJLZXkCAXwJAKQDAQULdW5sb2NrQmxvY2sEEHZhbGlkYXRvckFkZHJlc3MJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoQgBBQ51bmxvY2tCbG9ja0tleQIMVW5rbm93biBsb2NrBBF2YWxpZGF0b3JWb3Rlc0tleQkArAICAgZ2b3RlczoJANgEAQUQdmFsaWRhdG9yQWRkcmVzcwQJdXNlclZvdGVzCQERQGV4dHJOYXRpdmUoMTA1NSkBBQt1c2VyVm90ZUtleQQTdG90YWxWYWxpZGF0b3JWb3RlcwkBEUBleHRyTmF0aXZlKDEwNTUpAQURdmFsaWRhdG9yVm90ZXNLZXkECHVzZXJMb2NrCQERQGV4dHJOYXRpdmUoMTA1NSkBBQt1c2VyTG9ja0tleQQSdmFsaWRhdG9yU3RhdHVzS2V5CQCsAgICEHZhbGlkYXRvclN0YXR1czoJANgEAQUQdmFsaWRhdG9yQWRkcmVzcwkAzggCAwkBEUBleHRyTmF0aXZlKDEwNTYpAQUSdmFsaWRhdG9yU3RhdHVzS2V5CQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ10b3RhbFZvdGVza2V5CQBlAgUKdG90YWxWb3RlcwUJdXNlclZvdGVzBQNuaWwFA25pbAkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCAUKaW52b2NhdGlvbgZjYWxsZXIFCHVzZXJMb2NrBQp3eHhBc3NldElkCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRF2YWxpZGF0b3JWb3Rlc0tleQkAZQIFE3RvdGFsVmFsaWRhdG9yVm90ZXMFCXVzZXJWb3RlcwkAzAgCCQELRGVsZXRlRW50cnkBBQt1c2VyVm90ZUtleQkAzAgCCQELRGVsZXRlRW50cnkBBQ51bmxvY2tCbG9ja0tleQUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCmludm9jYXRpb24BB2xlYXNpbmcBCXZhbGlkYXRvcgQQdmFsaWRhdG9yQWRkcmVzcwkBEUBleHRyTmF0aXZlKDEwNjIpAQUJdmFsaWRhdG9yBBdfYXNzZXJ0VmFsaWRhdG9yQWRkcmVzcwkBFmFzc2VydFZhbGlkYXRvckFkZHJlc3MBBRB2YWxpZGF0b3JBZGRyZXNzAwkAAAIFF19hc3NlcnRWYWxpZGF0b3JBZGRyZXNzBRdfYXNzZXJ0VmFsaWRhdG9yQWRkcmVzcwQVX2Fzc2V0VmFsaWRhdG9yU3RhdHVzCQEbYXNzZXJ0QWN0aXZlVmFsaWRhdG9yU3RhdHVzAQUQdmFsaWRhdG9yQWRkcmVzcwMJAAACBRVfYXNzZXRWYWxpZGF0b3JTdGF0dXMFFV9hc3NldFZhbGlkYXRvclN0YXR1cwQTdmFsaWRhdG9yTGVhc2VJZEtleQkArAICAghsZWFzZUlkOgUJdmFsaWRhdG9yBBVsYXRlc3RMZWFzaW5nQ3ljbGVLZXkJAKwCAgITbGF0ZXN0TGVhc2luZ0N5Y2xlOgUJdmFsaWRhdG9yBA52YWxpZGF0b3JWb3RlcwkBC3ZhbHVlT3JFbHNlAgkAnwgBCQCsAgICBnZvdGVzOgUJdmFsaWRhdG9yAAAEEmN1cnJlbnRMZWFzZUFtb3VudAkBC3ZhbHVlT3JFbHNlAgkAnwgBCQCsAgICEHZhbGlkYXRvckxlYXNlczoFCXZhbGlkYXRvcgAABBNfY2hlY2tMZWFzaW5nU3RhdHVzAwkAAAIJAQt2YWx1ZU9yRWxzZQIJAJ8IAQUVbGF0ZXN0TGVhc2luZ0N5Y2xlS2V5AP///////////wEFDGN1cnJlbnRDeWNsZQkAAgECDkFscmVhZHkgbGVhc2VkBQR1bml0AwkAAAIFE19jaGVja0xlYXNpbmdTdGF0dXMFE19jaGVja0xlYXNpbmdTdGF0dXMEDWxwVG9rZW5Jc3N1ZWQICQETdmFsdWVPckVycm9yTWVzc2FnZQIJAOwHAQUNeFdhdmVzQXNzZXRJZAIPVWtub3duIGFzc2V0IGlkCHF1YW50aXR5BAlwb29sVmFsdWUJAGUCCAkA7wcBBQR0aGlzB3JlZ3VsYXIFHWN1cnJlbnRDeWNsZVJlcXVlc3RlZERlcG9zaXRzBBZ0b3RhbFJlcXVlc3RlZFdpdGhkcmF3CQELdmFsdWVPckVsc2UCCQCfCAECFnRvdGFsUmVxdWVzdGVkV2l0aGRyYXcAAAQbcHJldmlvdXNseVJlcXVlc3RlZFdpdGhkcmF3CQBlAgUWdG90YWxSZXF1ZXN0ZWRXaXRoZHJhdwUgY3VycmVudEN5Y2xlUmVxdWVzdGVkV2l0aGRyYXdhbHMEEXJlcXVlc3RlZFdpdGhkcmF3AwkAAAIFDWxwVG9rZW5Jc3N1ZWQAAAUbcHJldmlvdXNseVJlcXVlc3RlZFdpdGhkcmF3CQBrAwUbcHJldmlvdXNseVJlcXVlc3RlZFdpdGhkcmF3BQlwb29sVmFsdWUFDWxwVG9rZW5Jc3N1ZWQEEXRhcmdldExlYXNlQW1vdW50CQBrAwkAZQIFCXBvb2xWYWx1ZQURcmVxdWVzdGVkV2l0aGRyYXcFDnZhbGlkYXRvclZvdGVzBQp0b3RhbFZvdGVzBAZjYW5jZWwEByRtYXRjaDAJAKEIAQUTdmFsaWRhdG9yTGVhc2VJZEtleQMJAAECBQckbWF0Y2gwAgpCeXRlVmVjdG9yBAJpZAUHJG1hdGNoMAkAzAgCCQELTGVhc2VDYW5jZWwBBQJpZAUDbmlsAwkAAQIFByRtYXRjaDACBFVuaXQFA25pbAkAAgECC01hdGNoIGVycm9yAwkBAiE9AgURdGFyZ2V0TGVhc2VBbW91bnQFEmN1cnJlbnRMZWFzZUFtb3VudAQFbGVhc2UJAMQIAgUQdmFsaWRhdG9yQWRkcmVzcwURdGFyZ2V0TGVhc2VBbW91bnQJAM4IAgUGY2FuY2VsAwkAAAIFEXRhcmdldExlYXNlQW1vdW50AAAJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgIQdmFsaWRhdG9yTGVhc2VzOgUJdmFsaWRhdG9yBRF0YXJnZXRMZWFzZUFtb3VudAkAzAgCCQELRGVsZXRlRW50cnkBBRN2YWxpZGF0b3JMZWFzZUlkS2V5BQNuaWwJAMwIAgUFbGVhc2UJAMwIAgkBC0JpbmFyeUVudHJ5AgUTdmFsaWRhdG9yTGVhc2VJZEtleQkAuQgBBQVsZWFzZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICAhB2YWxpZGF0b3JMZWFzZXM6BQl2YWxpZGF0b3IFEXRhcmdldExlYXNlQW1vdW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCBRVsYXRlc3RMZWFzaW5nQ3ljbGVLZXkFDGN1cnJlbnRDeWNsZQUDbmlsCQACAQIPTm90aGluZyBjaGFuZ2VzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCmludm9jYXRpb24BD2VtZXJnZW5jeVZvdGluZwEJdmFsaWRhdG9yBBB2YWxpZGF0b3JBZGRyZXNzCQERQGV4dHJOYXRpdmUoMTA2MikBBQl2YWxpZGF0b3IEF19hc3NlcnRWYWxpZGF0b3JBZGRyZXNzCQEWYXNzZXJ0VmFsaWRhdG9yQWRkcmVzcwEFEHZhbGlkYXRvckFkZHJlc3MDCQAAAgUXX2Fzc2VydFZhbGlkYXRvckFkZHJlc3MFF19hc3NlcnRWYWxpZGF0b3JBZGRyZXNzBBVfYXNzZXRWYWxpZGF0b3JTdGF0dXMJARthc3NlcnRBY3RpdmVWYWxpZGF0b3JTdGF0dXMBBRB2YWxpZGF0b3JBZGRyZXNzAwkAAAIFFV9hc3NldFZhbGlkYXRvclN0YXR1cwUVX2Fzc2V0VmFsaWRhdG9yU3RhdHVzBBFfYXNzZXJ0T25lUGF5bWVudAkBEGFzc2VydE9uZVBheW1lbnQBBQppbnZvY2F0aW9uAwkAAAIFEV9hc3NlcnRPbmVQYXltZW50BRFfYXNzZXJ0T25lUGF5bWVudAQTX2Fzc2VydFBheW1lbnRBc3NldAkBEmFzc2VydFBheW1lbnRBc3NldAIFCmludm9jYXRpb24FDXhXYXZlc0Fzc2V0SWQDCQAAAgUTX2Fzc2VydFBheW1lbnRBc3NldAUTX2Fzc2VydFBheW1lbnRBc3NldAQKdm90ZUFtb3VudAgJAJEDAggFCmludm9jYXRpb24IcGF5bWVudHMAAAZhbW91bnQECWNhbGxlcktleQkApQgBCAUKaW52b2NhdGlvbgZjYWxsZXIEEWVtZXJnZW5jeVZvdGVzS2V5CQCsAgICD2VtZXJnZW5jeVZvdGVzOgUJdmFsaWRhdG9yBBVlbWVyZ2VuY3lVc2VyVm90ZXNLZXkJAKwCAgkArAICAhNlbWVyZ2VuY3lVc2VyVm90ZXM6BQljYWxsZXJLZXkFCXZhbGlkYXRvcgQOZW1lcmdlbmN5Vm90ZXMJAGQCBQp2b3RlQW1vdW50CQELdmFsdWVPckVsc2UCCQCfCAEFEWVtZXJnZW5jeVZvdGVzS2V5AAAECHF1YW50aXR5CAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQDsBwEFDXhXYXZlc0Fzc2V0SWQCD1Vrbm93biBhc3NldCBpZAhxdWFudGl0eQQMd3h4QXNzZXRJbmZvCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAOwHAQUKd3h4QXNzZXRJZAIPVWtub3duIGFzc2V0IGlkBA5pc1ZhbGlkYXRvckJhZAkAZgIJAGkCCQBoAgUOZW1lcmdlbmN5Vm90ZXMAZAUIcXVhbnRpdHkFGGVtZXJnZW5jeVZvdGluZ1RocmVzaG9sZAQKcHVuaXNobWVudAMFDmlzVmFsaWRhdG9yQmFkBBN2YWxpZGF0b3JMZWFzZUlkS2V5CQCsAgICCGxlYXNlSWQ6BQl2YWxpZGF0b3IEBmNhbmNlbAQHJG1hdGNoMAkAoQgBBRN2YWxpZGF0b3JMZWFzZUlkS2V5AwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEAmlkBQckbWF0Y2gwCQDMCAIJAQtMZWFzZUNhbmNlbAEFAmlkBQNuaWwDCQABAgUHJG1hdGNoMAIEVW5pdAUDbmlsCQACAQILTWF0Y2ggZXJyb3IEEXZhbGlkYXRvclZvdGVzS2V5CQCsAgICBnZvdGVzOgUJdmFsaWRhdG9yBBN0b3RhbFZhbGlkYXRvclZvdGVzCQELdmFsdWVPckVsc2UCCQCfCAEFEXZhbGlkYXRvclZvdGVzS2V5AAAJAM4IAgUGY2FuY2VsCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMIBQx3eHhBc3NldEluZm8GaXNzdWVyBRFyZXF1aXJlZFdYWEFtb3VudAUKd3h4QXNzZXRJZAkAzAgCCQEMSW50ZWdlckVudHJ5AgUNdG90YWxWb3Rlc2tleQkAZQIFCnRvdGFsVm90ZXMFE3RvdGFsVmFsaWRhdG9yVm90ZXMJAMwIAgkBDEJvb2xlYW5FbnRyeQIJAKwCAgIQdmFsaWRhdG9yU3RhdHVzOgUJdmFsaWRhdG9yBwkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgICEHZhbGlkYXRvckxlYXNlczoFCXZhbGlkYXRvcgkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgICCGxlYXNlSWQ6BQl2YWxpZGF0b3IJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICAhNsYXRlc3RMZWFzaW5nQ3ljbGU6BQl2YWxpZGF0b3IFA25pbAUDbmlsCQDOCAIFCnB1bmlzaG1lbnQJAMwIAgkBDEludGVnZXJFbnRyeQIFEWVtZXJnZW5jeVZvdGVzS2V5CQBkAgUKdm90ZUFtb3VudAUOZW1lcmdlbmN5Vm90ZXMJAMwIAgkBDEludGVnZXJFbnRyeQIFFWVtZXJnZW5jeVVzZXJWb3Rlc0tleQkAZAIJAQt2YWx1ZU9yRWxzZQIJAJ8IAQUVZW1lcmdlbmN5VXNlclZvdGVzS2V5AAAFDmVtZXJnZW5jeVZvdGVzBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4KaW52b2NhdGlvbgETcmVkZWVtRW1lcmdlbmN5Vm90ZQEJdmFsaWRhdG9yBBB2YWxpZGF0b3JBZGRyZXNzCQERQGV4dHJOYXRpdmUoMTA2MikBBQl2YWxpZGF0b3IECWNhbGxlcktleQkApQgBCAUKaW52b2NhdGlvbgZjYWxsZXIEFWVtZXJnZW5jeVVzZXJWb3Rlc0tleQkArAICCQCsAgICE2VtZXJnZW5jeVVzZXJWb3RlczoFCWNhbGxlcktleQUJdmFsaWRhdG9yBBJlbWVyZ2VuY3lVc2VyVm90ZXMJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnwgBBRVlbWVyZ2VuY3lVc2VyVm90ZXNLZXkCG05vIGVtZXJnZW5jeSB2b3RlcyBmb3IgdXNlcgkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCAUKaW52b2NhdGlvbgZjYWxsZXIFEmVtZXJnZW5jeVVzZXJWb3RlcwUNeFdhdmVzQXNzZXRJZAUDbmlsAFbPJjE=", "height": 3489018, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 7DCodDwbTH1DBru6Y9ckzdsKVe5ouFtDvafc9w5ux2VT Next: none Diff:
Old | New | Differences | |
---|---|---|---|
9 | 9 | ||
10 | 10 | let totalVoteskey = "totalVotes" | |
11 | 11 | ||
12 | - | ||
12 | + | let wxxAssetId = getBinaryValue("projectAssetId") | |
13 | 13 | ||
14 | + | let xWavesAssetId = getBinaryValue("xWavesAssetId") | |
14 | 15 | ||
15 | - | ||
16 | + | let currentCycle = ((lastBlock.height - getIntegerValue("startBlock")) / cycleDurationInBlocks) | |
16 | 17 | ||
18 | + | let currentCycleRequestedWithdrawals = valueOrElse(getInteger(("cycleRequestedWithdraw:" + toString(currentCycle))), 0) | |
17 | 19 | ||
18 | - | func getCurrentCycle () = { | |
19 | - | let startBlock = getIntegerValue("startBlock") | |
20 | - | ((lastBlock.height - startBlock) / cycleDurationInBlocks) | |
21 | - | } | |
20 | + | let currentCycleRequestedDeposits = valueOrElse(getInteger(("cycleRequestedDeposit:" + toString(currentCycle))), 0) | |
22 | 21 | ||
22 | + | let totalVotes = getIntegerValue(totalVoteskey) | |
23 | 23 | ||
24 | - | func assertValidatorAddress (validatorAddress) = if (isDefined(getString(this, ("validator:" + | |
24 | + | func assertValidatorAddress (validatorAddress) = if (isDefined(getString(this, ("validator:" + toString(validatorAddress))))) | |
25 | 25 | then unit | |
26 | 26 | else throw("Unknown validator") | |
27 | 27 | ||
42 | 42 | ||
43 | 43 | ||
44 | 44 | func assertActiveValidatorStatus (validatorAddress) = { | |
45 | - | let validatorStatusKey = ("validatorStatus:" + | |
45 | + | let validatorStatusKey = ("validatorStatus:" + toString(validatorAddress)) | |
46 | 46 | if (!(getBooleanValue(validatorStatusKey))) | |
47 | 47 | then throw("Unactive validator") | |
48 | 48 | else unit | |
49 | 49 | } | |
50 | 50 | ||
51 | 51 | ||
52 | - | func assertCycleLowerThatCurrent (cycle) = { | |
53 | - | let currentCycle = getCurrentCycle() | |
54 | - | if ((currentCycle > cycle)) | |
55 | - | then unit | |
56 | - | else throw("Invalid cycle") | |
57 | - | } | |
52 | + | func assertCycleLowerThatCurrent (cycle) = if ((currentCycle > cycle)) | |
53 | + | then unit | |
54 | + | else throw("Invalid cycle") | |
58 | 55 | ||
59 | 56 | ||
60 | - | func assertCallerIsContract (invocation) = if ((this | |
57 | + | func assertCallerIsContract (invocation) = if ((this != invocation.caller)) | |
61 | 58 | then throw("Unauthorized") | |
62 | 59 | else unit | |
63 | 60 | ||
64 | 61 | ||
65 | - | func getPrevCycleRequestedWithdrawals () = valueOrElse(getInteger(("cycleRequestedWithdraw:" + toString((getCurrentCycle() - 1)))), 0) | |
66 | - | ||
67 | - | ||
68 | - | func getPrevCycleRequestedDeposits () = valueOrElse(getInteger(("cycleRequestedDeposit:" + toString((getCurrentCycle() - 1)))), 0) | |
69 | - | ||
70 | - | ||
71 | - | func getCurrentCycleRequestedWithdrawals () = valueOrElse(getInteger(("cycleRequestedWithdraw:" + toString(getCurrentCycle()))), 0) | |
72 | - | ||
73 | - | ||
74 | - | func getCurrentCycleRequestedDeposits () = valueOrElse(getInteger(("cycleRequestedDeposit:" + toString(getCurrentCycle()))), 0) | |
75 | - | ||
76 | - | ||
77 | 62 | @Callable(invocation) | |
78 | - | func init ( | |
63 | + | func init (wxxTokenId) = { | |
79 | 64 | let callerCheck = assertCallerIsContract(invocation) | |
80 | 65 | if ((callerCheck == callerCheck)) | |
81 | 66 | then if (isDefined(getBinary("projectAssetId"))) | |
83 | 68 | else { | |
84 | 69 | let issue = Issue("xWaves", "xWaves", 0, 8, true) | |
85 | 70 | let xWavesAssetIdId = calculateAssetId(issue) | |
86 | - | [issue, IntegerEntry(totalVoteskey, 0), BinaryEntry("projectAssetId", | |
71 | + | [issue, IntegerEntry(totalVoteskey, 0), BinaryEntry("projectAssetId", wxxTokenId), BinaryEntry("xWavesAssetId", xWavesAssetIdId), IntegerEntry("startBlock", lastBlock.height), IntegerEntry("totalRequestedWithdraw", 0), IntegerEntry("requiredWXXAmount", requiredWXXAmount), IntegerEntry("emergencyVotingThreshold", emergencyVotingThreshold)] | |
87 | 72 | } | |
88 | 73 | else throw("Strict value is not equal to itself.") | |
89 | 74 | } | |
99 | 84 | if ((_assertPaymentAsset == _assertPaymentAsset)) | |
100 | 85 | then { | |
101 | 86 | let wavesAmount = invocation.payments[0].amount | |
102 | - | let callerKey = toBase58String(invocation.caller.bytes) | |
103 | - | let currentCycle = getCurrentCycle() | |
87 | + | let callerKey = toString(invocation.caller) | |
104 | 88 | let requestedDepositKey = ((("requestedDeposit:" + callerKey) + "|") + toString(currentCycle)) | |
105 | 89 | let requestedDeposits = valueOrElse(getInteger(requestedDepositKey), 0) | |
106 | 90 | let totalRequestedDeposits = valueOrElse(getInteger(("cycleRequestedDeposit:" + toString(currentCycle))), 0) | |
118 | 102 | let _assertCycle = assertCycleLowerThatCurrent(cycle) | |
119 | 103 | if ((_assertCycle == _assertCycle)) | |
120 | 104 | then { | |
121 | - | let | |
122 | - | let requestedDepositKey = ((("requestedDeposit:" + | |
105 | + | let recipientAddress = addressFromStringValue(recipient) | |
106 | + | let requestedDepositKey = ((("requestedDeposit:" + recipient) + "|") + toString(cycle)) | |
123 | 107 | let cycleRequestedDeposits = valueOrErrorMessage(getInteger(("cycleRequestedDeposit:" + toString(cycle))), "No requested deposits for cycle") | |
124 | 108 | let requestedDeposit = valueOrErrorMessage(getInteger(requestedDepositKey), "No requested deposit") | |
125 | 109 | let lpTokenIssued = valueOrErrorMessage(assetInfo(xWavesAssetId), "Uknown asset id").quantity | |
126 | 110 | let poolValue = (wavesBalance(this).regular - cycleRequestedDeposits) | |
127 | 111 | let xWavesAmount = if ((lpTokenIssued == 0)) | |
128 | 112 | then requestedDeposit | |
129 | - | else | |
113 | + | else fraction(requestedDeposit, lpTokenIssued, poolValue) | |
130 | 114 | let newCycleValue = (cycleRequestedDeposits - requestedDeposit) | |
131 | - | let cycleWithdrawChange = if (( | |
115 | + | let cycleWithdrawChange = if ((1 >= newCycleValue)) | |
132 | 116 | then [DeleteEntry(("cycleRequestedDeposit:" + toString(cycle)))] | |
133 | 117 | else [IntegerEntry(("cycleRequestedDeposit:" + toString(cycle)), newCycleValue)] | |
134 | - | (cycleWithdrawChange ++ [DeleteEntry(requestedDepositKey), Reissue(xWavesAssetId, xWavesAmount, true), ScriptTransfer( | |
118 | + | (cycleWithdrawChange ++ [DeleteEntry(requestedDepositKey), Reissue(xWavesAssetId, xWavesAmount, true), ScriptTransfer(recipientAddress, xWavesAmount, xWavesAssetId)]) | |
135 | 119 | } | |
136 | 120 | else throw("Strict value is not equal to itself.") | |
137 | 121 | } | |
143 | 127 | let _assertOnePayment = assertOnePayment(invocation) | |
144 | 128 | if ((_assertOnePayment == _assertOnePayment)) | |
145 | 129 | then { | |
146 | - | let _assertPaymentAsset = assertPaymentAsset(invocation, | |
130 | + | let _assertPaymentAsset = assertPaymentAsset(invocation, xWavesAssetId) | |
147 | 131 | if ((_assertPaymentAsset == _assertPaymentAsset)) | |
148 | 132 | then { | |
149 | 133 | let xWavesAmount = invocation.payments[0].amount | |
150 | - | let currentCycle = getCurrentCycle() | |
151 | - | let callerKey = toBase58String(invocation.caller.bytes) | |
134 | + | let callerKey = toString(invocation.caller) | |
152 | 135 | let requestedWithdrawForCallerKey = ((("requestedWithdraw:" + callerKey) + "|") + toString(currentCycle)) | |
153 | 136 | let requestedWithdrawForCaller = valueOrElse(getInteger(requestedWithdrawForCallerKey), 0) | |
154 | 137 | let totalRequestedWithdraw = valueOrElse(getInteger("totalRequestedWithdraw"), 0) | |
155 | - | let currentCycleRequestedWithdraw = | |
138 | + | let currentCycleRequestedWithdraw = currentCycleRequestedWithdrawals | |
156 | 139 | [IntegerEntry(requestedWithdrawForCallerKey, (requestedWithdrawForCaller + xWavesAmount)), IntegerEntry(("cycleRequestedWithdraw:" + toString(currentCycle)), (currentCycleRequestedWithdraw + xWavesAmount)), IntegerEntry("totalRequestedWithdraw", (totalRequestedWithdraw + xWavesAmount))] | |
157 | 140 | } | |
158 | 141 | else throw("Strict value is not equal to itself.") | |
167 | 150 | let _assertCycle = assertCycleLowerThatCurrent(cycle) | |
168 | 151 | if ((_assertCycle == _assertCycle)) | |
169 | 152 | then { | |
170 | - | let recipientKey = toBase58String(recipient) | |
171 | - | let xWavesAssetId = getXWavesAssetId() | |
172 | - | let requestedWithdrawKey = ((("requestedWithdraw:" + recipientKey) + "|") + toString(cycle)) | |
153 | + | let recipientAddress = addressFromStringValue(recipient) | |
154 | + | let requestedWithdrawKey = ((("requestedWithdraw:" + recipient) + "|") + toString(cycle)) | |
173 | 155 | let requestedWithdrawal = valueOrErrorMessage(getInteger(requestedWithdrawKey), "No requested withdraw") | |
174 | 156 | let cycleRequestedWithdraw = valueOrErrorMessage(getInteger(("cycleRequestedWithdraw:" + toString(cycle))), "No requested withdrawals for cycle") | |
175 | 157 | let poolValue = wavesBalance(this).regular | |
176 | 158 | let lpTokenIssued = valueOrErrorMessage(assetInfo(xWavesAssetId), "Uknown asset id").quantity | |
177 | 159 | let totalRequestedWithdraw = valueOrElse(getInteger("totalRequestedWithdraw"), 0) | |
178 | - | let wavesAmount = | |
160 | + | let wavesAmount = fraction(requestedWithdrawal, poolValue, lpTokenIssued) | |
179 | 161 | let newCycleValue = (cycleRequestedWithdraw - requestedWithdrawal) | |
180 | 162 | let cycleWithdrawChange = if ((newCycleValue == 0)) | |
181 | 163 | then [DeleteEntry(("cycleRequestedWithdraw:" + toString(cycle)))] | |
182 | 164 | else [IntegerEntry(("cycleRequestedWithdraw:" + toString(cycle)), newCycleValue)] | |
183 | - | (cycleWithdrawChange ++ [IntegerEntry("totalRequestedWithdraw", (totalRequestedWithdraw - requestedWithdrawal)), ScriptTransfer( | |
165 | + | (cycleWithdrawChange ++ [IntegerEntry("totalRequestedWithdraw", (totalRequestedWithdraw - requestedWithdrawal)), ScriptTransfer(recipientAddress, wavesAmount, unit), Burn(xWavesAssetId, requestedWithdrawal), DeleteEntry(requestedWithdrawKey)]) | |
184 | 166 | } | |
185 | 167 | else throw("Strict value is not equal to itself.") | |
186 | 168 | } | |
188 | 170 | ||
189 | 171 | ||
190 | 172 | @Callable(invocation) | |
191 | - | func register ( | |
173 | + | func register (validator,metadataUrl) = { | |
192 | 174 | let _assertOnePayment = assertOnePayment(invocation) | |
193 | 175 | if ((_assertOnePayment == _assertOnePayment)) | |
194 | 176 | then { | |
195 | - | let _assertPaymentAsset = assertPaymentAsset(invocation, | |
177 | + | let _assertPaymentAsset = assertPaymentAsset(invocation, wxxAssetId) | |
196 | 178 | if ((_assertPaymentAsset == _assertPaymentAsset)) | |
197 | 179 | then { | |
198 | - | let wxxAmount = invocation.payments[0].amount | |
199 | - | let validatorKey = ("validator:" + toBase58String(validatorAddress)) | |
200 | - | let validatorStatusKey = ("validatorStatus:" + toBase58String(validatorAddress)) | |
201 | - | let validatorRegistratorKey = ("validatorRegistrator:" + toBase58String(validatorAddress)) | |
202 | - | if (isDefined(getString(this, validatorKey))) | |
203 | - | then throw("Already registered") | |
204 | - | else if ((requiredWXXAmount != wxxAmount)) | |
205 | - | then throw("Invalid WXX amount") | |
206 | - | else [StringEntry(validatorKey, metadataUrl), BooleanEntry(validatorStatusKey, true), BinaryEntry(validatorRegistratorKey, invocation.caller.bytes)] | |
180 | + | let _assertValidAddress = addressFromStringValue(validator) | |
181 | + | if ((_assertValidAddress == _assertValidAddress)) | |
182 | + | then { | |
183 | + | let wxxAmount = invocation.payments[0].amount | |
184 | + | let validatorKey = ("validator:" + validator) | |
185 | + | let validatorStatusKey = ("validatorStatus:" + validator) | |
186 | + | let validatorRegistratorKey = ("validatorRegistrator:" + validator) | |
187 | + | if (isDefined(getString(this, validatorKey))) | |
188 | + | then throw("Already registered") | |
189 | + | else if ((requiredWXXAmount != wxxAmount)) | |
190 | + | then throw("Invalid WXX amount") | |
191 | + | else [StringEntry(validatorKey, metadataUrl), BooleanEntry(validatorStatusKey, true), BinaryEntry(validatorRegistratorKey, invocation.caller.bytes)] | |
192 | + | } | |
193 | + | else throw("Strict value is not equal to itself.") | |
207 | 194 | } | |
208 | 195 | else throw("Strict value is not equal to itself.") | |
209 | 196 | } | |
213 | 200 | ||
214 | 201 | ||
215 | 202 | @Callable(invocation) | |
216 | - | func deregister ( | |
217 | - | let | |
218 | - | let validatorRegistratorKey = ("validatorRegistrator:" + | |
219 | - | let validatorStatusKey = ("validatorStatus:" + | |
220 | - | let validatorVotesKey = ("votes:" + | |
203 | + | func deregister (validator) = { | |
204 | + | let validatorAddress = addressFromStringValue(validator) | |
205 | + | let validatorRegistratorKey = ("validatorRegistrator:" + validator) | |
206 | + | let validatorStatusKey = ("validatorStatus:" + validator) | |
207 | + | let validatorVotesKey = ("votes:" + validator) | |
221 | 208 | let _assertValidatorAddress = assertValidatorAddress(validatorAddress) | |
222 | 209 | if ((_assertValidatorAddress == _assertValidatorAddress)) | |
223 | 210 | then { | |
226 | 213 | else unit | |
227 | 214 | if ((_assetCallerIsRegistrator == _assetCallerIsRegistrator)) | |
228 | 215 | then { | |
229 | - | let validatorLeaseIdKey = ("leaseId:" + | |
216 | + | let validatorLeaseIdKey = ("leaseId:" + validator) | |
230 | 217 | let cancel = match getBinary(validatorLeaseIdKey) { | |
231 | 218 | case id: ByteVector => | |
232 | 219 | [LeaseCancel(id)] | |
238 | 225 | (((if (getBooleanValue(validatorStatusKey)) | |
239 | 226 | then { | |
240 | 227 | let validatorVotes = valueOrElse(getInteger(validatorVotesKey), 0) | |
241 | - | let totalVotes = getIntegerValue(totalVoteskey) | |
242 | - | [IntegerEntry(totalVoteskey, (totalVotes - validatorVotes)), ScriptTransfer(invocation.caller, requiredWXXAmount, getProjectAssetId())] | |
228 | + | [IntegerEntry(totalVoteskey, (totalVotes - validatorVotes)), ScriptTransfer(invocation.caller, requiredWXXAmount, wxxAssetId)] | |
243 | 229 | } | |
244 | - | else nil) ++ cancel) ++ [DeleteEntry(("votes:" + | |
230 | + | else nil) ++ cancel) ++ [DeleteEntry(("votes:" + validator)), DeleteEntry(validatorStatusKey), DeleteEntry(("validator:" + validator)), DeleteEntry(validatorVotesKey), DeleteEntry(("validatorLeases:" + validator)), DeleteEntry(validatorLeaseIdKey), DeleteEntry(("latestLeasingCycle:" + validator))]) | |
245 | 231 | } | |
246 | 232 | else throw("Strict value is not equal to itself.") | |
247 | 233 | } | |
251 | 237 | ||
252 | 238 | ||
253 | 239 | @Callable(invocation) | |
254 | - | func vote (validatorAddress,interval) = { | |
240 | + | func vote (validator,interval) = { | |
241 | + | let validatorAddress = addressFromStringValue(validator) | |
255 | 242 | let _assertValidatorAddress = assertValidatorAddress(validatorAddress) | |
256 | 243 | if ((_assertValidatorAddress == _assertValidatorAddress)) | |
257 | 244 | then { | |
261 | 248 | let _assertOnePayment = assertOnePayment(invocation) | |
262 | 249 | if ((_assertOnePayment == _assertOnePayment)) | |
263 | 250 | then { | |
264 | - | let _assertPaymentAsset = assertPaymentAsset(invocation, | |
251 | + | let _assertPaymentAsset = assertPaymentAsset(invocation, wxxAssetId) | |
265 | 252 | if ((_assertPaymentAsset == _assertPaymentAsset)) | |
266 | 253 | then { | |
267 | 254 | let _assertUint = assertUint(interval) | |
270 | 257 | let unlockBlock = (lastBlock.height + interval) | |
271 | 258 | let userVotes = invocation.payments[0].amount | |
272 | 259 | let userLock = invocation.payments[0].amount | |
273 | - | let validatorKey = toBase58String(validatorAddress) | |
274 | - | let callerKey = toBase58String(invocation.caller.bytes) | |
260 | + | let callerKey = toString(invocation.caller) | |
275 | 261 | let unlockBlockKey = ((("unlockBlock:" + callerKey) + "|") + toString(unlockBlock)) | |
276 | - | let totalValidatorVotesKey = ("votes:" + | |
262 | + | let totalValidatorVotesKey = ("votes:" + validator) | |
277 | 263 | let userVoteKey = ((("userVote:" + callerKey) + "|") + toString(unlockBlock)) | |
278 | 264 | let userLockKey = ((("userLock:" + callerKey) + "|") + toString(unlockBlock)) | |
279 | 265 | let totalValidatorVotes = valueOrElse(getInteger(totalValidatorVotesKey), 0) | |
280 | - | let totalVotes = valueOrElse(getInteger(totalVoteskey), 0) | |
281 | - | [IntegerEntry(userVoteKey, userVotes), IntegerEntry(userLockKey, userLock), BinaryEntry(unlockBlockKey, validatorAddress), IntegerEntry(totalValidatorVotesKey, (totalValidatorVotes + userVotes)), IntegerEntry(totalVoteskey, (totalVotes + userVotes))] | |
266 | + | [IntegerEntry(userVoteKey, userVotes), IntegerEntry(userLockKey, userLock), BinaryEntry(unlockBlockKey, validatorAddress.bytes), IntegerEntry(totalValidatorVotesKey, (totalValidatorVotes + userVotes)), IntegerEntry(totalVoteskey, (totalVotes + userVotes))] | |
282 | 267 | } | |
283 | 268 | else throw("Strict value is not equal to itself.") | |
284 | 269 | } | |
300 | 285 | else unit | |
301 | 286 | if ((_assertUnlockBlock == _assertUnlockBlock)) | |
302 | 287 | then { | |
303 | - | let callerKey = toBase58String(invocation.caller.bytes) | |
304 | - | let projectAssetId = getProjectAssetId() | |
288 | + | let callerKey = toString(invocation.caller) | |
305 | 289 | let unlockBlockKey = ((("unlockBlock:" + callerKey) + "|") + toString(unlockBlock)) | |
306 | 290 | let userVoteKey = ((("userVote:" + callerKey) + "|") + toString(unlockBlock)) | |
307 | 291 | let userLockKey = ((("userLock:" + callerKey) + "|") + toString(unlockBlock)) | |
309 | 293 | let validatorVotesKey = ("votes:" + toBase58String(validatorAddress)) | |
310 | 294 | let userVotes = getIntegerValue(userVoteKey) | |
311 | 295 | let totalValidatorVotes = getIntegerValue(validatorVotesKey) | |
312 | - | let totalVotes = getIntegerValue(totalVoteskey) | |
313 | 296 | let userLock = getIntegerValue(userLockKey) | |
314 | 297 | let validatorStatusKey = ("validatorStatus:" + toBase58String(validatorAddress)) | |
315 | 298 | ((if (getBooleanValue(validatorStatusKey)) | |
316 | 299 | then [IntegerEntry(totalVoteskey, (totalVotes - userVotes))] | |
317 | - | else nil) ++ [ScriptTransfer(invocation.caller, userLock, | |
300 | + | else nil) ++ [ScriptTransfer(invocation.caller, userLock, wxxAssetId), IntegerEntry(validatorVotesKey, (totalValidatorVotes - userVotes)), DeleteEntry(userVoteKey), DeleteEntry(unlockBlockKey)]) | |
318 | 301 | } | |
319 | 302 | else throw("Strict value is not equal to itself.") | |
320 | 303 | } | |
322 | 305 | ||
323 | 306 | ||
324 | 307 | @Callable(invocation) | |
325 | - | func leasing (validatorAddress) = { | |
308 | + | func leasing (validator) = { | |
309 | + | let validatorAddress = addressFromStringValue(validator) | |
326 | 310 | let _assertValidatorAddress = assertValidatorAddress(validatorAddress) | |
327 | 311 | if ((_assertValidatorAddress == _assertValidatorAddress)) | |
328 | 312 | then { | |
329 | 313 | let _assetValidatorStatus = assertActiveValidatorStatus(validatorAddress) | |
330 | 314 | if ((_assetValidatorStatus == _assetValidatorStatus)) | |
331 | 315 | then { | |
332 | - | let validatorKey = toBase58String(validatorAddress) | |
333 | - | let validatorLeaseIdKey = ("leaseId:" + validatorKey) | |
334 | - | let latestLeasingCycleKey = ("latestLeasingCycle:" + validatorKey) | |
335 | - | let totalVotes = valueOrElse(getInteger(totalVoteskey), 0) | |
336 | - | let validatorVotes = valueOrElse(getInteger(("votes:" + validatorKey)), 0) | |
337 | - | let currentLeaseAmount = valueOrElse(getInteger(("validatorLeases:" + validatorKey)), 0) | |
338 | - | let currentCycle = getCurrentCycle() | |
316 | + | let validatorLeaseIdKey = ("leaseId:" + validator) | |
317 | + | let latestLeasingCycleKey = ("latestLeasingCycle:" + validator) | |
318 | + | let validatorVotes = valueOrElse(getInteger(("votes:" + validator)), 0) | |
319 | + | let currentLeaseAmount = valueOrElse(getInteger(("validatorLeases:" + validator)), 0) | |
339 | 320 | let _checkLeasingStatus = if ((valueOrElse(getInteger(latestLeasingCycleKey), -1) == currentCycle)) | |
340 | 321 | then throw("Already leased") | |
341 | 322 | else unit | |
342 | 323 | if ((_checkLeasingStatus == _checkLeasingStatus)) | |
343 | 324 | then { | |
344 | - | let lpTokenIssued = valueOrErrorMessage(assetInfo( | |
345 | - | let poolValue = (wavesBalance(this).regular - | |
325 | + | let lpTokenIssued = valueOrErrorMessage(assetInfo(xWavesAssetId), "Uknown asset id").quantity | |
326 | + | let poolValue = (wavesBalance(this).regular - currentCycleRequestedDeposits) | |
346 | 327 | let totalRequestedWithdraw = valueOrElse(getInteger("totalRequestedWithdraw"), 0) | |
347 | - | let previouslyRequestedWithdraw = (totalRequestedWithdraw - | |
328 | + | let previouslyRequestedWithdraw = (totalRequestedWithdraw - currentCycleRequestedWithdrawals) | |
348 | 329 | let requestedWithdraw = if ((lpTokenIssued == 0)) | |
349 | 330 | then previouslyRequestedWithdraw | |
350 | - | else toInt(((toBigInt(previouslyRequestedWithdraw) * toBigInt(poolValue)) / toBigInt(lpTokenIssued))) | |
351 | - | let wavesAmount = (poolValue - requestedWithdraw) | |
352 | - | let targetLeaseAmountBigInt = ((toBigInt(wavesAmount) * toBigInt(validatorVotes)) / toBigInt(totalVotes)) | |
353 | - | let targetLeaseAmount = toInt(targetLeaseAmountBigInt) | |
331 | + | else fraction(previouslyRequestedWithdraw, poolValue, lpTokenIssued) | |
332 | + | let targetLeaseAmount = fraction((poolValue - requestedWithdraw), validatorVotes, totalVotes) | |
354 | 333 | let cancel = match getBinary(validatorLeaseIdKey) { | |
355 | 334 | case id: ByteVector => | |
356 | 335 | [LeaseCancel(id)] | |
361 | 340 | } | |
362 | 341 | if ((targetLeaseAmount != currentLeaseAmount)) | |
363 | 342 | then { | |
364 | - | let lease = Lease( | |
343 | + | let lease = Lease(validatorAddress, targetLeaseAmount) | |
365 | 344 | (cancel ++ (if ((targetLeaseAmount == 0)) | |
366 | - | then [IntegerEntry(("validatorLeases:" + | |
367 | - | else [lease, BinaryEntry(validatorLeaseIdKey, calculateLeaseId(lease)), IntegerEntry(("validatorLeases:" + | |
345 | + | then [IntegerEntry(("validatorLeases:" + validator), targetLeaseAmount), DeleteEntry(validatorLeaseIdKey)] | |
346 | + | else [lease, BinaryEntry(validatorLeaseIdKey, calculateLeaseId(lease)), IntegerEntry(("validatorLeases:" + validator), targetLeaseAmount), IntegerEntry(latestLeasingCycleKey, currentCycle)])) | |
368 | 347 | } | |
369 | 348 | else throw("Nothing changes") | |
370 | 349 | } | |
378 | 357 | ||
379 | 358 | ||
380 | 359 | @Callable(invocation) | |
381 | - | func emergencyVoting (validatorAddress) = { | |
360 | + | func emergencyVoting (validator) = { | |
361 | + | let validatorAddress = addressFromStringValue(validator) | |
382 | 362 | let _assertValidatorAddress = assertValidatorAddress(validatorAddress) | |
383 | 363 | if ((_assertValidatorAddress == _assertValidatorAddress)) | |
384 | 364 | then { | |
388 | 368 | let _assertOnePayment = assertOnePayment(invocation) | |
389 | 369 | if ((_assertOnePayment == _assertOnePayment)) | |
390 | 370 | then { | |
391 | - | let _assertPaymentAsset = assertPaymentAsset(invocation, | |
371 | + | let _assertPaymentAsset = assertPaymentAsset(invocation, xWavesAssetId) | |
392 | 372 | if ((_assertPaymentAsset == _assertPaymentAsset)) | |
393 | 373 | then { | |
394 | 374 | let voteAmount = invocation.payments[0].amount | |
395 | - | let callerKey = toBase58String(invocation.caller.bytes) | |
396 | - | let validatorKey = toBase58String(validatorAddress) | |
397 | - | let emergencyVotesKey = ("emergencyVotes:" + validatorKey) | |
398 | - | let emergencyUserVotesKey = (("emergencyUserVotes:" + callerKey) + validatorKey) | |
375 | + | let callerKey = toString(invocation.caller) | |
376 | + | let emergencyVotesKey = ("emergencyVotes:" + validator) | |
377 | + | let emergencyUserVotesKey = (("emergencyUserVotes:" + callerKey) + validator) | |
399 | 378 | let emergencyVotes = (voteAmount + valueOrElse(getInteger(emergencyVotesKey), 0)) | |
400 | - | let projectAssetId = getProjectAssetId() | |
401 | - | let quantity = valueOrErrorMessage(assetInfo(getXWavesAssetId()), "Uknown asset id").quantity | |
402 | - | let wxxAssetInfo = valueOrErrorMessage(assetInfo(projectAssetId), "Uknown asset id") | |
379 | + | let quantity = valueOrErrorMessage(assetInfo(xWavesAssetId), "Uknown asset id").quantity | |
380 | + | let wxxAssetInfo = valueOrErrorMessage(assetInfo(wxxAssetId), "Uknown asset id") | |
403 | 381 | let isValidatorBad = (((emergencyVotes * 100) / quantity) > emergencyVotingThreshold) | |
404 | 382 | let punishment = if (isValidatorBad) | |
405 | 383 | then { | |
406 | - | let validatorLeaseIdKey = ("leaseId:" + | |
384 | + | let validatorLeaseIdKey = ("leaseId:" + validator) | |
407 | 385 | let cancel = match getBinary(validatorLeaseIdKey) { | |
408 | 386 | case id: ByteVector => | |
409 | 387 | [LeaseCancel(id)] | |
412 | 390 | case _ => | |
413 | 391 | throw("Match error") | |
414 | 392 | } | |
415 | - | let validatorVotesKey = ("votes:" + | |
393 | + | let validatorVotesKey = ("votes:" + validator) | |
416 | 394 | let totalValidatorVotes = valueOrElse(getInteger(validatorVotesKey), 0) | |
417 | - | let totalVotes = getIntegerValue(totalVoteskey) | |
418 | - | (cancel ++ [ScriptTransfer(wxxAssetInfo.issuer, requiredWXXAmount, projectAssetId), IntegerEntry(totalVoteskey, (totalVotes - totalValidatorVotes)), BooleanEntry(("validatorStatus:" + validatorKey), false), DeleteEntry(("validatorLeases:" + validatorKey)), DeleteEntry(("leaseId:" + validatorKey)), DeleteEntry(("latestLeasingCycle:" + validatorKey))]) | |
395 | + | (cancel ++ [ScriptTransfer(wxxAssetInfo.issuer, requiredWXXAmount, wxxAssetId), IntegerEntry(totalVoteskey, (totalVotes - totalValidatorVotes)), BooleanEntry(("validatorStatus:" + validator), false), DeleteEntry(("validatorLeases:" + validator)), DeleteEntry(("leaseId:" + validator)), DeleteEntry(("latestLeasingCycle:" + validator))]) | |
419 | 396 | } | |
420 | 397 | else nil | |
421 | 398 | (punishment ++ [IntegerEntry(emergencyVotesKey, (voteAmount + emergencyVotes)), IntegerEntry(emergencyUserVotesKey, (valueOrElse(getInteger(emergencyUserVotesKey), 0) + emergencyVotes))]) | |
432 | 409 | ||
433 | 410 | ||
434 | 411 | @Callable(invocation) | |
435 | - | func redeemEmergencyVote ( | |
436 | - | let | |
437 | - | let | |
438 | - | let emergencyUserVotesKey = (("emergencyUserVotes:" + callerKey) + | |
412 | + | func redeemEmergencyVote (validator) = { | |
413 | + | let validatorAddress = addressFromStringValue(validator) | |
414 | + | let callerKey = toString(invocation.caller) | |
415 | + | let emergencyUserVotesKey = (("emergencyUserVotes:" + callerKey) + validator) | |
439 | 416 | let emergencyUserVotes = valueOrErrorMessage(getInteger(emergencyUserVotesKey), "No emergency votes for user") | |
440 | - | let xWavesAssetId = getXWavesAssetId() | |
441 | 417 | [ScriptTransfer(invocation.caller, emergencyUserVotes, xWavesAssetId)] | |
442 | 418 | } | |
443 | 419 |
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 7 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | 4 | let requiredWXXAmount = 10000000000 | |
5 | 5 | ||
6 | 6 | let cycleDurationInBlocks = 1000 | |
7 | 7 | ||
8 | 8 | let emergencyVotingThreshold = 10 | |
9 | 9 | ||
10 | 10 | let totalVoteskey = "totalVotes" | |
11 | 11 | ||
12 | - | ||
12 | + | let wxxAssetId = getBinaryValue("projectAssetId") | |
13 | 13 | ||
14 | + | let xWavesAssetId = getBinaryValue("xWavesAssetId") | |
14 | 15 | ||
15 | - | ||
16 | + | let currentCycle = ((lastBlock.height - getIntegerValue("startBlock")) / cycleDurationInBlocks) | |
16 | 17 | ||
18 | + | let currentCycleRequestedWithdrawals = valueOrElse(getInteger(("cycleRequestedWithdraw:" + toString(currentCycle))), 0) | |
17 | 19 | ||
18 | - | func getCurrentCycle () = { | |
19 | - | let startBlock = getIntegerValue("startBlock") | |
20 | - | ((lastBlock.height - startBlock) / cycleDurationInBlocks) | |
21 | - | } | |
20 | + | let currentCycleRequestedDeposits = valueOrElse(getInteger(("cycleRequestedDeposit:" + toString(currentCycle))), 0) | |
22 | 21 | ||
22 | + | let totalVotes = getIntegerValue(totalVoteskey) | |
23 | 23 | ||
24 | - | func assertValidatorAddress (validatorAddress) = if (isDefined(getString(this, ("validator:" + | |
24 | + | func assertValidatorAddress (validatorAddress) = if (isDefined(getString(this, ("validator:" + toString(validatorAddress))))) | |
25 | 25 | then unit | |
26 | 26 | else throw("Unknown validator") | |
27 | 27 | ||
28 | 28 | ||
29 | 29 | func assertOnePayment (invocation) = if ((size(invocation.payments) != 1)) | |
30 | 30 | then throw("Not one payment") | |
31 | 31 | else unit | |
32 | 32 | ||
33 | 33 | ||
34 | 34 | func assertPaymentAsset (invocation,expectedToken) = if ((invocation.payments[0].assetId != expectedToken)) | |
35 | 35 | then throw("Unexpected asset id") | |
36 | 36 | else unit | |
37 | 37 | ||
38 | 38 | ||
39 | 39 | func assertUint (v) = if ((0 > v)) | |
40 | 40 | then throw("Invalid uint") | |
41 | 41 | else unit | |
42 | 42 | ||
43 | 43 | ||
44 | 44 | func assertActiveValidatorStatus (validatorAddress) = { | |
45 | - | let validatorStatusKey = ("validatorStatus:" + | |
45 | + | let validatorStatusKey = ("validatorStatus:" + toString(validatorAddress)) | |
46 | 46 | if (!(getBooleanValue(validatorStatusKey))) | |
47 | 47 | then throw("Unactive validator") | |
48 | 48 | else unit | |
49 | 49 | } | |
50 | 50 | ||
51 | 51 | ||
52 | - | func assertCycleLowerThatCurrent (cycle) = { | |
53 | - | let currentCycle = getCurrentCycle() | |
54 | - | if ((currentCycle > cycle)) | |
55 | - | then unit | |
56 | - | else throw("Invalid cycle") | |
57 | - | } | |
52 | + | func assertCycleLowerThatCurrent (cycle) = if ((currentCycle > cycle)) | |
53 | + | then unit | |
54 | + | else throw("Invalid cycle") | |
58 | 55 | ||
59 | 56 | ||
60 | - | func assertCallerIsContract (invocation) = if ((this | |
57 | + | func assertCallerIsContract (invocation) = if ((this != invocation.caller)) | |
61 | 58 | then throw("Unauthorized") | |
62 | 59 | else unit | |
63 | 60 | ||
64 | 61 | ||
65 | - | func getPrevCycleRequestedWithdrawals () = valueOrElse(getInteger(("cycleRequestedWithdraw:" + toString((getCurrentCycle() - 1)))), 0) | |
66 | - | ||
67 | - | ||
68 | - | func getPrevCycleRequestedDeposits () = valueOrElse(getInteger(("cycleRequestedDeposit:" + toString((getCurrentCycle() - 1)))), 0) | |
69 | - | ||
70 | - | ||
71 | - | func getCurrentCycleRequestedWithdrawals () = valueOrElse(getInteger(("cycleRequestedWithdraw:" + toString(getCurrentCycle()))), 0) | |
72 | - | ||
73 | - | ||
74 | - | func getCurrentCycleRequestedDeposits () = valueOrElse(getInteger(("cycleRequestedDeposit:" + toString(getCurrentCycle()))), 0) | |
75 | - | ||
76 | - | ||
77 | 62 | @Callable(invocation) | |
78 | - | func init ( | |
63 | + | func init (wxxTokenId) = { | |
79 | 64 | let callerCheck = assertCallerIsContract(invocation) | |
80 | 65 | if ((callerCheck == callerCheck)) | |
81 | 66 | then if (isDefined(getBinary("projectAssetId"))) | |
82 | 67 | then throw("Initialized") | |
83 | 68 | else { | |
84 | 69 | let issue = Issue("xWaves", "xWaves", 0, 8, true) | |
85 | 70 | let xWavesAssetIdId = calculateAssetId(issue) | |
86 | - | [issue, IntegerEntry(totalVoteskey, 0), BinaryEntry("projectAssetId", | |
71 | + | [issue, IntegerEntry(totalVoteskey, 0), BinaryEntry("projectAssetId", wxxTokenId), BinaryEntry("xWavesAssetId", xWavesAssetIdId), IntegerEntry("startBlock", lastBlock.height), IntegerEntry("totalRequestedWithdraw", 0), IntegerEntry("requiredWXXAmount", requiredWXXAmount), IntegerEntry("emergencyVotingThreshold", emergencyVotingThreshold)] | |
87 | 72 | } | |
88 | 73 | else throw("Strict value is not equal to itself.") | |
89 | 74 | } | |
90 | 75 | ||
91 | 76 | ||
92 | 77 | ||
93 | 78 | @Callable(invocation) | |
94 | 79 | func requestDeposit () = { | |
95 | 80 | let _assertOnePayment = assertOnePayment(invocation) | |
96 | 81 | if ((_assertOnePayment == _assertOnePayment)) | |
97 | 82 | then { | |
98 | 83 | let _assertPaymentAsset = assertPaymentAsset(invocation, unit) | |
99 | 84 | if ((_assertPaymentAsset == _assertPaymentAsset)) | |
100 | 85 | then { | |
101 | 86 | let wavesAmount = invocation.payments[0].amount | |
102 | - | let callerKey = toBase58String(invocation.caller.bytes) | |
103 | - | let currentCycle = getCurrentCycle() | |
87 | + | let callerKey = toString(invocation.caller) | |
104 | 88 | let requestedDepositKey = ((("requestedDeposit:" + callerKey) + "|") + toString(currentCycle)) | |
105 | 89 | let requestedDeposits = valueOrElse(getInteger(requestedDepositKey), 0) | |
106 | 90 | let totalRequestedDeposits = valueOrElse(getInteger(("cycleRequestedDeposit:" + toString(currentCycle))), 0) | |
107 | 91 | [IntegerEntry(requestedDepositKey, (requestedDeposits + wavesAmount)), IntegerEntry(("cycleRequestedDeposit:" + toString(currentCycle)), (totalRequestedDeposits + wavesAmount))] | |
108 | 92 | } | |
109 | 93 | else throw("Strict value is not equal to itself.") | |
110 | 94 | } | |
111 | 95 | else throw("Strict value is not equal to itself.") | |
112 | 96 | } | |
113 | 97 | ||
114 | 98 | ||
115 | 99 | ||
116 | 100 | @Callable(invocation) | |
117 | 101 | func processDeposit (recipient,cycle) = { | |
118 | 102 | let _assertCycle = assertCycleLowerThatCurrent(cycle) | |
119 | 103 | if ((_assertCycle == _assertCycle)) | |
120 | 104 | then { | |
121 | - | let | |
122 | - | let requestedDepositKey = ((("requestedDeposit:" + | |
105 | + | let recipientAddress = addressFromStringValue(recipient) | |
106 | + | let requestedDepositKey = ((("requestedDeposit:" + recipient) + "|") + toString(cycle)) | |
123 | 107 | let cycleRequestedDeposits = valueOrErrorMessage(getInteger(("cycleRequestedDeposit:" + toString(cycle))), "No requested deposits for cycle") | |
124 | 108 | let requestedDeposit = valueOrErrorMessage(getInteger(requestedDepositKey), "No requested deposit") | |
125 | 109 | let lpTokenIssued = valueOrErrorMessage(assetInfo(xWavesAssetId), "Uknown asset id").quantity | |
126 | 110 | let poolValue = (wavesBalance(this).regular - cycleRequestedDeposits) | |
127 | 111 | let xWavesAmount = if ((lpTokenIssued == 0)) | |
128 | 112 | then requestedDeposit | |
129 | - | else | |
113 | + | else fraction(requestedDeposit, lpTokenIssued, poolValue) | |
130 | 114 | let newCycleValue = (cycleRequestedDeposits - requestedDeposit) | |
131 | - | let cycleWithdrawChange = if (( | |
115 | + | let cycleWithdrawChange = if ((1 >= newCycleValue)) | |
132 | 116 | then [DeleteEntry(("cycleRequestedDeposit:" + toString(cycle)))] | |
133 | 117 | else [IntegerEntry(("cycleRequestedDeposit:" + toString(cycle)), newCycleValue)] | |
134 | - | (cycleWithdrawChange ++ [DeleteEntry(requestedDepositKey), Reissue(xWavesAssetId, xWavesAmount, true), ScriptTransfer( | |
118 | + | (cycleWithdrawChange ++ [DeleteEntry(requestedDepositKey), Reissue(xWavesAssetId, xWavesAmount, true), ScriptTransfer(recipientAddress, xWavesAmount, xWavesAssetId)]) | |
135 | 119 | } | |
136 | 120 | else throw("Strict value is not equal to itself.") | |
137 | 121 | } | |
138 | 122 | ||
139 | 123 | ||
140 | 124 | ||
141 | 125 | @Callable(invocation) | |
142 | 126 | func requestWithdraw () = { | |
143 | 127 | let _assertOnePayment = assertOnePayment(invocation) | |
144 | 128 | if ((_assertOnePayment == _assertOnePayment)) | |
145 | 129 | then { | |
146 | - | let _assertPaymentAsset = assertPaymentAsset(invocation, | |
130 | + | let _assertPaymentAsset = assertPaymentAsset(invocation, xWavesAssetId) | |
147 | 131 | if ((_assertPaymentAsset == _assertPaymentAsset)) | |
148 | 132 | then { | |
149 | 133 | let xWavesAmount = invocation.payments[0].amount | |
150 | - | let currentCycle = getCurrentCycle() | |
151 | - | let callerKey = toBase58String(invocation.caller.bytes) | |
134 | + | let callerKey = toString(invocation.caller) | |
152 | 135 | let requestedWithdrawForCallerKey = ((("requestedWithdraw:" + callerKey) + "|") + toString(currentCycle)) | |
153 | 136 | let requestedWithdrawForCaller = valueOrElse(getInteger(requestedWithdrawForCallerKey), 0) | |
154 | 137 | let totalRequestedWithdraw = valueOrElse(getInteger("totalRequestedWithdraw"), 0) | |
155 | - | let currentCycleRequestedWithdraw = | |
138 | + | let currentCycleRequestedWithdraw = currentCycleRequestedWithdrawals | |
156 | 139 | [IntegerEntry(requestedWithdrawForCallerKey, (requestedWithdrawForCaller + xWavesAmount)), IntegerEntry(("cycleRequestedWithdraw:" + toString(currentCycle)), (currentCycleRequestedWithdraw + xWavesAmount)), IntegerEntry("totalRequestedWithdraw", (totalRequestedWithdraw + xWavesAmount))] | |
157 | 140 | } | |
158 | 141 | else throw("Strict value is not equal to itself.") | |
159 | 142 | } | |
160 | 143 | else throw("Strict value is not equal to itself.") | |
161 | 144 | } | |
162 | 145 | ||
163 | 146 | ||
164 | 147 | ||
165 | 148 | @Callable(invocation) | |
166 | 149 | func processWithdraw (recipient,cycle) = { | |
167 | 150 | let _assertCycle = assertCycleLowerThatCurrent(cycle) | |
168 | 151 | if ((_assertCycle == _assertCycle)) | |
169 | 152 | then { | |
170 | - | let recipientKey = toBase58String(recipient) | |
171 | - | let xWavesAssetId = getXWavesAssetId() | |
172 | - | let requestedWithdrawKey = ((("requestedWithdraw:" + recipientKey) + "|") + toString(cycle)) | |
153 | + | let recipientAddress = addressFromStringValue(recipient) | |
154 | + | let requestedWithdrawKey = ((("requestedWithdraw:" + recipient) + "|") + toString(cycle)) | |
173 | 155 | let requestedWithdrawal = valueOrErrorMessage(getInteger(requestedWithdrawKey), "No requested withdraw") | |
174 | 156 | let cycleRequestedWithdraw = valueOrErrorMessage(getInteger(("cycleRequestedWithdraw:" + toString(cycle))), "No requested withdrawals for cycle") | |
175 | 157 | let poolValue = wavesBalance(this).regular | |
176 | 158 | let lpTokenIssued = valueOrErrorMessage(assetInfo(xWavesAssetId), "Uknown asset id").quantity | |
177 | 159 | let totalRequestedWithdraw = valueOrElse(getInteger("totalRequestedWithdraw"), 0) | |
178 | - | let wavesAmount = | |
160 | + | let wavesAmount = fraction(requestedWithdrawal, poolValue, lpTokenIssued) | |
179 | 161 | let newCycleValue = (cycleRequestedWithdraw - requestedWithdrawal) | |
180 | 162 | let cycleWithdrawChange = if ((newCycleValue == 0)) | |
181 | 163 | then [DeleteEntry(("cycleRequestedWithdraw:" + toString(cycle)))] | |
182 | 164 | else [IntegerEntry(("cycleRequestedWithdraw:" + toString(cycle)), newCycleValue)] | |
183 | - | (cycleWithdrawChange ++ [IntegerEntry("totalRequestedWithdraw", (totalRequestedWithdraw - requestedWithdrawal)), ScriptTransfer( | |
165 | + | (cycleWithdrawChange ++ [IntegerEntry("totalRequestedWithdraw", (totalRequestedWithdraw - requestedWithdrawal)), ScriptTransfer(recipientAddress, wavesAmount, unit), Burn(xWavesAssetId, requestedWithdrawal), DeleteEntry(requestedWithdrawKey)]) | |
184 | 166 | } | |
185 | 167 | else throw("Strict value is not equal to itself.") | |
186 | 168 | } | |
187 | 169 | ||
188 | 170 | ||
189 | 171 | ||
190 | 172 | @Callable(invocation) | |
191 | - | func register ( | |
173 | + | func register (validator,metadataUrl) = { | |
192 | 174 | let _assertOnePayment = assertOnePayment(invocation) | |
193 | 175 | if ((_assertOnePayment == _assertOnePayment)) | |
194 | 176 | then { | |
195 | - | let _assertPaymentAsset = assertPaymentAsset(invocation, | |
177 | + | let _assertPaymentAsset = assertPaymentAsset(invocation, wxxAssetId) | |
196 | 178 | if ((_assertPaymentAsset == _assertPaymentAsset)) | |
197 | 179 | then { | |
198 | - | let wxxAmount = invocation.payments[0].amount | |
199 | - | let validatorKey = ("validator:" + toBase58String(validatorAddress)) | |
200 | - | let validatorStatusKey = ("validatorStatus:" + toBase58String(validatorAddress)) | |
201 | - | let validatorRegistratorKey = ("validatorRegistrator:" + toBase58String(validatorAddress)) | |
202 | - | if (isDefined(getString(this, validatorKey))) | |
203 | - | then throw("Already registered") | |
204 | - | else if ((requiredWXXAmount != wxxAmount)) | |
205 | - | then throw("Invalid WXX amount") | |
206 | - | else [StringEntry(validatorKey, metadataUrl), BooleanEntry(validatorStatusKey, true), BinaryEntry(validatorRegistratorKey, invocation.caller.bytes)] | |
180 | + | let _assertValidAddress = addressFromStringValue(validator) | |
181 | + | if ((_assertValidAddress == _assertValidAddress)) | |
182 | + | then { | |
183 | + | let wxxAmount = invocation.payments[0].amount | |
184 | + | let validatorKey = ("validator:" + validator) | |
185 | + | let validatorStatusKey = ("validatorStatus:" + validator) | |
186 | + | let validatorRegistratorKey = ("validatorRegistrator:" + validator) | |
187 | + | if (isDefined(getString(this, validatorKey))) | |
188 | + | then throw("Already registered") | |
189 | + | else if ((requiredWXXAmount != wxxAmount)) | |
190 | + | then throw("Invalid WXX amount") | |
191 | + | else [StringEntry(validatorKey, metadataUrl), BooleanEntry(validatorStatusKey, true), BinaryEntry(validatorRegistratorKey, invocation.caller.bytes)] | |
192 | + | } | |
193 | + | else throw("Strict value is not equal to itself.") | |
207 | 194 | } | |
208 | 195 | else throw("Strict value is not equal to itself.") | |
209 | 196 | } | |
210 | 197 | else throw("Strict value is not equal to itself.") | |
211 | 198 | } | |
212 | 199 | ||
213 | 200 | ||
214 | 201 | ||
215 | 202 | @Callable(invocation) | |
216 | - | func deregister ( | |
217 | - | let | |
218 | - | let validatorRegistratorKey = ("validatorRegistrator:" + | |
219 | - | let validatorStatusKey = ("validatorStatus:" + | |
220 | - | let validatorVotesKey = ("votes:" + | |
203 | + | func deregister (validator) = { | |
204 | + | let validatorAddress = addressFromStringValue(validator) | |
205 | + | let validatorRegistratorKey = ("validatorRegistrator:" + validator) | |
206 | + | let validatorStatusKey = ("validatorStatus:" + validator) | |
207 | + | let validatorVotesKey = ("votes:" + validator) | |
221 | 208 | let _assertValidatorAddress = assertValidatorAddress(validatorAddress) | |
222 | 209 | if ((_assertValidatorAddress == _assertValidatorAddress)) | |
223 | 210 | then { | |
224 | 211 | let _assetCallerIsRegistrator = if ((getBinaryValue(validatorRegistratorKey) != invocation.caller.bytes)) | |
225 | 212 | then throw("Wrong deregistrator") | |
226 | 213 | else unit | |
227 | 214 | if ((_assetCallerIsRegistrator == _assetCallerIsRegistrator)) | |
228 | 215 | then { | |
229 | - | let validatorLeaseIdKey = ("leaseId:" + | |
216 | + | let validatorLeaseIdKey = ("leaseId:" + validator) | |
230 | 217 | let cancel = match getBinary(validatorLeaseIdKey) { | |
231 | 218 | case id: ByteVector => | |
232 | 219 | [LeaseCancel(id)] | |
233 | 220 | case _: Unit => | |
234 | 221 | nil | |
235 | 222 | case _ => | |
236 | 223 | throw("Match error") | |
237 | 224 | } | |
238 | 225 | (((if (getBooleanValue(validatorStatusKey)) | |
239 | 226 | then { | |
240 | 227 | let validatorVotes = valueOrElse(getInteger(validatorVotesKey), 0) | |
241 | - | let totalVotes = getIntegerValue(totalVoteskey) | |
242 | - | [IntegerEntry(totalVoteskey, (totalVotes - validatorVotes)), ScriptTransfer(invocation.caller, requiredWXXAmount, getProjectAssetId())] | |
228 | + | [IntegerEntry(totalVoteskey, (totalVotes - validatorVotes)), ScriptTransfer(invocation.caller, requiredWXXAmount, wxxAssetId)] | |
243 | 229 | } | |
244 | - | else nil) ++ cancel) ++ [DeleteEntry(("votes:" + | |
230 | + | else nil) ++ cancel) ++ [DeleteEntry(("votes:" + validator)), DeleteEntry(validatorStatusKey), DeleteEntry(("validator:" + validator)), DeleteEntry(validatorVotesKey), DeleteEntry(("validatorLeases:" + validator)), DeleteEntry(validatorLeaseIdKey), DeleteEntry(("latestLeasingCycle:" + validator))]) | |
245 | 231 | } | |
246 | 232 | else throw("Strict value is not equal to itself.") | |
247 | 233 | } | |
248 | 234 | else throw("Strict value is not equal to itself.") | |
249 | 235 | } | |
250 | 236 | ||
251 | 237 | ||
252 | 238 | ||
253 | 239 | @Callable(invocation) | |
254 | - | func vote (validatorAddress,interval) = { | |
240 | + | func vote (validator,interval) = { | |
241 | + | let validatorAddress = addressFromStringValue(validator) | |
255 | 242 | let _assertValidatorAddress = assertValidatorAddress(validatorAddress) | |
256 | 243 | if ((_assertValidatorAddress == _assertValidatorAddress)) | |
257 | 244 | then { | |
258 | 245 | let _assetValidatorStatus = assertActiveValidatorStatus(validatorAddress) | |
259 | 246 | if ((_assetValidatorStatus == _assetValidatorStatus)) | |
260 | 247 | then { | |
261 | 248 | let _assertOnePayment = assertOnePayment(invocation) | |
262 | 249 | if ((_assertOnePayment == _assertOnePayment)) | |
263 | 250 | then { | |
264 | - | let _assertPaymentAsset = assertPaymentAsset(invocation, | |
251 | + | let _assertPaymentAsset = assertPaymentAsset(invocation, wxxAssetId) | |
265 | 252 | if ((_assertPaymentAsset == _assertPaymentAsset)) | |
266 | 253 | then { | |
267 | 254 | let _assertUint = assertUint(interval) | |
268 | 255 | if ((_assertUint == _assertUint)) | |
269 | 256 | then { | |
270 | 257 | let unlockBlock = (lastBlock.height + interval) | |
271 | 258 | let userVotes = invocation.payments[0].amount | |
272 | 259 | let userLock = invocation.payments[0].amount | |
273 | - | let validatorKey = toBase58String(validatorAddress) | |
274 | - | let callerKey = toBase58String(invocation.caller.bytes) | |
260 | + | let callerKey = toString(invocation.caller) | |
275 | 261 | let unlockBlockKey = ((("unlockBlock:" + callerKey) + "|") + toString(unlockBlock)) | |
276 | - | let totalValidatorVotesKey = ("votes:" + | |
262 | + | let totalValidatorVotesKey = ("votes:" + validator) | |
277 | 263 | let userVoteKey = ((("userVote:" + callerKey) + "|") + toString(unlockBlock)) | |
278 | 264 | let userLockKey = ((("userLock:" + callerKey) + "|") + toString(unlockBlock)) | |
279 | 265 | let totalValidatorVotes = valueOrElse(getInteger(totalValidatorVotesKey), 0) | |
280 | - | let totalVotes = valueOrElse(getInteger(totalVoteskey), 0) | |
281 | - | [IntegerEntry(userVoteKey, userVotes), IntegerEntry(userLockKey, userLock), BinaryEntry(unlockBlockKey, validatorAddress), IntegerEntry(totalValidatorVotesKey, (totalValidatorVotes + userVotes)), IntegerEntry(totalVoteskey, (totalVotes + userVotes))] | |
266 | + | [IntegerEntry(userVoteKey, userVotes), IntegerEntry(userLockKey, userLock), BinaryEntry(unlockBlockKey, validatorAddress.bytes), IntegerEntry(totalValidatorVotesKey, (totalValidatorVotes + userVotes)), IntegerEntry(totalVoteskey, (totalVotes + userVotes))] | |
282 | 267 | } | |
283 | 268 | else throw("Strict value is not equal to itself.") | |
284 | 269 | } | |
285 | 270 | else throw("Strict value is not equal to itself.") | |
286 | 271 | } | |
287 | 272 | else throw("Strict value is not equal to itself.") | |
288 | 273 | } | |
289 | 274 | else throw("Strict value is not equal to itself.") | |
290 | 275 | } | |
291 | 276 | else throw("Strict value is not equal to itself.") | |
292 | 277 | } | |
293 | 278 | ||
294 | 279 | ||
295 | 280 | ||
296 | 281 | @Callable(invocation) | |
297 | 282 | func redeem (unlockBlock) = { | |
298 | 283 | let _assertUnlockBlock = if ((unlockBlock > lastBlock.height)) | |
299 | 284 | then throw("Too early") | |
300 | 285 | else unit | |
301 | 286 | if ((_assertUnlockBlock == _assertUnlockBlock)) | |
302 | 287 | then { | |
303 | - | let callerKey = toBase58String(invocation.caller.bytes) | |
304 | - | let projectAssetId = getProjectAssetId() | |
288 | + | let callerKey = toString(invocation.caller) | |
305 | 289 | let unlockBlockKey = ((("unlockBlock:" + callerKey) + "|") + toString(unlockBlock)) | |
306 | 290 | let userVoteKey = ((("userVote:" + callerKey) + "|") + toString(unlockBlock)) | |
307 | 291 | let userLockKey = ((("userLock:" + callerKey) + "|") + toString(unlockBlock)) | |
308 | 292 | let validatorAddress = valueOrErrorMessage(getBinary(unlockBlockKey), "Unknown lock") | |
309 | 293 | let validatorVotesKey = ("votes:" + toBase58String(validatorAddress)) | |
310 | 294 | let userVotes = getIntegerValue(userVoteKey) | |
311 | 295 | let totalValidatorVotes = getIntegerValue(validatorVotesKey) | |
312 | - | let totalVotes = getIntegerValue(totalVoteskey) | |
313 | 296 | let userLock = getIntegerValue(userLockKey) | |
314 | 297 | let validatorStatusKey = ("validatorStatus:" + toBase58String(validatorAddress)) | |
315 | 298 | ((if (getBooleanValue(validatorStatusKey)) | |
316 | 299 | then [IntegerEntry(totalVoteskey, (totalVotes - userVotes))] | |
317 | - | else nil) ++ [ScriptTransfer(invocation.caller, userLock, | |
300 | + | else nil) ++ [ScriptTransfer(invocation.caller, userLock, wxxAssetId), IntegerEntry(validatorVotesKey, (totalValidatorVotes - userVotes)), DeleteEntry(userVoteKey), DeleteEntry(unlockBlockKey)]) | |
318 | 301 | } | |
319 | 302 | else throw("Strict value is not equal to itself.") | |
320 | 303 | } | |
321 | 304 | ||
322 | 305 | ||
323 | 306 | ||
324 | 307 | @Callable(invocation) | |
325 | - | func leasing (validatorAddress) = { | |
308 | + | func leasing (validator) = { | |
309 | + | let validatorAddress = addressFromStringValue(validator) | |
326 | 310 | let _assertValidatorAddress = assertValidatorAddress(validatorAddress) | |
327 | 311 | if ((_assertValidatorAddress == _assertValidatorAddress)) | |
328 | 312 | then { | |
329 | 313 | let _assetValidatorStatus = assertActiveValidatorStatus(validatorAddress) | |
330 | 314 | if ((_assetValidatorStatus == _assetValidatorStatus)) | |
331 | 315 | then { | |
332 | - | let validatorKey = toBase58String(validatorAddress) | |
333 | - | let validatorLeaseIdKey = ("leaseId:" + validatorKey) | |
334 | - | let latestLeasingCycleKey = ("latestLeasingCycle:" + validatorKey) | |
335 | - | let totalVotes = valueOrElse(getInteger(totalVoteskey), 0) | |
336 | - | let validatorVotes = valueOrElse(getInteger(("votes:" + validatorKey)), 0) | |
337 | - | let currentLeaseAmount = valueOrElse(getInteger(("validatorLeases:" + validatorKey)), 0) | |
338 | - | let currentCycle = getCurrentCycle() | |
316 | + | let validatorLeaseIdKey = ("leaseId:" + validator) | |
317 | + | let latestLeasingCycleKey = ("latestLeasingCycle:" + validator) | |
318 | + | let validatorVotes = valueOrElse(getInteger(("votes:" + validator)), 0) | |
319 | + | let currentLeaseAmount = valueOrElse(getInteger(("validatorLeases:" + validator)), 0) | |
339 | 320 | let _checkLeasingStatus = if ((valueOrElse(getInteger(latestLeasingCycleKey), -1) == currentCycle)) | |
340 | 321 | then throw("Already leased") | |
341 | 322 | else unit | |
342 | 323 | if ((_checkLeasingStatus == _checkLeasingStatus)) | |
343 | 324 | then { | |
344 | - | let lpTokenIssued = valueOrErrorMessage(assetInfo( | |
345 | - | let poolValue = (wavesBalance(this).regular - | |
325 | + | let lpTokenIssued = valueOrErrorMessage(assetInfo(xWavesAssetId), "Uknown asset id").quantity | |
326 | + | let poolValue = (wavesBalance(this).regular - currentCycleRequestedDeposits) | |
346 | 327 | let totalRequestedWithdraw = valueOrElse(getInteger("totalRequestedWithdraw"), 0) | |
347 | - | let previouslyRequestedWithdraw = (totalRequestedWithdraw - | |
328 | + | let previouslyRequestedWithdraw = (totalRequestedWithdraw - currentCycleRequestedWithdrawals) | |
348 | 329 | let requestedWithdraw = if ((lpTokenIssued == 0)) | |
349 | 330 | then previouslyRequestedWithdraw | |
350 | - | else toInt(((toBigInt(previouslyRequestedWithdraw) * toBigInt(poolValue)) / toBigInt(lpTokenIssued))) | |
351 | - | let wavesAmount = (poolValue - requestedWithdraw) | |
352 | - | let targetLeaseAmountBigInt = ((toBigInt(wavesAmount) * toBigInt(validatorVotes)) / toBigInt(totalVotes)) | |
353 | - | let targetLeaseAmount = toInt(targetLeaseAmountBigInt) | |
331 | + | else fraction(previouslyRequestedWithdraw, poolValue, lpTokenIssued) | |
332 | + | let targetLeaseAmount = fraction((poolValue - requestedWithdraw), validatorVotes, totalVotes) | |
354 | 333 | let cancel = match getBinary(validatorLeaseIdKey) { | |
355 | 334 | case id: ByteVector => | |
356 | 335 | [LeaseCancel(id)] | |
357 | 336 | case _: Unit => | |
358 | 337 | nil | |
359 | 338 | case _ => | |
360 | 339 | throw("Match error") | |
361 | 340 | } | |
362 | 341 | if ((targetLeaseAmount != currentLeaseAmount)) | |
363 | 342 | then { | |
364 | - | let lease = Lease( | |
343 | + | let lease = Lease(validatorAddress, targetLeaseAmount) | |
365 | 344 | (cancel ++ (if ((targetLeaseAmount == 0)) | |
366 | - | then [IntegerEntry(("validatorLeases:" + | |
367 | - | else [lease, BinaryEntry(validatorLeaseIdKey, calculateLeaseId(lease)), IntegerEntry(("validatorLeases:" + | |
345 | + | then [IntegerEntry(("validatorLeases:" + validator), targetLeaseAmount), DeleteEntry(validatorLeaseIdKey)] | |
346 | + | else [lease, BinaryEntry(validatorLeaseIdKey, calculateLeaseId(lease)), IntegerEntry(("validatorLeases:" + validator), targetLeaseAmount), IntegerEntry(latestLeasingCycleKey, currentCycle)])) | |
368 | 347 | } | |
369 | 348 | else throw("Nothing changes") | |
370 | 349 | } | |
371 | 350 | else throw("Strict value is not equal to itself.") | |
372 | 351 | } | |
373 | 352 | else throw("Strict value is not equal to itself.") | |
374 | 353 | } | |
375 | 354 | else throw("Strict value is not equal to itself.") | |
376 | 355 | } | |
377 | 356 | ||
378 | 357 | ||
379 | 358 | ||
380 | 359 | @Callable(invocation) | |
381 | - | func emergencyVoting (validatorAddress) = { | |
360 | + | func emergencyVoting (validator) = { | |
361 | + | let validatorAddress = addressFromStringValue(validator) | |
382 | 362 | let _assertValidatorAddress = assertValidatorAddress(validatorAddress) | |
383 | 363 | if ((_assertValidatorAddress == _assertValidatorAddress)) | |
384 | 364 | then { | |
385 | 365 | let _assetValidatorStatus = assertActiveValidatorStatus(validatorAddress) | |
386 | 366 | if ((_assetValidatorStatus == _assetValidatorStatus)) | |
387 | 367 | then { | |
388 | 368 | let _assertOnePayment = assertOnePayment(invocation) | |
389 | 369 | if ((_assertOnePayment == _assertOnePayment)) | |
390 | 370 | then { | |
391 | - | let _assertPaymentAsset = assertPaymentAsset(invocation, | |
371 | + | let _assertPaymentAsset = assertPaymentAsset(invocation, xWavesAssetId) | |
392 | 372 | if ((_assertPaymentAsset == _assertPaymentAsset)) | |
393 | 373 | then { | |
394 | 374 | let voteAmount = invocation.payments[0].amount | |
395 | - | let callerKey = toBase58String(invocation.caller.bytes) | |
396 | - | let validatorKey = toBase58String(validatorAddress) | |
397 | - | let emergencyVotesKey = ("emergencyVotes:" + validatorKey) | |
398 | - | let emergencyUserVotesKey = (("emergencyUserVotes:" + callerKey) + validatorKey) | |
375 | + | let callerKey = toString(invocation.caller) | |
376 | + | let emergencyVotesKey = ("emergencyVotes:" + validator) | |
377 | + | let emergencyUserVotesKey = (("emergencyUserVotes:" + callerKey) + validator) | |
399 | 378 | let emergencyVotes = (voteAmount + valueOrElse(getInteger(emergencyVotesKey), 0)) | |
400 | - | let projectAssetId = getProjectAssetId() | |
401 | - | let quantity = valueOrErrorMessage(assetInfo(getXWavesAssetId()), "Uknown asset id").quantity | |
402 | - | let wxxAssetInfo = valueOrErrorMessage(assetInfo(projectAssetId), "Uknown asset id") | |
379 | + | let quantity = valueOrErrorMessage(assetInfo(xWavesAssetId), "Uknown asset id").quantity | |
380 | + | let wxxAssetInfo = valueOrErrorMessage(assetInfo(wxxAssetId), "Uknown asset id") | |
403 | 381 | let isValidatorBad = (((emergencyVotes * 100) / quantity) > emergencyVotingThreshold) | |
404 | 382 | let punishment = if (isValidatorBad) | |
405 | 383 | then { | |
406 | - | let validatorLeaseIdKey = ("leaseId:" + | |
384 | + | let validatorLeaseIdKey = ("leaseId:" + validator) | |
407 | 385 | let cancel = match getBinary(validatorLeaseIdKey) { | |
408 | 386 | case id: ByteVector => | |
409 | 387 | [LeaseCancel(id)] | |
410 | 388 | case _: Unit => | |
411 | 389 | nil | |
412 | 390 | case _ => | |
413 | 391 | throw("Match error") | |
414 | 392 | } | |
415 | - | let validatorVotesKey = ("votes:" + | |
393 | + | let validatorVotesKey = ("votes:" + validator) | |
416 | 394 | let totalValidatorVotes = valueOrElse(getInteger(validatorVotesKey), 0) | |
417 | - | let totalVotes = getIntegerValue(totalVoteskey) | |
418 | - | (cancel ++ [ScriptTransfer(wxxAssetInfo.issuer, requiredWXXAmount, projectAssetId), IntegerEntry(totalVoteskey, (totalVotes - totalValidatorVotes)), BooleanEntry(("validatorStatus:" + validatorKey), false), DeleteEntry(("validatorLeases:" + validatorKey)), DeleteEntry(("leaseId:" + validatorKey)), DeleteEntry(("latestLeasingCycle:" + validatorKey))]) | |
395 | + | (cancel ++ [ScriptTransfer(wxxAssetInfo.issuer, requiredWXXAmount, wxxAssetId), IntegerEntry(totalVoteskey, (totalVotes - totalValidatorVotes)), BooleanEntry(("validatorStatus:" + validator), false), DeleteEntry(("validatorLeases:" + validator)), DeleteEntry(("leaseId:" + validator)), DeleteEntry(("latestLeasingCycle:" + validator))]) | |
419 | 396 | } | |
420 | 397 | else nil | |
421 | 398 | (punishment ++ [IntegerEntry(emergencyVotesKey, (voteAmount + emergencyVotes)), IntegerEntry(emergencyUserVotesKey, (valueOrElse(getInteger(emergencyUserVotesKey), 0) + emergencyVotes))]) | |
422 | 399 | } | |
423 | 400 | else throw("Strict value is not equal to itself.") | |
424 | 401 | } | |
425 | 402 | else throw("Strict value is not equal to itself.") | |
426 | 403 | } | |
427 | 404 | else throw("Strict value is not equal to itself.") | |
428 | 405 | } | |
429 | 406 | else throw("Strict value is not equal to itself.") | |
430 | 407 | } | |
431 | 408 | ||
432 | 409 | ||
433 | 410 | ||
434 | 411 | @Callable(invocation) | |
435 | - | func redeemEmergencyVote ( | |
436 | - | let | |
437 | - | let | |
438 | - | let emergencyUserVotesKey = (("emergencyUserVotes:" + callerKey) + | |
412 | + | func redeemEmergencyVote (validator) = { | |
413 | + | let validatorAddress = addressFromStringValue(validator) | |
414 | + | let callerKey = toString(invocation.caller) | |
415 | + | let emergencyUserVotesKey = (("emergencyUserVotes:" + callerKey) + validator) | |
439 | 416 | let emergencyUserVotes = valueOrErrorMessage(getInteger(emergencyUserVotesKey), "No emergency votes for user") | |
440 | - | let xWavesAssetId = getXWavesAssetId() | |
441 | 417 | [ScriptTransfer(invocation.caller, emergencyUserVotes, xWavesAssetId)] | |
442 | 418 | } | |
443 | 419 | ||
444 | 420 |
github/deemru/w8io/169f3d6 79.73 ms ◑![]()