tx · 3mLrEyZ1EP2zHrxWsj6SENQM18d1FVDMN85HDvi1B9wU

3My5T5LFFZoBKWquCciNddKbBioxyaNxiTm:  -0.01000000 Waves

2024.03.22 14:46 [3029201] smart account 3My5T5LFFZoBKWquCciNddKbBioxyaNxiTm > SELF 0.00000000 Waves

{ "type": 13, "id": "3mLrEyZ1EP2zHrxWsj6SENQM18d1FVDMN85HDvi1B9wU", "fee": 1000000, "feeAssetId": null, "timestamp": 1711108079497, "version": 2, "chainId": 84, "sender": "3My5T5LFFZoBKWquCciNddKbBioxyaNxiTm", "senderPublicKey": "2Z7jSeYihgvqrswc4rPBYdDo2MY4nQYaiRMVnt6rToBt", "proofs": [ "2ifzNaNcz4vFeeTGmm39UErrd7SSYat6ELy6QYvxt1SM8JcZ4NRqeSWHp6XSrUaafjESpq4RNwZqJKWmq7Wv7DXt" ], "script": "base64:BgIjCAISBAoCGAESAwoBCBIDCgEIEgMKAQESBAoCCAgSBAoCCAgIAAlTRVBBUkFUT1ICAl9fAAxLRVlfTVVMVElTSUcCCE1VTFRJU0lHAA9LRVlfUFVCTElDX0tFWVMCC1BVQkxJQ19LRVlTAApLRVlfUVVPUlVNAgZRVU9SVU0AC0tFWV9DT05GSVJNAgdDT05GSVJNAApLRVlfU1RBVFVTAgZTVEFUVVMBEF92YWxpZGF0ZUFkZHJlc3MBCGFkZHJlc3NfBAckbWF0Y2gwCQCmCAEFCGFkZHJlc3NfAwkAAQIFByRtYXRjaDACB0FkZHJlc3MEAWEFByRtYXRjaDAGBwEOX3ZhbGlkYXRlT3duZXICBGFjY18FZWxlbV8DCQAAAgUFZWxlbV8CAAkAAgECDWludmFsaWQgb3duZXIDCQECIT0CCQDIAQEJANkEAQUFZWxlbV8AIAkAAgECGGludmFsaWQgb3duZXIgcHVibGljIGtleQUEYWNjXwYBaQEEaW5pdAIHb3duZXJzXwdxdW9ydW1fBANlcnIDCQEJaXNEZWZpbmVkAQkAoggBBQxLRVlfTVVMVElTSUcJAAIBAhlpbml0OiBhbHJlYWR5IGluaXRpYWxpemVkBQR1bml0AwkAAAIFA2VycgUDZXJyBARlcnIxAwMJAGcCAAAJAJADAQUHb3duZXJzXwYJAGYCCQCQAwEFB293bmVyc18ACgkAAgECFGluaXQ6IGludmFsaWQgb3duZXJzAwMJAGcCAAAFB3F1b3J1bV8GCQBmAgUHcXVvcnVtXwkAkAMBBQdvd25lcnNfCQACAQIUaW5pdDogaW52YWxpZCBxdW9ydW0FBHVuaXQDCQAAAgUEZXJyMQUEZXJyMQQEZXJyMgoAAiRsBQdvd25lcnNfCgACJHMJAJADAQUCJGwKAAUkYWNjMAAACgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQ5fdmFsaWRhdGVPd25lcgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgMJAAACBQRlcnIyBQRlcnIyCQCUCgIJAMwIAgkBC1N0cmluZ0VudHJ5AgUMS0VZX01VTFRJU0lHCQClCAEFBHRoaXMJAMwIAgkBC1N0cmluZ0VudHJ5AgUPS0VZX1BVQkxJQ19LRVlTCQC5CQIFB293bmVyc18FCVNFUEFSQVRPUgkAzAgCCQEMSW50ZWdlckVudHJ5AgUKS0VZX1FVT1JVTQUHcXVvcnVtXwUDbmlsBQR1bml0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCGFkZE93bmVyAQpwdWJsaWNLZXlfBApwdWJsaWNLZXlzCQERQGV4dHJOYXRpdmUoMTA1OCkBBQ9LRVlfUFVCTElDX0tFWVMEDnB1YmxpY0tleXNMaXN0CQC1CQIFCnB1YmxpY0tleXMFCVNFUEFSQVRPUgMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECFWFkZE93bmVyOiBub3QgYWxsb3dlZAMJAQIhPQIJAQ5fdmFsaWRhdGVPd25lcgIAAAUKcHVibGljS2V5XwAACQACAQIcYWRkT3duZXI6IGludmFsaWQgcHVibGljIGtleQMJAQ9jb250YWluc0VsZW1lbnQCBQ5wdWJsaWNLZXlzTGlzdAUKcHVibGljS2V5XwkAAgECImFkZE93bmVyOiBwdWJsaWMga2V5IGFscmVhZHkgYWRkZWQDCQAAAgkAkAMBBQ5wdWJsaWNLZXlzTGlzdAAKCQACAQIZYWRkT3duZXI6IHRvbyBtYW55IG93bmVycwQVcHVibGljS2V5c0xpc3RVcGRhdGVkCQDNCAIFDnB1YmxpY0tleXNMaXN0BQpwdWJsaWNLZXlfBBFwdWJsaWNLZXlzVXBkYXRlZAkAzAgCCQELU3RyaW5nRW50cnkCBQ9LRVlfUFVCTElDX0tFWVMJALkJAgUVcHVibGljS2V5c0xpc3RVcGRhdGVkBQlTRVBBUkFUT1IFA25pbAkAlAoCBRFwdWJsaWNLZXlzVXBkYXRlZAUEdW5pdAFpAQtyZW1vdmVPd25lcgEKcHVibGljS2V5XwQGcXVvcnVtCQERQGV4dHJOYXRpdmUoMTA1NSkBBQpLRVlfUVVPUlVNBApwdWJsaWNLZXlzCQERQGV4dHJOYXRpdmUoMTA1OCkBBQ9LRVlfUFVCTElDX0tFWVMEDnB1YmxpY0tleXNMaXN0CQC1CQIFCnB1YmxpY0tleXMFCVNFUEFSQVRPUgMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECGHJlbW92ZU93bmVyOiBub3QgYWxsb3dlZAMJAAACBQpwdWJsaWNLZXlfAgAJAAIBAh9yZW1vdmVPd25lcjogaW52YWxpZCBwdWJsaWMga2V5AwkAAAIJAJADAQUOcHVibGljS2V5c0xpc3QAAQkAAgECG3JlbW92ZU93bmVyOiB0b28gZmV3IG93bmVycwQFaW5kZXgEByRtYXRjaDAJAM8IAgUOcHVibGljS2V5c0xpc3QFCnB1YmxpY0tleV8DCQABAgUHJG1hdGNoMAIDSW50BAFhBQckbWF0Y2gwBQFhCQACAQIacmVtb3ZlT3duZXI6IG5vIHN1Y2ggb3duZXIEFXB1YmxpY0tleXNMaXN0VXBkYXRlZAkA0QgCBQ5wdWJsaWNLZXlzTGlzdAUFaW5kZXgEEXB1YmxpY0tleXNVcGRhdGVkCQDMCAIJAQtTdHJpbmdFbnRyeQIFD0tFWV9QVUJMSUNfS0VZUwkAuQkCBRVwdWJsaWNLZXlzTGlzdFVwZGF0ZWQFCVNFUEFSQVRPUgUDbmlsBA1xdW9ydW1VcGRhdGVkAwkAZgIFBnF1b3J1bQkAkAMBBRVwdWJsaWNLZXlzTGlzdFVwZGF0ZWQJAMwIAgkBDEludGVnZXJFbnRyeQIFCktFWV9RVU9SVU0JAJADAQUVcHVibGljS2V5c0xpc3RVcGRhdGVkBQNuaWwFA25pbAkAlAoCCQDOCAIFEXB1YmxpY0tleXNVcGRhdGVkBQ1xdW9ydW1VcGRhdGVkBQR1bml0AWkBCXNldFF1b3J1bQEHcXVvcnVtXwQKcHVibGljS2V5cwkBEUBleHRyTmF0aXZlKDEwNTgpAQUPS0VZX1BVQkxJQ19LRVlTBA5wdWJsaWNLZXlzTGlzdAkAtQkCBQpwdWJsaWNLZXlzBQlTRVBBUkFUT1IDCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAAIBAhZzZXRRdW9ydW06IG5vdCBhbGxvd2VkAwMJAGcCAAAFB3F1b3J1bV8GCQBmAgUHcXVvcnVtXwkAkAMBBQ5wdWJsaWNLZXlzTGlzdAkAAgECGXNldFF1b3J1bTogaW52YWxpZCBxdW9ydW0JAJQKAgkAzAgCCQEMSW50ZWdlckVudHJ5AgUKS0VZX1FVT1JVTQUHcXVvcnVtXwUDbmlsBQR1bml0AWkBEmNvbmZpcm1UcmFuc2FjdGlvbgIFZGFwcF8FdHhJZF8ED2NhbGxlclB1YmxpY0tleQkA2AQBCAUBaQ9jYWxsZXJQdWJsaWNLZXkEBnF1b3J1bQkBEUBleHRyTmF0aXZlKDEwNTUpAQUKS0VZX1FVT1JVTQQKcHVibGljS2V5cwkBEUBleHRyTmF0aXZlKDEwNTgpAQUPS0VZX1BVQkxJQ19LRVlTBA5wdWJsaWNLZXlzTGlzdAkAtQkCBQpwdWJsaWNLZXlzBQlTRVBBUkFUT1IEEGNvbmZpcm1hdGlvbnNLZXkJALkJAgkAzAgCBQtLRVlfQ09ORklSTQkAzAgCBQVkYXBwXwkAzAgCBQV0eElkXwUDbmlsBQlTRVBBUkFUT1IEDWNvbmZpcm1hdGlvbnMJAQt2YWx1ZU9yRWxzZQIJAKIIAQUQY29uZmlybWF0aW9uc0tleQIABAlzdGF0dXNLZXkJALkJAgkAzAgCBQpLRVlfU1RBVFVTCQDMCAIFBWRhcHBfCQDMCAIFBXR4SWRfBQNuaWwFCVNFUEFSQVRPUgQDZXJyAwkBASEBCQEPY29udGFpbnNFbGVtZW50AgUOcHVibGljS2V5c0xpc3QFD2NhbGxlclB1YmxpY0tleQkAAgECHmNvbmZpcm1UcmFuc2FjdGlvbjogb25seSBhZG1pbgMJAQIhPQIJAMgBAQkA2QQBBQV0eElkXwAgCQACAQIgY29uZmlybVRyYW5zYWN0aW9uOiBpbnZhbGlkIHR4SWQDCQEBIQEJARBfdmFsaWRhdGVBZGRyZXNzAQUFZGFwcF8JAAIBAihjb25maXJtVHJhbnNhY3Rpb246IGludmFsaWQgZGFwcCBhZGRyZXNzAwkBCGNvbnRhaW5zAgUNY29uZmlybWF0aW9ucwUPY2FsbGVyUHVibGljS2V5CQACAQIlY29uZmlybVRyYW5zYWN0aW9uOiBhbHJlYWR5IGNvbmZpcm1lZAUEdW5pdAMJAAACBQNlcnIFA2VycgQSY29uZmlybWF0aW9uc0NvdW50CQBkAgABAwkAAAIFDWNvbmZpcm1hdGlvbnMCAAAACQCQAwEJALUJAgUNY29uZmlybWF0aW9ucwUJU0VQQVJBVE9SBBRjb25maXJtYXRpb25zVXBkYXRlZAMJAAACBQ1jb25maXJtYXRpb25zAgAFD2NhbGxlclB1YmxpY0tleQkArAICCQCsAgIFDWNvbmZpcm1hdGlvbnMFCVNFUEFSQVRPUgUPY2FsbGVyUHVibGljS2V5CQCUCgIJAMwIAgkBC1N0cmluZ0VudHJ5AgUQY29uZmlybWF0aW9uc0tleQUUY29uZmlybWF0aW9uc1VwZGF0ZWQJAMwIAgkBDEJvb2xlYW5FbnRyeQIFCXN0YXR1c0tleQkAZwIFEmNvbmZpcm1hdGlvbnNDb3VudAUGcXVvcnVtBQNuaWwFBHVuaXQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEScmV2b2tlQ29uZmlybWF0aW9uAgVkYXBwXwV0eElkXwQPY2FsbGVyUHVibGljS2V5CQDYBAEIBQFpD2NhbGxlclB1YmxpY0tleQQGcXVvcnVtCQERQGV4dHJOYXRpdmUoMTA1NSkBBQpLRVlfUVVPUlVNBApwdWJsaWNLZXlzCQERQGV4dHJOYXRpdmUoMTA1OCkBBQ9LRVlfUFVCTElDX0tFWVMEDnB1YmxpY0tleXNMaXN0CQC1CQIFCnB1YmxpY0tleXMFCVNFUEFSQVRPUgQQY29uZmlybWF0aW9uc0tleQkAuQkCCQDMCAIFC0tFWV9DT05GSVJNCQDMCAIFBWRhcHBfCQDMCAIFBXR4SWRfBQNuaWwFCVNFUEFSQVRPUgQNY29uZmlybWF0aW9ucwkBC3ZhbHVlT3JFbHNlAgkAoggBBRBjb25maXJtYXRpb25zS2V5AgAEEWNvbmZpcm1hdGlvbnNMaXN0CQC1CQIFDWNvbmZpcm1hdGlvbnMFCVNFUEFSQVRPUgQJc3RhdHVzS2V5CQC5CQIJAMwIAgUKS0VZX1NUQVRVUwkAzAgCBQVkYXBwXwkAzAgCBQV0eElkXwUDbmlsBQlTRVBBUkFUT1IEBnN0YXR1cwkBC3ZhbHVlT3JFbHNlAgkAoAgBBQlzdGF0dXNLZXkHBANlcnIDCQEBIQEJAQ9jb250YWluc0VsZW1lbnQCBQ5wdWJsaWNLZXlzTGlzdAUPY2FsbGVyUHVibGljS2V5CQACAQIecmV2b2tlQ29uZmlybWF0aW9uOiBvbmx5IGFkbWluAwkBAiE9AgkAyAEBCQDZBAEFBXR4SWRfACAJAAIBAiByZXZva2VDb25maXJtYXRpb246IGludmFsaWQgdHhJZAMJAQEhAQkBEF92YWxpZGF0ZUFkZHJlc3MBBQVkYXBwXwkAAgECKHJldm9rZUNvbmZpcm1hdGlvbjogaW52YWxpZCBkYXBwIGFkZHJlc3MDCQEBIQEJAQ9jb250YWluc0VsZW1lbnQCBRFjb25maXJtYXRpb25zTGlzdAUPY2FsbGVyUHVibGljS2V5CQACAQIhcmV2b2tlQ29uZmlybWF0aW9uOiBub3QgY29uZmlybWVkAwUGc3RhdHVzCQACAQIqcmV2b2tlQ29uZmlybWF0aW9uOiBxdW9ydW0gYWxyZWFkeSByZWFjaGVkBQR1bml0AwkAAAIFA2VycgUDZXJyBBhjb25maXJtYXRpb25zTGlzdFVwZGF0ZWQJANEIAgURY29uZmlybWF0aW9uc0xpc3QJAQV2YWx1ZQEJAM8IAgURY29uZmlybWF0aW9uc0xpc3QFD2NhbGxlclB1YmxpY0tleQQSY29uZmlybWF0aW9uc0NvdW50CQCQAwEFGGNvbmZpcm1hdGlvbnNMaXN0VXBkYXRlZAkAlAoCCQDMCAIJAQtTdHJpbmdFbnRyeQIFEGNvbmZpcm1hdGlvbnNLZXkJALkJAgUYY29uZmlybWF0aW9uc0xpc3RVcGRhdGVkBQlTRVBBUkFUT1IJAMwIAgkBDEJvb2xlYW5FbnRyeQIFCXN0YXR1c0tleQkAZwIFEmNvbmZpcm1hdGlvbnNDb3VudAUGcXVvcnVtBQNuaWwFBHVuaXQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BAnR4AQZ2ZXJpZnkABAckbWF0Y2gwCQCiCAEFDEtFWV9NVUxUSVNJRwMJAAECBQckbWF0Y2gwAgZTdHJpbmcECG11bHRpc2lnBQckbWF0Y2gwCQELdmFsdWVPckVsc2UCCQCbCAIJARFAZXh0ck5hdGl2ZSgxMDYyKQEFCG11bHRpc2lnCQC5CQIJAMwIAgUKS0VZX1NUQVRVUwkAzAgCCQClCAEFBHRoaXMJAMwIAgkA2AQBCAUCdHgCaWQFA25pbAUJU0VQQVJBVE9SBwkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAAgFAnR4D3NlbmRlclB1YmxpY0tledsxC/w=", "height": 3029201, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: none Next: none Full:
OldNewDifferences
1-# no script
1+{-# STDLIB_VERSION 6 #-}
2+{-# SCRIPT_TYPE ACCOUNT #-}
3+{-# CONTENT_TYPE DAPP #-}
4+let SEPARATOR = "__"
5+
6+let KEY_MULTISIG = "MULTISIG"
7+
8+let KEY_PUBLIC_KEYS = "PUBLIC_KEYS"
9+
10+let KEY_QUORUM = "QUORUM"
11+
12+let KEY_CONFIRM = "CONFIRM"
13+
14+let KEY_STATUS = "STATUS"
15+
16+func _validateAddress (address_) = match addressFromString(address_) {
17+ case a: Address =>
18+ true
19+ case _ =>
20+ false
21+}
22+
23+
24+func _validateOwner (acc_,elem_) = if ((elem_ == ""))
25+ then throw("invalid owner")
26+ else if ((size(fromBase58String(elem_)) != 32))
27+ then throw("invalid owner public key")
28+ else acc_
29+
30+
31+@Callable(i)
32+func init (owners_,quorum_) = {
33+ let err = if (isDefined(getString(KEY_MULTISIG)))
34+ then throw("init: already initialized")
35+ else unit
36+ if ((err == err))
37+ then {
38+ let err1 = if (if ((0 >= size(owners_)))
39+ then true
40+ else (size(owners_) > 10))
41+ then throw("init: invalid owners")
42+ else if (if ((0 >= quorum_))
43+ then true
44+ else (quorum_ > size(owners_)))
45+ then throw("init: invalid quorum")
46+ else unit
47+ if ((err1 == err1))
48+ then {
49+ let err2 = {
50+ let $l = owners_
51+ let $s = size($l)
52+ let $acc0 = 0
53+ func $f0_1 ($a,$i) = if (($i >= $s))
54+ then $a
55+ else _validateOwner($a, $l[$i])
56+
57+ func $f0_2 ($a,$i) = if (($i >= $s))
58+ then $a
59+ else throw("List size exceeds 10")
60+
61+ $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)
62+ }
63+ if ((err2 == err2))
64+ then $Tuple2([StringEntry(KEY_MULTISIG, toString(this)), StringEntry(KEY_PUBLIC_KEYS, makeString(owners_, SEPARATOR)), IntegerEntry(KEY_QUORUM, quorum_)], unit)
65+ else throw("Strict value is not equal to itself.")
66+ }
67+ else throw("Strict value is not equal to itself.")
68+ }
69+ else throw("Strict value is not equal to itself.")
70+ }
71+
72+
73+
74+@Callable(i)
75+func addOwner (publicKey_) = {
76+ let publicKeys = getStringValue(KEY_PUBLIC_KEYS)
77+ let publicKeysList = split(publicKeys, SEPARATOR)
78+ if ((i.caller != this))
79+ then throw("addOwner: not allowed")
80+ else if ((_validateOwner(0, publicKey_) != 0))
81+ then throw("addOwner: invalid public key")
82+ else if (containsElement(publicKeysList, publicKey_))
83+ then throw("addOwner: public key already added")
84+ else if ((size(publicKeysList) == 10))
85+ then throw("addOwner: too many owners")
86+ else {
87+ let publicKeysListUpdated = (publicKeysList :+ publicKey_)
88+ let publicKeysUpdated = [StringEntry(KEY_PUBLIC_KEYS, makeString(publicKeysListUpdated, SEPARATOR))]
89+ $Tuple2(publicKeysUpdated, unit)
90+ }
91+ }
92+
93+
94+
95+@Callable(i)
96+func removeOwner (publicKey_) = {
97+ let quorum = getIntegerValue(KEY_QUORUM)
98+ let publicKeys = getStringValue(KEY_PUBLIC_KEYS)
99+ let publicKeysList = split(publicKeys, SEPARATOR)
100+ if ((i.caller != this))
101+ then throw("removeOwner: not allowed")
102+ else if ((publicKey_ == ""))
103+ then throw("removeOwner: invalid public key")
104+ else if ((size(publicKeysList) == 1))
105+ then throw("removeOwner: too few owners")
106+ else {
107+ let index = match indexOf(publicKeysList, publicKey_) {
108+ case a: Int =>
109+ a
110+ case _ =>
111+ throw("removeOwner: no such owner")
112+ }
113+ let publicKeysListUpdated = removeByIndex(publicKeysList, index)
114+ let publicKeysUpdated = [StringEntry(KEY_PUBLIC_KEYS, makeString(publicKeysListUpdated, SEPARATOR))]
115+ let quorumUpdated = if ((quorum > size(publicKeysListUpdated)))
116+ then [IntegerEntry(KEY_QUORUM, size(publicKeysListUpdated))]
117+ else nil
118+ $Tuple2((publicKeysUpdated ++ quorumUpdated), unit)
119+ }
120+ }
121+
122+
123+
124+@Callable(i)
125+func setQuorum (quorum_) = {
126+ let publicKeys = getStringValue(KEY_PUBLIC_KEYS)
127+ let publicKeysList = split(publicKeys, SEPARATOR)
128+ if ((i.caller != this))
129+ then throw("setQuorum: not allowed")
130+ else if (if ((0 >= quorum_))
131+ then true
132+ else (quorum_ > size(publicKeysList)))
133+ then throw("setQuorum: invalid quorum")
134+ else $Tuple2([IntegerEntry(KEY_QUORUM, quorum_)], unit)
135+ }
136+
137+
138+
139+@Callable(i)
140+func confirmTransaction (dapp_,txId_) = {
141+ let callerPublicKey = toBase58String(i.callerPublicKey)
142+ let quorum = getIntegerValue(KEY_QUORUM)
143+ let publicKeys = getStringValue(KEY_PUBLIC_KEYS)
144+ let publicKeysList = split(publicKeys, SEPARATOR)
145+ let confirmationsKey = makeString([KEY_CONFIRM, dapp_, txId_], SEPARATOR)
146+ let confirmations = valueOrElse(getString(confirmationsKey), "")
147+ let statusKey = makeString([KEY_STATUS, dapp_, txId_], SEPARATOR)
148+ let err = if (!(containsElement(publicKeysList, callerPublicKey)))
149+ then throw("confirmTransaction: only admin")
150+ else if ((size(fromBase58String(txId_)) != 32))
151+ then throw("confirmTransaction: invalid txId")
152+ else if (!(_validateAddress(dapp_)))
153+ then throw("confirmTransaction: invalid dapp address")
154+ else if (contains(confirmations, callerPublicKey))
155+ then throw("confirmTransaction: already confirmed")
156+ else unit
157+ if ((err == err))
158+ then {
159+ let confirmationsCount = (1 + (if ((confirmations == ""))
160+ then 0
161+ else size(split(confirmations, SEPARATOR))))
162+ let confirmationsUpdated = if ((confirmations == ""))
163+ then callerPublicKey
164+ else ((confirmations + SEPARATOR) + callerPublicKey)
165+ $Tuple2([StringEntry(confirmationsKey, confirmationsUpdated), BooleanEntry(statusKey, (confirmationsCount >= quorum))], unit)
166+ }
167+ else throw("Strict value is not equal to itself.")
168+ }
169+
170+
171+
172+@Callable(i)
173+func revokeConfirmation (dapp_,txId_) = {
174+ let callerPublicKey = toBase58String(i.callerPublicKey)
175+ let quorum = getIntegerValue(KEY_QUORUM)
176+ let publicKeys = getStringValue(KEY_PUBLIC_KEYS)
177+ let publicKeysList = split(publicKeys, SEPARATOR)
178+ let confirmationsKey = makeString([KEY_CONFIRM, dapp_, txId_], SEPARATOR)
179+ let confirmations = valueOrElse(getString(confirmationsKey), "")
180+ let confirmationsList = split(confirmations, SEPARATOR)
181+ let statusKey = makeString([KEY_STATUS, dapp_, txId_], SEPARATOR)
182+ let status = valueOrElse(getBoolean(statusKey), false)
183+ let err = if (!(containsElement(publicKeysList, callerPublicKey)))
184+ then throw("revokeConfirmation: only admin")
185+ else if ((size(fromBase58String(txId_)) != 32))
186+ then throw("revokeConfirmation: invalid txId")
187+ else if (!(_validateAddress(dapp_)))
188+ then throw("revokeConfirmation: invalid dapp address")
189+ else if (!(containsElement(confirmationsList, callerPublicKey)))
190+ then throw("revokeConfirmation: not confirmed")
191+ else if (status)
192+ then throw("revokeConfirmation: quorum already reached")
193+ else unit
194+ if ((err == err))
195+ then {
196+ let confirmationsListUpdated = removeByIndex(confirmationsList, value(indexOf(confirmationsList, callerPublicKey)))
197+ let confirmationsCount = size(confirmationsListUpdated)
198+ $Tuple2([StringEntry(confirmationsKey, makeString(confirmationsListUpdated, SEPARATOR)), BooleanEntry(statusKey, (confirmationsCount >= quorum))], unit)
199+ }
200+ else throw("Strict value is not equal to itself.")
201+ }
202+
203+
204+@Verifier(tx)
205+func verify () = match getString(KEY_MULTISIG) {
206+ case multisig: String =>
207+ valueOrElse(getBoolean(addressFromStringValue(multisig), makeString([KEY_STATUS, toString(this), toBase58String(tx.id)], SEPARATOR)), false)
208+ case _ =>
209+ sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
210+}
211+

github/deemru/w8io/3ef1775 
27.65 ms