tx · EV3oUq2K1hfaiAdjiYFUh83zu1q2Tr9UCTmEFcHFSayu

3N8xXaYjE27Aa79d5hHrhHu9HaFoTBmhDEj:  -0.00900000 Waves

2022.11.29 05:27 [2337789] smart account 3N8xXaYjE27Aa79d5hHrhHu9HaFoTBmhDEj > SELF 0.00000000 Waves

{ "type": 13, "id": "EV3oUq2K1hfaiAdjiYFUh83zu1q2Tr9UCTmEFcHFSayu", "fee": 900000, "feeAssetId": null, "timestamp": 1669688839606, "version": 2, "chainId": 84, "sender": "3N8xXaYjE27Aa79d5hHrhHu9HaFoTBmhDEj", "senderPublicKey": "A2m227AHcq7gWfSU59Q3UJaqkEa7SccFYmJuWHbFrrKE", "proofs": [ "t5mdnx5Be2Mf3N65KmhzZrczBXg97pMjMEh6ifd6hwWHRxzUwBLXNDGr9W2Bh1Jkgmq4DWeMf12bYEwbat2GHQ8" ], "script": "base64:BgJJCAISBAoCCAgSBAoCBAgSAwoBBBIHCgUICAgIARIHCgUICAgIARIDCgEIEgUKAwgICBIDCgEIEgYKBAgIAQESBAoCCAgSAwoBCCEBDmdldFN0cmluZ0J5S2V5AQNrZXkJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwUDa2V5AgABD2dldEludGVnZXJCeUtleQEDa2V5CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFA2tleQAAAAVjaHJpcwkBDmdldFN0cmluZ0J5S2V5AQIMY29uZl9hZG1pbl8xAA5kYXBwUnVubmluZ0tleQIUY29uZl9kYXBwX2lzX3J1bm5pbmcAEW1haW50ZW5hbmNlTVNHS2V5AhRjb25mX21haW50ZW5hbmNlX21zZwASd2hpdGVsaXN0ZWRvbmx5S2V5AhVjb25mX3doaXRlbGlzdGVkX29ubHkAC2RhcHBSdW5uaW5nCQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMFDmRhcHBSdW5uaW5nS2V5BgAObWFpbnRlbmFuY2VNU0cJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwURbWFpbnRlbmFuY2VNU0dLZXkCAAAPd2hpdGVsaXN0ZWRvbmx5CQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMFEndoaXRlbGlzdGVkb25seUtleQYAC3VzZXJBbGxvd2VkAgdBTExPV0VEAA51c2VyUmVnaXN0ZXJlZAIKUkVHSVNURVJFRAAMdXNlclZlcmlmaWVkAghWRVJJRklFRAANdXNlclN1c3BlbmRlZAIJU1VTUEVOREVEAAt1c2VyUmVtb3ZlZAIHUkVNT1ZFRAASdXNlckNoYW5nZVJlcXVpcmVkAg9DSEFOR0VfUkVRVUlSRUQACXVzZXJSZXNldAIFUkVTRVQBC2tleVVzZXJBZGRyAQZjYWxsZXIJAKwCAgIFdXNlcl8FBmNhbGxlcgELa2V5VXNlck5hbWUBBmNhbGxlcgkArAICAgp1c2VyX25hbWVfBQZjYWxsZXIBC2tleVVzZXJEZXNjAQZjYWxsZXIJAKwCAgIKdXNlcl9kZXNjXwUGY2FsbGVyAQ1rZXlVc2VyU29jaWFsAQZjYWxsZXIJAKwCAgIMdXNlcl9zb2NpYWxfBQZjYWxsZXIBDGtleVVzZXJUaHVtYgEGY2FsbGVyCQCsAgICC3VzZXJfdGh1bWJfBQZjYWxsZXIBDWtleVVzZXJTdGF0dXMBBmNhbGxlcgkArAICAgx1c2VyX3N0YXR1c18FBmNhbGxlcgEQa2V5VXNlclJveWFsdGllcwEGY2FsbGVyCQCsAgICD3VzZXJfcm95YWx0aWVzXwUGY2FsbGVyAQtrZXlVc2VyRGF0ZQEGY2FsbGVyCQCsAgICCnVzZXJfZGF0ZV8FBmNhbGxlcgEMa2V5VXNlckVSQzIwAQZjYWxsZXIJAKwCAgILdXNlcl9FUkMyMF8FBmNhbGxlcgESa2V5QXJ0aXN0QWdlbnRBZGRyAQphcnRpc3RBZGRyCQCsAgICDWFydGlzdF9hZ2VudF8FCmFydGlzdEFkZHIBEmtleUFnZW50QXJ0aXN0QWRkcgIJYWdlbnRBZGRyCmFydGlzdEFkZHIJAKwCAgkArAICCQCsAgICBmFnZW50XwUJYWdlbnRBZGRyAgFfBQphcnRpc3RBZGRyAQ9rZXlQcmltYXJ5U2hhcmUBCmFydGlzdEFkZHIJAKwCAgIVYXJ0aXN0X2FnZW50X3ByaW1hcnlfBQphcnRpc3RBZGRyARFrZXlTZWNvbmRhcnlTaGFyZQEKYXJ0aXN0QWRkcgkArAICAhdhcnRpc3RfYWdlbnRfc2Vjb25kYXJ5XwUKYXJ0aXN0QWRkcgELdmFsaWRhdGVDSUQBA2NpZAMJAQhjb250YWlucwIFA2NpZAIBLwMDCQBmAgBMCQCxAgEFA2NpZAkAAAIJALECAQkAkQMCCQC1CQIFA2NpZAIBLwAAADsHCQBmAgAQCQCxAgEJAJEDAgkAtQkCBQNjaWQCAS8AAQcHAQ12YWxpZFVzZXJEYXRhBQZjYWxsZXIEbmFtZQtkZXNjcmlwdGlvbgV0aHVtYgppc0FuVXBkYXRlBAh2YWxpZENJRAMJAQIhPQIJALECAQUFdGh1bWIAAAkBC3ZhbGlkYXRlQ0lEAQUFdGh1bWIGAwkBASEBBQh2YWxpZENJRAkAAgECHENJRCBkb24ndCBtYXRjaCByZXF1aXJlbWVudCEDAwkAAAIFBG5hbWUCAAYJAAACBQtkZXNjcmlwdGlvbgIACQACAQIkTmFtZSBhbmQgZGVzY3JpcHRpb24gY2Fubm90IGJlIGVtcHR5AwkAZgIJALECAQULZGVzY3JpcHRpb24A2AQJAAIBAhk2MDAgQ2hhci4gbWF4IGRlc2NyaXB0aW9uAwkAZgIJALECAQUEbmFtZQAtCQACAQIRNDUgQ2hhci4gbWF4IG5hbWUEBnN0YXR1cwkBDmdldFN0cmluZ0J5S2V5AQkBDWtleVVzZXJTdGF0dXMBBQZjYWxsZXIDAwkAAAIFBnN0YXR1cwUNdXNlclN1c3BlbmRlZAYJAAACBQZzdGF0dXMFC3VzZXJSZW1vdmVkCQACAQIbQWNjb3VudCBzdXNwZW5kZWQvIHJlbW92ZWQuAwMJAQEhAQUKaXNBblVwZGF0ZQkAAAIFBnN0YXR1cwUOdXNlclJlZ2lzdGVyZWQHCQACAQISQWxyZWFkeSByZWdpc3RlcmVkAwMDCQEBIQEFCmlzQW5VcGRhdGUJAAACBQZzdGF0dXMCAAcFD3doaXRlbGlzdGVkb25seQcJAAIBAiNDYW4ndCByZWdpc3RlciwgZ2V0IGFwcHJvdmVkIGZpcnN0LgMDAwUKaXNBblVwZGF0ZQkAAAIFBnN0YXR1cwIABwYDBQppc0FuVXBkYXRlCQAAAgUGc3RhdHVzBQt1c2VyQWxsb3dlZAcJAAIBAg5SZWdpc3RlciBmaXJzdAYBEXZhbGlkYXRlTmV3U3RhdHVzAwZzdGF0dXMHYWRkcmVzcw1jdXJyZW50U3RhdHVzBAlhbGxTdGF0dXMJAMwIAgUMdXNlclZlcmlmaWVkCQDMCAIFDnVzZXJSZWdpc3RlcmVkCQDMCAIFDXVzZXJTdXNwZW5kZWQJAMwIAgULdXNlclJlbW92ZWQJAMwIAgULdXNlckFsbG93ZWQJAMwIAgUSdXNlckNoYW5nZVJlcXVpcmVkBQNuaWwEC3N0YXR1c1RvU2V0AwkBD2NvbnRhaW5zRWxlbWVudAIFCWFsbFN0YXR1cwUGc3RhdHVzBQZzdGF0dXMDAwkAAAIFBnN0YXR1cwUJdXNlclJlc2V0CQAAAgUNY3VycmVudFN0YXR1cwULdXNlckFsbG93ZWQHAgAJAAIBAg5Vbmtub3duIHN0YXR1cwQQdXNlcklzUmVnaXN0ZXJlZAkBD2dldEludGVnZXJCeUtleQEJAQtrZXlVc2VyRGF0ZQEFB2FkZHJlc3MDAwkAAAIFEHVzZXJJc1JlZ2lzdGVyZWQAAAkBAiE9AgULc3RhdHVzVG9TZXQFC3VzZXJBbGxvd2VkBwkAAgECMVlvdSBjYW50IHNldCB0aGlzIHN0YXR1cywgdXNlciBpcyBub3QgcmVnaXN0ZXJlZC4DAwkAAAIFDWN1cnJlbnRTdGF0dXMFC3VzZXJBbGxvd2VkCQAAAgULc3RhdHVzVG9TZXQFC3VzZXJBbGxvd2VkBwkAAgECFFVzZXIgYWxyZWFkeSBhbGxvd2VkAwMJAAACBQ1jdXJyZW50U3RhdHVzBQ51c2VyUmVnaXN0ZXJlZAkAAAIFC3N0YXR1c1RvU2V0BQt1c2VyQWxsb3dlZAcJAAIBAiFVc2VyIGFscmVhZHkgYWxsb3dlZCAmIHJlZ2lzdGVyZWQDAwkAAAIFDWN1cnJlbnRTdGF0dXMFDHVzZXJWZXJpZmllZAkAAAIFC3N0YXR1c1RvU2V0BQt1c2VyQWxsb3dlZAcJAAIBAh9Vc2VyIGFscmVhZHkgYWxsb3dlZCAmIHZlcmlmaWVkBQtzdGF0dXNUb1NldAEIbWFrZUpTT04DBG5hbWUFdGh1bWIEZGF0ZQkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgIPeyJ1c2VyX25hbWUiOiAiBQRuYW1lAhEiLCAidXNlcl90aHVtYiI6IgUFdGh1bWICDyIsInVzZXJfZGF0ZSI6IgUEZGF0ZQICIn0LBmludm9rZQEHc2V0Q29uZgIDa2V5A3ZhbAQGY2FsbGVyCQClCAEIBQZpbnZva2UGY2FsbGVyAwkBD2NvbnRhaW5zRWxlbWVudAIJAMwIAgUFY2hyaXMJAMwIAgkApQgBBQR0aGlzBQNuaWwFBmNhbGxlcgkAzAgCCQELU3RyaW5nRW50cnkCBQNrZXkFA3ZhbAUDbmlsCQACAQIiWW91IGFyZSBub3QgYWxsb3dlZCB0byBjaGFuZ2UgdGhpcwZpbnZva2UBCmFwcFJ1bm5pbmcCBmlzTGl2ZQdtZXNzYWdlBAZjYWxsZXIJAKUIAQgFBmludm9rZQZjYWxsZXIDCQEPY29udGFpbnNFbGVtZW50AgkAzAgCBQVjaHJpcwkAzAgCCQClCAEFBHRoaXMFA25pbAUGY2FsbGVyCQDMCAIJAQxCb29sZWFuRW50cnkCBQ5kYXBwUnVubmluZ0tleQUGaXNMaXZlCQDMCAIJAQtTdHJpbmdFbnRyeQIFEW1haW50ZW5hbmNlTVNHS2V5BQdtZXNzYWdlBQNuaWwJAAIBAiJZb3UgYXJlIG5vdCBhbGxvd2VkIHRvIGNoYW5nZSB0aGlzBmludm9rZQEQcmVnaXN0cmF0aW9uTW9kZQEGV0xvbmx5BAZjYWxsZXIJAKUIAQgFBmludm9rZQZjYWxsZXIDCQEPY29udGFpbnNFbGVtZW50AgkAzAgCBQVjaHJpcwkAzAgCCQClCAEFBHRoaXMFA25pbAUGY2FsbGVyCQDMCAIJAQxCb29sZWFuRW50cnkCBRJ3aGl0ZWxpc3RlZG9ubHlLZXkFBldMb25seQUDbmlsCQACAQIiWW91IGFyZSBub3QgYWxsb3dlZCB0byBjaGFuZ2UgdGhpcwZpbnZva2UBDHJlZ2lzdGVyVXNlcgUEbmFtZQtkZXNjcmlwdGlvbgV0aHVtYgZzb2NpYWwJcm95YWx0aWVzAwkBASEBBQtkYXBwUnVubmluZwkAAgEFDm1haW50ZW5hbmNlTVNHBAZjYWxsZXIJAKUIAQgFBmludm9rZQZjYWxsZXIEAmlkCQDYBAEIBQZpbnZva2UNdHJhbnNhY3Rpb25JZAQJdGltZXN0YW1wCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAMJAQEhAQkBDXZhbGlkVXNlckRhdGEFBQZjYWxsZXIFBG5hbWUFC2Rlc2NyaXB0aW9uBQV0aHVtYgcJAAIBAhRTb21ldGhpbmcgd2VudCB3cm9uZwQEanNvbgkBCG1ha2VKU09OAwkA2gQBCQCbAwEFBG5hbWUJANoEAQkAmwMBBQV0aHVtYgkApAMBBQl0aW1lc3RhbXADAwkAZgIAAAUJcm95YWx0aWVzBgkAZgIFCXJveWFsdGllcwAKCQACAQIiUm95YWx0aWVzIGNhbm5vdCBiZSBoaWdoZXIgdGhhbiAxMAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBC2tleVVzZXJEYXRlAQUGY2FsbGVyBQl0aW1lc3RhbXAJAMwIAgkBC1N0cmluZ0VudHJ5AgkBC2tleVVzZXJBZGRyAQUGY2FsbGVyCQCsAgIJAKwCAgUCaWQCAV8JAKQDAQUJdGltZXN0YW1wCQDMCAIJAQtTdHJpbmdFbnRyeQIJAQtrZXlVc2VyTmFtZQEFBmNhbGxlcgUEbmFtZQkAzAgCCQELU3RyaW5nRW50cnkCCQELa2V5VXNlckRlc2MBBQZjYWxsZXIFC2Rlc2NyaXB0aW9uCQDMCAIJAQtTdHJpbmdFbnRyeQIJAQ1rZXlVc2VyU29jaWFsAQUGY2FsbGVyBQZzb2NpYWwJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDGtleVVzZXJUaHVtYgEFBmNhbGxlcgUFdGh1bWIJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDWtleVVzZXJTdGF0dXMBBQZjYWxsZXIFDnVzZXJSZWdpc3RlcmVkCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEQa2V5VXNlclJveWFsdGllcwEFBmNhbGxlcgUJcm95YWx0aWVzCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgIIQUxMT1dFRF8FBmNhbGxlcgkAzAgCCQELU3RyaW5nRW50cnkCCQCsAgIJAKwCAgUOdXNlclJlZ2lzdGVyZWQCAV8FBmNhbGxlcgUEanNvbgUDbmlsBmludm9rZQEKdXBkYXRlVXNlcgUEbmFtZQtkZXNjcmlwdGlvbgV0aHVtYgZzb2NpYWwJcm95YWx0aWVzAwkBASEBBQtkYXBwUnVubmluZwkAAgEFDm1haW50ZW5hbmNlTVNHBAZjYWxsZXIJAKUIAQgFBmludm9rZQZjYWxsZXIEBnN0YXR1cwkBDmdldFN0cmluZ0J5S2V5AQkBDWtleVVzZXJTdGF0dXMBBQZjYWxsZXIDCQEBIQEJAQ12YWxpZFVzZXJEYXRhBQUGY2FsbGVyBQRuYW1lBQtkZXNjcmlwdGlvbgUFdGh1bWIGCQACAQIUU29tZXRoaW5nIHdlbnQgd3JvbmcEBGRhdGUJAQ9nZXRJbnRlZ2VyQnlLZXkBCQELa2V5VXNlckRhdGUBBQZjYWxsZXIEBGpzb24JAQhtYWtlSlNPTgMJANoEAQkAmwMBBQRuYW1lCQDaBAEJAJsDAQUFdGh1bWIJAKQDAQUEZGF0ZQMDCQBmAgAABQlyb3lhbHRpZXMGCQBmAgUJcm95YWx0aWVzAAoJAAIBAiJSb3lhbHRpZXMgY2Fubm90IGJlIGhpZ2hlciB0aGFuIDEwCQDMCAIJAQtTdHJpbmdFbnRyeQIJAQtrZXlVc2VyTmFtZQEFBmNhbGxlcgUEbmFtZQkAzAgCCQELU3RyaW5nRW50cnkCCQELa2V5VXNlckRlc2MBBQZjYWxsZXIFC2Rlc2NyaXB0aW9uCQDMCAIJAQtTdHJpbmdFbnRyeQIJAQ1rZXlVc2VyU29jaWFsAQUGY2FsbGVyBQZzb2NpYWwJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDGtleVVzZXJUaHVtYgEFBmNhbGxlcgUFdGh1bWIJAMwIAgkBDEludGVnZXJFbnRyeQIJARBrZXlVc2VyUm95YWx0aWVzAQUGY2FsbGVyBQlyb3lhbHRpZXMJAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICCQCsAgIFBnN0YXR1cwIBXwUGY2FsbGVyBQRqc29uBQNuaWwGaW52b2tlAQxzZXRFUkMyMFVzZXIBBWVyYzIwAwkBASEBBQtkYXBwUnVubmluZwkAAgEFDm1haW50ZW5hbmNlTVNHBAZjYWxsZXIJAKUIAQgFBmludm9rZQZjYWxsZXIEBnN0YXR1cwkBDmdldFN0cmluZ0J5S2V5AQkBDWtleVVzZXJTdGF0dXMBBQZjYWxsZXIDAwkBAiE9AgUGc3RhdHVzBQ51c2VyUmVnaXN0ZXJlZAkBAiE9AgUGc3RhdHVzBQx1c2VyVmVyaWZpZWQHCQACAQIgTm90IGFsbG93ZWQgdG8gc2V0IEVSQzIwIGFkZHJlc3MECGZpcnN0VHdvCQCvAgIFBWVyYzIwAAIDAwkBAiE9AgUIZmlyc3RUd28CAjB4BgkBAiE9AgkAsQIBBQVlcmMyMAAqCQACAQIcVGhpcyBpcyBub3QgYW4gZXJjMjAgYWRkcmVzcwkAzAgCCQELU3RyaW5nRW50cnkCCQEMa2V5VXNlckVSQzIwAQUGY2FsbGVyBQVlcmMyMAUDbmlsBmludm9rZQEQY2hhbmdlVXNlclN0YXR1cwMHYWRkcmVzcwZzdGF0dXMEbm90ZQQGY2FsbGVyCQClCAEIBQZpbnZva2UGY2FsbGVyBA1jdXJyZW50U3RhdHVzCQEOZ2V0U3RyaW5nQnlLZXkBCQENa2V5VXNlclN0YXR1cwEFB2FkZHJlc3MEC3N0YXR1c1RvU2V0CQERdmFsaWRhdGVOZXdTdGF0dXMDBQZzdGF0dXMFB2FkZHJlc3MFDWN1cnJlbnRTdGF0dXMEBG5hbWUJANoEAQkAmwMBCQEOZ2V0U3RyaW5nQnlLZXkBCQELa2V5VXNlck5hbWUBBQdhZGRyZXNzBAV0aHVtYgkA2gQBCQCbAwEJAQ5nZXRTdHJpbmdCeUtleQEJAQxrZXlVc2VyVGh1bWIBBQdhZGRyZXNzBARkYXRlCQEPZ2V0SW50ZWdlckJ5S2V5AQkBC2tleVVzZXJEYXRlAQUHYWRkcmVzcwQEanNvbgkBCG1ha2VKU09OAwUEbmFtZQUFdGh1bWIJAKQDAQUEZGF0ZQMJAQ9jb250YWluc0VsZW1lbnQCCQDMCAIFBWNocmlzCQDMCAIJAKUIAQUEdGhpcwUDbmlsBQZjYWxsZXIJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDWtleVVzZXJTdGF0dXMBBQdhZGRyZXNzBQtzdGF0dXNUb1NldAkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgIJAKwCAgUNY3VycmVudFN0YXR1cwIBXwUHYWRkcmVzcwkAzAgCCQELU3RyaW5nRW50cnkCCQCsAgIJAKwCAgULc3RhdHVzVG9TZXQCAV8FB2FkZHJlc3MFBGpzb24JAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICAgp1c2VyX25vdGVfBQdhZGRyZXNzBQRub3RlBQNuaWwJAAIBAiFOb3QgYWxsb3dlZCB0byBjaGFuZ2UgdXNlciBzdGF0dXMGaW52b2tlAQpkZWxldGVVc2VyAQdhZGRyZXNzBAZjYWxsZXIJAKUIAQgFBmludm9rZQZjYWxsZXIEDWN1cnJlbnRTdGF0dXMJAQ5nZXRTdHJpbmdCeUtleQEJAQ1rZXlVc2VyU3RhdHVzAQUHYWRkcmVzcwMJAQ9jb250YWluc0VsZW1lbnQCCQDMCAIFBWNocmlzCQDMCAIJAKUIAQUEdGhpcwUDbmlsBQZjYWxsZXIJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBC2tleVVzZXJEYXRlAQUHYWRkcmVzcwkAzAgCCQELRGVsZXRlRW50cnkBCQELa2V5VXNlckFkZHIBBQdhZGRyZXNzCQDMCAIJAQtEZWxldGVFbnRyeQEJAQtrZXlVc2VyTmFtZQEFB2FkZHJlc3MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBC2tleVVzZXJEZXNjAQUHYWRkcmVzcwkAzAgCCQELRGVsZXRlRW50cnkBCQENa2V5VXNlclNvY2lhbAEFB2FkZHJlc3MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBDGtleVVzZXJUaHVtYgEFB2FkZHJlc3MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICAgp1c2VyX25vdGVfBQdhZGRyZXNzCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgkArAICBQ1jdXJyZW50U3RhdHVzAgFfBQdhZGRyZXNzCQDMCAIJAQtEZWxldGVFbnRyeQEJARBrZXlVc2VyUm95YWx0aWVzAQUHYWRkcmVzcwkAzAgCCQELU3RyaW5nRW50cnkCCQENa2V5VXNlclN0YXR1cwEFB2FkZHJlc3MFC3VzZXJSZW1vdmVkBQNuaWwJAAIBAgtOb3QgYWxsb3dlZAFpAQhzZXRBZ2VudAQKYXJ0aXN0QWRkcglhZ2VudEFkZHIMcHJpbWFyeVNoYXJlDnNlY29uZGFyeVNoYXJlAwkBASEBBQtkYXBwUnVubmluZwkAAgEFDm1haW50ZW5hbmNlTVNHBAZjYWxsZXIJAKUIAQgFAWkGY2FsbGVyAwkBD2NvbnRhaW5zRWxlbWVudAIJAMwIAgUFY2hyaXMJAMwIAgkApQgBBQR0aGlzBQNuaWwFBmNhbGxlcgMDCQECIT0CCQCxAgEFCmFydGlzdEFkZHIAIwYJAQIhPQIJALECAQUJYWdlbnRBZGRyACMJAAIBAg1Xcm9uZyBhZGRyZXNzCQDMCAIJAQtTdHJpbmdFbnRyeQIJARJrZXlBcnRpc3RBZ2VudEFkZHIBBQphcnRpc3RBZGRyBQlhZ2VudEFkZHIJAMwIAgkBC1N0cmluZ0VudHJ5AgkBEmtleUFnZW50QXJ0aXN0QWRkcgIFCWFnZW50QWRkcgUKYXJ0aXN0QWRkcgUKYXJ0aXN0QWRkcgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBD2tleVByaW1hcnlTaGFyZQEFCmFydGlzdEFkZHIFDHByaW1hcnlTaGFyZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBEWtleVNlY29uZGFyeVNoYXJlAQUKYXJ0aXN0QWRkcgUOc2Vjb25kYXJ5U2hhcmUFA25pbAkAAgECE1lvdSBhcmUgbm90IGFsbG93ZWQBaQEKdW5zZXRBZ2VudAIKYXJ0aXN0QWRkcglhZ2VudEFkZHIDCQEBIQEFC2RhcHBSdW5uaW5nCQACAQUObWFpbnRlbmFuY2VNU0cEBmNhbGxlcgkApQgBCAUBaQZjYWxsZXIDCQEPY29udGFpbnNFbGVtZW50AgkAzAgCBQVjaHJpcwkAzAgCCQClCAEFBHRoaXMFA25pbAUGY2FsbGVyAwMJAQIhPQIJALECAQUKYXJ0aXN0QWRkcgAjBgkBAiE9AgkAsQIBBQlhZ2VudEFkZHIAIwkAAgECDVdyb25nIGFkZHJlc3MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBEmtleUFydGlzdEFnZW50QWRkcgEFCmFydGlzdEFkZHIJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBEmtleUFnZW50QXJ0aXN0QWRkcgIFCWFnZW50QWRkcgUKYXJ0aXN0QWRkcgkAzAgCCQELRGVsZXRlRW50cnkBCQEPa2V5UHJpbWFyeVNoYXJlAQUKYXJ0aXN0QWRkcgkAzAgCCQELRGVsZXRlRW50cnkBCQERa2V5U2Vjb25kYXJ5U2hhcmUBBQphcnRpc3RBZGRyBQNuaWwJAAIBAhNZb3UgYXJlIG5vdCBhbGxvd2VkAWkBC2RlbGV0ZUVudHJ5AQVlbnRyeQQGY2FsbGVyCQClCAEIBQFpBmNhbGxlcgMJAAACBQZjYWxsZXIFBWNocmlzCQDMCAIJAQtEZWxldGVFbnRyeQEFBWVudHJ5BQNuaWwJAAIBAgJubwAL3fPv", "height": 2337789, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: GV7getPrLuueS3efSPTKdhq3khZLpj9mB4SsP1aosNEj Next: 9CXTfCwftjtH3JVpAcgYxmiWuFD7rtXSnK1ePdyRhLUp Diff:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let VERSION = "1.3"
5-
64 func getStringByKey (key) = valueOrElse(getString(this, key), "")
7-
8-
9-func getBooleanByKey (key) = valueOrElse(getBoolean(this, key), false)
105
116
127 func getIntegerByKey (key) = valueOrElse(getInteger(this, key), 0)
138
149
1510 let chris = getStringByKey("conf_admin_1")
16-
17-let joep = getStringByKey("conf_admin_2")
1811
1912 let dappRunningKey = "conf_dapp_is_running"
2013
4033
4134 let userChangeRequired = "CHANGE_REQUIRED"
4235
43-let userUnregistered = "UNREGISTERED"
44-
4536 let userReset = "RESET"
4637
4738 func keyUserAddr (caller) = ("user_" + caller)
6051
6152
6253 func keyUserStatus (caller) = ("user_status_" + caller)
54+
55+
56+func keyUserRoyalties (caller) = ("user_royalties_" + caller)
6357
6458
6559 func keyUserDate (caller) = ("user_date_" + caller)
178172 @Callable(invoke)
179173 func appRunning (isLive,message) = {
180174 let caller = toString(invoke.caller)
181- if (containsElement([chris, joep, toString(this)], caller))
175+ if (containsElement([chris, toString(this)], caller))
182176 then [BooleanEntry(dappRunningKey, isLive), StringEntry(maintenanceMSGKey, message)]
183177 else throw("You are not allowed to change this")
184178 }
196190
197191
198192 @Callable(invoke)
199-func registerUser (name,description,thumb,social) = if (!(dappRunning))
193+func registerUser (name,description,thumb,social,royalties) = if (!(dappRunning))
200194 then throw(maintenanceMSG)
201195 else {
202196 let caller = toString(invoke.caller)
206200 then throw("Something went wrong")
207201 else {
208202 let json = makeJSON(toBase64String(toBytes(name)), toBase64String(toBytes(thumb)), toString(timestamp))
209-[IntegerEntry(keyUserDate(caller), timestamp), StringEntry(keyUserAddr(caller), ((id + "_") + toString(timestamp))), StringEntry(keyUserName(caller), name), StringEntry(keyUserDesc(caller), description), StringEntry(keyUserSocial(caller), social), StringEntry(keyUserThumb(caller), thumb), StringEntry(keyUserStatus(caller), userRegistered), DeleteEntry(("ALLOWED_" + caller)), StringEntry(((userRegistered + "_") + caller), json)]
203+ if (if ((0 > royalties))
204+ then true
205+ else (royalties > 10))
206+ then throw("Royalties cannot be higher than 10")
207+ else [IntegerEntry(keyUserDate(caller), timestamp), StringEntry(keyUserAddr(caller), ((id + "_") + toString(timestamp))), StringEntry(keyUserName(caller), name), StringEntry(keyUserDesc(caller), description), StringEntry(keyUserSocial(caller), social), StringEntry(keyUserThumb(caller), thumb), StringEntry(keyUserStatus(caller), userRegistered), IntegerEntry(keyUserRoyalties(caller), royalties), DeleteEntry(("ALLOWED_" + caller)), StringEntry(((userRegistered + "_") + caller), json)]
210208 }
211209 }
212210
213211
214212
215213 @Callable(invoke)
216-func updateUser (name,description,thumb,social) = if (!(dappRunning))
214+func updateUser (name,description,thumb,social,royalties) = if (!(dappRunning))
217215 then throw(maintenanceMSG)
218216 else {
219217 let caller = toString(invoke.caller)
223221 else {
224222 let date = getIntegerByKey(keyUserDate(caller))
225223 let json = makeJSON(toBase64String(toBytes(name)), toBase64String(toBytes(thumb)), toString(date))
226-[StringEntry(keyUserName(caller), name), StringEntry(keyUserDesc(caller), description), StringEntry(keyUserSocial(caller), social), StringEntry(keyUserThumb(caller), thumb), StringEntry(((status + "_") + caller), json)]
224+ if (if ((0 > royalties))
225+ then true
226+ else (royalties > 10))
227+ then throw("Royalties cannot be higher than 10")
228+ else [StringEntry(keyUserName(caller), name), StringEntry(keyUserDesc(caller), description), StringEntry(keyUserSocial(caller), social), StringEntry(keyUserThumb(caller), thumb), IntegerEntry(keyUserRoyalties(caller), royalties), StringEntry(((status + "_") + caller), json)]
227229 }
228230 }
229231
260262 let thumb = toBase64String(toBytes(getStringByKey(keyUserThumb(address))))
261263 let date = getIntegerByKey(keyUserDate(address))
262264 let json = makeJSON(name, thumb, toString(date))
263- if (containsElement([chris, joep, toString(this)], caller))
265+ if (containsElement([chris, toString(this)], caller))
264266 then [StringEntry(keyUserStatus(address), statusToSet), DeleteEntry(((currentStatus + "_") + address)), StringEntry(((statusToSet + "_") + address), json), StringEntry(("user_note_" + address), note)]
265267 else throw("Not allowed to change user status")
266268 }
272274 let caller = toString(invoke.caller)
273275 let currentStatus = getStringByKey(keyUserStatus(address))
274276 if (containsElement([chris, toString(this)], caller))
275- then [DeleteEntry(keyUserDate(address)), DeleteEntry(keyUserAddr(address)), DeleteEntry(keyUserName(address)), DeleteEntry(keyUserDesc(address)), DeleteEntry(keyUserSocial(address)), DeleteEntry(keyUserThumb(address)), DeleteEntry(("user_note_" + address)), DeleteEntry(((currentStatus + "_") + address)), StringEntry(keyUserStatus(address), userRemoved)]
277+ then [DeleteEntry(keyUserDate(address)), DeleteEntry(keyUserAddr(address)), DeleteEntry(keyUserName(address)), DeleteEntry(keyUserDesc(address)), DeleteEntry(keyUserSocial(address)), DeleteEntry(keyUserThumb(address)), DeleteEntry(("user_note_" + address)), DeleteEntry(((currentStatus + "_") + address)), DeleteEntry(keyUserRoyalties(address)), StringEntry(keyUserStatus(address), userRemoved)]
276278 else throw("Not allowed")
277279 }
278280
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let VERSION = "1.3"
5-
64 func getStringByKey (key) = valueOrElse(getString(this, key), "")
7-
8-
9-func getBooleanByKey (key) = valueOrElse(getBoolean(this, key), false)
105
116
127 func getIntegerByKey (key) = valueOrElse(getInteger(this, key), 0)
138
149
1510 let chris = getStringByKey("conf_admin_1")
16-
17-let joep = getStringByKey("conf_admin_2")
1811
1912 let dappRunningKey = "conf_dapp_is_running"
2013
2114 let maintenanceMSGKey = "conf_maintenance_msg"
2215
2316 let whitelistedonlyKey = "conf_whitelisted_only"
2417
2518 let dappRunning = valueOrElse(getBoolean(this, dappRunningKey), true)
2619
2720 let maintenanceMSG = valueOrElse(getString(this, maintenanceMSGKey), "")
2821
2922 let whitelistedonly = valueOrElse(getBoolean(this, whitelistedonlyKey), true)
3023
3124 let userAllowed = "ALLOWED"
3225
3326 let userRegistered = "REGISTERED"
3427
3528 let userVerified = "VERIFIED"
3629
3730 let userSuspended = "SUSPENDED"
3831
3932 let userRemoved = "REMOVED"
4033
4134 let userChangeRequired = "CHANGE_REQUIRED"
4235
43-let userUnregistered = "UNREGISTERED"
44-
4536 let userReset = "RESET"
4637
4738 func keyUserAddr (caller) = ("user_" + caller)
4839
4940
5041 func keyUserName (caller) = ("user_name_" + caller)
5142
5243
5344 func keyUserDesc (caller) = ("user_desc_" + caller)
5445
5546
5647 func keyUserSocial (caller) = ("user_social_" + caller)
5748
5849
5950 func keyUserThumb (caller) = ("user_thumb_" + caller)
6051
6152
6253 func keyUserStatus (caller) = ("user_status_" + caller)
54+
55+
56+func keyUserRoyalties (caller) = ("user_royalties_" + caller)
6357
6458
6559 func keyUserDate (caller) = ("user_date_" + caller)
6660
6761
6862 func keyUserERC20 (caller) = ("user_ERC20_" + caller)
6963
7064
7165 func keyArtistAgentAddr (artistAddr) = ("artist_agent_" + artistAddr)
7266
7367
7468 func keyAgentArtistAddr (agentAddr,artistAddr) = ((("agent_" + agentAddr) + "_") + artistAddr)
7569
7670
7771 func keyPrimaryShare (artistAddr) = ("artist_agent_primary_" + artistAddr)
7872
7973
8074 func keySecondaryShare (artistAddr) = ("artist_agent_secondary_" + artistAddr)
8175
8276
8377 func validateCID (cid) = if (contains(cid, "/"))
8478 then if (if ((76 > size(cid)))
8579 then (size(split(cid, "/")[0]) == 59)
8680 else false)
8781 then (16 > size(split(cid, "/")[1]))
8882 else false
8983 else false
9084
9185
9286 func validUserData (caller,name,description,thumb,isAnUpdate) = {
9387 let validCID = if ((size(thumb) != 0))
9488 then validateCID(thumb)
9589 else true
9690 if (!(validCID))
9791 then throw("CID don't match requirement!")
9892 else if (if ((name == ""))
9993 then true
10094 else (description == ""))
10195 then throw("Name and description cannot be empty")
10296 else if ((size(description) > 600))
10397 then throw("600 Char. max description")
10498 else if ((size(name) > 45))
10599 then throw("45 Char. max name")
106100 else {
107101 let status = getStringByKey(keyUserStatus(caller))
108102 if (if ((status == userSuspended))
109103 then true
110104 else (status == userRemoved))
111105 then throw("Account suspended/ removed.")
112106 else if (if (!(isAnUpdate))
113107 then (status == userRegistered)
114108 else false)
115109 then throw("Already registered")
116110 else if (if (if (!(isAnUpdate))
117111 then (status == "")
118112 else false)
119113 then whitelistedonly
120114 else false)
121115 then throw("Can't register, get approved first.")
122116 else if (if (if (isAnUpdate)
123117 then (status == "")
124118 else false)
125119 then true
126120 else if (isAnUpdate)
127121 then (status == userAllowed)
128122 else false)
129123 then throw("Register first")
130124 else true
131125 }
132126 }
133127
134128
135129 func validateNewStatus (status,address,currentStatus) = {
136130 let allStatus = [userVerified, userRegistered, userSuspended, userRemoved, userAllowed, userChangeRequired]
137131 let statusToSet = if (containsElement(allStatus, status))
138132 then status
139133 else if (if ((status == userReset))
140134 then (currentStatus == userAllowed)
141135 else false)
142136 then ""
143137 else throw("Unknown status")
144138 let userIsRegistered = getIntegerByKey(keyUserDate(address))
145139 if (if ((userIsRegistered == 0))
146140 then (statusToSet != userAllowed)
147141 else false)
148142 then throw("You cant set this status, user is not registered.")
149143 else if (if ((currentStatus == userAllowed))
150144 then (statusToSet == userAllowed)
151145 else false)
152146 then throw("User already allowed")
153147 else if (if ((currentStatus == userRegistered))
154148 then (statusToSet == userAllowed)
155149 else false)
156150 then throw("User already allowed & registered")
157151 else if (if ((currentStatus == userVerified))
158152 then (statusToSet == userAllowed)
159153 else false)
160154 then throw("User already allowed & verified")
161155 else statusToSet
162156 }
163157
164158
165159 func makeJSON (name,thumb,date) = (((((("{\"user_name\": \"" + name) + "\", \"user_thumb\":\"") + thumb) + "\",\"user_date\":\"") + date) + "\"}")
166160
167161
168162 @Callable(invoke)
169163 func setConf (key,val) = {
170164 let caller = toString(invoke.caller)
171165 if (containsElement([chris, toString(this)], caller))
172166 then [StringEntry(key, val)]
173167 else throw("You are not allowed to change this")
174168 }
175169
176170
177171
178172 @Callable(invoke)
179173 func appRunning (isLive,message) = {
180174 let caller = toString(invoke.caller)
181- if (containsElement([chris, joep, toString(this)], caller))
175+ if (containsElement([chris, toString(this)], caller))
182176 then [BooleanEntry(dappRunningKey, isLive), StringEntry(maintenanceMSGKey, message)]
183177 else throw("You are not allowed to change this")
184178 }
185179
186180
187181
188182 @Callable(invoke)
189183 func registrationMode (WLonly) = {
190184 let caller = toString(invoke.caller)
191185 if (containsElement([chris, toString(this)], caller))
192186 then [BooleanEntry(whitelistedonlyKey, WLonly)]
193187 else throw("You are not allowed to change this")
194188 }
195189
196190
197191
198192 @Callable(invoke)
199-func registerUser (name,description,thumb,social) = if (!(dappRunning))
193+func registerUser (name,description,thumb,social,royalties) = if (!(dappRunning))
200194 then throw(maintenanceMSG)
201195 else {
202196 let caller = toString(invoke.caller)
203197 let id = toBase58String(invoke.transactionId)
204198 let timestamp = lastBlock.timestamp
205199 if (!(validUserData(caller, name, description, thumb, false)))
206200 then throw("Something went wrong")
207201 else {
208202 let json = makeJSON(toBase64String(toBytes(name)), toBase64String(toBytes(thumb)), toString(timestamp))
209-[IntegerEntry(keyUserDate(caller), timestamp), StringEntry(keyUserAddr(caller), ((id + "_") + toString(timestamp))), StringEntry(keyUserName(caller), name), StringEntry(keyUserDesc(caller), description), StringEntry(keyUserSocial(caller), social), StringEntry(keyUserThumb(caller), thumb), StringEntry(keyUserStatus(caller), userRegistered), DeleteEntry(("ALLOWED_" + caller)), StringEntry(((userRegistered + "_") + caller), json)]
203+ if (if ((0 > royalties))
204+ then true
205+ else (royalties > 10))
206+ then throw("Royalties cannot be higher than 10")
207+ else [IntegerEntry(keyUserDate(caller), timestamp), StringEntry(keyUserAddr(caller), ((id + "_") + toString(timestamp))), StringEntry(keyUserName(caller), name), StringEntry(keyUserDesc(caller), description), StringEntry(keyUserSocial(caller), social), StringEntry(keyUserThumb(caller), thumb), StringEntry(keyUserStatus(caller), userRegistered), IntegerEntry(keyUserRoyalties(caller), royalties), DeleteEntry(("ALLOWED_" + caller)), StringEntry(((userRegistered + "_") + caller), json)]
210208 }
211209 }
212210
213211
214212
215213 @Callable(invoke)
216-func updateUser (name,description,thumb,social) = if (!(dappRunning))
214+func updateUser (name,description,thumb,social,royalties) = if (!(dappRunning))
217215 then throw(maintenanceMSG)
218216 else {
219217 let caller = toString(invoke.caller)
220218 let status = getStringByKey(keyUserStatus(caller))
221219 if (!(validUserData(caller, name, description, thumb, true)))
222220 then throw("Something went wrong")
223221 else {
224222 let date = getIntegerByKey(keyUserDate(caller))
225223 let json = makeJSON(toBase64String(toBytes(name)), toBase64String(toBytes(thumb)), toString(date))
226-[StringEntry(keyUserName(caller), name), StringEntry(keyUserDesc(caller), description), StringEntry(keyUserSocial(caller), social), StringEntry(keyUserThumb(caller), thumb), StringEntry(((status + "_") + caller), json)]
224+ if (if ((0 > royalties))
225+ then true
226+ else (royalties > 10))
227+ then throw("Royalties cannot be higher than 10")
228+ else [StringEntry(keyUserName(caller), name), StringEntry(keyUserDesc(caller), description), StringEntry(keyUserSocial(caller), social), StringEntry(keyUserThumb(caller), thumb), IntegerEntry(keyUserRoyalties(caller), royalties), StringEntry(((status + "_") + caller), json)]
227229 }
228230 }
229231
230232
231233
232234 @Callable(invoke)
233235 func setERC20User (erc20) = if (!(dappRunning))
234236 then throw(maintenanceMSG)
235237 else {
236238 let caller = toString(invoke.caller)
237239 let status = getStringByKey(keyUserStatus(caller))
238240 if (if ((status != userRegistered))
239241 then (status != userVerified)
240242 else false)
241243 then throw("Not allowed to set ERC20 address")
242244 else {
243245 let firstTwo = take(erc20, 2)
244246 if (if ((firstTwo != "0x"))
245247 then true
246248 else (size(erc20) != 42))
247249 then throw("This is not an erc20 address")
248250 else [StringEntry(keyUserERC20(caller), erc20)]
249251 }
250252 }
251253
252254
253255
254256 @Callable(invoke)
255257 func changeUserStatus (address,status,note) = {
256258 let caller = toString(invoke.caller)
257259 let currentStatus = getStringByKey(keyUserStatus(address))
258260 let statusToSet = validateNewStatus(status, address, currentStatus)
259261 let name = toBase64String(toBytes(getStringByKey(keyUserName(address))))
260262 let thumb = toBase64String(toBytes(getStringByKey(keyUserThumb(address))))
261263 let date = getIntegerByKey(keyUserDate(address))
262264 let json = makeJSON(name, thumb, toString(date))
263- if (containsElement([chris, joep, toString(this)], caller))
265+ if (containsElement([chris, toString(this)], caller))
264266 then [StringEntry(keyUserStatus(address), statusToSet), DeleteEntry(((currentStatus + "_") + address)), StringEntry(((statusToSet + "_") + address), json), StringEntry(("user_note_" + address), note)]
265267 else throw("Not allowed to change user status")
266268 }
267269
268270
269271
270272 @Callable(invoke)
271273 func deleteUser (address) = {
272274 let caller = toString(invoke.caller)
273275 let currentStatus = getStringByKey(keyUserStatus(address))
274276 if (containsElement([chris, toString(this)], caller))
275- then [DeleteEntry(keyUserDate(address)), DeleteEntry(keyUserAddr(address)), DeleteEntry(keyUserName(address)), DeleteEntry(keyUserDesc(address)), DeleteEntry(keyUserSocial(address)), DeleteEntry(keyUserThumb(address)), DeleteEntry(("user_note_" + address)), DeleteEntry(((currentStatus + "_") + address)), StringEntry(keyUserStatus(address), userRemoved)]
277+ then [DeleteEntry(keyUserDate(address)), DeleteEntry(keyUserAddr(address)), DeleteEntry(keyUserName(address)), DeleteEntry(keyUserDesc(address)), DeleteEntry(keyUserSocial(address)), DeleteEntry(keyUserThumb(address)), DeleteEntry(("user_note_" + address)), DeleteEntry(((currentStatus + "_") + address)), DeleteEntry(keyUserRoyalties(address)), StringEntry(keyUserStatus(address), userRemoved)]
276278 else throw("Not allowed")
277279 }
278280
279281
280282
281283 @Callable(i)
282284 func setAgent (artistAddr,agentAddr,primaryShare,secondaryShare) = if (!(dappRunning))
283285 then throw(maintenanceMSG)
284286 else {
285287 let caller = toString(i.caller)
286288 if (containsElement([chris, toString(this)], caller))
287289 then if (if ((size(artistAddr) != 35))
288290 then true
289291 else (size(agentAddr) != 35))
290292 then throw("Wrong address")
291293 else [StringEntry(keyArtistAgentAddr(artistAddr), agentAddr), StringEntry(keyAgentArtistAddr(agentAddr, artistAddr), artistAddr), IntegerEntry(keyPrimaryShare(artistAddr), primaryShare), IntegerEntry(keySecondaryShare(artistAddr), secondaryShare)]
292294 else throw("You are not allowed")
293295 }
294296
295297
296298
297299 @Callable(i)
298300 func unsetAgent (artistAddr,agentAddr) = if (!(dappRunning))
299301 then throw(maintenanceMSG)
300302 else {
301303 let caller = toString(i.caller)
302304 if (containsElement([chris, toString(this)], caller))
303305 then if (if ((size(artistAddr) != 35))
304306 then true
305307 else (size(agentAddr) != 35))
306308 then throw("Wrong address")
307309 else [DeleteEntry(keyArtistAgentAddr(artistAddr)), DeleteEntry(keyAgentArtistAddr(agentAddr, artistAddr)), DeleteEntry(keyPrimaryShare(artistAddr)), DeleteEntry(keySecondaryShare(artistAddr))]
308310 else throw("You are not allowed")
309311 }
310312
311313
312314
313315 @Callable(i)
314316 func deleteEntry (entry) = {
315317 let caller = toString(i.caller)
316318 if ((caller == chris))
317319 then [DeleteEntry(entry)]
318320 else throw("no")
319321 }
320322
321323

github/deemru/w8io/3ef1775 
64.17 ms