Smart Contract

FCLCrypto

A.86185fba578bc773.FCLCrypto

Valid From

84,170,293

Deployed

22h ago
Feb 27, 2026, 07:54:08 PM UTC

Dependents

0 imports
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