Skip to content

Commit

Permalink
feat(cli): improve cli integration ux
Browse files Browse the repository at this point in the history
- [x] Return transaction hash from signup command
- [x] Add indexed params for signup event
- [x] Add command to check if user is registered and get state index
  • Loading branch information
0xmad committed Feb 20, 2024
1 parent 53ba930 commit 7727ab1
Show file tree
Hide file tree
Showing 14 changed files with 144 additions and 19 deletions.
3 changes: 3 additions & 0 deletions cli/testScript.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ node build/ts/index.js deployPoll \
-t 30 -i 1 -m 2 -b 1 -v 2 -se false
node build/ts/index.js signup \
--pubkey macipk.e743ffb5298ef0f5c1f63b6464a48fea19ea7ee5a885c67ae1b24a1d04f03f07
node build/ts/index.js isRegisteredUser \
--pubkey macipk.e743ffb5298ef0f5c1f63b6464a48fea19ea7ee5a885c67ae1b24a1d04f03f07 \
--quiet false
node build/ts/index.js publish \
--pubkey macipk.e743ffb5298ef0f5c1f63b6464a48fea19ea7ee5a885c67ae1b24a1d04f03f07 \
--privkey macisk.0ab0281365e01cff60afc62310daec765e590487bf989a7c4986ebc3fd49895e \
Expand Down
18 changes: 16 additions & 2 deletions cli/tests/e2e/e2e.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { expect } from "chai";
import { getDefaultSigner } from "maci-contracts";
import { genRandomSalt } from "maci-crypto";
import { Keypair } from "maci-domainobjs";
Expand All @@ -23,6 +24,7 @@ import {
timeTravel,
topup,
verify,
isRegisteredUser,
} from "../../ts/commands";
import { DeployedContracts, GenProofsArgs, PollContracts } from "../../ts/utils";
import {
Expand Down Expand Up @@ -618,7 +620,7 @@ describe("e2e tests", function test() {
maciAddresses = await deploy({ ...deployArgs, signer });
});

it("should run the first poll", async () => {
it.only("should run the first poll", async () => {
// deploy a poll contract
pollAddresses = await deployPoll({ ...deployPollArgs, signer });

Expand All @@ -627,6 +629,16 @@ describe("e2e tests", function test() {
for (let i = 0; i < users.length; i += 1) {
// eslint-disable-next-line no-await-in-loop
await signup({ maciAddress: maciAddresses.maciAddress, maciPubKey: users[i].pubKey.serialize(), signer });

// eslint-disable-next-line no-await-in-loop
const { isRegistered, stateIndex } = await isRegisteredUser({
maciAddress: maciAddresses.maciAddress,
maciPubKey: users[i].pubKey.serialize(),
signer,
});

expect(isRegistered).to.eq(true);
expect(stateIndex).to.not.eq(undefined);
}

// publish
Expand Down Expand Up @@ -868,7 +880,9 @@ describe("e2e tests", function test() {

it("should signup one user", async () => {
stateIndex = BigInt(
await signup({ maciAddress: maciAddresses.maciAddress, maciPubKey: user.pubKey.serialize(), signer }),
await signup({ maciAddress: maciAddresses.maciAddress, maciPubKey: user.pubKey.serialize(), signer }).then(
(result) => result.stateIndex,
),
);
});

Expand Down
12 changes: 9 additions & 3 deletions cli/tests/e2e/keyChange.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ describe("keyChange tests", function test() {
// deploy a poll contract
await deployPoll({ ...deployPollArgs, signer });
stateIndex = BigInt(
await signup({ maciAddress: maciAddresses.maciAddress, maciPubKey: keypair1.pubKey.serialize(), signer }),
await signup({ maciAddress: maciAddresses.maciAddress, maciPubKey: keypair1.pubKey.serialize(), signer }).then(
(result) => result.stateIndex,
),
);
await publish({
pubkey: keypair1.pubKey.serialize(),
Expand Down Expand Up @@ -172,7 +174,9 @@ describe("keyChange tests", function test() {
// deploy a poll contract
await deployPoll({ ...deployPollArgs, signer });
stateIndex = BigInt(
await signup({ maciAddress: maciAddresses.maciAddress, maciPubKey: keypair1.pubKey.serialize(), signer }),
await signup({ maciAddress: maciAddresses.maciAddress, maciPubKey: keypair1.pubKey.serialize(), signer }).then(
(result) => result.stateIndex,
),
);
await publish({
pubkey: keypair1.pubKey.serialize(),
Expand Down Expand Up @@ -240,7 +244,9 @@ describe("keyChange tests", function test() {
// deploy a poll contract
await deployPoll({ ...deployPollArgs, signer });
stateIndex = BigInt(
await signup({ maciAddress: maciAddresses.maciAddress, maciPubKey: keypair1.pubKey.serialize(), signer }),
await signup({ maciAddress: maciAddresses.maciAddress, maciPubKey: keypair1.pubKey.serialize(), signer }).then(
(result) => result.stateIndex,
),
);
await publish({
pubkey: keypair1.pubKey.serialize(),
Expand Down
2 changes: 1 addition & 1 deletion cli/ts/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export { publish } from "./publish";
export { setVerifyingKeys } from "./setVerifyingKeys";
export { showContracts } from "./showContracts";
export { timeTravel } from "./timeTravel";
export { signup } from "./signup";
export { signup, isRegisteredUser } from "./signup";
export { topup } from "./topup";
export { verify } from "./verify";
export { genProofs } from "./genProofs";
Expand Down
43 changes: 38 additions & 5 deletions cli/ts/commands/signup.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { MACI__factory as MACIFactory } from "maci-contracts/typechain-types";
import { PubKey } from "maci-domainobjs";

import type { SignupArgs } from "../utils/interfaces";
import type { IRegisteredUserArgs, SignupArgs } from "../utils/interfaces";
import type { ContractTransactionReceipt } from "ethers";

import { banner } from "../utils/banner";
import { contractExists } from "../utils/contracts";
Expand All @@ -11,7 +12,7 @@ import { info, logError, logGreen, logYellow, success } from "../utils/theme";
/**
* Signup a user to the MACI contract
* @param SignupArgs - The arguments for the signup command
* @returns The state index of the user
* @returns The state index of the user and transaction hash
*/
export const signup = async ({
maciPubKey,
Expand All @@ -20,7 +21,7 @@ export const signup = async ({
ivcpDataArg,
signer,
quiet = true,
}: SignupArgs): Promise<string> => {
}: SignupArgs): Promise<{ stateIndex: string; hash: string }> => {
banner(quiet);

// validate user key
Expand Down Expand Up @@ -51,10 +52,12 @@ export const signup = async ({
const maciContract = MACIFactory.connect(maciAddress, signer);

let stateIndex = "";
let receipt: ContractTransactionReceipt | null = null;

try {
// sign up to the MACI contract
const tx = await maciContract.signUp(userMaciPubKey.asContractParam(), sgData, ivcpData);
const receipt = await tx.wait();
receipt = await tx.wait();

logYellow(quiet, info(`Transaction hash: ${tx.hash}`));

Expand All @@ -77,5 +80,35 @@ export const signup = async ({
logError((error as Error).message);
}

return stateIndex ? stateIndex.toString() : "";
return {
stateIndex: stateIndex ? stateIndex.toString() : "",
hash: receipt!.hash,
};
};

/**
* Checks if user is registered with public key
* @param IRegisteredArgs - The arguments for the register check command
* @returns user registered or not and state index
*/
export const isRegisteredUser = async ({
maciAddress,
maciPubKey,
signer,
quiet = true,
}: IRegisteredUserArgs): Promise<{ isRegistered: boolean; stateIndex?: string }> => {
banner(quiet);

const maciContract = MACIFactory.connect(maciAddress, signer);
const publicKey = PubKey.deserialize(maciPubKey).asContractParam();

const events = await maciContract.queryFilter(maciContract.filters.SignUp(undefined, publicKey.x, publicKey.y));
const stateIndex = events[0]?.args.toString() as string | undefined;

logGreen(quiet, success(`State index: ${stateIndex?.toString()}, registered: ${stateIndex !== undefined}`));

return {
isRegistered: stateIndex !== undefined,
stateIndex,
};
};
27 changes: 27 additions & 0 deletions cli/ts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
mergeSignups,
timeTravel,
signup,
isRegisteredUser,
topup,
verify,
genProofs,
Expand Down Expand Up @@ -408,6 +409,29 @@ program
program.error((error as Error).message, { exitCode: 1 });
}
});
program
.command("isRegisteredUser")
.description("Checks if user is registered with public key")
.requiredOption("-p, --pubkey <maciPubKey>", "the MACI public key")
.option("-x, --maci-address <maciAddress>", "the MACI contract address")
.option("-q, --quiet <quiet>", "whether to print values to the console", (value) => value === "true", false)
.action(async (cmdObj) => {
try {
const signer = await getSigner();
const network = await signer.provider?.getNetwork();

const maciContractAddress = cmdObj.maciAddress || readContractAddress("MACI", network?.name);

await isRegisteredUser({
maciPubKey: cmdObj.pubkey,
maciAddress: maciContractAddress,
signer,
quiet: cmdObj.quiet,
});
} catch (error) {
program.error((error as Error).message, { exitCode: 1 });
}
});
program
.command("topup")
.description("Top up an account with voice credits")
Expand Down Expand Up @@ -679,6 +703,7 @@ export {
proveOnChain,
setVerifyingKeys,
signup,
isRegisteredUser,
timeTravel,
topup,
verify,
Expand All @@ -701,4 +726,6 @@ export type {
ProveOnChainArgs,
DeployArgs,
SubsidyData,
IRegisteredUserArgs,
IGenKeypairArgs,
} from "./utils";
6 changes: 4 additions & 2 deletions cli/ts/sdk/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { genKeyPair } from "../commands/genKeyPair";
import { genMaciPubKey } from "../commands/genPubKey";
import { publish } from "../commands/publish";
import { signup } from "../commands/signup";
import { signup, isRegisteredUser } from "../commands/signup";
import { verify } from "../commands/verify";

export { genKeyPair, genMaciPubKey, publish, signup, verify };
export { genKeyPair, genMaciPubKey, publish, signup, isRegisteredUser, verify };

export type { Signer } from "ethers";

export type {
DeployedContracts,
Expand Down
2 changes: 2 additions & 0 deletions cli/ts/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export type {
TopupArgs,
VerifyArgs,
SubsidyData,
IRegisteredUserArgs,
IGenKeypairArgs,
} from "./interfaces";
export { compareVks } from "./vks";
export { delay } from "./time";
Expand Down
25 changes: 25 additions & 0 deletions cli/ts/utils/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,31 @@ export interface SignupArgs {
quiet?: boolean;
}

/**
* Interface for the arguments to the register check command
*/
export interface IRegisteredUserArgs {
/**
* A signer object
*/
signer: Signer;

/**
* The public key of the user
*/
maciPubKey: string;

/**
* The address of the MACI contract
*/
maciAddress: string;

/**
* Whether to log the output
*/
quiet?: boolean;
}

/**
* Interface for the arguments to the topup command
*/
Expand Down
10 changes: 8 additions & 2 deletions contracts/contracts/MACI.sol
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,13 @@ contract MACI is IMACI, Params, Utilities, Ownable {
}

// Events
event SignUp(uint256 _stateIndex, PubKey _userPubKey, uint256 _voiceCreditBalance, uint256 _timestamp);
event SignUp(
uint256 _stateIndex,
uint256 indexed _userPubKeyX,
uint256 indexed _userPubKeyY,
uint256 _voiceCreditBalance,
uint256 _timestamp
);
event DeployPoll(uint256 _pollId, PubKey _pubKey, PollContracts pollAddr);

/// @notice Only allow a Poll contract to call the modified function.
Expand Down Expand Up @@ -186,7 +192,7 @@ contract MACI is IMACI, Params, Utilities, Ownable {
uint256 stateLeaf = hashStateLeaf(StateLeaf(_pubKey, voiceCreditBalance, timestamp));
uint256 stateIndex = stateAq.enqueue(stateLeaf);

emit SignUp(stateIndex, _pubKey, voiceCreditBalance, timestamp);
emit SignUp(stateIndex, _pubKey.x, _pubKey.y, voiceCreditBalance, timestamp);
}

/// @notice Deploy a new Poll contract.
Expand Down
2 changes: 1 addition & 1 deletion contracts/deploy-config-example.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"EASGatekeeper": {
"deploy": true,
"easAddress": "0xC2679fBD37d54388Ce493F1DB75320D236e1815e",
"schema": "0xfdcfdad2dbe7489e0ce56b260348b7f14e8365a8a325aef9834818c00d46b31b",
"schema": "0xe2636f31239f7948afdd9a9c477048b7fc2a089c347af60e3aa1251e5bf63e5c",
"attester": "attester-address"
},
"MACI": {
Expand Down
10 changes: 8 additions & 2 deletions contracts/ts/genMaciState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,13 @@ export const genMaciStateFromContract = async (
assert(!!log);
const mutableLog = { ...log, topics: [...log.topics] };
const event = maciIface.parseLog(mutableLog) as unknown as {
args: { _stateIndex: number; _userPubKey: string[]; _voiceCreditBalance: number; _timestamp: number };
args: {
_stateIndex: number;
_userPubKeyX: string;
_userPubKeyY: string;
_voiceCreditBalance: number;
_timestamp: number;
};
};

actions.push({
Expand All @@ -95,7 +101,7 @@ export const genMaciStateFromContract = async (
transactionIndex: log.transactionIndex,
data: {
stateIndex: Number(event.args._stateIndex),
pubKey: new PubKey(event.args._userPubKey.map((x) => BigInt(x)) as [bigint, bigint]),
pubKey: new PubKey([BigInt(event.args._userPubKeyX), BigInt(event.args._userPubKeyY)]),
voiceCreditBalance: Number(event.args._voiceCreditBalance),
timestamp: Number(event.args._timestamp),
},
Expand Down
2 changes: 1 addition & 1 deletion integrationTests/ts/__tests__/integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ describe("Integration tests", function test() {
sgDataArg: SG_DATA,
ivcpDataArg: ivcpData,
signer,
}),
}).then((result) => result.stateIndex),
);

// signup on local maci state
Expand Down
Loading

0 comments on commit 7727ab1

Please sign in to comment.