Smart Contract
FCLCrypto
A.86185fba578bc773.FCLCrypto
1access(all) contract FCLCrypto {
2
3 access(all) view fun verifyUserSignatures(
4 address: Address,
5 message: String,
6 keyIndices: [Int],
7 signatures: [String]
8 ): Bool {
9 return self.verifySignatures(
10 address: address,
11 message: message,
12 keyIndices: keyIndices,
13 signatures: signatures,
14 domainSeparationTag: self.domainSeparationTagFlowUser,
15 )
16 }
17
18 access(all) view fun verifyAccountProofSignatures(
19 address: Address,
20 message: String,
21 keyIndices: [Int],
22 signatures: [String]
23 ): Bool {
24 return self.verifySignatures(
25 address: address,
26 message: message,
27 keyIndices: keyIndices,
28 signatures: signatures,
29 domainSeparationTag: self.domainSeparationTagAccountProof,
30 ) ||
31 self.verifySignatures(
32 address: address,
33 message: message,
34 keyIndices: keyIndices,
35 signatures: signatures,
36 domainSeparationTag: self.domainSeparationTagFlowUser,
37 )
38 }
39
40 access(self) view fun verifySignatures(
41 address: Address,
42 message: String,
43 keyIndices: [Int],
44 signatures: [String],
45 domainSeparationTag: String,
46 ): Bool {
47 pre {
48 keyIndices.length == signatures.length : "Key index list length does not match signature list length"
49 }
50
51 let account = getAccount(address)
52 let messageBytes = message.decodeHex()
53
54 var totalWeight: UFix64 = 0.0
55 let seenKeyIndices: {Int: Bool} = {}
56
57 var i = 0
58
59 for keyIndex in keyIndices {
60
61 let accountKey = account.keys.get(keyIndex: keyIndex) ?? panic("Key provided does not exist on account")
62 let signature = signatures[i].decodeHex()
63
64 // Ensure this key index has not already been seen
65
66 if seenKeyIndices[accountKey.keyIndex] ?? false {
67 return false
68 }
69
70 // Record the key index was seen
71
72 seenKeyIndices[accountKey.keyIndex] = true
73
74 // Ensure the key is not revoked
75
76 if accountKey.isRevoked {
77 return false
78 }
79
80 // Ensure the signature is valid
81
82 if !accountKey.publicKey.verify(
83 signature: signature,
84 signedData: messageBytes,
85 domainSeparationTag: domainSeparationTag,
86 hashAlgorithm: accountKey.hashAlgorithm
87 ) {
88 return false
89 }
90
91 totalWeight = totalWeight + accountKey.weight
92
93 i = i + 1
94 }
95
96 // Non-custodial users can only generate a weight of 999
97 return totalWeight >= 999.0
98 }
99
100 access(self) let domainSeparationTagFlowUser: String
101 access(self) let domainSeparationTagFCLUser: String
102 access(self) let domainSeparationTagAccountProof: String
103
104 init() {
105 self.domainSeparationTagFlowUser = "FLOW-V0.0-user"
106 self.domainSeparationTagFCLUser = "FCL-USER-V0.0"
107 self.domainSeparationTagAccountProof = "FCL-ACCOUNT-PROOF-V0.0"
108 }
109}
110