tx · 4N4rZ1ELVy3dbPE3EJvszDk9p19BebTYtkbupfJUuATA

3M7uzD8rT54fKQcP4s417if1VKU8yromEP2:  -0.05500000 Waves

2025.10.25 00:05 [551439] smart account 3M7uzD8rT54fKQcP4s417if1VKU8yromEP2 > SELF 0.00000000 Waves

{ "type": 13, "id": "4N4rZ1ELVy3dbPE3EJvszDk9p19BebTYtkbupfJUuATA", "fee": 5500000, "feeAssetId": null, "timestamp": 1761339922863, "version": 2, "chainId": 82, "sender": "3M7uzD8rT54fKQcP4s417if1VKU8yromEP2", "senderPublicKey": "2eFPamS5zez1159HEFEJaxs2XPq3AupPbNApNGffRjqf", "proofs": [ "4NfECV8Xs9T4sbWeNoStCRF54Z9GzfmdLgj3wB6mQYiELi3UFk9uLU48JX73PwLDTQxNJeR8QUXoeuHyFg2dkugC" ], "script": "base64:BgJZCAISBQoDGAEBEgMKAQgSAwoBCBIDCgEIEgMKAQgSAwoBARIICgYICAgICAgSAwoBCBIDCgEIEgMKAQgSCQoHCAgIAQgICBIDCgEIEgMKAQgSAwoBCBIAEgAaAAdWRVJTSU9OAgUxLjAuMAADU0VQAgFfAAZCSUdTRVACAl9fAAhrX0FETUlOUwILQURNSU5TX1BCS1MACmtfTUFOQUdFUlMCDU1BTkFHRVJTX1BCS1MAB2tfTElNSVQCDFZPVEVTX1FVT1JVTQAOa19TQ1JJUFRfVFlQRVMCDFNDUklQVF9UWVBFUwALa19JVEVSQVRJT04CCUlURVJBVElPTgAQa19BUFBST1ZFRF9DT1VOVAIOQVBQUk9WRURfQ09VTlQADGtfc2NyaXB0VHlwZQIKc2NyaXB0VHlwZQAMa19zY3JpcHRIYXNoAgpzY3JpcHRIYXNoABBrX3N0b3JhZ2VBZGRyZXNzAg5zdG9yYWdlQWRkcmVzcwAGa19kZXNjAgRkZXNjAAZrX2l0ZXICCWl0ZXJhdGlvbgALa19pbml0aWF0b3ICCWluaXRpYXRvcgAPa19jb25maXJtYXRpb25zAg1jb25maXJtYXRpb25zAA1rX3Jhd0NvZGVIYXNoAgtyYXdDb2RlSGFzaAEMX3ZhbGlkYXRlUGJrAQNwYmsEB2FkZHJlc3MJAKcIAQkA2QQBBQNwYmsDCQAAAgUHYWRkcmVzcwUHYWRkcmVzcwQKYWRkcmVzc1N0cgkApQgBBQdhZGRyZXNzAwkAAAIFCmFkZHJlc3NTdHIFCmFkZHJlc3NTdHIGCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuARBfdmFsaWRhdGVBZGRyZXNzAQdhZGRyZXNzBARhZGRyCQERQGV4dHJOYXRpdmUoMTA2MikBBQdhZGRyZXNzAwkAAAIFBGFkZHIFBGFkZHIGCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAQtfdmFsaWRhdGVUcwECdHMEBmN1cnJUcwQHJG1hdGNoMAkA7QcBBQZoZWlnaHQDCQABAgUHJG1hdGNoMAIJQmxvY2tJbmZvBAVibG9jawUHJG1hdGNoMAgFBWJsb2NrCXRpbWVzdGFtcAkAAgECEENhbid0IGZpbmQgYmxvY2sEB29uZUhvdXIJAGgCCQBoAgA8ADwA6AcEBW1pblRzCQBlAgUGY3VyclRzBQdvbmVIb3VyCQBnAgUCdHMFBW1pblRzAQlfZ2V0TGltaXQACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ8IAQUHa19MSU1JVAIYUXVvcnVtIGxpbWl0IG5vdCBkZWZpbmVkARFfZ2V0QXBwcm92ZWRDb3VudAAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnwgBBRBrX0FQUFJPVkVEX0NPVU5UAjVBbW91bnQgb2Ygc2ltdWx0YW5lb3VzbHkgYXBwcm92ZWQgc2NyaXB0cyBub3QgZGVmaW5lZAEIX2lzQWRtaW4BA3BiawQJYWRtaW5zU3RyCQELdmFsdWVPckVsc2UCCQCiCAEFCGtfQURNSU5TAgAEBmFkbWlucwkAtQkCBQlhZG1pbnNTdHICASwJAQIhPQIJAM8IAgUGYWRtaW5zBQNwYmsFBHVuaXQBCl9pc01hbmFnZXIBA3BiawQLbWFuYWdlcnNTdHIJAQt2YWx1ZU9yRWxzZQIJAKIIAQUKa19NQU5BR0VSUwIABAhtYW5hZ2VycwkAtQkCBQttYW5hZ2Vyc1N0cgIBLAkBAiE9AgkAzwgCBQhtYW5hZ2VycwUDcGJrBQR1bml0ARBfaXNWYWxpZE9wZXJhdG9yAQNwYmsEC21hbmFnZXJzU3RyCQELdmFsdWVPckVsc2UCCQCiCAEFCmtfTUFOQUdFUlMCAAQIbWFuYWdlcnMJALUJAgULbWFuYWdlcnNTdHICASwEB2lzQWRtaW4JAQhfaXNBZG1pbgEFA3BiawQJaXNNYW5hZ2VyCQEKX2lzTWFuYWdlcgEFA3BiawMFB2lzQWRtaW4GBQlpc01hbmFnZXIBCnNhdmVUeERhdGECBnRhc2tJZARkYXRhBAdpbmRpY2VzCQDMCAIAAQkAzAgCAAIJAMwIAgADCQDMCAIABAkAzAgCAAUJAMwIAgAGCQDMCAIABwkAzAgCAAgJAMwIAgAJCQDMCAIACgUDbmlsBAhkYXRhU2l6ZQkAsQIBBQRkYXRhBAppc05vdEVtcHR5AwkBAiE9AgUIZGF0YVNpemUAAAYJAAIBAh1zYXZlVHhEYXRhOiBFbXB0eSBkYXRhIHBhc3NlZAMJAAACBQppc05vdEVtcHR5BQppc05vdEVtcHR5BAljaHVua1NpemUAsOoBBAtjaHVua3NDb3VudAMJAAACCQBqAgUIZGF0YVNpemUFCWNodW5rU2l6ZQAACQBpAgUIZGF0YVNpemUFCWNodW5rU2l6ZQkAZAIJAGkCBQhkYXRhU2l6ZQUJY2h1bmtTaXplAAEKAQptYWtlQ2h1bmtzAgVhY2N1bQVpbmRleAQFY2h1bmsJAK8CAggFBWFjY3VtAl8xBQljaHVua1NpemUDCQAAAgkAsQIBBQVjaHVuawAABQVhY2N1bQQIbmV4dERhdGEJALACAggFBWFjY3VtAl8xBQljaHVua1NpemUJAJQKAgUIbmV4dERhdGEJAM0IAggFBWFjY3VtAl8yCQELU3RyaW5nRW50cnkCCQCsAgIJAKwCAgUGdGFza0lkAglfX3R4ZGF0YV8JAKQDAQUFaW5kZXgFBWNodW5rBAdlbnRyaWVzCgACJGwFB2luZGljZXMKAAIkcwkAkAMBBQIkbAoABSRhY2MwCQCUCgIFBGRhdGEJAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICBQZ0YXNrSWQCD19fdHhkYXRhX2NodW5rcwkApAMBBQtjaHVua3NDb3VudAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQptYWtlQ2h1bmtzAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKCAUHZW50cmllcwJfMgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLhABaQEEaW5pdAMLYWRtaW5zX3Bia3MFbGltaXQNYXBwcm92ZWRDb3VudAMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECDlNlbGYgY2FsbCBvbmx5BAtzaXplX2FkbWlucwMJAQIhPQIJAJADAQULYWRtaW5zX3Bia3MAAAYJAAIBAidBdCBsZWFzdCBvbmUgYWRtaW4gcGJrIHNob3VsZCBiZSBwYXNzZWQDCQAAAgULc2l6ZV9hZG1pbnMFC3NpemVfYWRtaW5zBAxjaGVja19hZG1pbnMDCQEBIQEJAQlpc0RlZmluZWQBCQCiCAEFCGtfQURNSU5TBgkAAgECDkFscmVhZHkgaW5pdGVkAwkAAAIFDGNoZWNrX2FkbWlucwUMY2hlY2tfYWRtaW5zBAl6ZXJvTGltaXQDCQBmAgUFbGltaXQAAAYJAAIBAhNMaW1pdCBzaG91bGQgYmUgPiAwAwkAAAIFCXplcm9MaW1pdAUJemVyb0xpbWl0BAhsaW1pdF9vawMJAGYCCQCQAwEFC2FkbWluc19wYmtzBQVsaW1pdAYJAAIBCQCsAgIJAKwCAgkArAICAjlMaW1pdCBxdW9ydW0gc2hvdWxkIGJlIDw9IHNpemUgb2YgbGlzdCBvZiBhZG1pbnMsIGxpbWl0OiAJAKQDAQUFbGltaXQCECwgY3VycmVudCBzaXplOiAJAKQDAQkAkAMBBQthZG1pbnNfcGJrcwMJAAACBQhsaW1pdF9vawUIbGltaXRfb2sKAQh2YWxpZGF0ZQIFYWNjdW0EbmV4dAkBDF92YWxpZGF0ZVBiawEFBG5leHQECHZhbGlkUmVzCgACJGwFC2FkbWluc19wYmtzCgACJHMJAJADAQUCJGwKAAUkYWNjMAIACgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQh2YWxpZGF0ZQIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgMJAAACBQh2YWxpZFJlcwUIdmFsaWRSZXMECWFkbWluc1N0cgkAuQkCBQthZG1pbnNfcGJrcwIBLAkAzAgCCQELU3RyaW5nRW50cnkCBQhrX0FETUlOUwUJYWRtaW5zU3RyCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQdrX0xJTUlUBQVsaW1pdAkAzAgCCQEMSW50ZWdlckVudHJ5AgUQa19BUFBST1ZFRF9DT1VOVAUNYXBwcm92ZWRDb3VudAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCGFkZEFkbWluAQNwYmsECWNhbGxlclBiawkA2AQBCAUBaQ9jYWxsZXJQdWJsaWNLZXkEB2lzQWRtaW4DCQEIX2lzQWRtaW4BBQljYWxsZXJQYmsGCQACAQIZT25seSBhZG1pbnMgY2FuIGFkZCBhZG1pbgMJAAACBQdpc0FkbWluBQdpc0FkbWluBAdpc1ZhbGlkAwkBDF92YWxpZGF0ZVBiawEFA3BiawYJAAIBAhFJbnZhbGlkIGFkbWluIHBiawMJAAACBQdpc1ZhbGlkBQdpc1ZhbGlkBAxuZXdBZG1pbnNTdHIJAKwCAgkArAICCQERQGV4dHJOYXRpdmUoMTA1OCkBBQhrX0FETUlOUwIBLAUDcGJrCQDMCAIJAQtTdHJpbmdFbnRyeQIFCGtfQURNSU5TBQxuZXdBZG1pbnNTdHIFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQtyZW1vdmVBZG1pbgEDcGJrBAljYWxsZXJQYmsJANgEAQgFAWkPY2FsbGVyUHVibGljS2V5BAdpc0FkbWluAwkBCF9pc0FkbWluAQUJY2FsbGVyUGJrBgkAAgECGU9ubHkgYWRtaW5zIGNhbiBhZGQgYWRtaW4DCQAAAgUHaXNBZG1pbgUHaXNBZG1pbgQHaXNWYWxpZAMJAQxfdmFsaWRhdGVQYmsBBQNwYmsGCQACAQIRSW52YWxpZCBhZG1pbiBwYmsDCQAAAgUHaXNWYWxpZAUHaXNWYWxpZAQMb2xkQWRtaW5zU3RyCQERQGV4dHJOYXRpdmUoMTA1OCkBBQhrX0FETUlOUwQJb2xkQWRtaW5zCQC1CQIFDG9sZEFkbWluc1N0cgIBLAQKY2hlY2tDb3VudAMJAGcCAAEJAJADAQUJb2xkQWRtaW5zCQACAQIvQ2Fubm90IHJlbW92ZSwgYXQgbGVhc3Qgb25lIGFkbWluIHNob3VsZCByZW1haW4GAwkAAAIFCmNoZWNrQ291bnQFCmNoZWNrQ291bnQEBWluZGV4CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAM8IAgUJb2xkQWRtaW5zBQNwYmsCGFRoaXMgcGJrIGlzIG5vdCBhbiBhZG1pbgQJbmV3QWRtaW5zCQDRCAIFCW9sZEFkbWlucwUFaW5kZXgEDG5ld0FkbWluc1N0cgkAuQkCBQluZXdBZG1pbnMCASwJAMwIAgkBC1N0cmluZ0VudHJ5AgUIa19BRE1JTlMFDG5ld0FkbWluc1N0cgUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDWFkZFNjcmlwdFR5cGUBCnNjcmlwdFR5cGUECWNhbGxlclBiawkA2AQBCAUBaQ9jYWxsZXJQdWJsaWNLZXkDCQEBIQEJAQhfaXNBZG1pbgEFCWNhbGxlclBiawkAAgECC05vdCBhbGxvd2VkBApjaGVja0VtcHR5AwkAAAIJALECAQUKc2NyaXB0VHlwZQAACQACAQIcU2NyaXB0IHR5cGUgY2FuIG5vdCBiZSBlbXB0eQYDCQAAAgUKY2hlY2tFbXB0eQUKY2hlY2tFbXB0eQQOc2NyaXB0VHlwZXNTdHIJAQt2YWx1ZU9yRWxzZQIJAKIIAQUOa19TQ1JJUFRfVFlQRVMCAAQLc2NyaXB0VHlwZXMJALwJAgUOc2NyaXB0VHlwZXNTdHICASwEC2NoZWNrRXhpc3RzAwkBAiE9AgkAzwgCBQtzY3JpcHRUeXBlcwUKc2NyaXB0VHlwZQUEdW5pdAkAAgEJAKwCAgkArAICAg1TY3JpcHQgdHlwZSA8BQpzY3JpcHRUeXBlAg8+IGFscmVhZHkgYWRkZWQGAwkAAAIFC2NoZWNrRXhpc3RzBQtjaGVja0V4aXN0cwQObmV3U2NyaXB0VHlwZXMDCQECIT0CBQ5zY3JpcHRUeXBlc1N0cgIACQDNCAIFC3NjcmlwdFR5cGVzBQpzY3JpcHRUeXBlCQDMCAIFCnNjcmlwdFR5cGUFA25pbAQRbmV3U2NyaXB0VHlwZXNTdHIJALkJAgUObmV3U2NyaXB0VHlwZXMCASwJAMwIAgkBC1N0cmluZ0VudHJ5AgUOa19TQ1JJUFRfVFlQRVMFEW5ld1NjcmlwdFR5cGVzU3RyBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEQcmVtb3ZlU2NyaXB0VHlwZQEKc2NyaXB0VHlwZQQJY2FsbGVyUGJrCQDYBAEIBQFpD2NhbGxlclB1YmxpY0tleQMJAQEhAQkBCF9pc0FkbWluAQUJY2FsbGVyUGJrCQACAQILTm90IGFsbG93ZWQEDnNjcmlwdFR5cGVzU3RyCQELdmFsdWVPckVsc2UCCQCiCAEFDmtfU0NSSVBUX1RZUEVTAgAEC3NjcmlwdFR5cGVzCQC8CQIFDnNjcmlwdFR5cGVzU3RyAgEsBAVpbmRleAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQDPCAIFC3NjcmlwdFR5cGVzBQpzY3JpcHRUeXBlCQCsAgIJAKwCAgINU2NyaXB0IHR5cGUgPAUKc2NyaXB0VHlwZQIQPiBpcyBub3QgcHJlc2VudAQObmV3U2NyaXB0VHlwZXMJANEIAgULc2NyaXB0VHlwZXMFBWluZGV4BBFuZXdTY3JpcHRUeXBlc1N0cgkAuQkCBQ5uZXdTY3JpcHRUeXBlcwIBLAkAzAgCCQELU3RyaW5nRW50cnkCBQ5rX1NDUklQVF9UWVBFUwURbmV3U2NyaXB0VHlwZXNTdHIFA25pbAFpAQhzZXRMaW1pdAEFbGltaXQECWNhbGxlclBiawkA2AQBCAUBaQ9jYWxsZXJQdWJsaWNLZXkDCQEBIQEJAQhfaXNBZG1pbgEFCWNhbGxlclBiawkAAgECHk9ubHkgd2hpdGVsaXN0ZWQgY2FuIHNldCBsaW1pdAQJemVyb0xpbWl0AwkAZgIFBWxpbWl0AAAGCQACAQITTGltaXQgc2hvdWxkIGJlID4gMAMJAAACBQl6ZXJvTGltaXQFCXplcm9MaW1pdAQGYWRtaW5zCQERQGV4dHJOYXRpdmUoMTA1OCkBBQhrX0FETUlOUwMJAGYCBQVsaW1pdAkAsQIBBQZhZG1pbnMJAAIBCQCsAgIJAKwCAgkArAICAjlMaW1pdCBxdW9ydW0gc2hvdWxkIGJlIDw9IHNpemUgb2YgbGlzdCBvZiBhZG1pbnMsIGxpbWl0OiAJAKQDAQUFbGltaXQCECwgY3VycmVudCBzaXplOiAJAKQDAQkAsQIBBQZhZG1pbnMJAMwIAgkBDEludGVnZXJFbnRyeQIFB2tfTElNSVQFBWxpbWl0BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEJYWRkU2NyaXB0BgpzY3JpcHRUeXBlDnN0b3JhZ2VBZGRyZXNzC19zY3JpcHRIYXNoBGRlc2MMaW5pdGlhdG9yQWRyC3Jhd0NvZGVIYXNoBAljYWxsZXJQYmsJANgEAQgFAWkPY2FsbGVyUHVibGljS2V5AwkBASEBCQEQX2lzVmFsaWRPcGVyYXRvcgEFCWNhbGxlclBiawkAAgECC05vdCBhbGxvd2VkBBFzdG9yYWdlU2NyaXB0SGFzaAkA2AQBCQEFdmFsdWUBCQDxBwEJARFAZXh0ck5hdGl2ZSgxMDYyKQEFDnN0b3JhZ2VBZGRyZXNzBA5zY3JpcHRUeXBlc1N0cgkBEUBleHRyTmF0aXZlKDEwNTgpAQUOa19TQ1JJUFRfVFlQRVMEEV9jaGVja1NjcmlwdFR5cGVzAwkAAAIJALMJAgUOc2NyaXB0VHlwZXNTdHIFCnNjcmlwdFR5cGUFBHVuaXQJAAIBCQCsAgICNWludmFsaWQgc2NyaXB0IHR5cGUgb3IgaXQgaXMgbm90IHByZXNlbnQgaW4gc3RvcmFnZTogBQpzY3JpcHRUeXBlBgMJAAACBRFfY2hlY2tTY3JpcHRUeXBlcwURX2NoZWNrU2NyaXB0VHlwZXMEEF9zY3JpcHRUeXBlQ2hlY2sDCQECIT0CBRFzdG9yYWdlU2NyaXB0SGFzaAULX3NjcmlwdEhhc2gJAAIBAjRTdG9yZWQgYW5kIHBhc3NlZCBhcyBhcmd1bWVudCBzY3JpcHRIYXNoZXMgbm90IG1hdGNoBgMJAAACBRBfc2NyaXB0VHlwZUNoZWNrBRBfc2NyaXB0VHlwZUNoZWNrBApfZGVzY0NoZWNrAwkAAAIJALECAQUEZGVzYwAACQACAQIaRGVzY3JpcHRpb24gY2FuJ3QgYmUgZW1wdHkGAwkAAAIFCl9kZXNjQ2hlY2sFCl9kZXNjQ2hlY2sED19pbml0aWF0b3JDaGVjawMJAQIhPQIJAKUIAQkApwgBCAUBaQ9jYWxsZXJQdWJsaWNLZXkFDGluaXRpYXRvckFkcgkAAgECJkluaXRpYXRvciBhZGRyZXNzIGRvZXNuJ3QgbWF0Y2ggY2FsbGVyBgMJAAACBQ9faW5pdGlhdG9yQ2hlY2sFD19pbml0aWF0b3JDaGVjawQJaXRlcmF0aW9uCQBkAgkBC3ZhbHVlT3JFbHNlAgkAnwgBCQCsAgIJAKwCAgULa19JVEVSQVRJT04FA1NFUAUKc2NyaXB0VHlwZQAAAAEECHNjcmlwdElkCQCsAgIJAKwCAgkArAICAghzY3JpcHQlJQUKc2NyaXB0VHlwZQICJSUFC19zY3JpcHRIYXNoCQDMCAIJAQtTdHJpbmdFbnRyeQIJAKwCAgkArAICBQhzY3JpcHRJZAUGQklHU0VQBQxrX3NjcmlwdFR5cGUFCnNjcmlwdFR5cGUJAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICCQCsAgIFCHNjcmlwdElkBQZCSUdTRVAFEGtfc3RvcmFnZUFkZHJlc3MFDnN0b3JhZ2VBZGRyZXNzCQDMCAIJAQtTdHJpbmdFbnRyeQIJAKwCAgkArAICBQhzY3JpcHRJZAUGQklHU0VQBQxrX3NjcmlwdEhhc2gFEXN0b3JhZ2VTY3JpcHRIYXNoCQDMCAIJAQtTdHJpbmdFbnRyeQIJAKwCAgkArAICBQhzY3JpcHRJZAUGQklHU0VQBQZrX2Rlc2MFBGRlc2MJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICBQhzY3JpcHRJZAUGQklHU0VQBQZrX2l0ZXIFCWl0ZXJhdGlvbgkAzAgCCQELU3RyaW5nRW50cnkCCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgUKc2NyaXB0VHlwZQUGQklHU0VQBQZrX2l0ZXIFBkJJR1NFUAkApAMBBQlpdGVyYXRpb24CBl9faGFzaAULX3NjcmlwdEhhc2gJAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICCQCsAgIFCHNjcmlwdElkBQZCSUdTRVAFC2tfaW5pdGlhdG9yBQxpbml0aWF0b3JBZHIJAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICCQCsAgIFCHNjcmlwdElkBQZCSUdTRVAFDWtfcmF3Q29kZUhhc2gFC3Jhd0NvZGVIYXNoCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgULa19JVEVSQVRJT04FA1NFUAUKc2NyaXB0VHlwZQUJaXRlcmF0aW9uBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEMcmVtb3ZlU2NyaXB0AQhzY3JpcHRJZAQJY2FsbGVyUGJrCQDYBAEIBQFpD2NhbGxlclB1YmxpY0tleQMJAQEhAQkBEF9pc1ZhbGlkT3BlcmF0b3IBBQljYWxsZXJQYmsJAAIBAgtOb3QgYWxsb3dlZAQMaW5pdGlhdG9yQWRyCQERQGV4dHJOYXRpdmUoMTA1OCkBCQCsAgIFCHNjcmlwdElkAgtfX2luaXRpYXRvcgMJAQIhPQIFDGluaXRpYXRvckFkcgkApQgBCQCnCAEIBQFpD2NhbGxlclB1YmxpY0tleQkAAgECF09ubHkgY3JlYXRvciBjYW4gcmVtb3ZlBApzY3JpcHRUeXBlCQERQGV4dHJOYXRpdmUoMTA1OCkBCQCsAgIJAKwCAgUIc2NyaXB0SWQFBkJJR1NFUAUMa19zY3JpcHRUeXBlBAtfc2NyaXB0SGFzaAkBEUBleHRyTmF0aXZlKDEwNTgpAQkArAICCQCsAgIFCHNjcmlwdElkBQZCSUdTRVAFDGtfc2NyaXB0SGFzaAQEaXRlcgkBEUBleHRyTmF0aXZlKDEwNTUpAQkArAICCQCsAgIFCHNjcmlwdElkBQZCSUdTRVAFBmtfaXRlcgQOYXBwcm92ZWRIYXNoZXMJAQt2YWx1ZU9yRWxzZQIJAKIIAQkArAICCQCsAgICB3NjcmlwdF8FCnNjcmlwdFR5cGUCCl9fYXBwcm92ZWQCAAQOX2NoZWNrQXBwcm92ZWQDCQECIT0CCQCzCQIFDmFwcHJvdmVkSGFzaGVzBQtfc2NyaXB0SGFzaAUEdW5pdAkAAgECJ0NhbnQgcmVtb3ZlIGFwcHJvdmVkIHNjcmlwdCwgdXNlIHJldm9rZQYDCQAAAgUOX2NoZWNrQXBwcm92ZWQFDl9jaGVja0FwcHJvdmVkCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgkArAICBQhzY3JpcHRJZAUGQklHU0VQBQxrX3NjcmlwdFR5cGUJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICCQCsAgIFCHNjcmlwdElkBQZCSUdTRVAFEGtfc3RvcmFnZUFkZHJlc3MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICCQCsAgIFCHNjcmlwdElkBQZCSUdTRVAFDGtfc2NyaXB0SGFzaAkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgIJAKwCAgUIc2NyaXB0SWQFBkJJR1NFUAUGa19kZXNjCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgkArAICBQhzY3JpcHRJZAUGQklHU0VQBQZrX2l0ZXIJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICCQCsAgIJAKwCAgUKc2NyaXB0VHlwZQINX19pdGVyYXRpb25fXwkApAMBBQRpdGVyAgZfX2hhc2gJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICCQCsAgIFCHNjcmlwdElkBQZCSUdTRVAFC2tfaW5pdGlhdG9yCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgkArAICBQhzY3JpcHRJZAUGQklHU0VQBQ1rX3Jhd0NvZGVIYXNoCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgkArAICBQhzY3JpcHRJZAUGQklHU0VQBQ9rX2NvbmZpcm1hdGlvbnMFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARVhZGRDb25maXJtYXRpb25TY3JpcHQBCHNjcmlwdElkBAljYWxsZXJQYmsJANgEAQgFAWkPY2FsbGVyUHVibGljS2V5BAVsaW1pdAkBCV9nZXRMaW1pdAADCQEBIQEJAQhfaXNBZG1pbgEFCWNhbGxlclBiawkAAgECF09ubHkgYWRtaW5zIGNhbiBjb25maXJtBAtfc2NyaXB0SGFzaAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCiCAEJAKwCAgUIc2NyaXB0SWQCDF9fc2NyaXB0SGFzaAIPSXZhbGlkIHNjcmlwdElkAwkAAAIFC19zY3JpcHRIYXNoBQtfc2NyaXB0SGFzaAQKc2NyaXB0VHlwZQkBEUBleHRyTmF0aXZlKDEwNTgpAQkArAICBQhzY3JpcHRJZAIMX19zY3JpcHRUeXBlBBFhcHByb3ZlZEhhc2hlc1N0cgkBC3ZhbHVlT3JFbHNlAgkAoggBCQCsAgIJAKwCAgIHc2NyaXB0XwUKc2NyaXB0VHlwZQIKX19hcHByb3ZlZAIABA5fY2hlY2tBcHByb3ZlZAMJAQIhPQIJALMJAgURYXBwcm92ZWRIYXNoZXNTdHIFC19zY3JpcHRIYXNoBQR1bml0CQACAQIfVGhpcyBzY3JpcHQgaXMgYXBwcm92ZWQgYWxyZWFkeQYDCQAAAgUOX2NoZWNrQXBwcm92ZWQFDl9jaGVja0FwcHJvdmVkBA9nbG9iYWxJdGVyYXRpb24JAQt2YWx1ZU9yRWxzZQIJAJ8IAQkArAICCQCsAgIFC2tfSVRFUkFUSU9OBQNTRVAFCnNjcmlwdFR5cGUAAAQNdGhpc0l0ZXJhdGlvbgkBBXZhbHVlAQkAnwgBCQCsAgIFCHNjcmlwdElkAgtfX2l0ZXJhdGlvbgQQY29uZmlybWF0aW9uc1N0cgkBC3ZhbHVlT3JFbHNlAgkAoggBCQCsAgIFCHNjcmlwdElkAg9fX2NvbmZpcm1hdGlvbnMCAAQNY29uZmlybWF0aW9ucwkAtQkCBRBjb25maXJtYXRpb25zU3RyAgEsAwkBAiE9AgkAzwgCBQ1jb25maXJtYXRpb25zBQljYWxsZXJQYmsFBHVuaXQJAAIBAiFZb3UgYWxyZWFkeSBjb25maXJtZWQgdGhpcyBzY3JpcHQEB25ld0xpc3QDCQECIT0CBRBjb25maXJtYXRpb25zU3RyAgAJAM0IAgUNY29uZmlybWF0aW9ucwUJY2FsbGVyUGJrCQDMCAIFCWNhbGxlclBiawUDbmlsBApuZXdMaXN0U3RyCQC5CQIFB25ld0xpc3QCASwECGFwcHJvdmVkCQBnAgkAkAMBBQduZXdMaXN0BQVsaW1pdAQGcmVzdWx0AwUIYXBwcm92ZWQEDWFwcHJvdmVkQ291bnQJARFfZ2V0QXBwcm92ZWRDb3VudAAEDmFwcHJvdmVkSGFzaGVzCQC8CQIFEWFwcHJvdmVkSGFzaGVzU3RyAgEsBBFhcHByb3ZlZEhhc2hlc05ldwMJAQIhPQIFEWFwcHJvdmVkSGFzaGVzU3RyAgAJAM0IAgUOYXBwcm92ZWRIYXNoZXMFC19zY3JpcHRIYXNoCQDMCAIFC19zY3JpcHRIYXNoBQNuaWwDCQBmAgkAkAMBBRFhcHByb3ZlZEhhc2hlc05ldwUNYXBwcm92ZWRDb3VudAQMaGFzaFRvUmVtb3ZlCQCRAwIFEWFwcHJvdmVkSGFzaGVzTmV3AAAEEHNjcmlwdFRvUmVtb3ZlSWQJAKwCAgkArAICCQCsAgICCHNjcmlwdCUlBQpzY3JpcHRUeXBlAgIlJQULX3NjcmlwdEhhc2gEFmFwcHJvdmVkSGFzaGVzU3RyaXBwZWQJANEIAgURYXBwcm92ZWRIYXNoZXNOZXcAAAkAzAgCCQELU3RyaW5nRW50cnkCCQCsAgIJAKwCAgIHc2NyaXB0XwUKc2NyaXB0VHlwZQIKX19hcHByb3ZlZAkAugkCBRZhcHByb3ZlZEhhc2hlc1N0cmlwcGVkAgEsCQDMCAIJAQtTdHJpbmdFbnRyeQIJAKwCAgkArAICBRBzY3JpcHRUb1JlbW92ZUlkBQZCSUdTRVAFD2tfY29uZmlybWF0aW9ucwIABQNuaWwJAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICCQCsAgICB3NjcmlwdF8FCnNjcmlwdFR5cGUCCl9fYXBwcm92ZWQJALoJAgURYXBwcm92ZWRIYXNoZXNOZXcCASwFA25pbAUDbmlsCQDOCAIFBnJlc3VsdAkAzAgCCQELU3RyaW5nRW50cnkCCQCsAgIFCHNjcmlwdElkAg9fX2NvbmZpcm1hdGlvbnMFCm5ld0xpc3RTdHIFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARhyZXZva2VDb25maXJtYXRpb25TY3JpcHQBCHNjcmlwdElkBAljYWxsZXJQYmsJANgEAQgFAWkPY2FsbGVyUHVibGljS2V5BAVsaW1pdAkBCV9nZXRMaW1pdAADCQEBIQEJAQhfaXNBZG1pbgEFCWNhbGxlclBiawkAAgECFk9ubHkgYWRtaW5zIGNhbiByZXZva2UEC19zY3JpcHRIYXNoCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKIIAQkArAICBQhzY3JpcHRJZAIMX19zY3JpcHRIYXNoAhBJbnZhbGlkIHNjcmlwdElkAwkAAAIFC19zY3JpcHRIYXNoBQtfc2NyaXB0SGFzaAQKc2NyaXB0VHlwZQkBEUBleHRyTmF0aXZlKDEwNTgpAQkArAICBQhzY3JpcHRJZAIMX19zY3JpcHRUeXBlBBFhcHByb3ZlZEhhc2hlc1N0cgkBC3ZhbHVlT3JFbHNlAgkAoggBCQCsAgIJAKwCAgIHc2NyaXB0XwUKc2NyaXB0VHlwZQIKX19hcHByb3ZlZAIABA5hcHByb3ZlZEhhc2hlcwkAvAkCBRFhcHByb3ZlZEhhc2hlc1N0cgIBLAQQY29uZmlybWF0aW9uc1N0cgkBC3ZhbHVlT3JFbHNlAgkAoggBCQCsAgIFCHNjcmlwdElkAg9fX2NvbmZpcm1hdGlvbnMCAAQNY29uZmlybWF0aW9ucwkAtQkCBRBjb25maXJtYXRpb25zU3RyAgEsBAxjb25maXJtSW5kZXgJAM8IAgUNY29uZmlybWF0aW9ucwUJY2FsbGVyUGJrAwkAAAIFDGNvbmZpcm1JbmRleAUEdW5pdAkAAgECMVlvdSBkaWRuJ3QgY29uZmlybSB0aGlzIHNjcmlwdCwgbm90aGluZyB0byByZXZva2UEEG5ld0NvbmZpcm1hdGlvbnMJANEIAgUNY29uZmlybWF0aW9ucwkBBXZhbHVlAQUMY29uZmlybUluZGV4BBNuZXdDb25maXJtYXRpb25zU3RyCQC5CQIFEG5ld0NvbmZpcm1hdGlvbnMCASwEC3dhc0FwcHJvdmVkCQECIT0CCQDPCAIFDmFwcHJvdmVkSGFzaGVzBQtfc2NyaXB0SGFzaAUEdW5pdAQNc3RpbGxBcHByb3ZlZAkAZwIJAJADAQUQbmV3Q29uZmlybWF0aW9ucwUFbGltaXQEDHN0YXRlQ2hhbmdlcwMDBQt3YXNBcHByb3ZlZAkBASEBBQ1zdGlsbEFwcHJvdmVkBwQPc2NyaXB0SGFzaEluZGV4CQEFdmFsdWUBCQDPCAIFDmFwcHJvdmVkSGFzaGVzBQtfc2NyaXB0SGFzaAQRbmV3QXBwcm92ZWRIYXNoZXMJANEIAgUOYXBwcm92ZWRIYXNoZXMFD3NjcmlwdEhhc2hJbmRleAQUbmV3QXBwcm92ZWRIYXNoZXNTdHIJALkJAgURbmV3QXBwcm92ZWRIYXNoZXMCASwJAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICCQCsAgICB3NjcmlwdF8FCnNjcmlwdFR5cGUCCl9fYXBwcm92ZWQFFG5ld0FwcHJvdmVkSGFzaGVzU3RyBQNuaWwFA25pbAkAzggCBQxzdGF0ZUNoYW5nZXMJAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICBQhzY3JpcHRJZAIPX19jb25maXJtYXRpb25zBRNuZXdDb25maXJtYXRpb25zU3RyBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEHYWRkVGFzawcEbmFtZQRkYXBwBHR4aWQJZXhlY3V0ZVRzBGRlc2MMaW5pdGlhdG9yQWRyBnR4ZGF0YQQJY2FsbGVyUGJrCQDYBAEIBQFpD2NhbGxlclB1YmxpY0tleQMJAQEhAQkBEF9pc1ZhbGlkT3BlcmF0b3IBBQljYWxsZXJQYmsJAAIBAgtOb3QgYWxsb3dlZAQKX25hbWVDaGVjawMJAAACCQCxAgEFBG5hbWUAAAkAAgECE05hbWUgY2FuJ3QgYmUgZW1wdHkGAwkAAAIFCl9uYW1lQ2hlY2sFCl9uYW1lQ2hlY2sECl9kYXBwQ2hlY2sDCQEBIQEJARBfdmFsaWRhdGVBZGRyZXNzAQUEZGFwcAkAAgECDkluY29ycmVjdCBkYXBwBgMJAAACBQpfZGFwcENoZWNrBQpfZGFwcENoZWNrBApfdHhpZENoZWNrAwkAAAIJALECAQUEdHhpZAAACQACAQITdHhpZCBjYW4ndCBiZSBlbXB0eQYDCQAAAgUKX3R4aWRDaGVjawUKX3R4aWRDaGVjawQPX3RpbWVzdGFtcENoZWNrAwkBASEBCQELX3ZhbGlkYXRlVHMBBQlleGVjdXRlVHMJAAIBAkRJbnZhbGlkIGV4ZWN1dGlvbiB0aW1lc3RhbXAgLSBjYW5ub3QgYmUgbW9yZSB0aGFuIDEgaG91ciBpbiB0aGUgcGFzdAYDCQAAAgUPX3RpbWVzdGFtcENoZWNrBQ9fdGltZXN0YW1wQ2hlY2sECl9kZXNjQ2hlY2sDCQAAAgkAsQIBBQRkZXNjAAAJAAIBAhpEZXNjcmlwdGlvbiBjYW4ndCBiZSBlbXB0eQYDCQAAAgUKX2Rlc2NDaGVjawUKX2Rlc2NDaGVjawQPX2luaXRpYXRvckNoZWNrAwkBAiE9AgkApQgBCQCnCAEIBQFpD2NhbGxlclB1YmxpY0tleQUMaW5pdGlhdG9yQWRyCQACAQImSW5pdGlhdG9yIGFkZHJlc3MgZG9lc24ndCBtYXRjaCBjYWxsZXIGAwkAAAIFD19pbml0aWF0b3JDaGVjawUPX2luaXRpYXRvckNoZWNrBAxfdHhkYXRhQ2hlY2sDCQAAAgkAsQIBBQZ0eGRhdGEAAAkAAgECFlR4IGRhdGEgY2FuJ3QgYmUgZW1wdHkGAwkAAAIFDF90eGRhdGFDaGVjawUMX3R4ZGF0YUNoZWNrBAZ0YXNrSWQJAKwCAgkArAICCQCsAgICA3R4XwUEZGFwcAUDU0VQBQR0eGlkCQDMCAIJAQtTdHJpbmdFbnRyeQIJAKwCAgUGdGFza0lkAgZfX25hbWUFBG5hbWUJAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICBQZ0YXNrSWQCBl9fZGFwcAUEZGFwcAkAzAgCCQELU3RyaW5nRW50cnkCCQCsAgIFBnRhc2tJZAIGX190eElkBQR0eGlkCQDMCAIJAQtTdHJpbmdFbnRyeQIJAKwCAgUGdGFza0lkAgZfX2Rlc2MFBGRlc2MJAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICBQZ0YXNrSWQCCF9fdHhkYXRhBQZ0eGRhdGEJAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICBQZ0YXNrSWQCC19faW5pdGlhdG9yBQxpbml0aWF0b3JBZHIJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgUGdGFza0lkAgRfX3RzBQlleGVjdXRlVHMFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQpyZW1vdmVUYXNrAQZ0YXNrSWQECWNhbGxlclBiawkA2AQBCAUBaQ9jYWxsZXJQdWJsaWNLZXkDCQEBIQEJARBfaXNWYWxpZE9wZXJhdG9yAQUJY2FsbGVyUGJrCQACAQILTm90IGFsbG93ZWQEDGluaXRpYXRvckFkcgkBEUBleHRyTmF0aXZlKDEwNTgpAQkArAICBQZ0YXNrSWQCC19faW5pdGlhdG9yAwkBAiE9AgUMaW5pdGlhdG9yQWRyCQClCAEJAKcIAQgFAWkPY2FsbGVyUHVibGljS2V5CQACAQIXT25seSBjcmVhdG9yIGNhbiByZW1vdmUJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICBQZ0YXNrSWQCBl9fbmFtZQkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgIFBnRhc2tJZAIGX19kYXBwCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgUGdGFza0lkAgZfX3R4SWQJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICBQZ0YXNrSWQCBl9fZGVzYwkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgIFBnRhc2tJZAIIX190eGRhdGEJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICBQZ0YXNrSWQCC19faW5pdGlhdG9yCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgUGdGFza0lkAgRfX3RzCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgUGdGFza0lkAg9fX2NvbmZpcm1hdGlvbnMJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICBQZ0YXNrSWQCCl9fYXBwcm92ZWQFA25pbAFpAQ9hZGRDb25maXJtYXRpb24BBnRhc2tJZAQJY2FsbGVyUGJrCQDYBAEIBQFpD2NhbGxlclB1YmxpY0tleQQFbGltaXQJAQlfZ2V0TGltaXQAAwkBASEBCQEIX2lzQWRtaW4BBQljYWxsZXJQYmsJAAIBAhdPbmx5IGFkbWlucyBjYW4gY29uZmlybQQEdHhJZAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCiCAEJAKwCAgUGdGFza0lkAgZfX3R4SWQCC0l2YWxpZCB0YXNrAwkAAAIFBHR4SWQFBHR4SWQEBGRhcHAJARFAZXh0ck5hdGl2ZSgxMDU4KQEJAKwCAgUGdGFza0lkAgZfX2RhcHAEEGNvbmZpcm1hdGlvbnNTdHIJAQt2YWx1ZU9yRWxzZQIJAKIIAQkArAICBQZ0YXNrSWQCD19fY29uZmlybWF0aW9ucwIABA1jb25maXJtYXRpb25zCQC1CQIFEGNvbmZpcm1hdGlvbnNTdHICASwDCQECIT0CCQDPCAIFDWNvbmZpcm1hdGlvbnMFCWNhbGxlclBiawUEdW5pdAkAAgECH1lvdSBhbHJlYWR5IGNvbmZpcm1lZCB0aGlzIHRhc2sEB25ld0xpc3QDCQECIT0CBRBjb25maXJtYXRpb25zU3RyAgAJAM0IAgUNY29uZmlybWF0aW9ucwUJY2FsbGVyUGJrCQDMCAIFCWNhbGxlclBiawUDbmlsBApuZXdMaXN0U3RyCQC5CQIFB25ld0xpc3QCASwECGFwcHJvdmVkCQBnAgkAkAMBBQduZXdMaXN0BQVsaW1pdAkAzAgCCQELU3RyaW5nRW50cnkCCQCsAgIFBnRhc2tJZAIPX19jb25maXJtYXRpb25zBQpuZXdMaXN0U3RyCQDMCAIJAQxCb29sZWFuRW50cnkCCQCsAgIJAKwCAgkArAICBQRkYXBwBQNTRVAFBHR4SWQCCl9fYXBwcm92ZWQFCGFwcHJvdmVkBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEKcmV2b2tlVGFzawEGdGFza0lkBAljYWxsZXJQYmsJANgEAQgFAWkPY2FsbGVyUHVibGljS2V5BAVsaW1pdAkBCV9nZXRMaW1pdAADCQEBIQEJAQhfaXNBZG1pbgEFCWNhbGxlclBiawkAAgECFE9ubHkgYWRtaW5zIGNhbiBjYWxsBAR0eElkCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKIIAQkArAICBQZ0YXNrSWQCBl9fdHhJZAILSXZhbGlkIHRhc2sDCQAAAgUEdHhJZAUEdHhJZAQQY29uZmlybWF0aW9uc1N0cgkBC3ZhbHVlT3JFbHNlAgkAoggBCQCsAgIFBnRhc2tJZAIPX19jb25maXJtYXRpb25zAgAEDWNvbmZpcm1hdGlvbnMJALUJAgUQY29uZmlybWF0aW9uc1N0cgIBLAQHaW5kZXhNeQkAzwgCBQ1jb25maXJtYXRpb25zBQljYWxsZXJQYmsDCQAAAgUHaW5kZXhNeQUEdW5pdAkAAgECMFlvdSBkaWQgbm90IGNvbmZpcm0gdGhpcyB0YXNrLCBub3RoaW5nIHRvIHJldm9rZQQEZGFwcAkBEUBleHRyTmF0aXZlKDEwNTgpAQkArAICBQZ0YXNrSWQCBl9fZGFwcAQHbmV3TGlzdAkA0QgCBQ1jb25maXJtYXRpb25zCQEFdmFsdWUBBQdpbmRleE15BApuZXdMaXN0U3RyCQC5CQIFB25ld0xpc3QCASwECGFwcHJvdmVkCQBnAgkAkAMBBQduZXdMaXN0BQVsaW1pdAkAzAgCCQELU3RyaW5nRW50cnkCCQCsAgIFBnRhc2tJZAIPX19jb25maXJtYXRpb25zBQpuZXdMaXN0U3RyCQDMCAIJAQxCb29sZWFuRW50cnkCCQCsAgIJAKwCAgkArAICBQRkYXBwBQNTRVAFBHR4SWQCCl9fYXBwcm92ZWQFCGFwcHJvdmVkBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEEdGVzdAAEAXgEByRtYXRjaDAJAO0HAQUGaGVpZ2h0AwkAAQIFByRtYXRjaDACCUJsb2NrSW5mbwQFYmxvY2sFByRtYXRjaDAJAAIBCQCkAwEIBQVibG9jawl0aW1lc3RhbXAJAAIBAhBDYW4ndCBmaW5kIGJsb2NrAwkAAAIFAXgFAXgFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQpjbGVhcl90ZXN0AAQHaW5kaWNlcwkAzAgCAAEJAMwIAgACCQDMCAIAAwkAzAgCAAQJAMwIAgAFCQDMCAIABgkAzAgCAAcJAMwIAgAICQDMCAIACQkAzAgCAAoFA25pbAoBDHJlbW92ZUNodW5rcwIFYWNjdW0FaW5kZXgJAM0IAgUFYWNjdW0JAQtEZWxldGVFbnRyeQEJAKwCAgkArAICAgh0ZXN0dGFzawIJX190eGRhdGFfCQCkAwEFBWluZGV4BAdlbnRyaWVzCgACJGwFB2luZGljZXMKAAIkcwkAkAMBBQIkbAoABSRhY2MwCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgIIdGVzdHRhc2sCD19fdHhkYXRhX2NodW5rcwUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQxyZW1vdmVDaHVua3MCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEwCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoFB2VudHJpZXMBAnR4AQZ2ZXJpZnkABBBNVUxUSVNJR19BRERSRVNTCQCmCAECIzNNN3V6RDhyVDU0ZktRY1A0czQxN2lmMVZLVTh5cm9tRVAyBA1DT05UUkFDVF9UWVBFAhFBUFBST1ZFUl9DT05UUkFDVAMJAQIhPQIFEE1VTFRJU0lHX0FERFJFU1MFBHVuaXQEByRtYXRjaDAFAnR4AwkAAQIFByRtYXRjaDACFFNldFNjcmlwdFRyYW5zYWN0aW9uBAN0dHgFByRtYXRjaDAEC3NjcmlwdEhhc2hhCQDYBAEJAQV2YWx1ZQEJAPYDAQkBBXZhbHVlAQgFA3R0eAZzY3JpcHQEDmFwcHJvdmVkSGFzaGVzCQEFdmFsdWUBCQCdCAIJAQV2YWx1ZQEFEE1VTFRJU0lHX0FERFJFU1MJAKwCAgkArAICAgdzY3JpcHRfBQ1DT05UUkFDVF9UWVBFAgpfX2FwcHJvdmVkCQECIT0CCQCzCQIFDmFwcHJvdmVkSGFzaGVzBQtzY3JpcHRIYXNoYQUEdW5pdAQDb3R4BQckbWF0Y2gwCQELdmFsdWVPckVsc2UCCQCbCAIJAQV2YWx1ZQEFEE1VTFRJU0lHX0FERFJFU1MJAKwCAgkArAICCQCsAgIJAKUIAQUEdGhpcwIBXwkA2AQBCAUDb3R4AmlkAgpfX2FwcHJvdmVkBwkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAAgFAnR4D3NlbmRlclB1YmxpY0tleWDBNmE=", "height": 551439, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: CNfBwEk4R4WwfHoYVxm9C8AKyG1gKJckBzfSRgzkmJ8z Next: 8oz4SpfzMQw8UQ9VHetB7gq3LQ21mDqswNB4h8jvwb41 Diff:
OldNewDifferences
301301 let newScriptTypes = removeByIndex(scriptTypes, index)
302302 let newScriptTypesStr = makeString(newScriptTypes, ",")
303303 [StringEntry(k_SCRIPT_TYPES, newScriptTypesStr)]
304+ }
305+ }
306+
307+
308+
309+@Callable(i)
310+func setLimit (limit) = {
311+ let callerPbk = toBase58String(i.callerPublicKey)
312+ if (!(_isAdmin(callerPbk)))
313+ then throw("Only whitelisted can set limit")
314+ else {
315+ let zeroLimit = if ((limit > 0))
316+ then true
317+ else throw("Limit should be > 0")
318+ if ((zeroLimit == zeroLimit))
319+ then {
320+ let admins = getStringValue(k_ADMINS)
321+ if ((limit > size(admins)))
322+ then throw(((("Limit quorum should be <= size of list of admins, limit: " + toString(limit)) + ", current size: ") + toString(size(admins))))
323+ else [IntegerEntry(k_LIMIT, limit)]
324+ }
325+ else throw("Strict value is not equal to itself.")
304326 }
305327 }
306328
612634
613635
614636 @Callable(i)
615-func setLimit (limit) = {
616- let callerPbk = toBase58String(i.callerPublicKey)
617- if (!(_isAdmin(callerPbk)))
618- then throw("Only whitelisted can set limit")
619- else {
620- let zeroLimit = if ((limit > 0))
621- then true
622- else throw("Limit should be > 0")
623- if ((zeroLimit == zeroLimit))
624- then {
625- let admins = getStringValue(k_ADMINS)
626- if ((limit > size(admins)))
627- then throw(((("Limit quorum should be <= size of list of admins, limit: " + toString(limit)) + ", current size: ") + toString(size(admins))))
628- else [IntegerEntry(k_LIMIT, limit)]
629- }
630- else throw("Strict value is not equal to itself.")
631- }
632- }
633-
634-
635-
636-@Callable(i)
637637 func test () = {
638638 let x = match blockInfoByHeight(height) {
639639 case block: BlockInfo =>
671671 }
672672
673673
674+@Verifier(tx)
675+func verify () = {
676+ let MULTISIG_ADDRESS = addressFromString("3M7uzD8rT54fKQcP4s417if1VKU8yromEP2")
677+ let CONTRACT_TYPE = "APPROVER_CONTRACT"
678+ if ((MULTISIG_ADDRESS != unit))
679+ then match tx {
680+ case ttx: SetScriptTransaction =>
681+ let scriptHasha = toBase58String(value(blake2b256(value(ttx.script))))
682+ let approvedHashes = value(getString(value(MULTISIG_ADDRESS), (("script_" + CONTRACT_TYPE) + "__approved")))
683+ (indexOf(approvedHashes, scriptHasha) != unit)
684+ case otx =>
685+ valueOrElse(getBoolean(value(MULTISIG_ADDRESS), (((toString(this) + "_") + toBase58String(otx.id)) + "__approved")), false)
686+ }
687+ else sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
688+ }
689+
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let VERSION = "1.0.0"
55
66 let SEP = "_"
77
88 let BIGSEP = "__"
99
1010 let k_ADMINS = "ADMINS_PBKS"
1111
1212 let k_MANAGERS = "MANAGERS_PBKS"
1313
1414 let k_LIMIT = "VOTES_QUORUM"
1515
1616 let k_SCRIPT_TYPES = "SCRIPT_TYPES"
1717
1818 let k_ITERATION = "ITERATION"
1919
2020 let k_APPROVED_COUNT = "APPROVED_COUNT"
2121
2222 let k_scriptType = "scriptType"
2323
2424 let k_scriptHash = "scriptHash"
2525
2626 let k_storageAddress = "storageAddress"
2727
2828 let k_desc = "desc"
2929
3030 let k_iter = "iteration"
3131
3232 let k_initiator = "initiator"
3333
3434 let k_confirmations = "confirmations"
3535
3636 let k_rawCodeHash = "rawCodeHash"
3737
3838 func _validatePbk (pbk) = {
3939 let address = addressFromPublicKey(fromBase58String(pbk))
4040 if ((address == address))
4141 then {
4242 let addressStr = toString(address)
4343 if ((addressStr == addressStr))
4444 then true
4545 else throw("Strict value is not equal to itself.")
4646 }
4747 else throw("Strict value is not equal to itself.")
4848 }
4949
5050
5151 func _validateAddress (address) = {
5252 let addr = addressFromStringValue(address)
5353 if ((addr == addr))
5454 then true
5555 else throw("Strict value is not equal to itself.")
5656 }
5757
5858
5959 func _validateTs (ts) = {
6060 let currTs = match blockInfoByHeight(height) {
6161 case block: BlockInfo =>
6262 block.timestamp
6363 case _ =>
6464 throw("Can't find block")
6565 }
6666 let oneHour = ((60 * 60) * 1000)
6767 let minTs = (currTs - oneHour)
6868 (ts >= minTs)
6969 }
7070
7171
7272 func _getLimit () = valueOrErrorMessage(getInteger(k_LIMIT), "Quorum limit not defined")
7373
7474
7575 func _getApprovedCount () = valueOrErrorMessage(getInteger(k_APPROVED_COUNT), "Amount of simultaneously approved scripts not defined")
7676
7777
7878 func _isAdmin (pbk) = {
7979 let adminsStr = valueOrElse(getString(k_ADMINS), "")
8080 let admins = split(adminsStr, ",")
8181 (indexOf(admins, pbk) != unit)
8282 }
8383
8484
8585 func _isManager (pbk) = {
8686 let managersStr = valueOrElse(getString(k_MANAGERS), "")
8787 let managers = split(managersStr, ",")
8888 (indexOf(managers, pbk) != unit)
8989 }
9090
9191
9292 func _isValidOperator (pbk) = {
9393 let managersStr = valueOrElse(getString(k_MANAGERS), "")
9494 let managers = split(managersStr, ",")
9595 let isAdmin = _isAdmin(pbk)
9696 let isManager = _isManager(pbk)
9797 if (isAdmin)
9898 then true
9999 else isManager
100100 }
101101
102102
103103 func saveTxData (taskId,data) = {
104104 let indices = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
105105 let dataSize = size(data)
106106 let isNotEmpty = if ((dataSize != 0))
107107 then true
108108 else throw("saveTxData: Empty data passed")
109109 if ((isNotEmpty == isNotEmpty))
110110 then {
111111 let chunkSize = 30000
112112 let chunksCount = if (((dataSize % chunkSize) == 0))
113113 then (dataSize / chunkSize)
114114 else ((dataSize / chunkSize) + 1)
115115 func makeChunks (accum,index) = {
116116 let chunk = take(accum._1, chunkSize)
117117 if ((size(chunk) == 0))
118118 then accum
119119 else {
120120 let nextData = drop(accum._1, chunkSize)
121121 $Tuple2(nextData, (accum._2 :+ StringEntry(((taskId + "__txdata_") + toString(index)), chunk)))
122122 }
123123 }
124124
125125 let entries = {
126126 let $l = indices
127127 let $s = size($l)
128128 let $acc0 = $Tuple2(data, [StringEntry((taskId + "__txdata_chunks"), toString(chunksCount))])
129129 func $f0_1 ($a,$i) = if (($i >= $s))
130130 then $a
131131 else makeChunks($a, $l[$i])
132132
133133 func $f0_2 ($a,$i) = if (($i >= $s))
134134 then $a
135135 else throw("List size exceeds 10")
136136
137137 $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
138138 }
139139 entries._2
140140 }
141141 else throw("Strict value is not equal to itself.")
142142 }
143143
144144
145145 @Callable(i)
146146 func init (admins_pbks,limit,approvedCount) = if ((i.caller != this))
147147 then throw("Self call only")
148148 else {
149149 let size_admins = if ((size(admins_pbks) != 0))
150150 then true
151151 else throw("At least one admin pbk should be passed")
152152 if ((size_admins == size_admins))
153153 then {
154154 let check_admins = if (!(isDefined(getString(k_ADMINS))))
155155 then true
156156 else throw("Already inited")
157157 if ((check_admins == check_admins))
158158 then {
159159 let zeroLimit = if ((limit > 0))
160160 then true
161161 else throw("Limit should be > 0")
162162 if ((zeroLimit == zeroLimit))
163163 then {
164164 let limit_ok = if ((size(admins_pbks) > limit))
165165 then true
166166 else throw(((("Limit quorum should be <= size of list of admins, limit: " + toString(limit)) + ", current size: ") + toString(size(admins_pbks))))
167167 if ((limit_ok == limit_ok))
168168 then {
169169 func validate (accum,next) = _validatePbk(next)
170170
171171 let validRes = {
172172 let $l = admins_pbks
173173 let $s = size($l)
174174 let $acc0 = ""
175175 func $f0_1 ($a,$i) = if (($i >= $s))
176176 then $a
177177 else validate($a, $l[$i])
178178
179179 func $f0_2 ($a,$i) = if (($i >= $s))
180180 then $a
181181 else throw("List size exceeds 10")
182182
183183 $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
184184 }
185185 if ((validRes == validRes))
186186 then {
187187 let adminsStr = makeString(admins_pbks, ",")
188188 [StringEntry(k_ADMINS, adminsStr), IntegerEntry(k_LIMIT, limit), IntegerEntry(k_APPROVED_COUNT, approvedCount)]
189189 }
190190 else throw("Strict value is not equal to itself.")
191191 }
192192 else throw("Strict value is not equal to itself.")
193193 }
194194 else throw("Strict value is not equal to itself.")
195195 }
196196 else throw("Strict value is not equal to itself.")
197197 }
198198 else throw("Strict value is not equal to itself.")
199199 }
200200
201201
202202
203203 @Callable(i)
204204 func addAdmin (pbk) = {
205205 let callerPbk = toBase58String(i.callerPublicKey)
206206 let isAdmin = if (_isAdmin(callerPbk))
207207 then true
208208 else throw("Only admins can add admin")
209209 if ((isAdmin == isAdmin))
210210 then {
211211 let isValid = if (_validatePbk(pbk))
212212 then true
213213 else throw("Invalid admin pbk")
214214 if ((isValid == isValid))
215215 then {
216216 let newAdminsStr = ((getStringValue(k_ADMINS) + ",") + pbk)
217217 [StringEntry(k_ADMINS, newAdminsStr)]
218218 }
219219 else throw("Strict value is not equal to itself.")
220220 }
221221 else throw("Strict value is not equal to itself.")
222222 }
223223
224224
225225
226226 @Callable(i)
227227 func removeAdmin (pbk) = {
228228 let callerPbk = toBase58String(i.callerPublicKey)
229229 let isAdmin = if (_isAdmin(callerPbk))
230230 then true
231231 else throw("Only admins can add admin")
232232 if ((isAdmin == isAdmin))
233233 then {
234234 let isValid = if (_validatePbk(pbk))
235235 then true
236236 else throw("Invalid admin pbk")
237237 if ((isValid == isValid))
238238 then {
239239 let oldAdminsStr = getStringValue(k_ADMINS)
240240 let oldAdmins = split(oldAdminsStr, ",")
241241 let checkCount = if ((1 >= size(oldAdmins)))
242242 then throw("Cannot remove, at least one admin should remain")
243243 else true
244244 if ((checkCount == checkCount))
245245 then {
246246 let index = valueOrErrorMessage(indexOf(oldAdmins, pbk), "This pbk is not an admin")
247247 let newAdmins = removeByIndex(oldAdmins, index)
248248 let newAdminsStr = makeString(newAdmins, ",")
249249 [StringEntry(k_ADMINS, newAdminsStr)]
250250 }
251251 else throw("Strict value is not equal to itself.")
252252 }
253253 else throw("Strict value is not equal to itself.")
254254 }
255255 else throw("Strict value is not equal to itself.")
256256 }
257257
258258
259259
260260 @Callable(i)
261261 func addScriptType (scriptType) = {
262262 let callerPbk = toBase58String(i.callerPublicKey)
263263 if (!(_isAdmin(callerPbk)))
264264 then throw("Not allowed")
265265 else {
266266 let checkEmpty = if ((size(scriptType) == 0))
267267 then throw("Script type can not be empty")
268268 else true
269269 if ((checkEmpty == checkEmpty))
270270 then {
271271 let scriptTypesStr = valueOrElse(getString(k_SCRIPT_TYPES), "")
272272 let scriptTypes = split_4C(scriptTypesStr, ",")
273273 let checkExists = if ((indexOf(scriptTypes, scriptType) != unit))
274274 then throw((("Script type <" + scriptType) + "> already added"))
275275 else true
276276 if ((checkExists == checkExists))
277277 then {
278278 let newScriptTypes = if ((scriptTypesStr != ""))
279279 then (scriptTypes :+ scriptType)
280280 else [scriptType]
281281 let newScriptTypesStr = makeString(newScriptTypes, ",")
282282 [StringEntry(k_SCRIPT_TYPES, newScriptTypesStr)]
283283 }
284284 else throw("Strict value is not equal to itself.")
285285 }
286286 else throw("Strict value is not equal to itself.")
287287 }
288288 }
289289
290290
291291
292292 @Callable(i)
293293 func removeScriptType (scriptType) = {
294294 let callerPbk = toBase58String(i.callerPublicKey)
295295 if (!(_isAdmin(callerPbk)))
296296 then throw("Not allowed")
297297 else {
298298 let scriptTypesStr = valueOrElse(getString(k_SCRIPT_TYPES), "")
299299 let scriptTypes = split_4C(scriptTypesStr, ",")
300300 let index = valueOrErrorMessage(indexOf(scriptTypes, scriptType), (("Script type <" + scriptType) + "> is not present"))
301301 let newScriptTypes = removeByIndex(scriptTypes, index)
302302 let newScriptTypesStr = makeString(newScriptTypes, ",")
303303 [StringEntry(k_SCRIPT_TYPES, newScriptTypesStr)]
304+ }
305+ }
306+
307+
308+
309+@Callable(i)
310+func setLimit (limit) = {
311+ let callerPbk = toBase58String(i.callerPublicKey)
312+ if (!(_isAdmin(callerPbk)))
313+ then throw("Only whitelisted can set limit")
314+ else {
315+ let zeroLimit = if ((limit > 0))
316+ then true
317+ else throw("Limit should be > 0")
318+ if ((zeroLimit == zeroLimit))
319+ then {
320+ let admins = getStringValue(k_ADMINS)
321+ if ((limit > size(admins)))
322+ then throw(((("Limit quorum should be <= size of list of admins, limit: " + toString(limit)) + ", current size: ") + toString(size(admins))))
323+ else [IntegerEntry(k_LIMIT, limit)]
324+ }
325+ else throw("Strict value is not equal to itself.")
304326 }
305327 }
306328
307329
308330
309331 @Callable(i)
310332 func addScript (scriptType,storageAddress,_scriptHash,desc,initiatorAdr,rawCodeHash) = {
311333 let callerPbk = toBase58String(i.callerPublicKey)
312334 if (!(_isValidOperator(callerPbk)))
313335 then throw("Not allowed")
314336 else {
315337 let storageScriptHash = toBase58String(value(scriptHash(addressFromStringValue(storageAddress))))
316338 let scriptTypesStr = getStringValue(k_SCRIPT_TYPES)
317339 let _checkScriptTypes = if ((indexOf(scriptTypesStr, scriptType) == unit))
318340 then throw(("invalid script type or it is not present in storage: " + scriptType))
319341 else true
320342 if ((_checkScriptTypes == _checkScriptTypes))
321343 then {
322344 let _scriptTypeCheck = if ((storageScriptHash != _scriptHash))
323345 then throw("Stored and passed as argument scriptHashes not match")
324346 else true
325347 if ((_scriptTypeCheck == _scriptTypeCheck))
326348 then {
327349 let _descCheck = if ((size(desc) == 0))
328350 then throw("Description can't be empty")
329351 else true
330352 if ((_descCheck == _descCheck))
331353 then {
332354 let _initiatorCheck = if ((toString(addressFromPublicKey(i.callerPublicKey)) != initiatorAdr))
333355 then throw("Initiator address doesn't match caller")
334356 else true
335357 if ((_initiatorCheck == _initiatorCheck))
336358 then {
337359 let iteration = (valueOrElse(getInteger(((k_ITERATION + SEP) + scriptType)), 0) + 1)
338360 let scriptId = ((("script%%" + scriptType) + "%%") + _scriptHash)
339361 [StringEntry(((scriptId + BIGSEP) + k_scriptType), scriptType), StringEntry(((scriptId + BIGSEP) + k_storageAddress), storageAddress), StringEntry(((scriptId + BIGSEP) + k_scriptHash), storageScriptHash), StringEntry(((scriptId + BIGSEP) + k_desc), desc), IntegerEntry(((scriptId + BIGSEP) + k_iter), iteration), StringEntry((((((scriptType + BIGSEP) + k_iter) + BIGSEP) + toString(iteration)) + "__hash"), _scriptHash), StringEntry(((scriptId + BIGSEP) + k_initiator), initiatorAdr), StringEntry(((scriptId + BIGSEP) + k_rawCodeHash), rawCodeHash), IntegerEntry(((k_ITERATION + SEP) + scriptType), iteration)]
340362 }
341363 else throw("Strict value is not equal to itself.")
342364 }
343365 else throw("Strict value is not equal to itself.")
344366 }
345367 else throw("Strict value is not equal to itself.")
346368 }
347369 else throw("Strict value is not equal to itself.")
348370 }
349371 }
350372
351373
352374
353375 @Callable(i)
354376 func removeScript (scriptId) = {
355377 let callerPbk = toBase58String(i.callerPublicKey)
356378 if (!(_isValidOperator(callerPbk)))
357379 then throw("Not allowed")
358380 else {
359381 let initiatorAdr = getStringValue((scriptId + "__initiator"))
360382 if ((initiatorAdr != toString(addressFromPublicKey(i.callerPublicKey))))
361383 then throw("Only creator can remove")
362384 else {
363385 let scriptType = getStringValue(((scriptId + BIGSEP) + k_scriptType))
364386 let _scriptHash = getStringValue(((scriptId + BIGSEP) + k_scriptHash))
365387 let iter = getIntegerValue(((scriptId + BIGSEP) + k_iter))
366388 let approvedHashes = valueOrElse(getString((("script_" + scriptType) + "__approved")), "")
367389 let _checkApproved = if ((indexOf(approvedHashes, _scriptHash) != unit))
368390 then throw("Cant remove approved script, use revoke")
369391 else true
370392 if ((_checkApproved == _checkApproved))
371393 then [DeleteEntry(((scriptId + BIGSEP) + k_scriptType)), DeleteEntry(((scriptId + BIGSEP) + k_storageAddress)), DeleteEntry(((scriptId + BIGSEP) + k_scriptHash)), DeleteEntry(((scriptId + BIGSEP) + k_desc)), DeleteEntry(((scriptId + BIGSEP) + k_iter)), DeleteEntry((((scriptType + "__iteration__") + toString(iter)) + "__hash")), DeleteEntry(((scriptId + BIGSEP) + k_initiator)), DeleteEntry(((scriptId + BIGSEP) + k_rawCodeHash)), DeleteEntry(((scriptId + BIGSEP) + k_confirmations))]
372394 else throw("Strict value is not equal to itself.")
373395 }
374396 }
375397 }
376398
377399
378400
379401 @Callable(i)
380402 func addConfirmationScript (scriptId) = {
381403 let callerPbk = toBase58String(i.callerPublicKey)
382404 let limit = _getLimit()
383405 if (!(_isAdmin(callerPbk)))
384406 then throw("Only admins can confirm")
385407 else {
386408 let _scriptHash = valueOrErrorMessage(getString((scriptId + "__scriptHash")), "Ivalid scriptId")
387409 if ((_scriptHash == _scriptHash))
388410 then {
389411 let scriptType = getStringValue((scriptId + "__scriptType"))
390412 let approvedHashesStr = valueOrElse(getString((("script_" + scriptType) + "__approved")), "")
391413 let _checkApproved = if ((indexOf(approvedHashesStr, _scriptHash) != unit))
392414 then throw("This script is approved already")
393415 else true
394416 if ((_checkApproved == _checkApproved))
395417 then {
396418 let globalIteration = valueOrElse(getInteger(((k_ITERATION + SEP) + scriptType)), 0)
397419 let thisIteration = value(getInteger((scriptId + "__iteration")))
398420 let confirmationsStr = valueOrElse(getString((scriptId + "__confirmations")), "")
399421 let confirmations = split(confirmationsStr, ",")
400422 if ((indexOf(confirmations, callerPbk) != unit))
401423 then throw("You already confirmed this script")
402424 else {
403425 let newList = if ((confirmationsStr != ""))
404426 then (confirmations :+ callerPbk)
405427 else [callerPbk]
406428 let newListStr = makeString(newList, ",")
407429 let approved = (size(newList) >= limit)
408430 let result = if (approved)
409431 then {
410432 let approvedCount = _getApprovedCount()
411433 let approvedHashes = split_4C(approvedHashesStr, ",")
412434 let approvedHashesNew = if ((approvedHashesStr != ""))
413435 then (approvedHashes :+ _scriptHash)
414436 else [_scriptHash]
415437 if ((size(approvedHashesNew) > approvedCount))
416438 then {
417439 let hashToRemove = approvedHashesNew[0]
418440 let scriptToRemoveId = ((("script%%" + scriptType) + "%%") + _scriptHash)
419441 let approvedHashesStripped = removeByIndex(approvedHashesNew, 0)
420442 [StringEntry((("script_" + scriptType) + "__approved"), makeString_2C(approvedHashesStripped, ",")), StringEntry(((scriptToRemoveId + BIGSEP) + k_confirmations), "")]
421443 }
422444 else [StringEntry((("script_" + scriptType) + "__approved"), makeString_2C(approvedHashesNew, ","))]
423445 }
424446 else nil
425447 (result ++ [StringEntry((scriptId + "__confirmations"), newListStr)])
426448 }
427449 }
428450 else throw("Strict value is not equal to itself.")
429451 }
430452 else throw("Strict value is not equal to itself.")
431453 }
432454 }
433455
434456
435457
436458 @Callable(i)
437459 func revokeConfirmationScript (scriptId) = {
438460 let callerPbk = toBase58String(i.callerPublicKey)
439461 let limit = _getLimit()
440462 if (!(_isAdmin(callerPbk)))
441463 then throw("Only admins can revoke")
442464 else {
443465 let _scriptHash = valueOrErrorMessage(getString((scriptId + "__scriptHash")), "Invalid scriptId")
444466 if ((_scriptHash == _scriptHash))
445467 then {
446468 let scriptType = getStringValue((scriptId + "__scriptType"))
447469 let approvedHashesStr = valueOrElse(getString((("script_" + scriptType) + "__approved")), "")
448470 let approvedHashes = split_4C(approvedHashesStr, ",")
449471 let confirmationsStr = valueOrElse(getString((scriptId + "__confirmations")), "")
450472 let confirmations = split(confirmationsStr, ",")
451473 let confirmIndex = indexOf(confirmations, callerPbk)
452474 if ((confirmIndex == unit))
453475 then throw("You didn't confirm this script, nothing to revoke")
454476 else {
455477 let newConfirmations = removeByIndex(confirmations, value(confirmIndex))
456478 let newConfirmationsStr = makeString(newConfirmations, ",")
457479 let wasApproved = (indexOf(approvedHashes, _scriptHash) != unit)
458480 let stillApproved = (size(newConfirmations) >= limit)
459481 let stateChanges = if (if (wasApproved)
460482 then !(stillApproved)
461483 else false)
462484 then {
463485 let scriptHashIndex = value(indexOf(approvedHashes, _scriptHash))
464486 let newApprovedHashes = removeByIndex(approvedHashes, scriptHashIndex)
465487 let newApprovedHashesStr = makeString(newApprovedHashes, ",")
466488 [StringEntry((("script_" + scriptType) + "__approved"), newApprovedHashesStr)]
467489 }
468490 else nil
469491 (stateChanges ++ [StringEntry((scriptId + "__confirmations"), newConfirmationsStr)])
470492 }
471493 }
472494 else throw("Strict value is not equal to itself.")
473495 }
474496 }
475497
476498
477499
478500 @Callable(i)
479501 func addTask (name,dapp,txid,executeTs,desc,initiatorAdr,txdata) = {
480502 let callerPbk = toBase58String(i.callerPublicKey)
481503 if (!(_isValidOperator(callerPbk)))
482504 then throw("Not allowed")
483505 else {
484506 let _nameCheck = if ((size(name) == 0))
485507 then throw("Name can't be empty")
486508 else true
487509 if ((_nameCheck == _nameCheck))
488510 then {
489511 let _dappCheck = if (!(_validateAddress(dapp)))
490512 then throw("Incorrect dapp")
491513 else true
492514 if ((_dappCheck == _dappCheck))
493515 then {
494516 let _txidCheck = if ((size(txid) == 0))
495517 then throw("txid can't be empty")
496518 else true
497519 if ((_txidCheck == _txidCheck))
498520 then {
499521 let _timestampCheck = if (!(_validateTs(executeTs)))
500522 then throw("Invalid execution timestamp - cannot be more than 1 hour in the past")
501523 else true
502524 if ((_timestampCheck == _timestampCheck))
503525 then {
504526 let _descCheck = if ((size(desc) == 0))
505527 then throw("Description can't be empty")
506528 else true
507529 if ((_descCheck == _descCheck))
508530 then {
509531 let _initiatorCheck = if ((toString(addressFromPublicKey(i.callerPublicKey)) != initiatorAdr))
510532 then throw("Initiator address doesn't match caller")
511533 else true
512534 if ((_initiatorCheck == _initiatorCheck))
513535 then {
514536 let _txdataCheck = if ((size(txdata) == 0))
515537 then throw("Tx data can't be empty")
516538 else true
517539 if ((_txdataCheck == _txdataCheck))
518540 then {
519541 let taskId = ((("tx_" + dapp) + SEP) + txid)
520542 [StringEntry((taskId + "__name"), name), StringEntry((taskId + "__dapp"), dapp), StringEntry((taskId + "__txId"), txid), StringEntry((taskId + "__desc"), desc), StringEntry((taskId + "__txdata"), txdata), StringEntry((taskId + "__initiator"), initiatorAdr), IntegerEntry((taskId + "__ts"), executeTs)]
521543 }
522544 else throw("Strict value is not equal to itself.")
523545 }
524546 else throw("Strict value is not equal to itself.")
525547 }
526548 else throw("Strict value is not equal to itself.")
527549 }
528550 else throw("Strict value is not equal to itself.")
529551 }
530552 else throw("Strict value is not equal to itself.")
531553 }
532554 else throw("Strict value is not equal to itself.")
533555 }
534556 else throw("Strict value is not equal to itself.")
535557 }
536558 }
537559
538560
539561
540562 @Callable(i)
541563 func removeTask (taskId) = {
542564 let callerPbk = toBase58String(i.callerPublicKey)
543565 if (!(_isValidOperator(callerPbk)))
544566 then throw("Not allowed")
545567 else {
546568 let initiatorAdr = getStringValue((taskId + "__initiator"))
547569 if ((initiatorAdr != toString(addressFromPublicKey(i.callerPublicKey))))
548570 then throw("Only creator can remove")
549571 else [DeleteEntry((taskId + "__name")), DeleteEntry((taskId + "__dapp")), DeleteEntry((taskId + "__txId")), DeleteEntry((taskId + "__desc")), DeleteEntry((taskId + "__txdata")), DeleteEntry((taskId + "__initiator")), DeleteEntry((taskId + "__ts")), DeleteEntry((taskId + "__confirmations")), DeleteEntry((taskId + "__approved"))]
550572 }
551573 }
552574
553575
554576
555577 @Callable(i)
556578 func addConfirmation (taskId) = {
557579 let callerPbk = toBase58String(i.callerPublicKey)
558580 let limit = _getLimit()
559581 if (!(_isAdmin(callerPbk)))
560582 then throw("Only admins can confirm")
561583 else {
562584 let txId = valueOrErrorMessage(getString((taskId + "__txId")), "Ivalid task")
563585 if ((txId == txId))
564586 then {
565587 let dapp = getStringValue((taskId + "__dapp"))
566588 let confirmationsStr = valueOrElse(getString((taskId + "__confirmations")), "")
567589 let confirmations = split(confirmationsStr, ",")
568590 if ((indexOf(confirmations, callerPbk) != unit))
569591 then throw("You already confirmed this task")
570592 else {
571593 let newList = if ((confirmationsStr != ""))
572594 then (confirmations :+ callerPbk)
573595 else [callerPbk]
574596 let newListStr = makeString(newList, ",")
575597 let approved = (size(newList) >= limit)
576598 [StringEntry((taskId + "__confirmations"), newListStr), BooleanEntry((((dapp + SEP) + txId) + "__approved"), approved)]
577599 }
578600 }
579601 else throw("Strict value is not equal to itself.")
580602 }
581603 }
582604
583605
584606
585607 @Callable(i)
586608 func revokeTask (taskId) = {
587609 let callerPbk = toBase58String(i.callerPublicKey)
588610 let limit = _getLimit()
589611 if (!(_isAdmin(callerPbk)))
590612 then throw("Only admins can call")
591613 else {
592614 let txId = valueOrErrorMessage(getString((taskId + "__txId")), "Ivalid task")
593615 if ((txId == txId))
594616 then {
595617 let confirmationsStr = valueOrElse(getString((taskId + "__confirmations")), "")
596618 let confirmations = split(confirmationsStr, ",")
597619 let indexMy = indexOf(confirmations, callerPbk)
598620 if ((indexMy == unit))
599621 then throw("You did not confirm this task, nothing to revoke")
600622 else {
601623 let dapp = getStringValue((taskId + "__dapp"))
602624 let newList = removeByIndex(confirmations, value(indexMy))
603625 let newListStr = makeString(newList, ",")
604626 let approved = (size(newList) >= limit)
605627 [StringEntry((taskId + "__confirmations"), newListStr), BooleanEntry((((dapp + SEP) + txId) + "__approved"), approved)]
606628 }
607629 }
608630 else throw("Strict value is not equal to itself.")
609631 }
610632 }
611633
612634
613635
614636 @Callable(i)
615-func setLimit (limit) = {
616- let callerPbk = toBase58String(i.callerPublicKey)
617- if (!(_isAdmin(callerPbk)))
618- then throw("Only whitelisted can set limit")
619- else {
620- let zeroLimit = if ((limit > 0))
621- then true
622- else throw("Limit should be > 0")
623- if ((zeroLimit == zeroLimit))
624- then {
625- let admins = getStringValue(k_ADMINS)
626- if ((limit > size(admins)))
627- then throw(((("Limit quorum should be <= size of list of admins, limit: " + toString(limit)) + ", current size: ") + toString(size(admins))))
628- else [IntegerEntry(k_LIMIT, limit)]
629- }
630- else throw("Strict value is not equal to itself.")
631- }
632- }
633-
634-
635-
636-@Callable(i)
637637 func test () = {
638638 let x = match blockInfoByHeight(height) {
639639 case block: BlockInfo =>
640640 throw(toString(block.timestamp))
641641 case _ =>
642642 throw("Can't find block")
643643 }
644644 if ((x == x))
645645 then nil
646646 else throw("Strict value is not equal to itself.")
647647 }
648648
649649
650650
651651 @Callable(i)
652652 func clear_test () = {
653653 let indices = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
654654 func removeChunks (accum,index) = (accum :+ DeleteEntry((("testtask" + "__txdata_") + toString(index))))
655655
656656 let entries = {
657657 let $l = indices
658658 let $s = size($l)
659659 let $acc0 = [DeleteEntry(("testtask" + "__txdata_chunks"))]
660660 func $f0_1 ($a,$i) = if (($i >= $s))
661661 then $a
662662 else removeChunks($a, $l[$i])
663663
664664 func $f0_2 ($a,$i) = if (($i >= $s))
665665 then $a
666666 else throw("List size exceeds 10")
667667
668668 $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10)
669669 }
670670 entries
671671 }
672672
673673
674+@Verifier(tx)
675+func verify () = {
676+ let MULTISIG_ADDRESS = addressFromString("3M7uzD8rT54fKQcP4s417if1VKU8yromEP2")
677+ let CONTRACT_TYPE = "APPROVER_CONTRACT"
678+ if ((MULTISIG_ADDRESS != unit))
679+ then match tx {
680+ case ttx: SetScriptTransaction =>
681+ let scriptHasha = toBase58String(value(blake2b256(value(ttx.script))))
682+ let approvedHashes = value(getString(value(MULTISIG_ADDRESS), (("script_" + CONTRACT_TYPE) + "__approved")))
683+ (indexOf(approvedHashes, scriptHasha) != unit)
684+ case otx =>
685+ valueOrElse(getBoolean(value(MULTISIG_ADDRESS), (((toString(this) + "_") + toBase58String(otx.id)) + "__approved")), false)
686+ }
687+ else sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
688+ }
689+

github/deemru/w8io
63.83 ms