@devtion/actions 0.0.0-7e983e3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +83 -0
- package/dist/index.mjs +2608 -0
- package/dist/index.node.js +2714 -0
- package/dist/types/hardhat.config.d.ts +6 -0
- package/dist/types/hardhat.config.d.ts.map +1 -0
- package/dist/types/src/helpers/authentication.d.ts +21 -0
- package/dist/types/src/helpers/authentication.d.ts.map +1 -0
- package/dist/types/src/helpers/constants.d.ts +194 -0
- package/dist/types/src/helpers/constants.d.ts.map +1 -0
- package/dist/types/src/helpers/contracts.d.ts +57 -0
- package/dist/types/src/helpers/contracts.d.ts.map +1 -0
- package/dist/types/src/helpers/crypto.d.ts +27 -0
- package/dist/types/src/helpers/crypto.d.ts.map +1 -0
- package/dist/types/src/helpers/database.d.ts +105 -0
- package/dist/types/src/helpers/database.d.ts.map +1 -0
- package/dist/types/src/helpers/functions.d.ts +145 -0
- package/dist/types/src/helpers/functions.d.ts.map +1 -0
- package/dist/types/src/helpers/security.d.ts +10 -0
- package/dist/types/src/helpers/security.d.ts.map +1 -0
- package/dist/types/src/helpers/services.d.ts +38 -0
- package/dist/types/src/helpers/services.d.ts.map +1 -0
- package/dist/types/src/helpers/storage.d.ts +121 -0
- package/dist/types/src/helpers/storage.d.ts.map +1 -0
- package/dist/types/src/helpers/tasks.d.ts +2 -0
- package/dist/types/src/helpers/tasks.d.ts.map +1 -0
- package/dist/types/src/helpers/utils.d.ts +139 -0
- package/dist/types/src/helpers/utils.d.ts.map +1 -0
- package/dist/types/src/helpers/verification.d.ts +95 -0
- package/dist/types/src/helpers/verification.d.ts.map +1 -0
- package/dist/types/src/helpers/vm.d.ts +112 -0
- package/dist/types/src/helpers/vm.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +15 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/types/enums.d.ts +133 -0
- package/dist/types/src/types/enums.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +603 -0
- package/dist/types/src/types/index.d.ts.map +1 -0
- package/package.json +87 -0
- package/src/helpers/authentication.ts +37 -0
- package/src/helpers/constants.ts +312 -0
- package/src/helpers/contracts.ts +268 -0
- package/src/helpers/crypto.ts +55 -0
- package/src/helpers/database.ts +221 -0
- package/src/helpers/functions.ts +438 -0
- package/src/helpers/security.ts +86 -0
- package/src/helpers/services.ts +83 -0
- package/src/helpers/storage.ts +329 -0
- package/src/helpers/tasks.ts +56 -0
- package/src/helpers/utils.ts +743 -0
- package/src/helpers/verification.ts +354 -0
- package/src/helpers/vm.ts +392 -0
- package/src/index.ts +162 -0
- package/src/types/enums.ts +141 -0
- package/src/types/index.ts +650 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import { groth16, zKey } from "snarkjs"
|
|
2
|
+
import fs from "fs"
|
|
3
|
+
import { Firestore, where } from "firebase/firestore"
|
|
4
|
+
import { Functions } from "firebase/functions"
|
|
5
|
+
import {
|
|
6
|
+
numExpIterations,
|
|
7
|
+
commonTerms,
|
|
8
|
+
finalContributionIndex,
|
|
9
|
+
verifierSmartContractAcronym,
|
|
10
|
+
verificationKeyAcronym,
|
|
11
|
+
solidityVersion
|
|
12
|
+
} from "./constants"
|
|
13
|
+
import { compareHashes } from "./crypto"
|
|
14
|
+
import {
|
|
15
|
+
downloadCeremonyArtifact,
|
|
16
|
+
getBucketName,
|
|
17
|
+
getVerificationKeyStorageFilePath,
|
|
18
|
+
getVerifierContractStorageFilePath,
|
|
19
|
+
getWasmStorageFilePath,
|
|
20
|
+
getZkeyStorageFilePath
|
|
21
|
+
} from "./storage"
|
|
22
|
+
import {
|
|
23
|
+
fromQueryToFirebaseDocumentInfo,
|
|
24
|
+
getCeremonyCircuits,
|
|
25
|
+
getCircuitContributionsFromContributor,
|
|
26
|
+
queryCollection
|
|
27
|
+
} from "./database"
|
|
28
|
+
import { formatZkeyIndex } from "./utils"
|
|
29
|
+
import { CeremonyArtifacts } from "../types/index"
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Verify that a zKey is valid
|
|
33
|
+
* @param r1csLocalFilePath <string> path to the r1cs file
|
|
34
|
+
* @param zkeyLocalPath <string> path to the zKey file
|
|
35
|
+
* @param potLocalFilePath <string> path to the PoT file
|
|
36
|
+
* @param logger <any> logger instance
|
|
37
|
+
* @returns <boolean> true if the zKey is valid, false otherwise
|
|
38
|
+
*/
|
|
39
|
+
export const verifyZKey = async (
|
|
40
|
+
r1csLocalFilePath: string,
|
|
41
|
+
zkeyLocalPath: string,
|
|
42
|
+
potLocalFilePath: string,
|
|
43
|
+
logger?: any
|
|
44
|
+
): Promise<boolean> => {
|
|
45
|
+
if (!fs.existsSync(r1csLocalFilePath)) throw new Error(`R1CS file not found at ${r1csLocalFilePath}`)
|
|
46
|
+
|
|
47
|
+
if (!fs.existsSync(zkeyLocalPath)) throw new Error(`zKey file not found at ${zkeyLocalPath}`)
|
|
48
|
+
|
|
49
|
+
if (!fs.existsSync(potLocalFilePath)) throw new Error(`PoT file not found at ${potLocalFilePath}`)
|
|
50
|
+
|
|
51
|
+
const res = await zKey.verifyFromR1cs(r1csLocalFilePath, potLocalFilePath, zkeyLocalPath, logger)
|
|
52
|
+
return res
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Generates a GROTH16 proof
|
|
57
|
+
* @param circuitInput <object> Input to the circuit
|
|
58
|
+
* @param zkeyFilePath <string> Path to the proving key
|
|
59
|
+
* @param wasmFilePath <string> Path to the compiled circuit
|
|
60
|
+
* @param logger <any> Optional logger
|
|
61
|
+
* @returns <Promise<object>> The proof
|
|
62
|
+
*/
|
|
63
|
+
export const generateGROTH16Proof = async (
|
|
64
|
+
circuitInput: object,
|
|
65
|
+
zkeyFilePath: string,
|
|
66
|
+
wasmFilePath: string,
|
|
67
|
+
logger?: any
|
|
68
|
+
): Promise<any> => {
|
|
69
|
+
try {
|
|
70
|
+
const { proof, publicSignals } = await groth16.fullProve(circuitInput, wasmFilePath, zkeyFilePath, logger)
|
|
71
|
+
return {
|
|
72
|
+
proof,
|
|
73
|
+
publicSignals
|
|
74
|
+
}
|
|
75
|
+
} catch (error: any) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
"There was an error while generating a proof. Please check that the input is correct, as well as the required system paths; and please try again."
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Verifies a GROTH16 proof
|
|
84
|
+
* @param verificationKeyPath <string> Path to the verification key
|
|
85
|
+
* @param publicSignals <object> Public signals
|
|
86
|
+
* @param proof <object> Proof
|
|
87
|
+
* @returns <Promise<boolean>> Whether the proof is valid or not
|
|
88
|
+
*/
|
|
89
|
+
export const verifyGROTH16Proof = async (
|
|
90
|
+
verificationKeyPath: string,
|
|
91
|
+
publicSignals: object,
|
|
92
|
+
proof: object
|
|
93
|
+
): Promise<boolean> => {
|
|
94
|
+
const verificationKey = JSON.parse(fs.readFileSync(verificationKeyPath).toString())
|
|
95
|
+
const success = await groth16.verify(verificationKey, publicSignals, proof)
|
|
96
|
+
return success
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Helper method to extract the Solidity verifier
|
|
101
|
+
* from a final zKey file and save it to a local file.
|
|
102
|
+
* @param finalZkeyPath <string> The path to the zKey file.
|
|
103
|
+
* @return <any> The Solidity verifier code.
|
|
104
|
+
*/
|
|
105
|
+
export const exportVerifierContract = async (finalZkeyPath: string, templatePath: string) => {
|
|
106
|
+
// Extract verifier.
|
|
107
|
+
let verifierCode = await zKey.exportSolidityVerifier(
|
|
108
|
+
finalZkeyPath,
|
|
109
|
+
{
|
|
110
|
+
groth16: fs.readFileSync(templatePath).toString()
|
|
111
|
+
},
|
|
112
|
+
console
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
// Update solidity version.
|
|
116
|
+
verifierCode = verifierCode.replace(/pragma solidity \^\d+\.\d+\.\d+/, `pragma solidity ^${solidityVersion}`)
|
|
117
|
+
|
|
118
|
+
return verifierCode
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Helpers method to extract the vKey from a final zKey file
|
|
123
|
+
* @param finalZkeyPath <string> The path to the zKey file.
|
|
124
|
+
* @return <any> The vKey.
|
|
125
|
+
*/
|
|
126
|
+
export const exportVkey = async (finalZkeyPath: string) => {
|
|
127
|
+
const verificationKeyJSONData = await zKey.exportVerificationKey(finalZkeyPath)
|
|
128
|
+
return verificationKeyJSONData
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Helper method to extract the Solidity verifier and the Verification key
|
|
133
|
+
* from a final zKey file and save them to local files.
|
|
134
|
+
* @param finalZkeyPath <string> The path to the zKey file.
|
|
135
|
+
* @param verifierLocalPath <string> The path to the local file where the verifier will be saved.
|
|
136
|
+
* @param vKeyLocalPath <string> The path to the local file where the vKey will be saved.
|
|
137
|
+
* @param templatePath <string> The path to the template file.
|
|
138
|
+
*/
|
|
139
|
+
export const exportVerifierAndVKey = async (
|
|
140
|
+
finalZkeyPath: string,
|
|
141
|
+
verifierLocalPath: string,
|
|
142
|
+
vKeyLocalPath: string,
|
|
143
|
+
templatePath: string
|
|
144
|
+
) => {
|
|
145
|
+
const verifierCode = await exportVerifierContract(finalZkeyPath, templatePath)
|
|
146
|
+
fs.writeFileSync(verifierLocalPath, verifierCode)
|
|
147
|
+
const verificationKeyJSONData = await exportVkey(finalZkeyPath)
|
|
148
|
+
fs.writeFileSync(vKeyLocalPath, JSON.stringify(verificationKeyJSONData))
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Generate a zKey from scratch (useful to compute either the genesis or final zKey)
|
|
153
|
+
* @param isFinalizing <boolean> Whether the ceremony is finalizing or not
|
|
154
|
+
* @param r1csLocalPath <string> The path to the local r1cs file
|
|
155
|
+
* @param potLocalPath <string> The path to the local pot file
|
|
156
|
+
* @param zkeyLocalPath <string> The path to save the generated zKey
|
|
157
|
+
* @param logger <any> The logger instance
|
|
158
|
+
* @param finalContributionZKeyLocalPath <string> The path to the local zkey file of the final contribution (only for final zKey)
|
|
159
|
+
* @param coordinatorIdentifier <string> The identifier of the coordinator (only for final zKey)
|
|
160
|
+
* @param beacon <string> The beacon value for the last contribution (only for final zKey)
|
|
161
|
+
*/
|
|
162
|
+
export const generateZkeyFromScratch = async (
|
|
163
|
+
isFinalizing: boolean,
|
|
164
|
+
r1csLocalPath: string,
|
|
165
|
+
potLocalPath: string,
|
|
166
|
+
zkeyLocalPath: string,
|
|
167
|
+
logger: any,
|
|
168
|
+
finalContributionZKeyLocalPath?: string,
|
|
169
|
+
coordinatorIdentifier?: string,
|
|
170
|
+
beacon?: string
|
|
171
|
+
) => {
|
|
172
|
+
if (!fs.existsSync(r1csLocalPath) || !fs.existsSync(potLocalPath))
|
|
173
|
+
throw new Error(
|
|
174
|
+
"There was an error while opening the local files. Please make sure that you provided the right paths and try again."
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
if (isFinalizing) {
|
|
178
|
+
if (!fs.existsSync(finalContributionZKeyLocalPath!))
|
|
179
|
+
throw new Error(
|
|
180
|
+
"There was an error while opening the last zKey generated by a contributor. Please make sure that you provided the right path and try again."
|
|
181
|
+
)
|
|
182
|
+
await zKey.beacon(
|
|
183
|
+
finalContributionZKeyLocalPath,
|
|
184
|
+
zkeyLocalPath,
|
|
185
|
+
coordinatorIdentifier,
|
|
186
|
+
beacon,
|
|
187
|
+
numExpIterations,
|
|
188
|
+
logger
|
|
189
|
+
)
|
|
190
|
+
} else await zKey.newZKey(r1csLocalPath, potLocalPath, zkeyLocalPath, logger)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Helper function used to compare two ceremony artifacts
|
|
195
|
+
* @param firebaseFunctions <Functions> Firebase functions object
|
|
196
|
+
* @param localPath1 <string> Local path to store the first artifact
|
|
197
|
+
* @param localPath2 <string> Local path to store the second artifact
|
|
198
|
+
* @param storagePath1 <string> Storage path to the first artifact
|
|
199
|
+
* @param storagePath2 <string> Storage path to the second artifact
|
|
200
|
+
* @param bucketName1 <string> Bucket name of the first artifact
|
|
201
|
+
* @param bucketName2 <string> Bucket name of the second artifact
|
|
202
|
+
* @param cleanup <boolean> Whether to delete the downloaded files or not
|
|
203
|
+
* @returns <Promise<boolean>> true if the hashes match, false otherwise
|
|
204
|
+
*/
|
|
205
|
+
export const compareCeremonyArtifacts = async (
|
|
206
|
+
firebaseFunctions: Functions,
|
|
207
|
+
localPath1: string,
|
|
208
|
+
localPath2: string,
|
|
209
|
+
storagePath1: string,
|
|
210
|
+
storagePath2: string,
|
|
211
|
+
bucketName1: string,
|
|
212
|
+
bucketName2: string,
|
|
213
|
+
cleanup: boolean
|
|
214
|
+
): Promise<boolean> => {
|
|
215
|
+
// 1. download files
|
|
216
|
+
await downloadCeremonyArtifact(firebaseFunctions, bucketName1, storagePath1, localPath1)
|
|
217
|
+
await downloadCeremonyArtifact(firebaseFunctions, bucketName2, storagePath2, localPath2)
|
|
218
|
+
// 2. compare hashes
|
|
219
|
+
const res = await compareHashes(localPath1, localPath2)
|
|
220
|
+
// 3. cleanup
|
|
221
|
+
if (cleanup) {
|
|
222
|
+
fs.unlinkSync(localPath1)
|
|
223
|
+
fs.unlinkSync(localPath2)
|
|
224
|
+
}
|
|
225
|
+
// 4. return result
|
|
226
|
+
return res
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Given a ceremony prefix, download all the ceremony artifacts
|
|
231
|
+
* @param functions <Functions> firebase functions instance
|
|
232
|
+
* @param firestore <Firestore> firebase firestore instance
|
|
233
|
+
* @param ceremonyPrefix <string> ceremony prefix
|
|
234
|
+
* @param outputDirectory <string> output directory where to
|
|
235
|
+
* @returns <Promise<CeremonyArtifacts[]>> array of ceremony artifacts
|
|
236
|
+
*/
|
|
237
|
+
export const downloadAllCeremonyArtifacts = async (
|
|
238
|
+
functions: Functions,
|
|
239
|
+
firestore: Firestore,
|
|
240
|
+
ceremonyPrefix: string,
|
|
241
|
+
outputDirectory: string
|
|
242
|
+
): Promise<CeremonyArtifacts[]> => {
|
|
243
|
+
// mkdir if not exists
|
|
244
|
+
if (!fs.existsSync(outputDirectory)) {
|
|
245
|
+
fs.mkdirSync(outputDirectory)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (!process.env.CONFIG_CEREMONY_BUCKET_POSTFIX)
|
|
249
|
+
throw new Error("CONFIG_CEREMONY_BUCKET_POSTFIX not set. Please review your env file and try again.")
|
|
250
|
+
|
|
251
|
+
const ceremonyArtifacts: CeremonyArtifacts[] = []
|
|
252
|
+
|
|
253
|
+
// find the ceremony given the prefix
|
|
254
|
+
const ceremonyQuery = await queryCollection(firestore, commonTerms.collections.ceremonies.name, [
|
|
255
|
+
where(commonTerms.collections.ceremonies.fields.prefix, "==", ceremonyPrefix)
|
|
256
|
+
])
|
|
257
|
+
// get the data
|
|
258
|
+
const ceremonyData = fromQueryToFirebaseDocumentInfo(ceremonyQuery.docs)
|
|
259
|
+
if (ceremonyData.length === 0)
|
|
260
|
+
throw new Error("Ceremony not found. Please review your ceremony prefix and try again.")
|
|
261
|
+
const ceremony = ceremonyData.at(0)!
|
|
262
|
+
// reconstruct the bucket name
|
|
263
|
+
const bucketName = getBucketName(ceremonyPrefix, process.env.CONFIG_CEREMONY_BUCKET_POSTFIX!)
|
|
264
|
+
|
|
265
|
+
const circuits = await getCeremonyCircuits(firestore, ceremony.id)
|
|
266
|
+
if (circuits.length === 0)
|
|
267
|
+
throw new Error("No circuits found for this ceremony. Please review your ceremony prefix and try again.")
|
|
268
|
+
|
|
269
|
+
// for each circuit we have to download artifacts
|
|
270
|
+
for (const circuit of circuits) {
|
|
271
|
+
// make a directory for storing the circuit artifacts
|
|
272
|
+
const circuitDir = `${outputDirectory}/${ceremony.data.prefix}/${circuit.data.prefix}`
|
|
273
|
+
fs.mkdirSync(circuitDir, { recursive: true })
|
|
274
|
+
|
|
275
|
+
// get all required file names in storage and for local storage
|
|
276
|
+
const { potStoragePath } = circuit.data.files
|
|
277
|
+
const potLocalPath = `${circuitDir}/${circuit.data.files.potFilename}`
|
|
278
|
+
const { r1csStoragePath } = circuit.data.files
|
|
279
|
+
const r1csLocalPath = `${circuitDir}/${circuit.data.files.r1csFilename}`
|
|
280
|
+
const contributions = circuit.data.waitingQueue.completedContributions
|
|
281
|
+
const zkeyIndex = formatZkeyIndex(contributions)
|
|
282
|
+
const lastZKeyStoragePath = getZkeyStorageFilePath(
|
|
283
|
+
circuit.data.prefix,
|
|
284
|
+
`${circuit.data.prefix}_${zkeyIndex}.zkey`
|
|
285
|
+
)
|
|
286
|
+
const lastZKeyLocalPath = `${circuitDir}/${circuit.data.prefix}_${zkeyIndex}.zkey`
|
|
287
|
+
const finalZKeyName = `${circuit.data.prefix}_${finalContributionIndex}.zkey`
|
|
288
|
+
const finalZkeyStoragePath = getZkeyStorageFilePath(circuit.data.prefix, finalZKeyName)
|
|
289
|
+
const finalZKeyLocalPath = `${circuitDir}/${finalZKeyName}`
|
|
290
|
+
|
|
291
|
+
const verifierStoragePath = getVerifierContractStorageFilePath(
|
|
292
|
+
circuit.data.prefix,
|
|
293
|
+
`${verifierSmartContractAcronym}.sol`
|
|
294
|
+
)
|
|
295
|
+
const verifierLocalPath = `${circuitDir}/${circuit.data.prefix}_${verifierSmartContractAcronym}.sol`
|
|
296
|
+
|
|
297
|
+
const vKeyStoragePath = getVerificationKeyStorageFilePath(circuit.data.prefix, `${verificationKeyAcronym}.json`)
|
|
298
|
+
const vKeyLocalPath = `${circuitDir}/${circuit.data.prefix}_${verificationKeyAcronym}.json`
|
|
299
|
+
|
|
300
|
+
const wasmStoragePath = getWasmStorageFilePath(circuit.data.prefix, `${circuit.data.prefix}.wasm`)
|
|
301
|
+
const wasmLocalPath = `${circuitDir}/${circuit.data.prefix}.wasm`
|
|
302
|
+
|
|
303
|
+
// download everything
|
|
304
|
+
await downloadCeremonyArtifact(functions, bucketName, potStoragePath, potLocalPath)
|
|
305
|
+
await downloadCeremonyArtifact(functions, bucketName, r1csStoragePath, r1csLocalPath)
|
|
306
|
+
await downloadCeremonyArtifact(functions, bucketName, lastZKeyStoragePath, lastZKeyLocalPath)
|
|
307
|
+
await downloadCeremonyArtifact(functions, bucketName, finalZkeyStoragePath, finalZKeyLocalPath)
|
|
308
|
+
await downloadCeremonyArtifact(functions, bucketName, verifierStoragePath, verifierLocalPath)
|
|
309
|
+
await downloadCeremonyArtifact(functions, bucketName, vKeyStoragePath, vKeyLocalPath)
|
|
310
|
+
await downloadCeremonyArtifact(functions, bucketName, wasmStoragePath, wasmLocalPath)
|
|
311
|
+
|
|
312
|
+
ceremonyArtifacts.push({
|
|
313
|
+
circuitPrefix: circuit.data.prefix,
|
|
314
|
+
circuitId: circuit.id,
|
|
315
|
+
directoryRoot: circuitDir,
|
|
316
|
+
potLocalFilePath: potLocalPath,
|
|
317
|
+
r1csLocalFilePath: r1csLocalPath,
|
|
318
|
+
finalZkeyLocalFilePath: finalZKeyLocalPath,
|
|
319
|
+
lastZkeyLocalFilePath: lastZKeyLocalPath,
|
|
320
|
+
verifierLocalFilePath: verifierLocalPath,
|
|
321
|
+
verificationKeyLocalFilePath: vKeyLocalPath,
|
|
322
|
+
wasmLocalFilePath: wasmLocalPath
|
|
323
|
+
})
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return ceremonyArtifacts
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Fetch the final contribution beacon from Firestore
|
|
331
|
+
* @param firestore <Firestore> firebase firestore instance
|
|
332
|
+
* @param ceremonyId <string> ceremony id
|
|
333
|
+
* @param circuitId <string> circuit id
|
|
334
|
+
* @param participantId <string> participant id
|
|
335
|
+
* @returns <Promise<string>> final contribution beacon
|
|
336
|
+
*/
|
|
337
|
+
export const getFinalContributionBeacon = async (
|
|
338
|
+
firestore: Firestore,
|
|
339
|
+
ceremonyId: string,
|
|
340
|
+
circuitId: string,
|
|
341
|
+
participantId: string
|
|
342
|
+
): Promise<string> => {
|
|
343
|
+
const contributions = await getCircuitContributionsFromContributor(firestore, ceremonyId, circuitId, participantId)
|
|
344
|
+
|
|
345
|
+
const filtered = contributions
|
|
346
|
+
.filter((contributionDocument: any) => contributionDocument.data.zkeyIndex === finalContributionIndex)
|
|
347
|
+
.at(0)
|
|
348
|
+
if (!filtered)
|
|
349
|
+
throw new Error(
|
|
350
|
+
"Final contribution not found. Please check that you provided the correct input data and try again."
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
return filtered.data.beacon.value
|
|
354
|
+
}
|