@devtion/devcli 0.0.0-dev → 0.0.0-e312890
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 +3 -1
- package/dist/.env +54 -39
- package/dist/index.js +553 -121
- package/dist/public/mini-semaphore.wasm +0 -0
- package/dist/public/mini-semaphore.zkey +0 -0
- package/dist/types/commands/authBandada.d.ts +2 -0
- package/dist/types/commands/authSIWE.d.ts +7 -0
- package/dist/types/commands/ceremony/index.d.ts +3 -0
- package/dist/types/commands/ceremony/listParticipants.d.ts +2 -0
- package/dist/types/commands/contribute.d.ts +1 -1
- package/dist/types/commands/finalize.d.ts +4 -3
- package/dist/types/commands/index.d.ts +2 -0
- package/dist/types/commands/observe.d.ts +1 -1
- package/dist/types/commands/setup.d.ts +4 -4
- package/dist/types/lib/bandada.d.ts +6 -0
- package/dist/types/lib/files.d.ts +1 -0
- package/dist/types/lib/localConfigs.d.ts +38 -0
- package/dist/types/lib/prompts.d.ts +7 -7
- package/dist/types/lib/utils.d.ts +3 -2
- package/dist/types/types/index.d.ts +69 -0
- package/package.json +106 -97
- package/src/commands/auth.ts +24 -8
- package/src/commands/authBandada.ts +120 -0
- package/src/commands/authSIWE.ts +185 -0
- package/src/commands/ceremony/index.ts +20 -0
- package/src/commands/ceremony/listParticipants.ts +56 -0
- package/src/commands/contribute.ts +56 -29
- package/src/commands/finalize.ts +27 -14
- package/src/commands/index.ts +3 -1
- package/src/commands/listCeremonies.ts +2 -3
- package/src/commands/logout.ts +3 -1
- package/src/commands/observe.ts +8 -4
- package/src/commands/setup.ts +59 -48
- package/src/commands/validate.ts +2 -3
- package/src/index.ts +35 -13
- package/src/lib/bandada.ts +51 -0
- package/src/lib/errors.ts +2 -2
- package/src/lib/localConfigs.ts +55 -1
- package/src/lib/prompts.ts +23 -26
- package/src/lib/services.ts +39 -16
- package/src/lib/utils.ts +53 -15
- package/src/types/index.ts +75 -0
package/src/commands/index.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
export { default as setup } from "./setup.js"
|
|
2
2
|
export { default as auth } from "./auth.js"
|
|
3
|
+
export { default as authBandada } from "./authBandada.js"
|
|
4
|
+
export { default as authSIWE } from "./authSIWE.js"
|
|
3
5
|
export { default as contribute } from "./contribute.js"
|
|
4
6
|
export { default as observe } from "./observe.js"
|
|
5
7
|
export { default as finalize } from "./finalize.js"
|
|
6
8
|
export { default as clean } from "./clean.js"
|
|
7
9
|
export { default as logout } from "./logout.js"
|
|
8
10
|
export { default as validate } from "./validate.js"
|
|
9
|
-
export { default as listCeremonies} from "./listCeremonies.js"
|
|
11
|
+
export { default as listCeremonies } from "./listCeremonies.js"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { commonTerms, getAllCollectionDocs } from "@
|
|
1
|
+
import { commonTerms, getAllCollectionDocs } from "@devtion/actions"
|
|
2
2
|
import { showError } from "../lib/errors.js"
|
|
3
3
|
import { bootstrapCommandExecutionAndServices } from "../lib/services.js"
|
|
4
4
|
|
|
@@ -17,11 +17,10 @@ const listCeremonies = async () => {
|
|
|
17
17
|
|
|
18
18
|
// loop through all ceremonies
|
|
19
19
|
for (const ceremony of ceremonies) names.push(ceremony.data().prefix)
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
// print them to the console
|
|
22
22
|
console.log(names.join(", "))
|
|
23
23
|
process.exit(0)
|
|
24
|
-
|
|
25
24
|
} catch (err: any) {
|
|
26
25
|
showError(`${err.toString()}`, false)
|
|
27
26
|
// we want to exit with a non-zero exit code
|
package/src/commands/logout.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { showError } from "../lib/errors.js"
|
|
|
6
6
|
import { askForConfirmation } from "../lib/prompts.js"
|
|
7
7
|
import { customSpinner, sleep, terminate } from "../lib/utils.js"
|
|
8
8
|
import theme from "../lib/theme.js"
|
|
9
|
-
import { deleteLocalAccessToken } from "../lib/localConfigs.js"
|
|
9
|
+
import { deleteLocalAccessToken, deleteLocalAuthMethod, deleteLocalBandadaIdentity } from "../lib/localConfigs.js"
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Logout command.
|
|
@@ -52,7 +52,9 @@ const logout = async () => {
|
|
|
52
52
|
await signOut(auth)
|
|
53
53
|
|
|
54
54
|
// Delete local token.
|
|
55
|
+
deleteLocalAuthMethod()
|
|
55
56
|
deleteLocalAccessToken()
|
|
57
|
+
deleteLocalBandadaIdentity()
|
|
56
58
|
|
|
57
59
|
await sleep(3000) // ~3s.
|
|
58
60
|
|
package/src/commands/observe.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
getOpenedCeremonies,
|
|
8
8
|
isCoordinator,
|
|
9
9
|
convertToDoubleDigits
|
|
10
|
-
} from "@
|
|
10
|
+
} from "@devtion/actions"
|
|
11
11
|
import { Firestore } from "firebase/firestore"
|
|
12
12
|
import logSymbols from "log-symbols"
|
|
13
13
|
import readline from "readline"
|
|
@@ -15,7 +15,7 @@ import { COMMAND_ERRORS, GENERIC_ERRORS, showError } from "../lib/errors.js"
|
|
|
15
15
|
import { promptForCeremonySelection } from "../lib/prompts.js"
|
|
16
16
|
import { bootstrapCommandExecutionAndServices, checkAuth } from "../lib/services.js"
|
|
17
17
|
import theme from "../lib/theme.js"
|
|
18
|
-
import {customSpinner, getSecondsMinutesHoursFromMillis, sleep } from "../lib/utils.js"
|
|
18
|
+
import { customSpinner, getSecondsMinutesHoursFromMillis, sleep } from "../lib/utils.js"
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Clean cursor lines from current position back to root (default: zero).
|
|
@@ -143,11 +143,15 @@ const observe = async () => {
|
|
|
143
143
|
// Preserve command execution only for coordinators].
|
|
144
144
|
if (!(await isCoordinator(user))) showError(COMMAND_ERRORS.COMMAND_NOT_COORDINATOR, true)
|
|
145
145
|
|
|
146
|
-
// Get running
|
|
146
|
+
// Get running ceremonies info (if any).
|
|
147
147
|
const runningCeremoniesDocs = await getOpenedCeremonies(firestoreDatabase)
|
|
148
148
|
|
|
149
149
|
// Ask to select a ceremony.
|
|
150
|
-
const ceremony = await promptForCeremonySelection(
|
|
150
|
+
const ceremony = await promptForCeremonySelection(
|
|
151
|
+
runningCeremoniesDocs,
|
|
152
|
+
false,
|
|
153
|
+
"Which ceremony would you like to observe?"
|
|
154
|
+
)
|
|
151
155
|
|
|
152
156
|
console.log(`${logSymbols.info} Refresh rate set to ~3 seconds for waiting queue updates\n`)
|
|
153
157
|
|
package/src/commands/setup.ts
CHANGED
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import { zKey } from "snarkjs"
|
|
4
4
|
import boxen from "boxen"
|
|
5
|
-
import { createWriteStream, Dirent, renameSync } from "fs"
|
|
5
|
+
import { createWriteStream, Dirent, renameSync, existsSync } from "fs"
|
|
6
6
|
import { pipeline } from "node:stream"
|
|
7
7
|
import { promisify } from "node:util"
|
|
8
8
|
import fetch from "node-fetch"
|
|
9
9
|
import { Functions } from "firebase/functions"
|
|
10
|
-
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3"
|
|
11
10
|
import {
|
|
12
11
|
CeremonyTimeoutType,
|
|
13
12
|
CircomCompilerData,
|
|
@@ -37,7 +36,7 @@ import {
|
|
|
37
36
|
setupCeremony,
|
|
38
37
|
parseCeremonyFile,
|
|
39
38
|
CircuitContributionVerificationMechanism
|
|
40
|
-
} from "@
|
|
39
|
+
} from "@devtion/actions"
|
|
41
40
|
import { customSpinner, simpleLoader, sleep, terminate } from "../lib/utils.js"
|
|
42
41
|
import {
|
|
43
42
|
promptCeremonyInputData,
|
|
@@ -63,7 +62,6 @@ import {
|
|
|
63
62
|
getFileStats,
|
|
64
63
|
checkAndMakeNewDirectoryIfNonexistent
|
|
65
64
|
} from "../lib/files.js"
|
|
66
|
-
import { Readable } from "stream"
|
|
67
65
|
|
|
68
66
|
/**
|
|
69
67
|
* Handle whatever is needed to obtain the input data for a circuit that the coordinator would like to add to the ceremony.
|
|
@@ -183,7 +181,7 @@ export const handleAdditionOfCircuitsToCeremony = async (
|
|
|
183
181
|
|
|
184
182
|
if (matchingWasms.length !== 1) showError(COMMAND_ERRORS.COMMAND_SETUP_MISMATCH_R1CS_WASM, true)
|
|
185
183
|
|
|
186
|
-
// Get input data for
|
|
184
|
+
// Get input data for chosen circuit.
|
|
187
185
|
const circuitInputData = await getInputDataToAddCircuitToCeremony(
|
|
188
186
|
choosenCircuitFilename,
|
|
189
187
|
matchingWasms[0],
|
|
@@ -273,7 +271,7 @@ export const displayCeremonySummary = (ceremonyInputData: CeremonyInputData, cir
|
|
|
273
271
|
|
|
274
272
|
/**
|
|
275
273
|
* Check if the smallest Powers of Tau has already been downloaded/stored in the correspondent local path
|
|
276
|
-
* @dev we are downloading the Powers of Tau file from
|
|
274
|
+
* @dev we are downloading the Powers of Tau file from Perpetual Powers of Tau Phase 1 Trusted Setup.
|
|
277
275
|
* @param powers <string> - the smallest amount of powers needed for the given circuit (should be in a 'XY' stringified form).
|
|
278
276
|
* @param ptauCompleteFilename <string> - the complete file name of the powers of tau file to be downloaded.
|
|
279
277
|
* @returns <Promise<void>>
|
|
@@ -295,7 +293,7 @@ export const checkAndDownloadSmallestPowersOfTau = async (
|
|
|
295
293
|
const spinner = customSpinner(
|
|
296
294
|
`Downloading the ${theme.text.bold(
|
|
297
295
|
`#${powers}`
|
|
298
|
-
)} smallest PoT file needed from the
|
|
296
|
+
)} smallest PoT file needed from the Perpetual Powers of Tau Phase 1 Trusted Setup...`,
|
|
299
297
|
`clock`
|
|
300
298
|
)
|
|
301
299
|
spinner.start()
|
|
@@ -324,7 +322,7 @@ export const checkAndDownloadSmallestPowersOfTau = async (
|
|
|
324
322
|
* number of powers greater than or equal to the powers needed by the zKey), the coordinator will be asked
|
|
325
323
|
* to provide a number of powers manually, ranging from the smallest possible to the largest.
|
|
326
324
|
* @param neededPowers <number> - the smallest amount of powers needed by the zKey.
|
|
327
|
-
* @returns Promise<string, string> - the information about the
|
|
325
|
+
* @returns Promise<string, string> - the information about the chosen Powers of Tau file for the pre-computed zKey
|
|
328
326
|
* along with related powers.
|
|
329
327
|
*/
|
|
330
328
|
export const handlePreComputedZkeyPowersOfTauSelection = async (
|
|
@@ -465,10 +463,10 @@ export const handleCircuitArtifactUploadToStorage = async (
|
|
|
465
463
|
* @notice The setup command allows the coordinator of the ceremony to prepare the next ceremony by interacting with the CLI.
|
|
466
464
|
* @dev For proper execution, the command must be run in a folder containing the R1CS files related to the circuits
|
|
467
465
|
* for which the coordinator wants to create the ceremony. The command will download the necessary Tau powers
|
|
468
|
-
* from
|
|
466
|
+
* from PPoT ceremony Phase 1 Setup Ceremony.
|
|
469
467
|
* @param cmd? <any> - the path to the ceremony setup file.
|
|
470
468
|
*/
|
|
471
|
-
const setup = async (cmd: { template?: string
|
|
469
|
+
const setup = async (cmd: { template?: string; auth?: string }) => {
|
|
472
470
|
// Setup command state.
|
|
473
471
|
const circuits: Array<CircuitDocument> = [] // Circuits.
|
|
474
472
|
let ceremonyId: string = "" // The unique identifier of the ceremony.
|
|
@@ -476,8 +474,10 @@ const setup = async (cmd: { template?: string, auth?: string}) => {
|
|
|
476
474
|
const { firebaseApp, firebaseFunctions, firestoreDatabase } = await bootstrapCommandExecutionAndServices()
|
|
477
475
|
|
|
478
476
|
// Check for authentication.
|
|
479
|
-
const { user, providerUserId } = cmd.auth
|
|
480
|
-
|
|
477
|
+
const { user, providerUserId } = cmd.auth
|
|
478
|
+
? await authWithToken(firebaseApp, cmd.auth)
|
|
479
|
+
: await checkAuth(firebaseApp)
|
|
480
|
+
|
|
481
481
|
// Preserve command execution only for coordinators.
|
|
482
482
|
if (!(await isCoordinator(user))) showError(COMMAND_ERRORS.COMMAND_NOT_COORDINATOR, true)
|
|
483
483
|
|
|
@@ -503,7 +503,7 @@ const setup = async (cmd: { template?: string, auth?: string}) => {
|
|
|
503
503
|
// if there is the file option, then set up the non interactively
|
|
504
504
|
if (cmd.template) {
|
|
505
505
|
// 1. parse the file
|
|
506
|
-
// tmp data - do not cleanup files as we need them
|
|
506
|
+
// tmp data - do not cleanup files as we need them
|
|
507
507
|
const spinner = customSpinner(`Parsing ${theme.text.bold(cmd.template!)} setup configuration file...`, `clock`)
|
|
508
508
|
spinner.start()
|
|
509
509
|
const setupCeremonyData = await parseCeremonyFile(cmd.template!)
|
|
@@ -516,9 +516,6 @@ const setup = async (cmd: { template?: string, auth?: string}) => {
|
|
|
516
516
|
const bucketName = await handleCeremonyBucketCreation(firebaseFunctions, ceremonySetupData.ceremonyPrefix)
|
|
517
517
|
console.log(`\n${theme.symbols.success} Ceremony bucket name: ${theme.text.bold(bucketName)}`)
|
|
518
518
|
|
|
519
|
-
// create S3 clienbt
|
|
520
|
-
const s3 = new S3Client({region: 'us-east-1'})
|
|
521
|
-
|
|
522
519
|
// loop through each circuit
|
|
523
520
|
for await (const circuit of setupCeremonyData.circuits) {
|
|
524
521
|
// Local paths.
|
|
@@ -529,36 +526,44 @@ const setup = async (cmd: { template?: string, auth?: string}) => {
|
|
|
529
526
|
const zkeyLocalPathAndFileName = getZkeyLocalFilePath(circuit.files.initialZkeyFilename)
|
|
530
527
|
|
|
531
528
|
// 2. download the pot and wasm files
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
529
|
+
await checkAndDownloadSmallestPowersOfTau(
|
|
530
|
+
convertToDoubleDigits(circuit.metadata?.pot!),
|
|
531
|
+
circuit.files.potFilename
|
|
532
|
+
)
|
|
533
|
+
|
|
534
|
+
// 3. generate the zKey
|
|
536
535
|
const spinner = customSpinner(
|
|
537
|
-
`
|
|
538
|
-
`#${circuit.name}`
|
|
539
|
-
)} WASM file from the project's bucket...`,
|
|
536
|
+
`Generating genesis zKey for circuit ${theme.text.bold(circuit.name)}...`,
|
|
540
537
|
`clock`
|
|
541
538
|
)
|
|
542
539
|
spinner.start()
|
|
543
|
-
const command = new GetObjectCommand({ Bucket: ceremonySetupData.circuitArtifacts[index].artifacts.bucket, Key: ceremonySetupData.circuitArtifacts[index].artifacts.wasmStoragePath })
|
|
544
|
-
|
|
545
|
-
const response = await s3.send(command)
|
|
546
540
|
|
|
547
|
-
if (
|
|
548
|
-
|
|
541
|
+
if (existsSync(zkeyLocalPathAndFileName)) {
|
|
542
|
+
spinner.succeed(
|
|
543
|
+
`The genesis zKey for circuit ${theme.text.bold(circuit.name)} is already present on disk`
|
|
544
|
+
)
|
|
545
|
+
} else {
|
|
546
|
+
await zKey.newZKey(
|
|
547
|
+
r1csLocalPathAndFileName,
|
|
548
|
+
getPotLocalFilePath(circuit.files.potFilename),
|
|
549
|
+
zkeyLocalPathAndFileName,
|
|
550
|
+
undefined
|
|
551
|
+
)
|
|
552
|
+
spinner.succeed(
|
|
553
|
+
`Generation of the genesis zKey for circuit ${theme.text.bold(circuit.name)} completed successfully`
|
|
554
|
+
)
|
|
549
555
|
}
|
|
550
556
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
await zKey.newZKey(r1csLocalPathAndFileName, getPotLocalFilePath(circuit.files.potFilename), zkeyLocalPathAndFileName, undefined)
|
|
557
|
-
|
|
557
|
+
const hashSpinner = customSpinner(
|
|
558
|
+
`Calculating hashes for circuit ${theme.text.bold(circuit.name)}...`,
|
|
559
|
+
`clock`
|
|
560
|
+
)
|
|
561
|
+
hashSpinner.start()
|
|
558
562
|
// 4. calculate the hashes
|
|
559
563
|
const wasmBlake2bHash = await blake512FromPath(wasmLocalPathAndFileName)
|
|
560
564
|
const potBlake2bHash = await blake512FromPath(getPotLocalFilePath(circuit.files.potFilename))
|
|
561
565
|
const initialZkeyBlake2bHash = await blake512FromPath(zkeyLocalPathAndFileName)
|
|
566
|
+
hashSpinner.succeed(`Hashes for circuit ${theme.text.bold(circuit.name)} calculated successfully`)
|
|
562
567
|
|
|
563
568
|
// 5. upload the artifacts
|
|
564
569
|
|
|
@@ -570,7 +575,7 @@ const setup = async (cmd: { template?: string, auth?: string}) => {
|
|
|
570
575
|
zkeyLocalPathAndFileName,
|
|
571
576
|
circuit.files.initialZkeyFilename
|
|
572
577
|
)
|
|
573
|
-
|
|
578
|
+
|
|
574
579
|
// Check if PoT file has been already uploaded to storage.
|
|
575
580
|
const alreadyUploadedPot = await checkIfObjectExist(
|
|
576
581
|
firebaseFunctions,
|
|
@@ -611,25 +616,31 @@ const setup = async (cmd: { template?: string, auth?: string}) => {
|
|
|
611
616
|
// 6 update the setup data object
|
|
612
617
|
ceremonySetupData.circuits[index].files = {
|
|
613
618
|
...circuit.files,
|
|
614
|
-
potBlake2bHash
|
|
615
|
-
wasmBlake2bHash
|
|
616
|
-
initialZkeyBlake2bHash
|
|
619
|
+
potBlake2bHash,
|
|
620
|
+
wasmBlake2bHash,
|
|
621
|
+
initialZkeyBlake2bHash
|
|
617
622
|
}
|
|
618
623
|
|
|
619
624
|
ceremonySetupData.circuits[index].zKeySizeInBytes = getFileStats(zkeyLocalPathAndFileName).size
|
|
620
625
|
}
|
|
621
|
-
|
|
622
626
|
|
|
623
627
|
// 7. setup the ceremony
|
|
624
|
-
const ceremonyId = await setupCeremony(
|
|
625
|
-
|
|
626
|
-
ceremonySetupData.ceremonyInputData
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
628
|
+
const ceremonyId = await setupCeremony(
|
|
629
|
+
firebaseFunctions,
|
|
630
|
+
ceremonySetupData.ceremonyInputData,
|
|
631
|
+
ceremonySetupData.ceremonyPrefix,
|
|
632
|
+
ceremonySetupData.circuits
|
|
633
|
+
)
|
|
634
|
+
console.log(
|
|
635
|
+
`Congratulations, the setup of ceremony ${theme.text.bold(
|
|
636
|
+
ceremonySetupData.ceremonyInputData.title
|
|
637
|
+
)} (${`UID: ${theme.text.bold(ceremonyId)}`}) has been successfully completed ${
|
|
638
|
+
theme.emojis.tada
|
|
639
|
+
}. You will be able to find all the files and info respectively in the ceremony bucket and database document.`
|
|
640
|
+
)
|
|
641
|
+
|
|
631
642
|
terminate(providerUserId)
|
|
632
|
-
}
|
|
643
|
+
}
|
|
633
644
|
|
|
634
645
|
// Look for R1CS files.
|
|
635
646
|
const r1csFilePaths = await filterDirectoryFilesByExtension(cwd, `.r1cs`)
|
package/src/commands/validate.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { parseCeremonyFile } from "@
|
|
1
|
+
import { parseCeremonyFile } from "@devtion/actions"
|
|
2
2
|
import { showError } from "../lib/errors.js"
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Validate ceremony setup command.
|
|
6
6
|
*/
|
|
7
|
-
const validate = async (cmd: { template: string
|
|
7
|
+
const validate = async (cmd: { template: string; constraints?: number }) => {
|
|
8
8
|
try {
|
|
9
9
|
// parse the file and cleanup after
|
|
10
10
|
const parsedFile = await parseCeremonyFile(cmd.template, true)
|
|
@@ -18,7 +18,6 @@ const validate = async (cmd: { template: string, constraints?: number }) => {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
console.log(true)
|
|
21
|
-
|
|
22
21
|
} catch (err: any) {
|
|
23
22
|
showError(`${err.toString()}`, false)
|
|
24
23
|
// we want to exit with a non-zero exit code
|
package/src/index.ts
CHANGED
|
@@ -4,7 +4,20 @@ import { createCommand } from "commander"
|
|
|
4
4
|
import { readFileSync } from "fs"
|
|
5
5
|
import { dirname } from "path"
|
|
6
6
|
import { fileURLToPath } from "url"
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
setup,
|
|
9
|
+
auth,
|
|
10
|
+
authSIWE,
|
|
11
|
+
authBandada,
|
|
12
|
+
contribute,
|
|
13
|
+
observe,
|
|
14
|
+
finalize,
|
|
15
|
+
clean,
|
|
16
|
+
logout,
|
|
17
|
+
validate,
|
|
18
|
+
listCeremonies
|
|
19
|
+
} from "./commands/index.js"
|
|
20
|
+
import setCeremonyCommands from "./commands/ceremony/index.js"
|
|
8
21
|
|
|
9
22
|
// Get pkg info (e.g., name, version).
|
|
10
23
|
const packagePath = `${dirname(fileURLToPath(import.meta.url))}/..`
|
|
@@ -16,51 +29,60 @@ program.name(name).description(description).version(version)
|
|
|
16
29
|
|
|
17
30
|
// User commands.
|
|
18
31
|
program.command("auth").description("authenticate yourself using your Github account (OAuth 2.0)").action(auth)
|
|
32
|
+
program
|
|
33
|
+
.command("auth-bandada")
|
|
34
|
+
.description("authenticate yourself in a privacy-perserving manner using Bandada")
|
|
35
|
+
.action(authBandada)
|
|
36
|
+
program
|
|
37
|
+
.command("auth-siwe")
|
|
38
|
+
.description("authenticate yourself using your Ethereum account (Sign In With Ethereum - SIWE)")
|
|
39
|
+
.action(authSIWE)
|
|
19
40
|
program
|
|
20
41
|
.command("contribute")
|
|
21
42
|
.description("compute contributions for a Phase2 Trusted Setup ceremony circuits")
|
|
22
43
|
.option("-c, --ceremony <string>", "the prefix of the ceremony you want to contribute for", "")
|
|
23
44
|
.option("-e, --entropy <string>", "the entropy (aka toxic waste) of your contribution", "")
|
|
45
|
+
.option("-a, --auth <string>", "the Github OAuth 2.0 token", "")
|
|
24
46
|
.action(contribute)
|
|
25
47
|
program
|
|
26
48
|
.command("clean")
|
|
27
49
|
.description("clean up output generated by commands from the current working directory")
|
|
28
50
|
.action(clean)
|
|
29
|
-
program
|
|
30
|
-
.command("list")
|
|
31
|
-
.description("List all ceremonies prefixes")
|
|
32
|
-
.action(listCeremonies)
|
|
51
|
+
program.command("list").description("List all ceremonies prefixes").action(listCeremonies)
|
|
33
52
|
program
|
|
34
53
|
.command("logout")
|
|
35
54
|
.description("sign out from Firebae Auth service and delete Github OAuth 2.0 token from local storage")
|
|
36
55
|
.action(logout)
|
|
37
56
|
program
|
|
38
57
|
.command("validate")
|
|
39
|
-
.description("
|
|
58
|
+
.description("validate that a Ceremony Setup file is correct")
|
|
40
59
|
.requiredOption("-t, --template <path>", "The path to the ceremony setup template", "")
|
|
41
60
|
.option("-c, --constraints <number>", "The number of constraints to check against")
|
|
42
61
|
.action(validate)
|
|
43
62
|
|
|
44
63
|
// Only coordinator commands.
|
|
45
|
-
const
|
|
64
|
+
const coordinate = program.command("coordinate").description("commands for coordinating a ceremony")
|
|
46
65
|
|
|
47
|
-
|
|
66
|
+
coordinate
|
|
48
67
|
.command("setup")
|
|
49
68
|
.description("setup a Groth16 Phase 2 Trusted Setup ceremony for zk-SNARK circuits")
|
|
50
|
-
.option(
|
|
51
|
-
.option(
|
|
69
|
+
.option("-t, --template <path>", "The path to the ceremony setup template", "")
|
|
70
|
+
.option("-a, --auth <string>", "The Github OAuth 2.0 token", "")
|
|
52
71
|
.action(setup)
|
|
53
|
-
|
|
54
|
-
|
|
72
|
+
|
|
73
|
+
coordinate
|
|
55
74
|
.command("observe")
|
|
56
75
|
.description("observe in real-time the waiting queue of each ceremony circuit")
|
|
57
76
|
.action(observe)
|
|
58
77
|
|
|
59
|
-
|
|
78
|
+
coordinate
|
|
60
79
|
.command("finalize")
|
|
61
80
|
.description(
|
|
62
81
|
"finalize a Phase2 Trusted Setup ceremony by applying a beacon, exporting verification key and verifier contract"
|
|
63
82
|
)
|
|
83
|
+
.option("-a, --auth <string>", "the Github OAuth 2.0 token", "")
|
|
64
84
|
.action(finalize)
|
|
65
85
|
|
|
86
|
+
setCeremonyCommands(program)
|
|
87
|
+
|
|
66
88
|
program.parseAsync(process.argv)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { ApiSdk, GroupResponse } from "@bandada/api-sdk"
|
|
2
|
+
import { Identity } from "@semaphore-protocol/identity"
|
|
3
|
+
import open from "open"
|
|
4
|
+
|
|
5
|
+
import { askForConfirmation } from "../lib/prompts.js"
|
|
6
|
+
import { showError } from "./errors.js"
|
|
7
|
+
import theme from "../lib/theme.js"
|
|
8
|
+
|
|
9
|
+
const { BANDADA_API_URL } = process.env
|
|
10
|
+
|
|
11
|
+
const bandadaApi = new ApiSdk(BANDADA_API_URL)
|
|
12
|
+
|
|
13
|
+
export const getGroup = async (groupId: string): Promise<GroupResponse | null> => {
|
|
14
|
+
try {
|
|
15
|
+
const group = await bandadaApi.getGroup(groupId)
|
|
16
|
+
return group
|
|
17
|
+
} catch (error: any) {
|
|
18
|
+
showError(`Bandada getGroup error: ${error}`, true)
|
|
19
|
+
return null
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const getMembersOfGroup = async (groupId: string): Promise<string[] | null> => {
|
|
24
|
+
try {
|
|
25
|
+
const group = await bandadaApi.getGroup(groupId)
|
|
26
|
+
return group.members
|
|
27
|
+
} catch (error: any) {
|
|
28
|
+
showError(`Bandada getMembersOfGroup error: ${error}`, true)
|
|
29
|
+
return null
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const addMemberToGroup = async (groupId: string, dashboardUrl: string, identity: Identity) => {
|
|
34
|
+
const commitment = identity.commitment.toString()
|
|
35
|
+
const group = await bandadaApi.getGroup(groupId)
|
|
36
|
+
const providerName = group.credentials.id.split("_")[0].toLowerCase()
|
|
37
|
+
|
|
38
|
+
// 6. open a new window with the url:
|
|
39
|
+
const url = `${dashboardUrl}credentials?group=${groupId}&member=${commitment}&provider=${providerName}`
|
|
40
|
+
console.log(`${theme.text.bold(`Verification URL:`)} ${theme.text.underlined(url)}`)
|
|
41
|
+
open(url)
|
|
42
|
+
|
|
43
|
+
const { confirmation } = await askForConfirmation("Did you join the Bandada group in the browser?")
|
|
44
|
+
if (!confirmation) showError("You must join the Bandada group to continue the login process", true)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const isGroupMember = async (groupId: string, identity: Identity): Promise<boolean> => {
|
|
48
|
+
const commitment = identity.commitment.toString()
|
|
49
|
+
const isMember: boolean = await bandadaApi.isGroupMember(groupId, commitment)
|
|
50
|
+
return isMember
|
|
51
|
+
}
|
package/src/lib/errors.ts
CHANGED
|
@@ -6,7 +6,7 @@ export const CORE_SERVICES_ERRORS = {
|
|
|
6
6
|
FIREBASE_TOKEN_EXPIRED_REMOVED_PERMISSIONS: `The Github authorization has failed due to lack of association between your account and the CLI`,
|
|
7
7
|
FIREBASE_USER_DISABLED: `The Github account has been suspended by the ceremony coordinator(s), blocking the possibility of contribution. Please, contact them to understand the motivation behind it.`,
|
|
8
8
|
FIREBASE_FAILED_CREDENTIALS_VERIFICATION: `Firebase cannot verify your Github credentials due to network errors. Please, try once again later.`,
|
|
9
|
-
FIREBASE_NETWORK_ERROR: `Unable to reach Firebase due to network
|
|
9
|
+
FIREBASE_NETWORK_ERROR: `Unable to reach Firebase due to network errors. Please, try once again later and make sure your Internet connection is stable.`,
|
|
10
10
|
FIREBASE_CEREMONY_NOT_OPENED: `There are no ceremonies opened to contributions`,
|
|
11
11
|
FIREBASE_CEREMONY_NOT_CLOSED: `There are no ceremonies ready to finalization`,
|
|
12
12
|
AWS_CEREMONY_BUCKET_CREATION: `Unable to create a new bucket for the ceremony. Something went wrong during the creation. Please, repeat the process by providing a new ceremony name of the ceremony.`,
|
|
@@ -34,7 +34,7 @@ export const COMMAND_ERRORS = {
|
|
|
34
34
|
COMMAND_SETUP_NO_R1CS: `Unable to retrieve R1CS files from current working directory. Please, run this command from a working directory where the R1CS files are located to continue with the setup process. We kindly ask you to run the command from an empty directory containing only the R1CS and WASM files.`,
|
|
35
35
|
COMMAND_SETUP_NO_WASM: `Unable to retrieve WASM files from current working directory. Please, run this command from a working directory where the WASM files are located to continue with the setup process. We kindly ask you to run the command from an empty directory containing only the WASM and R1CS files.`,
|
|
36
36
|
COMMAND_SETUP_MISMATCH_R1CS_WASM: `The folder contains more R1CS files than WASM files (or vice versa). Please, run this command from a working directory where each R1CS is paired with its corresponding file WASM.`,
|
|
37
|
-
COMMAND_SETUP_DOWNLOAD_PTAU: `Unable to download Powers of Tau file from
|
|
37
|
+
COMMAND_SETUP_DOWNLOAD_PTAU: `Unable to download Powers of Tau file from PPoT Phase 1 Trusted Setup. Possible causes may involve an error while making the request (be sure to have a stable internet connection). Please, we kindly ask you to terminate the current session and repeat the process.`,
|
|
38
38
|
COMMAND_SETUP_ABORT: `You chose to abort the setup process.`,
|
|
39
39
|
COMMAND_CONTRIBUTE_NO_OPENED_CEREMONIES: `Unfortunately, there is no ceremony for which you can make a contribution at this time. Please, try again later.`,
|
|
40
40
|
COMMAND_CONTRIBUTE_NO_PARTICIPANT_DATA: `Unable to retrieve your data as ceremony participant. Please, terminate the current session and try again later. If the error persists, please contact the ceremony coordinator.`,
|
package/src/lib/localConfigs.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { commonTerms } from "@
|
|
1
|
+
import { commonTerms } from "@devtion/actions"
|
|
2
2
|
import Conf from "conf"
|
|
3
3
|
import { dirname } from "path"
|
|
4
4
|
import { readFileSync } from "fs"
|
|
@@ -24,6 +24,14 @@ const config = new Conf({
|
|
|
24
24
|
accessToken: {
|
|
25
25
|
type: "string",
|
|
26
26
|
default: ""
|
|
27
|
+
},
|
|
28
|
+
bandadaIdentity: {
|
|
29
|
+
type: "string",
|
|
30
|
+
default: ""
|
|
31
|
+
},
|
|
32
|
+
authMethod: {
|
|
33
|
+
type: "string",
|
|
34
|
+
default: ""
|
|
27
35
|
}
|
|
28
36
|
}
|
|
29
37
|
})
|
|
@@ -91,6 +99,52 @@ export const setLocalAccessToken = (token: string) => config.set("accessToken",
|
|
|
91
99
|
*/
|
|
92
100
|
export const deleteLocalAccessToken = () => config.delete("accessToken")
|
|
93
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Return the Bandada identity, if present.
|
|
104
|
+
* @returns <string | undefined> - the Bandada identity if present, otherwise undefined.
|
|
105
|
+
*/
|
|
106
|
+
export const getLocalBandadaIdentity = (): string | unknown => config.get("bandadaIdentity")
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Check if the Bandada identity exists in the local storage.
|
|
110
|
+
* @returns <boolean>
|
|
111
|
+
*/
|
|
112
|
+
export const checkLocalBandadaIdentity = (): boolean => config.has("bandadaIdentity") && !!config.get("bandadaIdentity")
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Set the Bandada identity.
|
|
116
|
+
* @param identity <string> - the Bandada identity to be stored.
|
|
117
|
+
*/
|
|
118
|
+
export const setLocalBandadaIdentity = (identity: string) => config.set("bandadaIdentity", identity)
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Delete the stored Bandada identity.
|
|
122
|
+
*/
|
|
123
|
+
export const deleteLocalBandadaIdentity = () => config.delete("bandadaIdentity")
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Return the authentication method, if present.
|
|
127
|
+
* @returns <string | undefined> - the authentication method if present, otherwise undefined.
|
|
128
|
+
*/
|
|
129
|
+
export const getLocalAuthMethod = (): string | unknown => config.get("authMethod")
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Check if the authentication method exists in the local storage.
|
|
133
|
+
* @returns <boolean>
|
|
134
|
+
*/
|
|
135
|
+
export const checkLocalAuthMethod = (): boolean => config.has("authMethod") && !!config.get("authMethod")
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Set the authentication method.
|
|
139
|
+
* @param method <string> - the authentication method to be stored.
|
|
140
|
+
*/
|
|
141
|
+
export const setLocalAuthMethod = (method: string) => config.set("authMethod", method)
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Delete the stored authentication method.
|
|
145
|
+
*/
|
|
146
|
+
export const deleteLocalAuthMethod = () => config.delete("authMethod")
|
|
147
|
+
|
|
94
148
|
/**
|
|
95
149
|
* Get the complete local file path.
|
|
96
150
|
* @param cwd <string> - the current working directory path.
|