From d3cab947fcc2f49fa1252f72d15889dc21975591 Mon Sep 17 00:00:00 2001 From: ctrlc03 <93448202+ctrlc03@users.noreply.github.com> Date: Thu, 2 May 2024 20:37:30 +0100 Subject: [PATCH] refactor(topup): remove the topup feature remove the topup feature until a more appropriate design is proposed. Currently the feature is not used in production and adds unnecessary complexity to the code. A re-design is necessary to make it an effective feature. BREAKING CHANGE: No more topups --- .../circom/core/non-qv/processMessages.circom | 51 +-- .../circom/core/qv/processMessages.circom | 54 +-- circuits/circom/utils/hashers.circom | 22 +- circuits/circom/utils/messageToCommand.circom | 10 +- circuits/circom/utils/processTopup.circom | 95 ----- circuits/ts/__tests__/ProcessMessages.test.ts | 79 +---- cli/tests/e2e/e2e.test.ts | 72 ---- cli/tests/unit/airdrop.test.ts | 35 -- cli/tests/unit/topup.test.ts | 58 --- cli/ts/commands/airdrop.ts | 80 ----- cli/ts/commands/deploy.ts | 12 +- cli/ts/commands/index.ts | 2 - cli/ts/commands/topup.ts | 67 ---- cli/ts/index.ts | 56 --- cli/ts/utils/index.ts | 2 - cli/ts/utils/interfaces.ts | 71 ---- contracts/contracts/MACI.sol | 17 +- contracts/contracts/MessageProcessor.sol | 4 +- contracts/contracts/Poll.sol | 31 +- contracts/contracts/PollFactory.sol | 8 +- contracts/contracts/Tally.sol | 2 +- contracts/contracts/TopupCredit.sol | 40 --- contracts/contracts/interfaces/IPoll.sol | 9 +- .../contracts/interfaces/IPollFactory.sol | 3 - contracts/contracts/utilities/DomainObjs.sol | 3 +- contracts/contracts/utilities/Params.sol | 2 - contracts/contracts/utilities/Utilities.sol | 9 +- contracts/tests/MACI.test.ts | 2 +- contracts/tests/MessageProcessor.test.ts | 2 +- contracts/tests/Poll.test.ts | 53 +-- contracts/tests/PollFactory.test.ts | 2 - contracts/tests/Tally.test.ts | 6 +- contracts/tests/TallyNonQv.test.ts | 2 +- contracts/tests/Utilities.test.ts | 23 +- contracts/tests/utils.ts | 14 +- contracts/ts/deploy.ts | 12 - contracts/ts/genMaciState.ts | 32 +- contracts/ts/index.ts | 1 - contracts/ts/types.ts | 7 - core/ts/Poll.ts | 331 ++++++------------ core/ts/__tests__/MaciState.test.ts | 41 --- core/ts/__tests__/Poll.test.ts | 18 +- core/ts/utils/types.ts | 8 +- crypto/ts/__tests__/Crypto.test.ts | 26 +- crypto/ts/hashing.ts | 13 +- crypto/ts/index.ts | 2 +- domainobjs/ts/__tests__/commands.test.ts | 37 +- domainobjs/ts/__tests__/message.test.ts | 52 ++- domainobjs/ts/commands/PCommand.ts | 11 +- domainobjs/ts/commands/TCommand.ts | 65 ---- domainobjs/ts/commands/index.ts | 3 +- domainobjs/ts/commands/types.ts | 21 +- domainobjs/ts/index.ts | 9 +- domainobjs/ts/message.ts | 26 +- domainobjs/ts/types.ts | 1 - integrationTests/ts/__tests__/utils/utils.ts | 13 +- 56 files changed, 250 insertions(+), 1477 deletions(-) delete mode 100644 circuits/circom/utils/processTopup.circom delete mode 100644 cli/tests/unit/airdrop.test.ts delete mode 100644 cli/tests/unit/topup.test.ts delete mode 100644 cli/ts/commands/airdrop.ts delete mode 100644 cli/ts/commands/topup.ts delete mode 100644 contracts/contracts/TopupCredit.sol delete mode 100644 domainobjs/ts/commands/TCommand.ts diff --git a/circuits/circom/core/non-qv/processMessages.circom b/circuits/circom/core/non-qv/processMessages.circom index 644126dc03..0b23232346 100644 --- a/circuits/circom/core/non-qv/processMessages.circom +++ b/circuits/circom/core/non-qv/processMessages.circom @@ -9,8 +9,8 @@ include "../../utils/hashers.circom"; include "../../utils/messageToCommand.circom"; include "../../utils/privToPubKey.circom"; include "../../utils/processMessagesInputHasher.circom"; -include "../../utils/processTopup.circom"; include "../../utils/non-qv/stateLeafAndBallotTransformer.circom"; +include "../../trees/incrementalMerkleTree.circom"; include "../../trees/incrementalQuinaryTree.circom"; /** @@ -36,7 +36,7 @@ include "../../trees/incrementalQuinaryTree.circom"; // Default for Binary trees. var STATE_TREE_ARITY = 2; var batchSize = MESSAGE_TREE_ARITY ** msgBatchDepth; - var MSG_LENGTH = 11; + var MSG_LENGTH = 10; var PACKED_CMD_LENGTH = 4; var STATE_LEAF_LENGTH = 4; var BALLOT_LENGTH = 2; @@ -292,7 +292,6 @@ include "../../trees/incrementalQuinaryTree.circom"; } (computedNewVoteStateRoot[i], computedNewVoteBallotRoot[i]) = ProcessOneNonQv(stateTreeDepth, voteOptionTreeDepth)( - msgs[i][0], numSignUps, maxVoteOptions, pollEndTimestamp, @@ -306,7 +305,6 @@ include "../../trees/incrementalQuinaryTree.circom"; currentVoteWeights[i], currentVoteWeightsPathElement, computedCommandsStateIndex[i], - msgs[i][1], computedCommandsNewPubKey[i], computedCommandsVoteOptionIndex[i], computedCommandsNewVoteWeight[i], @@ -318,27 +316,8 @@ include "../../trees/incrementalQuinaryTree.circom"; computedCommandsPackedCommandOut[i] ); - // Process as topup type message. - computedNewTopupStateRoot[i] = ProcessTopup(stateTreeDepth)( - msgs[i][0], - msgs[i][1], - msgs[i][2], - numSignUps, - actualStateTreeDepth, - currentStateLeaves[i], - currentStateLeavesPathElement - ); - - // Pick the correct result by Message type. - tmpStateRoot1[i] <== computedNewVoteStateRoot[i] * (2 - msgs[i][0]); - tmpStateRoot2[i] <== computedNewTopupStateRoot[i] * (msgs[i][0] - 1); - - tmpBallotRoot1[i] <== computedNewVoteBallotRoot[i] * (2 - msgs[i][0]); - tmpBallotRoot2[i] <== ballotRoots[i + 1] * (msgs[i][0] - 1); - - stateRoots[i] <== tmpStateRoot1[i] + tmpStateRoot2[i]; - - ballotRoots[i] <== tmpBallotRoot1[i] + tmpBallotRoot2[i]; + stateRoots[i] <== computedNewVoteStateRoot[i]; + ballotRoots[i] <== computedNewVoteBallotRoot[i]; } var computedNewSbCommitment = PoseidonHasher(3)([stateRoots[0], ballotRoots[0], newSbSalt]); @@ -357,7 +336,7 @@ template ProcessOneNonQv(stateTreeDepth, voteOptionTreeDepth) { // Constants defining the structure and size of state and ballots. var STATE_LEAF_LENGTH = 4; var BALLOT_LENGTH = 2; - var MSG_LENGTH = 11; + var MSG_LENGTH = 10; var PACKED_CMD_LENGTH = 4; var MESSAGE_TREE_ARITY = 5; var STATE_TREE_ARITY = 2; @@ -376,7 +355,6 @@ template ProcessOneNonQv(stateTreeDepth, voteOptionTreeDepth) { var N_BITS = 252; // Inputs representing the message and the current state. - signal input msgType; signal input numSignUps; signal input maxVoteOptions; signal input pollEndTimestamp; @@ -403,7 +381,6 @@ template ProcessOneNonQv(stateTreeDepth, voteOptionTreeDepth) { // Inputs related to the command being processed. signal input cmdStateIndex; - signal input topupStateIndex; signal input cmdNewPubKey[2]; signal input cmdVoteOptionIndex; signal input cmdNewVoteWeight; @@ -418,12 +395,6 @@ template ProcessOneNonQv(stateTreeDepth, voteOptionTreeDepth) { signal output newBallotRoot; // Intermediate signals. - // cmdStateIndex * (2 - msgType). - signal tmpIndex1; - // topupStateIndex * (msgType - 1). - signal tmpIndex2; - // sum of tmpIndex1 + tmpIndex2. - signal indexByType; // currentVoteWeight * currentVoteWeight. signal b; // cmdNewVoteWeight * cmdNewVoteWeight. @@ -455,14 +426,10 @@ template ProcessOneNonQv(stateTreeDepth, voteOptionTreeDepth) { packedCmd ); - // 2. If msgType and isValid are equal to zero, generate indices for leaf zero. - // Otherwise, generate indices for commmand.stateIndex or topupStateIndex depending on msgType. - tmpIndex1 <== cmdStateIndex * (2 - msgType); - tmpIndex2 <== topupStateIndex * (msgType - 1); - indexByType <== tmpIndex1 + tmpIndex2; - - var stateLeafIndexValid = SafeLessThan(N_BITS)([indexByType, numSignUps]); - var stateIndexMux = Mux1()([0, indexByType], stateLeafIndexValid); + // 2. If isValid is equal to zero, generate indices for leaf zero. + // Otherwise, generate indices for commmand.stateIndex. + var stateLeafIndexValid = SafeLessThan(N_BITS)([cmdStateIndex, numSignUps]); + var stateIndexMux = Mux1()([0, cmdStateIndex], stateLeafIndexValid); var computedStateLeafPathIndices[stateTreeDepth] = MerkleGeneratePathIndices(stateTreeDepth)(stateIndexMux); // 3. Verify that the original state leaf exists in the given state root. diff --git a/circuits/circom/core/qv/processMessages.circom b/circuits/circom/core/qv/processMessages.circom index c432e23342..8ac4da038f 100644 --- a/circuits/circom/core/qv/processMessages.circom +++ b/circuits/circom/core/qv/processMessages.circom @@ -9,7 +9,6 @@ include "../../utils/hashers.circom"; include "../../utils/messageToCommand.circom"; include "../../utils/privToPubKey.circom"; include "../../utils/processMessagesInputHasher.circom"; -include "../../utils/processTopup.circom"; include "../../utils/qv/stateLeafAndBallotTransformer.circom"; include "../../trees/incrementalQuinaryTree.circom"; include "../../trees/incrementalMerkleTree.circom"; @@ -37,7 +36,7 @@ template ProcessMessages( // Default for binary trees. var STATE_TREE_ARITY = 2; var batchSize = MESSAGE_TREE_ARITY ** msgBatchDepth; - var MSG_LENGTH = 11; + var MSG_LENGTH = 10; var PACKED_CMD_LENGTH = 4; var STATE_LEAF_LENGTH = 4; var BALLOT_LENGTH = 2; @@ -123,10 +122,6 @@ template ProcessMessages( // signals (for processing purposes). signal stateRoots[batchSize + 1]; signal ballotRoots[batchSize + 1]; - signal tmpStateRoot1[batchSize]; - signal tmpStateRoot2[batchSize]; - signal tmpBallotRoot1[batchSize]; - signal tmpBallotRoot2[batchSize]; // Must verify the current sb commitment. var computedCurrentSbCommitment = PoseidonHasher(3)([currentStateRoot, currentBallotRoot, currentSbSalt]); @@ -292,7 +287,6 @@ template ProcessMessages( } (computedNewVoteStateRoot[i], computedNewVoteBallotRoot[i]) = ProcessOne(stateTreeDepth, voteOptionTreeDepth)( - msgs[i][0], numSignUps, maxVoteOptions, pollEndTimestamp, @@ -306,7 +300,6 @@ template ProcessMessages( currentVoteWeights[i], currentVoteWeightsPathElement, computedCommandsStateIndex[i], - msgs[i][1], computedCommandsNewPubKey[i], computedCommandsVoteOptionIndex[i], computedCommandsNewVoteWeight[i], @@ -318,27 +311,8 @@ template ProcessMessages( computedCommandsPackedCommandOut[i] ); - // Process as topup type message. - computedNewTopupStateRoot[i] = ProcessTopup(stateTreeDepth)( - msgs[i][0], - msgs[i][1], - msgs[i][2], - numSignUps, - actualStateTreeDepth, - currentStateLeaves[i], - currentStateLeavesPathElement - ); - - // Pick the correct result by Message type. - tmpStateRoot1[i] <== computedNewVoteStateRoot[i] * (2 - msgs[i][0]); - tmpStateRoot2[i] <== computedNewTopupStateRoot[i] * (msgs[i][0] - 1); - - tmpBallotRoot1[i] <== computedNewVoteBallotRoot[i] * (2 - msgs[i][0]); - tmpBallotRoot2[i] <== ballotRoots[i + 1] * (msgs[i][0] - 1); - - stateRoots[i] <== tmpStateRoot1[i] + tmpStateRoot2[i]; - - ballotRoots[i] <== tmpBallotRoot1[i] + tmpBallotRoot2[i]; + stateRoots[i] <== computedNewVoteStateRoot[i]; + ballotRoots[i] <== computedNewVoteBallotRoot[i]; } var computedNewSbCommitment = PoseidonHasher(3)([stateRoots[0], ballotRoots[0], newSbSalt]); @@ -357,7 +331,7 @@ template ProcessOne(stateTreeDepth, voteOptionTreeDepth) { // Constants defining the structure and size of state and ballots. var STATE_LEAF_LENGTH = 4; var BALLOT_LENGTH = 2; - var MSG_LENGTH = 11; + var MSG_LENGTH = 10; var PACKED_CMD_LENGTH = 4; var MESSAGE_TREE_ARITY = 5; var STATE_TREE_ARITY = 2; @@ -376,7 +350,6 @@ template ProcessOne(stateTreeDepth, voteOptionTreeDepth) { var N_BITS = 252; // Inputs representing the message and the current state. - signal input msgType; signal input numSignUps; signal input maxVoteOptions; signal input pollEndTimestamp; @@ -403,7 +376,6 @@ template ProcessOne(stateTreeDepth, voteOptionTreeDepth) { // Inputs related to the command being processed. signal input cmdStateIndex; - signal input topupStateIndex; signal input cmdNewPubKey[2]; signal input cmdVoteOptionIndex; signal input cmdNewVoteWeight; @@ -418,12 +390,6 @@ template ProcessOne(stateTreeDepth, voteOptionTreeDepth) { signal output newBallotRoot; // Intermediate signals. - // cmdStateIndex * (2 - msgType). - signal tmpIndex1; - // topupStateIndex * (msgType - 1). - signal tmpIndex2; - // sum of tmpIndex1 + tmpIndex2. - signal indexByType; // currentVoteWeight * currentVoteWeight. signal b; // cmdNewVoteWeight * cmdNewVoteWeight. @@ -455,14 +421,10 @@ template ProcessOne(stateTreeDepth, voteOptionTreeDepth) { packedCmd ); - // 2. If msgType and isValid are equal to zero, generate indices for leaf zero. - // Otherwise, generate indices for commmand.stateIndex or topupStateIndex depending on msgType. - tmpIndex1 <== cmdStateIndex * (2 - msgType); - tmpIndex2 <== topupStateIndex * (msgType - 1); - indexByType <== tmpIndex1 + tmpIndex2; - - var stateLeafIndexValid = SafeLessThan(N_BITS)([indexByType, numSignUps]); - var stateIndexMux = Mux1()([0, indexByType], stateLeafIndexValid); + // 2. If isValid is equal to zero, generate indices for leaf zero. + // Otherwise, generate indices for commmand.stateIndex. + var stateLeafIndexValid = SafeLessThan(N_BITS)([cmdStateIndex, numSignUps]); + var stateIndexMux = Mux1()([0, cmdStateIndex], stateLeafIndexValid); var computedStateLeafPathIndices[stateTreeDepth] = MerkleGeneratePathIndices(stateTreeDepth)(stateIndexMux); // 3. Verify that the original state leaf exists in the given state root. diff --git a/circuits/circom/utils/hashers.circom b/circuits/circom/utils/hashers.circom index e1d7a2568c..4be6531964 100644 --- a/circuits/circom/utils/hashers.circom +++ b/circuits/circom/utils/hashers.circom @@ -70,22 +70,21 @@ template PoseidonHasher(n) { /** * Hashes a MACI message and the public key used for message encryption. - * This template processes 11 message inputs and a 2-element public key + * This template processes 10 message inputs and a 2-element public key * combining them using the Poseidon hash function. The hashing process involves two stages: * 1. hashing message parts in groups of five and, * 2. hashing the grouped results alongside the first message input and * the encryption public key to produce a final hash output. */ template MessageHasher() { - // 11 inputs are the MACI message. - signal input in[11]; + // The MACI message is composed of 10 parts. + signal input in[10]; // the public key used to encrypt the message. signal input encPubKey[2]; // we output an hash. signal output hash; - // Hasher5( - // in[0] + // Hasher4( // Hasher5_1(in[1], in[2], in[3], in[4], in[5]), // Hasher5_2(in[6], in[7], in[8], in[9], in[10]) // in[11], @@ -94,24 +93,23 @@ template MessageHasher() { var computedHasher5_1; computedHasher5_1 = PoseidonHasher(5)([ + in[0], in[1], in[2], in[3], - in[4], - in[5] + in[4] ]); var computedHasher5_2; computedHasher5_2 = PoseidonHasher(5)([ - in[6], + in[5], + in[6], in[7], in[8], - in[9], - in[10] + in[9] ]); - hash <== PoseidonHasher(5)([ - in[0], + hash <== PoseidonHasher(4)([ computedHasher5_1, computedHasher5_2, encPubKey[0], diff --git a/circuits/circom/utils/messageToCommand.circom b/circuits/circom/utils/messageToCommand.circom index 9f25e131af..5777937393 100644 --- a/circuits/circom/utils/messageToCommand.circom +++ b/circuits/circom/utils/messageToCommand.circom @@ -21,9 +21,9 @@ template MessageToCommand() { var UNPACKED_CMD_LENGTH = 8; var UNPACK_ELEM_LENGTH = 5; var DECRYPTED_LENGTH = 9; - var MESSAGE_PARTS = 11; + var MESSAGE_PARTS = 10; - // The message is an array of 11 parts. + // The message is an array of 10 parts. signal input message[MESSAGE_PARTS]; signal input encPrivKey; signal input encPubKey[2]; @@ -48,9 +48,9 @@ template MessageToCommand() { var computedDecryptor[DECRYPTED_LENGTH] = PoseidonDecryptWithoutCheck(MSG_LENGTH)( [ // nb. the first one is the msg type => skip. - message[1], message[2], message[3], message[4], - message[5], message[6], message[7], message[8], - message[9], message[10] + message[0], message[1], message[2], message[3], + message[4], message[5], message[6], message[7], + message[8], message[9] ], 0, computedEcdh diff --git a/circuits/circom/utils/processTopup.circom b/circuits/circom/utils/processTopup.circom deleted file mode 100644 index 365cdcc3d7..0000000000 --- a/circuits/circom/utils/processTopup.circom +++ /dev/null @@ -1,95 +0,0 @@ -pragma circom 2.0.0; - -// circomlib import -include "./mux1.circom"; -// zk-kit imports -include "./safe-comparators.circom"; -// local imports -include "./hashers.circom"; -include "../trees/incrementalMerkleTree.circom"; - -/** - * Processes top-ups for a state tree, managing updates based on the transaction's message type and amount. - * Through conditional logic ensures messages are valid within the specified state tree depth and user sign-up count. - * Through mux components and balance checks, it updates the state leaf's voice credit balance, while verifying - * the message fields against the current state tree structure. - * - * nb. the message type of top-up command is always equal to two. - */ -template ProcessTopup(stateTreeDepth) { - // Constants defining the structure and size of state and ballots. - var STATE_LEAF_LENGTH = 4; - var MSG_LENGTH = 11; - var STATE_TREE_ARITY = 2; - - // Indices for elements within a state leaf. - // Public key. - var STATE_LEAF_PUB_X_IDX = 0; - var STATE_LEAF_PUB_Y_IDX = 1; - // Voice Credit balance. - var STATE_LEAF_VOICE_CREDIT_BALANCE_IDX = 2; - // Timestamp. - var STATE_LEAF_TIMESTAMP_IDX = 3; - var N_BITS = 252; - - // Inputs for the template. - signal input msgType; - signal input stateTreeIndex; - signal input amount; - signal input numSignUps; - - // The actual state tree depth (can be <= stateTreeDepth) - signal input actualStateTreeDepth; - // The state leaf and related path elements. - signal input stateLeaf[STATE_LEAF_LENGTH]; - // Sibling nodes at each level of the state tree to verify the specific state leaf. - signal input stateLeafPathElements[stateTreeDepth][STATE_TREE_ARITY - 1]; - - signal output newStateRoot; - - // skipping state leaf verify (checked in ProcessOne template). - - // Amount to be processed, adjusted based on msgType. - signal amt; - // State tree index, adjusted based on msgType. - signal index; - // New credit balance after processing the message. - signal newCreditBalance; - - // nb. msgType of top-up command is 2. - amt <== amount * (msgType - 1); - index <== stateTreeIndex * (msgType - 1); - - // check the state index and, if invalid, set index and amount to zero. - var computedIsStateLeafIndexValid = LessEqThan(N_BITS)([index, numSignUps]); - var computedIndexMux = Mux1()([0, index], computedIsStateLeafIndexValid); - var computedAmtMux = Mux1()([0, amt], computedIsStateLeafIndexValid); - - // check less than field size. - newCreditBalance <== stateLeaf[STATE_LEAF_VOICE_CREDIT_BALANCE_IDX] + computedAmtMux; - - var computedIsCreditBalanceValid = LessEqThan(N_BITS)([ - stateLeaf[STATE_LEAF_VOICE_CREDIT_BALANCE_IDX], - newCreditBalance - ]); - - // If the new one is <= the old one, then we have a valid topup. - var computedCreditBalanceMux = Mux1()([stateLeaf[STATE_LEAF_VOICE_CREDIT_BALANCE_IDX], newCreditBalance], computedIsCreditBalanceValid); - - // update the voice balance balance. - var computedNewStateLeaf = PoseidonHasher(4)([ - stateLeaf[STATE_LEAF_PUB_X_IDX], - stateLeaf[STATE_LEAF_PUB_Y_IDX], - computedCreditBalanceMux, - stateLeaf[STATE_LEAF_TIMESTAMP_IDX] - ]); - - var computedStateLeafPathIndices[stateTreeDepth] = MerkleGeneratePathIndices(stateTreeDepth)(computedIndexMux); - - newStateRoot <== BinaryMerkleRoot(stateTreeDepth)( - computedNewStateLeaf, - actualStateTreeDepth, - computedStateLeafPathIndices, - stateLeafPathElements - ); -} \ No newline at end of file diff --git a/circuits/ts/__tests__/ProcessMessages.test.ts b/circuits/ts/__tests__/ProcessMessages.test.ts index 020a56622f..6562ec6501 100644 --- a/circuits/ts/__tests__/ProcessMessages.test.ts +++ b/circuits/ts/__tests__/ProcessMessages.test.ts @@ -101,7 +101,7 @@ describe("ProcessMessage circuit", function test() { poll = maciState.polls.get(pollId)!; poll.updatePoll(BigInt(maciState.stateLeaves.length)); - const nothing = new Message(1n, [ + const nothing = new Message([ 8370432830353022751713833565135785980866757267633941821328460903436894336785n, 0n, 0n, @@ -499,77 +499,6 @@ describe("ProcessMessage circuit", function test() { }); }); - describe("1 user, 1 topup, 2 messages", () => { - const maciState = new MaciState(STATE_TREE_DEPTH); - const voteOptionIndex = BigInt(0); - let stateIndex: bigint; - let pollId: bigint; - let poll: Poll; - const userKeypair = new Keypair(); - - before(() => { - // Sign up and publish - stateIndex = BigInt( - maciState.signUp(userKeypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))), - ); - - pollId = maciState.deployPoll( - BigInt(Math.floor(Date.now() / 1000) + duration), - maxValues, - treeDepths, - messageBatchSize, - coordinatorKeypair, - ); - - poll = maciState.polls.get(pollId)!; - poll.updatePoll(BigInt(maciState.stateLeaves.length)); - }); - - it("should work when publishing 2 vote messages and a topup (the second vote uses more than initial voice credit balance)", async () => { - // First command (valid) - const command1 = new PCommand( - stateIndex, // BigInt(1), - userKeypair.pubKey, - voteOptionIndex + 1n, // voteOptionIndex, - 5n, // vote weight - BigInt(2), // nonce - BigInt(pollId), - ); - - const signature1 = command1.sign(userKeypair.privKey); - - const ecdhKeypair1 = new Keypair(); - const sharedKey1 = Keypair.genEcdhSharedKey(ecdhKeypair1.privKey, coordinatorKeypair.pubKey); - const message1 = command1.encrypt(signature1, sharedKey1); - - poll.publishMessage(message1, ecdhKeypair1.pubKey); - - poll.topupMessage(new Message(2n, [BigInt(stateIndex), 50n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n])); - - // First command (valid) - const command = new PCommand( - stateIndex, // BigInt(1), - userKeypair.pubKey, - voteOptionIndex, // voteOptionIndex, - 10n, // vote weight - BigInt(1), // nonce - BigInt(pollId), - ); - - const signature = command.sign(userKeypair.privKey); - - const ecdhKeypair = new Keypair(); - const sharedKey = Keypair.genEcdhSharedKey(ecdhKeypair.privKey, coordinatorKeypair.pubKey); - const message = command.encrypt(signature, sharedKey); - - poll.publishMessage(message, ecdhKeypair.pubKey); - - const inputs = poll.processMessages(pollId) as unknown as IProcessMessagesInputs; - const witness = await circuit.calculateWitness(inputs); - await circuit.expectConstraintPass(witness); - }); - }); - describe("1 user, 2 messages", () => { const maciState = new MaciState(STATE_TREE_DEPTH); const voteOptionIndex = 1n; @@ -597,7 +526,7 @@ describe("ProcessMessage circuit", function test() { poll = maciState.polls.get(pollId)!; poll.updatePoll(BigInt(maciState.stateLeaves.length)); - const nothing = new Message(1n, [ + const nothing = new Message([ 8370432830353022751713833565135785980866757267633941821328460903436894336785n, 0n, 0n, @@ -714,7 +643,7 @@ describe("ProcessMessage circuit", function test() { poll = maciState.polls.get(pollId)!; poll.updatePoll(BigInt(maciState.stateLeaves.length)); - const nothing = new Message(1n, [ + const nothing = new Message([ 8370432830353022751713833565135785980866757267633941821328460903436894336785n, 0n, 0n, @@ -839,7 +768,7 @@ describe("ProcessMessage circuit", function test() { poll = maciState.polls.get(pollId)!; poll.updatePoll(BigInt(maciState.stateLeaves.length)); - const nothing = new Message(1n, [ + const nothing = new Message([ 8370432830353022751713833565135785980866757267633941821328460903436894336785n, 0n, 0n, diff --git a/cli/tests/e2e/e2e.test.ts b/cli/tests/e2e/e2e.test.ts index d427d12625..f022d08be8 100644 --- a/cli/tests/e2e/e2e.test.ts +++ b/cli/tests/e2e/e2e.test.ts @@ -8,7 +8,6 @@ import fs from "fs"; import type { Signer } from "ethers"; import { - airdrop, checkVerifyingKeys, deploy, deployPoll, @@ -22,7 +21,6 @@ import { setVerifyingKeys, signup, timeTravel, - topup, verify, isRegisteredUser, } from "../../ts/commands"; @@ -63,7 +61,6 @@ import { clean, isArm } from "../utils"; test if keys are set correctly given a set of files 1 signup and 1 valid message for multiple polls 7 signups and 1 message, another polls and 6 messages - 1 signup, 1 topup message and 1 vote message */ describe("e2e tests", function test() { const useWasm = isArm(); @@ -953,73 +950,4 @@ describe("e2e tests", function test() { await verify({ ...verifyArgs(), signer }); }); }); - - describe("topup message", () => { - const user = new Keypair(); - const tokenAmount = 100; - let stateIndex: bigint | undefined; - - after(() => { - clean(); - }); - - before(async () => { - // deploy the smart contracts - maciAddresses = await deploy({ ...deployArgs, signer }); - // deploy a poll contract - pollAddresses = await deployPoll({ ...deployPollArgs, signer }); - }); - - it("should signup one user", async () => { - stateIndex = BigInt( - await signup({ maciAddress: maciAddresses.maciAddress, maciPubKey: user.pubKey.serialize(), signer }).then( - (result) => result.stateIndex, - ), - ); - }); - - it("should airdrop topup tokens to the coordinator user", async () => { - await airdrop({ - amount: tokenAmount, - pollId: 0n, - contractAddress: maciAddresses.topupCreditAddress, - maciAddress: maciAddresses.maciAddress, - signer, - }); - }); - - it("should publish one topup message", async () => { - await topup({ - amount: tokenAmount, - stateIndex: Number(stateIndex!), - pollId: 0n, - maciAddress: maciAddresses.maciAddress, - signer, - }); - }); - - it("should publish one vote message", async () => { - await publish({ - pubkey: user.pubKey.serialize(), - stateIndex: stateIndex!, - voteOptionIndex: 5n, - nonce: 1n, - pollId: 0n, - newVoteWeight: 3n, - maciAddress: maciAddresses.maciAddress, - salt: genRandomSalt(), - privateKey: user.privKey.serialize(), - signer, - }); - }); - - it("should generate proofs and verify them", async () => { - await timeTravel({ ...timeTravelArgs, signer }); - await mergeMessages({ ...mergeMessagesArgs, signer }); - await mergeSignups({ ...mergeSignupsArgs, signer }); - await genProofs({ ...genProofsArgs, signer }); - await proveOnChain({ ...proveOnChainArgs, signer }); - await verify({ ...verifyArgs(), signer }); - }); - }); }); diff --git a/cli/tests/unit/airdrop.test.ts b/cli/tests/unit/airdrop.test.ts deleted file mode 100644 index ee55c4ce8e..0000000000 --- a/cli/tests/unit/airdrop.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import chai, { expect } from "chai"; -import chaiAsPromised from "chai-as-promised"; -import { Signer, ZeroAddress } from "ethers"; -import { deployTopupCredit, getDefaultSigner } from "maci-contracts"; - -import { airdrop } from "../../ts"; - -chai.use(chaiAsPromised); - -describe("airdrop", () => { - let signer: Signer; - let topupContractAddress: string | undefined; - - before(async () => { - signer = await getDefaultSigner(); - const topupContract = await deployTopupCredit(await getDefaultSigner(), true); - topupContractAddress = await topupContract.getAddress(); - }); - - it("should airdrop tokens to the coordinator", async () => { - await expect(airdrop({ amount: 100, contractAddress: topupContractAddress, signer })).to.be.fulfilled; - }); - - it("should throw when the amount is negative", async () => { - await expect(airdrop({ amount: -1, contractAddress: topupContractAddress, signer })).to.be.rejectedWith( - "Invalid amount", - ); - }); - - it("should throw when the ERC20 contract address is invalid", async () => { - await expect(airdrop({ amount: 100, contractAddress: ZeroAddress, signer })).to.be.rejectedWith( - "Invalid ERC20 contract address", - ); - }); -}); diff --git a/cli/tests/unit/topup.test.ts b/cli/tests/unit/topup.test.ts deleted file mode 100644 index 5160081420..0000000000 --- a/cli/tests/unit/topup.test.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { expect } from "chai"; -import { Signer } from "ethers"; -import { - deployConstantInitialVoiceCreditProxy, - deployFreeForAllSignUpGatekeeper, - deployMaci, - deployTopupCredit, - getDefaultSigner, -} from "maci-contracts"; - -import { topup } from "../../ts"; - -describe("topup", () => { - let signer: Signer; - let maciAddress: string; - - before(async () => { - signer = await getDefaultSigner(); - const signupGatekepper = await deployFreeForAllSignUpGatekeeper(signer, true); - const topupCredit = await deployTopupCredit(signer, true); - const initialVoiceCreditProxyAddress = await deployConstantInitialVoiceCreditProxy(100, signer, true); - const [signUpTokenGatekeeperContractAddress, initialVoiceCreditBalanceAddress, topupCreditContractAddress] = - await Promise.all([ - signupGatekepper.getAddress(), - initialVoiceCreditProxyAddress.getAddress(), - topupCredit.getAddress(), - ]); - - const { maciContract } = await deployMaci({ - signUpTokenGatekeeperContractAddress, - initialVoiceCreditBalanceAddress, - topupCreditContractAddress, - signer, - stateTreeDepth: 10, - quiet: true, - }); - - maciAddress = await maciContract.getAddress(); - }); - - it("should throw when the state index is invalid", async () => { - await expect(topup({ amount: 100, pollId: 0n, stateIndex: 0, maciAddress, signer })).to.be.rejectedWith( - "State index must be greater than 0", - ); - }); - - it("should throw when the poll ID is invalid", async () => { - await expect(topup({ amount: 100, pollId: -1n, stateIndex: 1, maciAddress, signer })).to.be.rejectedWith( - "Poll ID must be a positive integer", - ); - }); - - it("should throw when the amount is invalid", async () => { - await expect(topup({ amount: 0, pollId: 0n, stateIndex: 1, maciAddress, signer })).to.be.rejectedWith( - "Topup amount must be greater than 0", - ); - }); -}); diff --git a/cli/ts/commands/airdrop.ts b/cli/ts/commands/airdrop.ts deleted file mode 100644 index 67ce7d3e5c..0000000000 --- a/cli/ts/commands/airdrop.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { MACI__factory as MACIFactory, TopupCredit__factory as TopupCreditFactory } from "maci-contracts"; - -import { type AirdropArgs, logError, logGreen, success, readContractAddress, contractExists, banner } from "../utils"; - -/** - * Utility that can be used to get - * topup credits airdropped - * to the coordinator - * @param AirdropArgs - The arguments for the airdrop command - */ -export const airdrop = async ({ - amount, - contractAddress, - pollId, - maciAddress, - signer, - quiet = true, -}: AirdropArgs): Promise => { - banner(quiet); - const network = await signer.provider?.getNetwork(); - - // get the topup credit address from storage - const topupCredit = readContractAddress("TopupCredit", network?.name); - - // we want to ensure that we have either the address stored - // or that it was passed as a parameter - if (!topupCredit && !contractAddress) { - logError("Please provide an ERC20 contract address"); - } - - const ERC20Address = contractAddress || topupCredit; - - // check if the contract exists - if (!(await contractExists(signer.provider!, ERC20Address))) { - logError("Invalid ERC20 contract address"); - } - - // create the contract instance - const tokenContract = TopupCreditFactory.connect(ERC20Address, signer); - - if (amount < 0) { - logError("Invalid amount"); - } - - // try to get the tokens airdropped - try { - const tx = await tokenContract.airdrop(amount.toString(), { - gasLimit: 1000000, - }); - await tx.wait(); - - logGreen(quiet, success(`Airdropped ${amount} credits to ${await signer.getAddress()}`)); - } catch (error) { - logError((error as Error).message); - } - - // if there is a poll id provided, we can pre-approve all of the tokens - // so there is no need to do it afterwards - if (pollId !== undefined) { - const maciContractAddress = readContractAddress("MACI", network?.name) - ? readContractAddress("MACI", network?.name) - : maciAddress; - - if (!maciAddress) { - logError("Please provide a MACI contract address"); - } - - const maciContract = MACIFactory.connect(maciContractAddress!, signer); - - const pollAddr = await maciContract.getPoll(pollId); - try { - const tx = await tokenContract.approve(pollAddr, amount, { gasLimit: 1000000 }); - await tx.wait(); - - logGreen(quiet, success(`Approved ${pollAddr} to spend ${amount} credits`)); - } catch (error) { - logError((error as Error).message); - } - } -}; diff --git a/cli/ts/commands/deploy.ts b/cli/ts/commands/deploy.ts index 2f98c9d89e..1c27885965 100644 --- a/cli/ts/commands/deploy.ts +++ b/cli/ts/commands/deploy.ts @@ -3,7 +3,6 @@ import { deployFreeForAllSignUpGatekeeper, deployVerifier, deployMaci, - deployTopupCredit, } from "maci-contracts"; import { @@ -74,19 +73,12 @@ export const deploy = async ({ // deploy a verifier contract const verifierContract = await deployVerifier(signer, true); - // topup credit - const topUpCredit = await deployTopupCredit(signer, true); - - const [verifierContractAddress, topUpCreditAddress] = await Promise.all([ - verifierContract.getAddress(), - topUpCredit.getAddress(), - ]); + const verifierContractAddress = await verifierContract.getAddress(); // deploy MACI, stateAq, PollFactory and poseidon const { maciContract, pollFactoryContract, poseidonAddrs } = await deployMaci({ signUpTokenGatekeeperContractAddress: signupGatekeeperContractAddress, initialVoiceCreditBalanceAddress: initialVoiceCreditProxyContractAddress, - topupCreditContractAddress: topUpCreditAddress, poseidonAddresses: { poseidonT3, poseidonT4, @@ -109,7 +101,6 @@ export const deploy = async ({ storeContractAddress("Verifier", verifierContractAddress, network?.name); storeContractAddress("MACI", maciContractAddress, network?.name); storeContractAddress("PollFactory", pollFactoryContractAddress, network?.name); - storeContractAddress("TopupCredit", topUpCreditAddress, network?.name); storeContractAddress("PoseidonT3", poseidonAddrs.poseidonT3, network?.name); storeContractAddress("PoseidonT4", poseidonAddrs.poseidonT4, network?.name); storeContractAddress("PoseidonT5", poseidonAddrs.poseidonT5, network?.name); @@ -122,7 +113,6 @@ export const deploy = async ({ maciAddress: maciContractAddress, pollFactoryAddress: pollFactoryContractAddress, verifierAddress: verifierContractAddress, - topupCreditAddress: topUpCreditAddress, poseidonT3Address: poseidonAddrs.poseidonT3, poseidonT4Address: poseidonAddrs.poseidonT4, poseidonT5Address: poseidonAddrs.poseidonT5, diff --git a/cli/ts/commands/index.ts b/cli/ts/commands/index.ts index 3b4e38c159..ba6beff754 100644 --- a/cli/ts/commands/index.ts +++ b/cli/ts/commands/index.ts @@ -1,4 +1,3 @@ -export { airdrop } from "./airdrop"; export { deploy } from "./deploy"; export { deployPoll } from "./deployPoll"; export { getPoll } from "./poll"; @@ -12,7 +11,6 @@ export { setVerifyingKeys } from "./setVerifyingKeys"; export { showContracts } from "./showContracts"; export { timeTravel } from "./timeTravel"; export { signup, isRegisteredUser } from "./signup"; -export { topup } from "./topup"; export { verify } from "./verify"; export { genProofs } from "./genProofs"; export { fundWallet } from "./fundWallet"; diff --git a/cli/ts/commands/topup.ts b/cli/ts/commands/topup.ts deleted file mode 100644 index 6d185cc2b7..0000000000 --- a/cli/ts/commands/topup.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { MACI__factory as MACIFactory, Poll__factory as PollFactory } from "maci-contracts"; - -import { type TopupArgs, logError, readContractAddress, contractExists, banner } from "../utils"; - -/** - * Publish a topup message - * @param TopupArgs - The arguments for the topup command - */ -export const topup = async ({ - amount, - stateIndex, - pollId, - maciAddress, - signer, - quiet = true, -}: TopupArgs): Promise => { - banner(quiet); - const network = await signer.provider?.getNetwork(); - - // ensure we have a valid MACI contract address - if (!maciAddress && !readContractAddress(maciAddress!, network?.name)) { - logError("Invalid MACI contract address"); - return; - } - - const maciContractAddress = maciAddress || readContractAddress(maciAddress!, network?.name); - - if (!(await contractExists(signer.provider!, maciContractAddress))) { - logError("There is no contract deployed at the specified address"); - } - - // validate the params - if (amount < 1) { - logError("Topup amount must be greater than 0"); - } - - if (stateIndex < 1) { - logError("State index must be greater than 0"); - } - - if (pollId < 0) { - logError("Poll ID must be a positive integer"); - } - - const maciContract = MACIFactory.connect(maciContractAddress, signer); - const pollAddr = await maciContract.getPoll(pollId); - - if (!(await contractExists(signer.provider!, pollAddr))) { - logError("There is no Poll contract with this poll ID linked to the specified MACI contract."); - } - - const pollContract = PollFactory.connect(pollAddr, signer); - - try { - // submit the topup message on chain - const tx = await pollContract.topup(stateIndex, amount.toString(), { - gasLimit: 1000000, - }); - const receipt = await tx.wait(); - - if (receipt?.status !== 1) { - logError("The transaction failed"); - } - } catch (error) { - logError((error as Error).message); - } -}; diff --git a/cli/ts/index.ts b/cli/ts/index.ts index ff03f39670..dc04417ffb 100644 --- a/cli/ts/index.ts +++ b/cli/ts/index.ts @@ -11,7 +11,6 @@ import "./cliInit"; import { genKeyPair, genMaciPubKey, - airdrop, deployVkRegistryContract, deploy, showContracts, @@ -24,7 +23,6 @@ import { timeTravel, signup, isRegisteredUser, - topup, verify, genProofs, fundWallet, @@ -139,31 +137,6 @@ program .action((cmdObj) => { genKeyPair({ seed: cmdObj.seed, quiet: cmdObj.quiet }); }); -program - .command("airdrop") - .description("airdrop topup credits to the coordinator") - .requiredOption("-a, --amount ", "the amount of topup", parseInt) - .option("-x, --maci-address ", "the MACI contract address") - .option("-o, --poll-id ", "poll id", BigInt) - .option("-t, --token-address ", "the token address") - .option("-q, --quiet ", "whether to print values to the console", (value) => value === "true", false) - .option("-r, --rpc-provider ", "the rpc provider URL") - .action(async (cmdObj) => { - try { - const signer = await getSigner(); - - await airdrop({ - amount: cmdObj.amount, - maciAddress: cmdObj.maciAddress, - pollId: cmdObj.pollId, - contractAddress: cmdObj.tokenAddress, - quiet: cmdObj.quiet, - signer, - }); - } catch (error) { - program.error((error as Error).message, { exitCode: 1 }); - } - }); program .command("deployVkRegistry") .description("deploy a new verification key registry contract") @@ -453,31 +426,6 @@ program program.error((error as Error).message, { exitCode: 1 }); } }); -program - .command("topup") - .description("Top up an account with voice credits") - .requiredOption("-a, --amount ", "the amount of topup", parseInt) - .option("-x, --maci-address ", "the MACI contract address") - .requiredOption("-i, --state-index ", "state leaf index", parseInt) - .requiredOption("-o, --poll-id ", "poll id", BigInt) - .option("-q, --quiet ", "whether to print values to the console", (value) => value === "true", false) - .option("-r, --rpc-provider ", "the rpc provider URL") - .action(async (cmdObj) => { - try { - const signer = await getSigner(); - - await topup({ - amount: cmdObj.amount, - stateIndex: cmdObj.stateIndex, - pollId: cmdObj.pollId, - maciAddress: cmdObj.maciAddress, - quiet: cmdObj.quiet, - signer, - }); - } catch (error) { - program.error((error as Error).message, { exitCode: 1 }); - } - }); program .command("fundWallet") .description("Fund a wallet with Ether") @@ -668,7 +616,6 @@ if (require.main === module) { // export everything so we can use in other packages export { - airdrop, checkVerifyingKeys, deploy, deployPoll, @@ -688,7 +635,6 @@ export { signup, isRegisteredUser, timeTravel, - topup, verify, } from "./commands"; @@ -703,8 +649,6 @@ export type { SignupArgs, MergeMessagesArgs, MergeSignupsArgs, - AirdropArgs, - TopupArgs, VerifyArgs, ProveOnChainArgs, DeployArgs, diff --git a/cli/ts/utils/index.ts b/cli/ts/utils/index.ts index 49f6aedae6..2d9f4a59f7 100644 --- a/cli/ts/utils/index.ts +++ b/cli/ts/utils/index.ts @@ -15,7 +15,6 @@ export { DEFAULT_SR_QUEUE_OPS, } from "./defaults"; export type { - AirdropArgs, CheckVerifyingKeysArgs, DeployVkRegistryArgs, DeployArgs, @@ -36,7 +35,6 @@ export type { DeployPollArgs, PollContracts, TallyData, - TopupArgs, VerifyArgs, IRegisteredUserArgs, IGenKeypairArgs, diff --git a/cli/ts/utils/interfaces.ts b/cli/ts/utils/interfaces.ts index 231c88c69a..24021d0caf 100644 --- a/cli/ts/utils/interfaces.ts +++ b/cli/ts/utils/interfaces.ts @@ -7,7 +7,6 @@ import type { Groth16Proof, PublicSignals } from "snarkjs"; export interface DeployedContracts { maciAddress: string; pollFactoryAddress: string; - topupCreditAddress: string; poseidonT3Address: string; poseidonT4Address: string; poseidonT5Address: string; @@ -148,41 +147,6 @@ export interface ISnarkJSVerificationKey { IC: BigNumberish[][]; } -/** - * Interface for the arguments to the airdrop command - */ -export interface AirdropArgs { - /** - * The amount of credits to airdrop - */ - amount: number; - - /** - * A signer object - */ - signer: Signer; - - /** - * The address of the ERC20 contract - */ - contractAddress?: string; - - /** - * The id of the poll - */ - pollId?: bigint; - - /** - * The address of the MACI contract - */ - maciAddress?: string; - - /** - * Whether to log the output - */ - quiet?: boolean; -} - /** * Interface for the arguments to the checkVerifyingKeys command */ @@ -989,41 +953,6 @@ export interface IGetPollData { isStateAqMerged: boolean; } -/** - * Interface for the arguments to the topup command - */ -export interface TopupArgs { - /** - * The amount to topup - */ - amount: number; - - /** - * The state index of the user - */ - stateIndex: number; - - /** - * The poll ID - */ - pollId: bigint; - - /** - * The address of the MACI contract - */ - maciAddress?: string; - - /** - * A signer object - */ - signer: Signer; - - /** - * Whether to log the output - */ - quiet?: boolean; -} - /** * Interface for the arguments to the verifyProof command */ diff --git a/contracts/contracts/MACI.sol b/contracts/contracts/MACI.sol index a967557f04..5d610ed439 100644 --- a/contracts/contracts/MACI.sol +++ b/contracts/contracts/MACI.sol @@ -8,7 +8,6 @@ import { InitialVoiceCreditProxy } from "./initialVoiceCreditProxy/InitialVoiceC import { SignUpGatekeeper } from "./gatekeepers/SignUpGatekeeper.sol"; import { IMACI } from "./interfaces/IMACI.sol"; import { Params } from "./utilities/Params.sol"; -import { TopupCredit } from "./TopupCredit.sol"; import { Utilities } from "./utilities/Utilities.sol"; import { DomainObjs } from "./utilities/DomainObjs.sol"; import { CurveBabyJubJub } from "./crypto/BabyJubJub.sol"; @@ -40,9 +39,6 @@ contract MACI is IMACI, DomainObjs, Params, Utilities, Ownable(msg.sender) { /// @notice A mapping of poll IDs to Poll contracts. mapping(uint256 => address) public polls; - /// @notice ERC20 contract that hold topup credits - TopupCredit public immutable topupCredit; - /// @notice Factory contract that deploy a Poll contract IPollFactory public immutable pollFactory; @@ -107,7 +103,6 @@ contract MACI is IMACI, DomainObjs, Params, Utilities, Ownable(msg.sender) { /// @param _tallyFactory The TallyFactory contract /// @param _signUpGatekeeper The SignUpGatekeeper contract /// @param _initialVoiceCreditProxy The InitialVoiceCreditProxy contract - /// @param _topupCredit The TopupCredit contract /// @param _stateTreeDepth The depth of the state tree constructor( IPollFactory _pollFactory, @@ -115,7 +110,6 @@ contract MACI is IMACI, DomainObjs, Params, Utilities, Ownable(msg.sender) { ITallyFactory _tallyFactory, SignUpGatekeeper _signUpGatekeeper, InitialVoiceCreditProxy _initialVoiceCreditProxy, - TopupCredit _topupCredit, uint8 _stateTreeDepth ) payable { // initialize and insert the blank leaf @@ -125,7 +119,6 @@ contract MACI is IMACI, DomainObjs, Params, Utilities, Ownable(msg.sender) { pollFactory = _pollFactory; messageProcessorFactory = _messageProcessorFactory; tallyFactory = _tallyFactory; - topupCredit = _topupCredit; signUpGatekeeper = _signUpGatekeeper; initialVoiceCreditProxy = _initialVoiceCreditProxy; stateTreeDepth = _stateTreeDepth; @@ -212,15 +205,7 @@ contract MACI is IMACI, DomainObjs, Params, Utilities, Ownable(msg.sender) { address _owner = owner(); - address p = pollFactory.deploy( - _duration, - maxValues, - _treeDepths, - _coordinatorPubKey, - address(this), - topupCredit, - _owner - ); + address p = pollFactory.deploy(_duration, maxValues, _treeDepths, _coordinatorPubKey, address(this), _owner); address mp = messageProcessorFactory.deploy(_verifier, _vkRegistry, p, _owner, _mode); address tally = tallyFactory.deploy(_verifier, _vkRegistry, p, mp, _owner, _mode); diff --git a/contracts/contracts/MessageProcessor.sol b/contracts/contracts/MessageProcessor.sol index 6a187cd001..1aaf20024a 100644 --- a/contracts/contracts/MessageProcessor.sol +++ b/contracts/contracts/MessageProcessor.sol @@ -86,7 +86,7 @@ contract MessageProcessor is Ownable(msg.sender), SnarkCommon, Hasher, CommonUti // calculate the message batch size from the message tree subdepth uint256 messageBatchSize = TREE_ARITY ** messageTreeSubDepth; - (, AccQueue messageAq, ) = poll.extContracts(); + (, AccQueue messageAq) = poll.extContracts(); // Require that the message queue has been merged uint256 messageRoot = messageAq.getMainRoot(messageTreeDepth); @@ -169,7 +169,7 @@ contract MessageProcessor is Ownable(msg.sender), SnarkCommon, Hasher, CommonUti // get the message batch size from the message tree subdepth // get the number of signups (uint256 numSignUps, uint256 numMessages) = poll.numSignUpsAndMessages(); - (IMACI maci, , ) = poll.extContracts(); + (IMACI maci, ) = poll.extContracts(); // Calculate the public input hash (a SHA256 hash of several values) uint256 publicInputHash = genProcessMessagesPublicInputHash( diff --git a/contracts/contracts/Poll.sol b/contracts/contracts/Poll.sol index 49393558bf..c8933b1f7c 100644 --- a/contracts/contracts/Poll.sol +++ b/contracts/contracts/Poll.sol @@ -79,7 +79,6 @@ contract Poll is Params, Utilities, SnarkCommon, Ownable(msg.sender), EmptyBallo error InvalidBatchLength(); event PublishMessage(Message _message, PubKey _encPubKey); - event TopupMessage(Message _message); event MergeMaciStateAqSubRoots(uint256 indexed _numSrQueueOps); event MergeMaciStateAq(uint256 indexed _stateRoot, uint256 indexed _numSignups); event MergeMessageAqSubRoots(uint256 indexed _numSrQueueOps); @@ -153,36 +152,12 @@ contract Poll is Params, Utilities, SnarkCommon, Ownable(msg.sender), EmptyBallo dat[0] = NOTHING_UP_MY_SLEEVE; dat[1] = 0; - (Message memory _message, PubKey memory _padKey, uint256 placeholderLeaf) = padAndHashMessage(dat, 1); + (Message memory _message, PubKey memory _padKey, uint256 placeholderLeaf) = padAndHashMessage(dat); extContracts.messageAq.enqueue(placeholderLeaf); emit PublishMessage(_message, _padKey); } - /// @inheritdoc IPoll - function topup(uint256 stateIndex, uint256 amount) public virtual isWithinVotingDeadline { - // we check that we do not exceed the max number of messages - if (numMessages >= maxValues.maxMessages) revert TooManyMessages(); - - // cannot realistically overflow - unchecked { - numMessages++; - } - - /// @notice topupCredit is a trusted token contract which reverts if the transfer fails - extContracts.topupCredit.transferFrom(msg.sender, address(this), amount); - - uint256[2] memory dat; - dat[0] = stateIndex; - dat[1] = amount; - - (Message memory _message, , uint256 messageLeaf) = padAndHashMessage(dat, 2); - - extContracts.messageAq.enqueue(messageLeaf); - - emit TopupMessage(_message); - } - /// @inheritdoc IPoll function publishMessage(Message memory _message, PubKey calldata _encPubKey) public virtual isWithinVotingDeadline { // we check that we do not exceed the max number of messages @@ -198,10 +173,6 @@ contract Poll is Params, Utilities, SnarkCommon, Ownable(msg.sender), EmptyBallo numMessages++; } - // we enforce that msgType here is 1 so we don't need checks - // at the circuit level - _message.msgType = 1; - uint256 messageLeaf = hashMessageAndEncPubKey(_message, _encPubKey); extContracts.messageAq.enqueue(messageLeaf); diff --git a/contracts/contracts/PollFactory.sol b/contracts/contracts/PollFactory.sol index 5cff4bd914..a88c41969f 100644 --- a/contracts/contracts/PollFactory.sol +++ b/contracts/contracts/PollFactory.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.20; import { IMACI } from "./interfaces/IMACI.sol"; import { AccQueue } from "./trees/AccQueue.sol"; import { AccQueueQuinaryMaci } from "./trees/AccQueueQuinaryMaci.sol"; -import { TopupCredit } from "./TopupCredit.sol"; import { Params } from "./utilities/Params.sol"; import { DomainObjs } from "./utilities/DomainObjs.sol"; import { Poll } from "./Poll.sol"; @@ -31,7 +30,6 @@ contract PollFactory is Params, DomainObjs, IPollFactory { TreeDepths calldata _treeDepths, PubKey calldata _coordinatorPubKey, address _maci, - TopupCredit _topupCredit, address _pollOwner ) public virtual returns (address pollAddr) { /// @notice Validate _maxValues @@ -46,11 +44,7 @@ contract PollFactory is Params, DomainObjs, IPollFactory { AccQueue messageAq = new AccQueueQuinaryMaci(_treeDepths.messageTreeSubDepth); /// @notice the smart contracts that a Poll would interact with - ExtContracts memory extContracts = ExtContracts({ - maci: IMACI(_maci), - messageAq: messageAq, - topupCredit: _topupCredit - }); + ExtContracts memory extContracts = ExtContracts({ maci: IMACI(_maci), messageAq: messageAq }); // deploy the poll Poll poll = new Poll(_duration, _maxValues, _treeDepths, _coordinatorPubKey, extContracts); diff --git a/contracts/contracts/Tally.sol b/contracts/contracts/Tally.sol index e3ca1d658f..ca9e5050e3 100644 --- a/contracts/contracts/Tally.sol +++ b/contracts/contracts/Tally.sol @@ -183,7 +183,7 @@ contract Tally is Ownable(msg.sender), SnarkCommon, CommonUtilities, Hasher, Dom ) public view returns (bool isValid) { (uint8 intStateTreeDepth, , , uint8 voteOptionTreeDepth) = poll.treeDepths(); - (IMACI maci, , ) = poll.extContracts(); + (IMACI maci, ) = poll.extContracts(); // Get the verifying key VerifyingKey memory vk = vkRegistry.getTallyVk(maci.stateTreeDepth(), intStateTreeDepth, voteOptionTreeDepth, mode); diff --git a/contracts/contracts/TopupCredit.sol b/contracts/contracts/TopupCredit.sol deleted file mode 100644 index 9a13ebe938..0000000000 --- a/contracts/contracts/TopupCredit.sol +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; - -/// @title TopupCredit -/// @notice A contract representing a token used to topup a MACI's voter -/// credits -contract TopupCredit is ERC20, Ownable(msg.sender) { - uint8 public constant DECIMALS = 1; - uint256 public constant MAXIMUM_AIRDROP_AMOUNT = 100000 * 10 ** DECIMALS; - - /// @notice custom errors - error ExceedLimit(); - - /// @notice create a new TopupCredit token - constructor() payable ERC20("TopupCredit", "TopupCredit") {} - - /// @notice mint tokens to an account - /// @param account the account to mint tokens to - /// @param amount the amount of tokens to mint - function airdropTo(address account, uint256 amount) public onlyOwner { - if (amount >= MAXIMUM_AIRDROP_AMOUNT) { - revert ExceedLimit(); - } - - _mint(account, amount); - } - - /// @notice mint tokens to the contract owner - /// @param amount the amount of tokens to mint - function airdrop(uint256 amount) public onlyOwner { - if (amount >= MAXIMUM_AIRDROP_AMOUNT) { - revert ExceedLimit(); - } - - _mint(msg.sender, amount); - } -} diff --git a/contracts/contracts/interfaces/IPoll.sol b/contracts/contracts/interfaces/IPoll.sol index 919eea19e5..1d05b937e2 100644 --- a/contracts/contracts/interfaces/IPoll.sol +++ b/contracts/contracts/interfaces/IPoll.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.10; import { DomainObjs } from "../utilities/DomainObjs.sol"; import { IMACI } from "./IMACI.sol"; import { AccQueue } from "../trees/AccQueue.sol"; -import { TopupCredit } from "../TopupCredit.sol"; /// @title IPoll /// @notice Poll interface @@ -14,11 +13,6 @@ interface IPoll { /// @return numMsgs The number of messages sent by voters function numSignUpsAndMessages() external view returns (uint256 numSignups, uint256 numMsgs); - /// @notice Allows to publish a Topup message - /// @param stateIndex The index of user in the state queue - /// @param amount The amount of credits to topup - function topup(uint256 stateIndex, uint256 amount) external; - /// @notice Allows anyone to publish a message (an encrypted command and signature). /// This function also enqueues the message. /// @param _message The message to publish @@ -68,8 +62,7 @@ interface IPoll { /// @notice Get the external contracts /// @return maci The IMACI contract /// @return messageAq The AccQueue contract - /// @return topupCredit The TopupCredit contract - function extContracts() external view returns (IMACI maci, AccQueue messageAq, TopupCredit topupCredit); + function extContracts() external view returns (IMACI maci, AccQueue messageAq); /// @notice Get the hash of coordinator's public key /// @return _coordinatorPubKeyHash the hash of coordinator's public key diff --git a/contracts/contracts/interfaces/IPollFactory.sol b/contracts/contracts/interfaces/IPollFactory.sol index ee903f3a8e..c8066453dc 100644 --- a/contracts/contracts/interfaces/IPollFactory.sol +++ b/contracts/contracts/interfaces/IPollFactory.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.10; -import { TopupCredit } from "../TopupCredit.sol"; import { Params } from "../utilities/Params.sol"; import { DomainObjs } from "../utilities/DomainObjs.sol"; @@ -14,7 +13,6 @@ interface IPollFactory { /// @param _treeDepths The depths of the merkle trees /// @param _coordinatorPubKey The coordinator's public key /// @param _maci The MACI contract interface reference - /// @param _topupCredit The TopupCredit contract /// @param _pollOwner The owner of the poll /// @return The deployed Poll contract function deploy( @@ -23,7 +21,6 @@ interface IPollFactory { Params.TreeDepths memory _treeDepths, DomainObjs.PubKey memory _coordinatorPubKey, address _maci, - TopupCredit _topupCredit, address _pollOwner ) external returns (address); } diff --git a/contracts/contracts/utilities/DomainObjs.sol b/contracts/contracts/utilities/DomainObjs.sol index c5bbb1072d..dec3513b5f 100644 --- a/contracts/contracts/utilities/DomainObjs.sol +++ b/contracts/contracts/utilities/DomainObjs.sol @@ -16,9 +16,8 @@ contract DomainObjs { /// @title Message /// @notice this struct represents a MACI message - /// @dev msgType: 1 for vote message, 2 for topup message (size 2) + /// @dev msgType: 1 for vote message struct Message { - uint256 msgType; uint256[MESSAGE_DATA_LENGTH] data; } diff --git a/contracts/contracts/utilities/Params.sol b/contracts/contracts/utilities/Params.sol index a3ad64d5cc..06fb4bdd33 100644 --- a/contracts/contracts/utilities/Params.sol +++ b/contracts/contracts/utilities/Params.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.20; import { IMACI } from "../interfaces/IMACI.sol"; import { AccQueue } from "../trees/AccQueue.sol"; -import { TopupCredit } from "../TopupCredit.sol"; /// @title Params /// @notice This contracts contains a number of structures @@ -31,6 +30,5 @@ contract Params { struct ExtContracts { IMACI maci; AccQueue messageAq; - TopupCredit topupCredit; } } diff --git a/contracts/contracts/utilities/Utilities.sol b/contracts/contracts/utilities/Utilities.sol index 6a5216c7f6..44c54c24e3 100644 --- a/contracts/contracts/utilities/Utilities.sol +++ b/contracts/contracts/utilities/Utilities.sol @@ -1,5 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; + import { DomainObjs } from "./DomainObjs.sol"; import { Hasher } from "../crypto/Hasher.sol"; import { SnarkConstants } from "../crypto/SnarkConstants.sol"; @@ -28,13 +29,11 @@ contract Utilities is SnarkConstants, DomainObjs, Hasher { /// @notice An utility function used to pad and hash a MACI message /// @param dataToPad the data to be padded - /// @param msgType the type of the message /// @return message The padded message /// @return padKey The padding public key /// @return msgHash The hash of the padded message and encryption key function padAndHashMessage( - uint256[2] memory dataToPad, - uint256 msgType + uint256[2] memory dataToPad ) public pure returns (Message memory message, PubKey memory padKey, uint256 msgHash) { // add data and pad it to 10 elements (automatically cause it's the default value) uint256[10] memory dat; @@ -42,7 +41,7 @@ contract Utilities is SnarkConstants, DomainObjs, Hasher { dat[1] = dataToPad[1]; padKey = PubKey(PAD_PUBKEY_X, PAD_PUBKEY_Y); - message = Message({ msgType: msgType, data: dat }); + message = Message({ data: dat }); msgHash = hashMessageAndEncPubKey(message, padKey); } @@ -72,6 +71,6 @@ contract Utilities is SnarkConstants, DomainObjs, Hasher { m[3] = _message.data[8]; m[4] = _message.data[9]; - msgHash = hash5([_message.msgType, hash5(n), hash5(m), _encPubKey.x, _encPubKey.y]); + msgHash = hash4([hash5(n), hash5(m), _encPubKey.x, _encPubKey.y]); } } diff --git a/contracts/tests/MACI.test.ts b/contracts/tests/MACI.test.ts index a575af2f09..eeeaf08541 100644 --- a/contracts/tests/MACI.test.ts +++ b/contracts/tests/MACI.test.ts @@ -252,7 +252,7 @@ describe("MACI", function test() { for (let i = 1; i < 10; i += 1) { messageData.push(BigInt(0)); } - const message = new Message(BigInt(1), messageData); + const message = new Message(messageData); const padKey = new PubKey([ BigInt("10457101036533406547632367118273992217979173478358440826365724437999023779287"), BigInt("19824078218392094440610104313265183977899662750282163392862422243483260492317"), diff --git a/contracts/tests/MessageProcessor.test.ts b/contracts/tests/MessageProcessor.test.ts index 502ec550ae..2243fcdbb8 100644 --- a/contracts/tests/MessageProcessor.test.ts +++ b/contracts/tests/MessageProcessor.test.ts @@ -107,7 +107,7 @@ describe("MessageProcessor", () => { for (let i = 1; i < 10; i += 1) { messageData.push(BigInt(0)); } - const message = new Message(BigInt(1), messageData); + const message = new Message(messageData); const padKey = new PubKey([ BigInt("10457101036533406547632367118273992217979173478358440826365724437999023779287"), BigInt("19824078218392094440610104313265183977899662750282163392862422243483260492317"), diff --git a/contracts/tests/Poll.test.ts b/contracts/tests/Poll.test.ts index df96a69103..00047460d5 100644 --- a/contracts/tests/Poll.test.ts +++ b/contracts/tests/Poll.test.ts @@ -7,15 +7,13 @@ import { NOTHING_UP_MY_SLEEVE } from "maci-crypto"; import { Keypair, Message, PCommand, PubKey } from "maci-domainobjs"; import { EMode } from "../ts/constants"; -import { getDefaultSigner, getSigners } from "../ts/utils"; +import { getDefaultSigner } from "../ts/utils"; import { AccQueue, AccQueueQuinaryMaci__factory as AccQueueQuinaryMaciFactory, Poll__factory as PollFactory, - IERC20Errors__factory as IERC20ErrorsFactory, MACI, Poll as PollContract, - TopupCredit, Verifier, VkRegistry, } from "../typechain-types"; @@ -37,7 +35,6 @@ describe("Poll", () => { let pollContract: PollContract; let verifierContract: Verifier; let vkRegistryContract: VkRegistry; - let topupCreditContract: TopupCredit; let signer: Signer; let deployTime: number; const coordinator = new Keypair(); @@ -53,7 +50,6 @@ describe("Poll", () => { maciContract = r.maciContract; verifierContract = r.mockVerifierContract as Verifier; vkRegistryContract = r.vkRegistryContract; - topupCreditContract = r.topupCreditContract; // deploy on chain poll const tx = await maciContract.deployPoll( @@ -97,7 +93,7 @@ describe("Poll", () => { for (let i = 1; i < 10; i += 1) { messageData.push(BigInt(0)); } - const message = new Message(BigInt(1), messageData); + const message = new Message(messageData); const padKey = new PubKey([ BigInt("10457101036533406547632367118273992217979173478358440826365724437999023779287"), BigInt("19824078218392094440610104313265183977899662750282163392862422243483260492317"), @@ -166,51 +162,6 @@ describe("Poll", () => { }); }); - describe("topup", () => { - let voter: Signer; - - before(async () => { - // transfer tokens to a user and pre-approve - [, voter] = await getSigners(); - await topupCreditContract.airdropTo(voter.getAddress(), 200n); - await topupCreditContract.connect(voter).approve(await pollContract.getAddress(), 1000n); - }); - - it("should allow to publish a topup message when the caller has enough topup tokens", async () => { - const tx = await pollContract.connect(voter).topup(1n, 50n); - const receipt = await tx.wait(); - expect(receipt?.status).to.eq(1); - - // publish on local maci state - maciState.polls.get(pollId)?.topupMessage(new Message(2n, [1n, 50n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n])); - }); - - it("should throw when the user does not have enough tokens", async () => { - const pollAddress = await pollContract.getAddress(); - - await expect(pollContract.connect(signer).topup(1n, 50n)).to.be.revertedWithCustomError( - IERC20ErrorsFactory.connect(pollAddress), - "ERC20InsufficientAllowance", - ); - }); - - it("should emit an event when publishing a topup message", async () => { - expect(await pollContract.connect(voter).topup(1n, 50n)).to.emit(pollContract, "TopupMessage"); - // publish on local maci state - maciState.polls.get(pollId)?.topupMessage(new Message(2n, [1n, 50n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n])); - }); - - it("should successfully increase the number of messages", async () => { - const numMessages = await pollContract.numMessages(); - await pollContract.connect(voter).topup(1n, 50n); - const newNumMessages = await pollContract.numMessages(); - expect(newNumMessages.toString()).to.eq((numMessages + 1n).toString()); - - // publish on local maci state - maciState.polls.get(pollId)?.topupMessage(new Message(2n, [1n, 50n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n])); - }); - }); - describe("publishMessage", () => { it("should publish a message to the Poll contract", async () => { const command = new PCommand(1n, keypair.pubKey, 0n, 9n, 1n, pollId, 0n); diff --git a/contracts/tests/PollFactory.test.ts b/contracts/tests/PollFactory.test.ts index 77e361eedf..71eca8f922 100644 --- a/contracts/tests/PollFactory.test.ts +++ b/contracts/tests/PollFactory.test.ts @@ -26,7 +26,6 @@ describe("pollFactory", () => { treeDepths, coordinatorPubKey.asContractParam(), ZeroAddress, - ZeroAddress, await signer.getAddress(), ); const receipt = await tx.wait(); @@ -44,7 +43,6 @@ describe("pollFactory", () => { treeDepths, coordinatorPubKey.asContractParam(), ZeroAddress, - ZeroAddress, await signer.getAddress(), ), ).to.be.revertedWithCustomError(pollFactory, "InvalidMaxValues"); diff --git a/contracts/tests/Tally.test.ts b/contracts/tests/Tally.test.ts index bb821c0322..327811fac1 100644 --- a/contracts/tests/Tally.test.ts +++ b/contracts/tests/Tally.test.ts @@ -119,7 +119,7 @@ describe("TallyVotes", () => { for (let i = 1; i < 10; i += 1) { messageData.push(BigInt(0)); } - const message = new Message(BigInt(1), messageData); + const message = new Message(messageData); const padKey = new PubKey([ BigInt("10457101036533406547632367118273992217979173478358440826365724437999023779287"), BigInt("19824078218392094440610104313265183977899662750282163392862422243483260492317"), @@ -309,7 +309,7 @@ describe("TallyVotes", () => { for (let i = 1; i < 10; i += 1) { messageData.push(BigInt(0)); } - const message = new Message(BigInt(1), messageData); + const message = new Message(messageData); const padKey = new PubKey([ BigInt("10457101036533406547632367118273992217979173478358440826365724437999023779287"), BigInt("19824078218392094440610104313265183977899662750282163392862422243483260492317"), @@ -454,7 +454,7 @@ describe("TallyVotes", () => { for (let i = 1; i < 10; i += 1) { messageData.push(BigInt(0)); } - const message = new Message(BigInt(1), messageData); + const message = new Message(messageData); const padKey = new PubKey([ BigInt("10457101036533406547632367118273992217979173478358440826365724437999023779287"), BigInt("19824078218392094440610104313265183977899662750282163392862422243483260492317"), diff --git a/contracts/tests/TallyNonQv.test.ts b/contracts/tests/TallyNonQv.test.ts index 7c45850c30..36e3b7cbf5 100644 --- a/contracts/tests/TallyNonQv.test.ts +++ b/contracts/tests/TallyNonQv.test.ts @@ -118,7 +118,7 @@ describe("TallyVotesNonQv", () => { for (let i = 1; i < 10; i += 1) { messageData.push(BigInt(0)); } - const message = new Message(BigInt(1), messageData); + const message = new Message(messageData); const padKey = new PubKey([ BigInt("10457101036533406547632367118273992217979173478358440826365724437999023779287"), BigInt("19824078218392094440610104313265183977899662750282163392862422243483260492317"), diff --git a/contracts/tests/Utilities.test.ts b/contracts/tests/Utilities.test.ts index 2b57d56854..81b10b284d 100644 --- a/contracts/tests/Utilities.test.ts +++ b/contracts/tests/Utilities.test.ts @@ -1,6 +1,6 @@ import { expect } from "chai"; import { BigNumberish, ZeroAddress } from "ethers"; -import { StateLeaf, Keypair } from "maci-domainobjs"; +import { StateLeaf, Keypair, Message, PubKey } from "maci-domainobjs"; import { linkPoseidonLibraries } from "../tasks/helpers/abi"; import { deployPoseidonContracts, createContractFactory } from "../ts/deploy"; @@ -66,13 +66,11 @@ describe("Utilities", () => { describe("padAndHashMessage", () => { it("should correctly pad and hash a message", async () => { const dataToPad: [BigNumberish, BigNumberish] = [1234, 1234]; - const msgType = BigInt(2) as BigNumberish; // Call the padAndHashMessage function - const { message, padKey } = await utilitiesContract.padAndHashMessage(dataToPad, msgType); + const { message, padKey } = await utilitiesContract.padAndHashMessage(dataToPad); // Validate the returned message - expect(message.msgType.toString()).to.eq(msgType.toString()); expect(message.data.slice(0, 2)).to.deep.eq(dataToPad); for (let i = 2; i < 10; i += 1) { expect(message.data[i]).to.eq(0); @@ -86,5 +84,22 @@ describe("Utilities", () => { "19824078218392094440610104313265183977899662750282163392862422243483260492317", ); }); + + it("should produce the same hash locally", async () => { + const message = new Message([0n, 0n, 1234n, 1234n, 0n, 0n, 0n, 0n, 0n, 0n]); + const padKey = new PubKey([ + 10457101036533406547632367118273992217979173478358440826365724437999023779287n, + 19824078218392094440610104313265183977899662750282163392862422243483260492317n, + ]); + + const expectedHash = message.hash(padKey); + + const onChainHash = await utilitiesContract.hashMessageAndEncPubKey( + message.asContractParam(), + padKey.asContractParam(), + ); + + expect(onChainHash.toString()).to.eq(expectedHash.toString()); + }); }); }); diff --git a/contracts/tests/utils.ts b/contracts/tests/utils.ts index dbe9f7f4b4..1df7e27653 100644 --- a/contracts/tests/utils.ts +++ b/contracts/tests/utils.ts @@ -14,7 +14,6 @@ import { deployMaci, deployMockVerifier, deployPoseidonContracts, - deployTopupCredit, deployVkRegistry, createContractFactory, } from "../ts/deploy"; @@ -521,18 +520,14 @@ export const deployTestContracts = async ( // VkRegistry const vkRegistryContract = await deployVkRegistry(signer, true); - const topupCreditContract = await deployTopupCredit(signer, true); - const [gatekeeperContractAddress, constantIntialVoiceCreditProxyContractAddress, topupCreditContractAddress] = - await Promise.all([ - gatekeeperContract.getAddress(), - constantIntialVoiceCreditProxyContract.getAddress(), - topupCreditContract.getAddress(), - ]); + const [gatekeeperContractAddress, constantIntialVoiceCreditProxyContractAddress] = await Promise.all([ + gatekeeperContract.getAddress(), + constantIntialVoiceCreditProxyContract.getAddress(), + ]); const { maciContract } = await deployMaci({ signUpTokenGatekeeperContractAddress: gatekeeperContractAddress, initialVoiceCreditBalanceAddress: constantIntialVoiceCreditProxyContractAddress, - topupCreditContractAddress, signer, stateTreeDepth, quiet, @@ -544,6 +539,5 @@ export const deployTestContracts = async ( constantIntialVoiceCreditProxyContract, maciContract, vkRegistryContract, - topupCreditContract, }; }; diff --git a/contracts/ts/deploy.ts b/contracts/ts/deploy.ts index 9c6c49d20d..4b5d00fc68 100644 --- a/contracts/ts/deploy.ts +++ b/contracts/ts/deploy.ts @@ -23,7 +23,6 @@ import { PoseidonT6, SignUpToken, SignUpTokenGatekeeper, - TopupCredit, Verifier, VkRegistry, PollFactory__factory as PollFactoryFactory, @@ -72,15 +71,6 @@ export const deployContract = async ( return deployment.deployContract({ name: contractName as EContracts, signer }, ...args); }; -/** - * Deploy a TopupCredit contract - * @param signer - the signer to use to deploy the contract - * @param quiet - whether to suppress console output - * @returns the deployed TopupCredit contract - */ -export const deployTopupCredit = async (signer?: Signer, quiet = false): Promise => - deployContract("TopupCredit", signer, quiet); - /** * Deploy a VkRegistry contract * @param signer - the signer to use to deploy the contract @@ -236,7 +226,6 @@ export const deployPollFactory = async (signer: Signer, quiet = false): Promise< export const deployMaci = async ({ signUpTokenGatekeeperContractAddress, initialVoiceCreditBalanceAddress, - topupCreditContractAddress, signer, poseidonAddresses, stateTreeDepth = 10, @@ -298,7 +287,6 @@ export const deployMaci = async ({ tallyAddress, signUpTokenGatekeeperContractAddress, initialVoiceCreditBalanceAddress, - topupCreditContractAddress, stateTreeDepth, ); diff --git a/contracts/ts/genMaciState.ts b/contracts/ts/genMaciState.ts index b95f666e85..c6cf76d728 100644 --- a/contracts/ts/genMaciState.ts +++ b/contracts/ts/genMaciState.ts @@ -146,13 +146,11 @@ export const genMaciStateFromContract = async ( const [ publishMessageLogs, - topupLogs, mergeMessageAqSubRootsLogs, mergeMessageAqLogs, // eslint-disable-next-line no-await-in-loop ] = await Promise.all([ pollContract.queryFilter(pollContract.filters.PublishMessage(), i, toBlock), - pollContract.queryFilter(pollContract.filters.TopupMessage(), i, toBlock), pollContract.queryFilter(pollContract.filters.MergeMessageAqSubRoots(), i, toBlock), pollContract.queryFilter(pollContract.filters.MergeMessageAq(), i, toBlock), ]); @@ -160,11 +158,7 @@ export const genMaciStateFromContract = async ( publishMessageLogs.forEach((event) => { assert(!!event); - const message = new Message( - BigInt(event.args._message[0]), - - event.args._message[1].map((x) => BigInt(x)), - ); + const message = new Message(event.args._message[0].map((x) => BigInt(x))); const encPubKey = new PubKey(event.args._encPubKey.map((x) => BigInt(x.toString())) as [bigint, bigint]); @@ -179,24 +173,6 @@ export const genMaciStateFromContract = async ( }); }); - topupLogs.forEach((event) => { - assert(!!event); - - const message = new Message( - BigInt(event.args._message[0]), - event.args._message[1].map((x) => BigInt(x)), - ); - - actions.push({ - type: "TopupMessage", - blockNumber: event.blockNumber, - transactionIndex: event.transactionIndex, - data: { - message, - }, - }); - }); - mergeMessageAqSubRootsLogs.forEach((event) => { assert(!!event); @@ -261,12 +237,6 @@ export const genMaciStateFromContract = async ( break; } - case action.type === "TopupMessage": { - const { message } = action.data; - maciState.polls.get(pollId)?.topupMessage(message!); - break; - } - // ensure that the message root is correct (i.e. all messages have been published offchain) case action.type === "MergeMessageAq": { assert(maciState.polls.get(pollId)?.messageTree.root.toString() === action.data.messageRoot?.toString()); diff --git a/contracts/ts/index.ts b/contracts/ts/index.ts index 4f1b71052a..5362834f44 100644 --- a/contracts/ts/index.ts +++ b/contracts/ts/index.ts @@ -1,6 +1,5 @@ export { deployMockVerifier, - deployTopupCredit, deployVkRegistry, deployMaci, deployContract, diff --git a/contracts/ts/types.ts b/contracts/ts/types.ts index 8c4d9ac27f..8f24321ea4 100644 --- a/contracts/ts/types.ts +++ b/contracts/ts/types.ts @@ -8,7 +8,6 @@ import type { PoseidonT4, PoseidonT5, PoseidonT6, - TopupCredit, VkRegistry, } from "../typechain-types"; import type { BigNumberish, Signer } from "ethers"; @@ -80,7 +79,6 @@ export interface IDeployedTestContracts { constantIntialVoiceCreditProxyContract: ConstantInitialVoiceCreditProxy; maciContract: MACI; vkRegistryContract: VkRegistry; - topupCreditContract: TopupCredit; } /** @@ -131,11 +129,6 @@ export interface IDeployMaciArgs { */ initialVoiceCreditBalanceAddress: string; - /** - * The address of the TopupCredit contract - */ - topupCreditContractAddress: string; - /** * The signer to use to deploy the contract */ diff --git a/core/ts/Poll.ts b/core/ts/Poll.ts index dd732884ff..330a24f448 100644 --- a/core/ts/Poll.ts +++ b/core/ts/Poll.ts @@ -13,19 +13,15 @@ import { } from "maci-crypto"; import { PCommand, - TCommand, Keypair, Ballot, PubKey, PrivKey, Message, blankStateLeaf, - type ICommand, type StateLeaf, type IMessageContractParams, - type IJsonCommand, type IJsonPCommand, - type IJsonTCommand, blankStateLeafHash, } from "maci-domainobjs"; @@ -79,7 +75,7 @@ export class Poll implements IPoll { messageTree: IncrementalQuinTree; - commands: ICommand[] = []; + commands: PCommand[] = []; encPubKeys: PubKey[] = []; @@ -327,34 +323,6 @@ export class Poll implements IPoll { } }; - /** - * Top up the voice credit balance of a user. - * @param message - The message to top up the voice credit balance - */ - topupMessage = (message: Message): void => { - assert(message.msgType === 2n, "A Topup message must have msgType 2"); - - message.data.forEach((d) => { - assert(d < SNARK_FIELD_SIZE, "The message data is not in the correct range"); - }); - - const padKey = new PubKey([ - BigInt("10457101036533406547632367118273992217979173478358440826365724437999023779287"), - BigInt("19824078218392094440610104313265183977899662750282163392862422243483260492317"), - ]); - - // save the message - this.messages.push(message); - // save the pad key - this.encPubKeys.push(padKey); - // insert the message into the message tree - this.messageTree.insert(message.hash(padKey)); - - // we create a topup command and save it - const command = new TCommand(message.data[0], message.data[1], BigInt(this.pollId)); - this.commands.push(command as ICommand); - }; - /** * Inserts a Message and the corresponding public key used to generate the * ECDH shared key which was used to encrypt said message. @@ -362,7 +330,6 @@ export class Poll implements IPoll { * @param encPubKey - The public key used to encrypt the message */ publishMessage = (message: Message, encPubKey: PubKey): void => { - assert(message.msgType === 1n, "A vote or key change message must have msgType 1"); assert( encPubKey.rawPubKey[0] < SNARK_FIELD_SIZE && encPubKey.rawPubKey[1] < SNARK_FIELD_SIZE, "The public key is not in the correct range", @@ -386,12 +353,12 @@ export class Poll implements IPoll { // step 2. we decrypt it const { command } = PCommand.decrypt(message, sharedKey); // step 3. we store it in the commands array - this.commands.push(command as ICommand); + this.commands.push(command); } catch (e) { // if there is an error we store an empty command const keyPair = new Keypair(); const command = new PCommand(0n, keyPair.pubKey, 0n, 0n, 0n, 0n, 0n); - this.commands.push(command as ICommand); + this.commands.push(command); } }; @@ -509,189 +476,117 @@ export class Poll implements IPoll { message = this.messages[idx]; encPubKey = this.encPubKeys[idx]; - // based on the message type we have to process it differently - switch (message.msgType) { - case 1n: - try { - // check if the command is valid - const r = this.processMessage(message, encPubKey, qv); - const index = r.stateLeafIndex!; - - // we add at position 0 the original data - currentStateLeaves.unshift(r.originalStateLeaf!); - currentBallots.unshift(r.originalBallot!); - currentVoteWeights.unshift(r.originalVoteWeight!); - currentVoteWeightsPathElements.unshift(r.originalVoteWeightsPathElements!); - currentStateLeavesPathElements.unshift(r.originalStateLeafPathElements!); - currentBallotsPathElements.unshift(r.originalBallotPathElements!); - - // update the state leaves with the new state leaf (result of processing the message) - this.stateLeaves[index] = r.newStateLeaf!.copy(); - - // we also update the state tree with the hash of the new state leaf - this.stateTree?.update(index, r.newStateLeaf!.hash()); - - // store the new ballot - this.ballots[index] = r.newBallot!; - // update the ballot tree - this.ballotTree?.update(index, r.newBallot!.hash()); - } catch (e) { - // if the error is not a ProcessMessageError we throw it and exit here - // otherwise we continue processing but add the default blank data instead of - // this invalid message - if (e instanceof ProcessMessageError) { - // if logging is enabled, and it's not the first message, print the error - if (!quiet && idx !== 0) { - // eslint-disable-next-line no-console - console.log(`Error at message index ${idx} - ${e.message}`); - } + try { + // check if the command is valid + const r = this.processMessage(message, encPubKey, qv); + const index = r.stateLeafIndex!; + + // we add at position 0 the original data + currentStateLeaves.unshift(r.originalStateLeaf!); + currentBallots.unshift(r.originalBallot!); + currentVoteWeights.unshift(r.originalVoteWeight!); + currentVoteWeightsPathElements.unshift(r.originalVoteWeightsPathElements!); + currentStateLeavesPathElements.unshift(r.originalStateLeafPathElements!); + currentBallotsPathElements.unshift(r.originalBallotPathElements!); + + // update the state leaves with the new state leaf (result of processing the message) + this.stateLeaves[index] = r.newStateLeaf!.copy(); + + // we also update the state tree with the hash of the new state leaf + this.stateTree?.update(index, r.newStateLeaf!.hash()); + + // store the new ballot + this.ballots[index] = r.newBallot!; + // update the ballot tree + this.ballotTree?.update(index, r.newBallot!.hash()); + } catch (e) { + // if the error is not a ProcessMessageError we throw it and exit here + // otherwise we continue processing but add the default blank data instead of + // this invalid message + if (e instanceof ProcessMessageError) { + // if logging is enabled, and it's not the first message, print the error + if (!quiet && idx !== 0) { + // eslint-disable-next-line no-console + console.log(`Error at message index ${idx} - ${e.message}`); + } - // @note we want to send the correct state leaf to the circuit - // even if a message is invalid - // this way if a message is invalid we can still generate a proof of processing - // we also want to prevent a DoS attack by a voter - // which sends a message that when force decrypted on the circuit - // results in a valid state index thus forcing the circuit to look - // for a valid state leaf, and failing to generate a proof - - // gen shared key - const sharedKey = Keypair.genEcdhSharedKey(this.coordinatorKeypair.privKey, encPubKey); - - // force decrypt it - const { command } = PCommand.decrypt(message, sharedKey, true); - - // cache state leaf index - const stateLeafIndex = command.stateIndex; - - // if the state leaf index is valid then use it - if (stateLeafIndex < this.stateLeaves.length) { - currentStateLeaves.unshift(this.stateLeaves[Number(stateLeafIndex)].copy()); - currentStateLeavesPathElements.unshift(this.stateTree!.genProof(Number(stateLeafIndex)).pathElements); - - // copy the ballot - const ballot = this.ballots[Number(stateLeafIndex)].copy(); - currentBallots.unshift(ballot); - currentBallotsPathElements.unshift(this.ballotTree!.genProof(Number(stateLeafIndex)).pathElements); - - // @note we check that command.voteOptionIndex is valid so < maxVoteOptions - // this might be unnecessary but we do it to prevent a possible DoS attack - // from voters who could potentially encrypt a message in such as way that - // when decrypted it results in a valid state leaf index but an invalid vote option index - if (command.voteOptionIndex < this.maxValues.maxVoteOptions) { - currentVoteWeights.unshift(ballot.votes[Number(command.voteOptionIndex)]); - - // create a new quinary tree and add all votes we have so far - const vt = new IncrementalQuinTree( - this.treeDepths.voteOptionTreeDepth, - 0n, - MESSAGE_TREE_ARITY, - hash5, - ); - - // fill the vote option tree with the votes we have so far - for (let j = 0; j < this.ballots[0].votes.length; j += 1) { - vt.insert(ballot.votes[j]); - } - - // get the path elements for the first vote leaf - currentVoteWeightsPathElements.unshift(vt.genProof(Number(command.voteOptionIndex)).pathElements); - } else { - currentVoteWeights.unshift(ballot.votes[0]); - - // create a new quinary tree and add all votes we have so far - const vt = new IncrementalQuinTree( - this.treeDepths.voteOptionTreeDepth, - 0n, - STATE_TREE_ARITY, - hash5, - ); - - // fill the vote option tree with the votes we have so far - for (let j = 0; j < this.ballots[0].votes.length; j += 1) { - vt.insert(ballot.votes[j]); - } - - // get the path elements for the first vote leaf - currentVoteWeightsPathElements.unshift(vt.genProof(0).pathElements); - } - } else { - // just use state leaf index 0 - currentStateLeaves.unshift(this.stateLeaves[0].copy()); - currentStateLeavesPathElements.unshift(this.stateTree!.genProof(0).pathElements); - currentBallots.unshift(this.ballots[0].copy()); - currentBallotsPathElements.unshift(this.ballotTree!.genProof(0).pathElements); - - // Since the command is invalid, we use a zero vote weight - currentVoteWeights.unshift(this.ballots[0].votes[0]); - - // create a new quinary tree and add an empty vote - const vt = new IncrementalQuinTree( - this.treeDepths.voteOptionTreeDepth, - 0n, - MESSAGE_TREE_ARITY, - hash5, - ); - vt.insert(this.ballots[0].votes[0]); - // get the path elements for this empty vote weight leaf - currentVoteWeightsPathElements.unshift(vt.genProof(0).pathElements); + // @note we want to send the correct state leaf to the circuit + // even if a message is invalid + // this way if a message is invalid we can still generate a proof of processing + // we also want to prevent a DoS attack by a voter + // which sends a message that when force decrypted on the circuit + // results in a valid state index thus forcing the circuit to look + // for a valid state leaf, and failing to generate a proof + + // gen shared key + const sharedKey = Keypair.genEcdhSharedKey(this.coordinatorKeypair.privKey, encPubKey); + + // force decrypt it + const { command } = PCommand.decrypt(message, sharedKey, true); + + // cache state leaf index + const stateLeafIndex = command.stateIndex; + + // if the state leaf index is valid then use it + if (stateLeafIndex < this.stateLeaves.length) { + currentStateLeaves.unshift(this.stateLeaves[Number(stateLeafIndex)].copy()); + currentStateLeavesPathElements.unshift(this.stateTree!.genProof(Number(stateLeafIndex)).pathElements); + + // copy the ballot + const ballot = this.ballots[Number(stateLeafIndex)].copy(); + currentBallots.unshift(ballot); + currentBallotsPathElements.unshift(this.ballotTree!.genProof(Number(stateLeafIndex)).pathElements); + + // @note we check that command.voteOptionIndex is valid so < maxVoteOptions + // this might be unnecessary but we do it to prevent a possible DoS attack + // from voters who could potentially encrypt a message in such as way that + // when decrypted it results in a valid state leaf index but an invalid vote option index + if (command.voteOptionIndex < this.maxValues.maxVoteOptions) { + currentVoteWeights.unshift(ballot.votes[Number(command.voteOptionIndex)]); + + // create a new quinary tree and add all votes we have so far + const vt = new IncrementalQuinTree(this.treeDepths.voteOptionTreeDepth, 0n, MESSAGE_TREE_ARITY, hash5); + + // fill the vote option tree with the votes we have so far + for (let j = 0; j < this.ballots[0].votes.length; j += 1) { + vt.insert(ballot.votes[j]); } - } else { - throw e; - } - } - break; - case 2n: - try { - // -------------------------------------- - // generate topup circuit inputs - const stateIndex = Number(message.data[0] >= BigInt(this.ballots.length) ? 0n : message.data[0]); - const amount = message.data[0] >= BigInt(this.ballots.length) ? 0n : message.data[1]; - - currentStateLeaves.unshift(this.stateLeaves[stateIndex].copy()); - currentStateLeavesPathElements.unshift(this.stateTree!.genProof(stateIndex).pathElements); - - // create a copy of the state leaf - const newStateLeaf = this.stateLeaves[stateIndex].copy(); - // update the voice credit balance - newStateLeaf.voiceCreditBalance += amount; - - // we should not be in this state as it means we are dealing with very large numbers which will cause problems in the circuits - if (newStateLeaf.voiceCreditBalance > SNARK_FIELD_SIZE) { - throw new Error( - "State leaf voice credit balance exceeds SNARK_FIELD_SIZE. This should not be a state MACI should find itself in, as it will cause complications in the circuits. Rounds should not accept topups with large values.", - ); - } - // save it - this.stateLeaves[stateIndex] = newStateLeaf; - // update the state tree - this.stateTree?.update(stateIndex, newStateLeaf.hash()); + // get the path elements for the first vote leaf + currentVoteWeightsPathElements.unshift(vt.genProof(Number(command.voteOptionIndex)).pathElements); + } else { + currentVoteWeights.unshift(ballot.votes[0]); - // we still need them as placeholder for vote command - const currentBallot = this.ballots[stateIndex].copy(); - currentBallots.unshift(currentBallot); - currentBallotsPathElements.unshift(this.ballotTree!.genProof(Number(stateIndex)).pathElements); - currentVoteWeights.unshift(currentBallot.votes[0]); + // create a new quinary tree and add all votes we have so far + const vt = new IncrementalQuinTree(this.treeDepths.voteOptionTreeDepth, 0n, MESSAGE_TREE_ARITY, hash5); - // create a quinary tree to fill with the votes of the current ballot - const vt = new IncrementalQuinTree(this.treeDepths.voteOptionTreeDepth, 0n, MESSAGE_TREE_ARITY, hash5); + // fill the vote option tree with the votes we have so far + for (let j = 0; j < this.ballots[0].votes.length; j += 1) { + vt.insert(ballot.votes[j]); + } - for (let j = 0; j < this.ballots[0].votes.length; j += 1) { - vt.insert(currentBallot.votes[j]); + // get the path elements for the first vote leaf + currentVoteWeightsPathElements.unshift(vt.genProof(0).pathElements); } + } else { + // just use state leaf index 0 + currentStateLeaves.unshift(this.stateLeaves[0].copy()); + currentStateLeavesPathElements.unshift(this.stateTree!.genProof(0).pathElements); + currentBallots.unshift(this.ballots[0].copy()); + currentBallotsPathElements.unshift(this.ballotTree!.genProof(0).pathElements); + + // Since the command is invalid, we use a zero vote weight + currentVoteWeights.unshift(this.ballots[0].votes[0]); - // add to the first position the path elements of the vote weight tree + // create a new quinary tree and add an empty vote + const vt = new IncrementalQuinTree(this.treeDepths.voteOptionTreeDepth, 0n, MESSAGE_TREE_ARITY, hash5); + vt.insert(this.ballots[0].votes[0]); + // get the path elements for this empty vote weight leaf currentVoteWeightsPathElements.unshift(vt.genProof(0).pathElements); - } catch (e) { - if (!quiet) { - // eslint-disable-next-line no-console - console.log("Error processing topup message: ", (e as Error).message); - } - throw e; } - break; - default: - break; + } else { + throw e; + } } } else { // Since we don't have a command at that position, use a blank state leaf @@ -1401,7 +1296,7 @@ export class Poll implements IPoll { batchSizes: this.batchSizes, maxValues: this.maxValues, messages: this.messages.map((message) => message.toJSON()), - commands: this.commands.map((command) => command.toJSON() as IJsonCommand), + commands: this.commands.map((command) => command.toJSON()), ballots: this.ballots.map((ballot) => ballot.toJSON()), encPubKeys: this.encPubKeys.map((encPubKey) => encPubKey.serialize()), currentMessageBatchIndex: this.currentMessageBatchIndex!, @@ -1432,21 +1327,7 @@ export class Poll implements IPoll { poll.ballots = json.ballots.map((ballot) => Ballot.fromJSON(ballot)); poll.encPubKeys = json.encPubKeys.map((key: string) => PubKey.deserialize(key)); poll.messages = json.messages.map((message) => Message.fromJSON(message as IMessageContractParams)); - poll.commands = json.commands.map((command: IJsonCommand) => { - switch (command.cmdType) { - case "1": { - return PCommand.fromJSON(command as IJsonPCommand) as ICommand; - } - - case "2": { - return TCommand.fromJSON(command as IJsonTCommand) as ICommand; - } - - default: { - return { cmdType: command.cmdType } as unknown as ICommand; - } - } - }); + poll.commands = json.commands.map((command: IJsonPCommand) => PCommand.fromJSON(command)); poll.tallyResult = json.results.map((result: string) => BigInt(result)); poll.currentMessageBatchIndex = json.currentMessageBatchIndex; poll.numBatchesProcessed = json.numBatchesProcessed; diff --git a/core/ts/__tests__/MaciState.test.ts b/core/ts/__tests__/MaciState.test.ts index 6ff6993b5b..9539b66738 100644 --- a/core/ts/__tests__/MaciState.test.ts +++ b/core/ts/__tests__/MaciState.test.ts @@ -126,11 +126,6 @@ describe("MaciState", function test() { }); it("should create a JSON object from a MaciState object", () => { - // test loading a topup message - m1.polls.get(pollId)!.topupMessage(new Message(2n, [0n, 5n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n])); - - // mock a message with invalid message type - m1.polls.get(pollId)!.messages[1].msgType = 3n; const json = m1.toJSON(); fs.writeFileSync(stateFile, JSON.stringify(json, null, 4)); const content = JSON.parse(fs.readFileSync(stateFile).toString()) as IJsonMaciState; @@ -151,40 +146,4 @@ describe("MaciState", function test() { expect(maciState.polls.get(0n)).to.eq(null); }); }); - - describe("topup", () => { - const maciState = new MaciState(STATE_TREE_DEPTH); - const pollId = maciState.deployPoll( - BigInt(Math.floor(Date.now() / 1000) + duration), - maxValues, - treeDepths, - messageBatchSize, - coordinatorKeypair, - ); - const poll = maciState.polls.get(pollId)!; - - it("should allow to publish a topup message", () => { - const user1Keypair = new Keypair(); - // signup the user - const user1StateIndex = maciState.signUp( - user1Keypair.pubKey, - voiceCreditBalance, - BigInt(Math.floor(Date.now() / 1000)), - ); - - const message = new Message(2n, [BigInt(user1StateIndex), 50n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n]); - - poll.topupMessage(message); - - expect(poll.messages.length).to.eq(1); - }); - - it("should throw if the message has an invalid message type", () => { - const message = new Message(1n, [1n, 50n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n]); - - expect(() => { - poll.topupMessage(message); - }).to.throw("A Topup message must have msgType 2"); - }); - }); }); diff --git a/core/ts/__tests__/Poll.test.ts b/core/ts/__tests__/Poll.test.ts index 4989ebdcdd..7de35c2fc6 100644 --- a/core/ts/__tests__/Poll.test.ts +++ b/core/ts/__tests__/Poll.test.ts @@ -1,5 +1,5 @@ import { expect } from "chai"; -import { PCommand, Message, Keypair, StateLeaf, PrivKey, Ballot } from "maci-domainobjs"; +import { PCommand, Keypair, StateLeaf, PrivKey, Ballot } from "maci-domainobjs"; import { MaciState } from "../MaciState"; import { Poll } from "../Poll"; @@ -322,20 +322,10 @@ describe("Poll", function test() { expect(() => poll.processMessages(pollId)).to.not.throw; }); - it("should correctly process a topup message and increase an user's voice credit balance", () => { - const topupMessage = new Message(2n, [BigInt(user1StateIndex), 50n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n]); - - poll.topupMessage(topupMessage); - - const balanceBefore = poll.stateLeaves[user1StateIndex].voiceCreditBalance; - - poll.processMessages(pollId); - - // check balance - expect(poll.stateLeaves[user1StateIndex].voiceCreditBalance.toString()).to.eq((balanceBefore + 50n).toString()); - }); - it("should throw when called after all messages have been processed", () => { + while (poll.hasUnprocessedMessages()) { + poll.processMessages(pollId); + } expect(() => poll.processMessages(pollId)).to.throw("No more messages to process"); }); }); diff --git a/core/ts/utils/types.ts b/core/ts/utils/types.ts index 4ca716b1d8..93647507fa 100644 --- a/core/ts/utils/types.ts +++ b/core/ts/utils/types.ts @@ -4,16 +4,13 @@ import type { PathElements } from "maci-crypto"; import type { Ballot, IJsonBallot, - IJsonCommand, IJsonPCommand, IJsonStateLeaf, - IJsonTCommand, Keypair, Message, PCommand, PubKey, StateLeaf, - TCommand, } from "maci-domainobjs"; /** @@ -82,7 +79,6 @@ export interface IMaciState { export interface IPoll { // These methods are used for sending a message to the poll from user publishMessage(message: Message, encPubKey: PubKey): void; - topupMessage(message: Message): void; // These methods are used to generate circuit inputs processMessages(pollId: bigint): IProcessMessagesCircuitInputs; tallyVotes(): ITallyCircuitInputs; @@ -105,7 +101,7 @@ export interface IJsonPoll { batchSizes: BatchSizes; maxValues: MaxValues; messages: unknown[]; - commands: IJsonCommand[] | IJsonTCommand[] | IJsonPCommand[]; + commands: IJsonPCommand[]; ballots: IJsonBallot[]; encPubKeys: string[]; currentMessageBatchIndex: number; @@ -140,7 +136,7 @@ export interface IProcessMessagesOutput { newBallot?: Ballot; originalBallot?: Ballot; originalBallotPathElements?: PathElements; - command?: PCommand | TCommand; + command?: PCommand; } /** diff --git a/crypto/ts/__tests__/Crypto.test.ts b/crypto/ts/__tests__/Crypto.test.ts index 81327db915..97d2cec2cf 100644 --- a/crypto/ts/__tests__/Crypto.test.ts +++ b/crypto/ts/__tests__/Crypto.test.ts @@ -8,7 +8,7 @@ import { hash3, hash4, hash5, - hash13, + hash12, hashLeftRight, hashN, hashOne, @@ -320,9 +320,9 @@ describe("Crypto", function test() { expect(hash).to.not.eq(BigInt(0)); }); }); - describe("hash13", () => { + describe("hash12", () => { it("should produce the same output for the same input", () => { - const res1 = hash13([ + const res1 = hash12([ BigInt(1), BigInt(2), BigInt(3), @@ -335,9 +335,8 @@ describe("Crypto", function test() { BigInt(10), BigInt(11), BigInt(12), - BigInt(13), ]); - const res2 = hash13([ + const res2 = hash12([ BigInt(1), BigInt(2), BigInt(3), @@ -350,12 +349,11 @@ describe("Crypto", function test() { BigInt(10), BigInt(11), BigInt(12), - BigInt(13), ]); expect(res1).to.eq(res2); }); it("should produce different outputs for different inputs", () => { - const res1 = hash13([ + const res1 = hash12([ BigInt(1), BigInt(2), BigInt(3), @@ -368,9 +366,8 @@ describe("Crypto", function test() { BigInt(10), BigInt(11), BigInt(12), - BigInt(13), ]); - const res2 = hash13([ + const res2 = hash12([ BigInt(2), BigInt(1), BigInt(3), @@ -383,12 +380,11 @@ describe("Crypto", function test() { BigInt(10), BigInt(11), BigInt(12), - BigInt(13), ]); expect(res1).to.not.eq(res2); }); it("should produce a non zero value", () => { - const hash = hash13([ + const hash = hash12([ BigInt(1), BigInt(2), BigInt(3), @@ -401,13 +397,12 @@ describe("Crypto", function test() { BigInt(10), BigInt(11), BigInt(12), - BigInt(13), ]); expect(hash).to.not.eq(BigInt(0)); }); it("should throw when elements is more than numElement", () => { expect(() => - hash13([ + hash12([ BigInt(1), BigInt(2), BigInt(3), @@ -421,12 +416,11 @@ describe("Crypto", function test() { BigInt(11), BigInt(12), BigInt(13), - BigInt(14), ]), - ).to.throw("the length of the elements array should be at most 13; got 14"); + ).to.throw("the length of the elements array should be at most 12; got 13"); }); it("should work (and apply padding) when passed less than numElement elements", () => { - const hash = hash13([BigInt(1), BigInt(2)]); + const hash = hash12([BigInt(1), BigInt(2)]); expect(hash).to.not.eq(BigInt(0)); }); }); diff --git a/crypto/ts/hashing.ts b/crypto/ts/hashing.ts index 140a0453dd..4f3b5da1b6 100644 --- a/crypto/ts/hashing.ts +++ b/crypto/ts/hashing.ts @@ -127,8 +127,8 @@ export const hash5 = (elements: Plaintext): bigint => hashN(5, elements); * @param elements The elements to hash * @returns The hash of the elements */ -export const hash13 = (elements: Plaintext): bigint => { - const max = 13; +export const hash12 = (elements: Plaintext): bigint => { + const max = 12; const elementLength = elements.length; if (elementLength > max) { @@ -143,12 +143,11 @@ export const hash13 = (elements: Plaintext): bigint => { } } - return poseidonT6([ - elementsPadded[0], - poseidonT6(elementsPadded.slice(1, 6)), - poseidonT6(elementsPadded.slice(6, 11)), + return poseidonT5([ + poseidonT6(elementsPadded.slice(0, 5)), + poseidonT6(elementsPadded.slice(5, 10)), + elementsPadded[10], elementsPadded[11], - elementsPadded[12], ]); }; diff --git a/crypto/ts/index.ts b/crypto/ts/index.ts index c97301a41c..7da88db0e6 100644 --- a/crypto/ts/index.ts +++ b/crypto/ts/index.ts @@ -21,7 +21,7 @@ export { export { G1Point, G2Point, genRandomBabyJubValue } from "./babyjub"; -export { sha256Hash, hashLeftRight, hashN, hash2, hash3, hash4, hash5, hash13, hashOne } from "./hashing"; +export { sha256Hash, hashLeftRight, hashN, hash2, hash3, hash4, hash5, hash12, hashOne } from "./hashing"; export { inCurve } from "@zk-kit/baby-jubjub"; diff --git a/domainobjs/ts/__tests__/commands.test.ts b/domainobjs/ts/__tests__/commands.test.ts index 972c302f21..8f8b6e96cf 100644 --- a/domainobjs/ts/__tests__/commands.test.ts +++ b/domainobjs/ts/__tests__/commands.test.ts @@ -1,7 +1,7 @@ import { expect } from "chai"; import { genRandomSalt } from "maci-crypto"; -import { PCommand, Keypair, TCommand } from ".."; +import { PCommand, Keypair } from ".."; describe("Commands", () => { const { privKey, pubKey } = new Keypair(); @@ -23,10 +23,6 @@ describe("Commands", () => { ); expect(command).to.not.eq(null); }); - it("should create a TCommand", () => { - const command: TCommand = new TCommand(random50bitBigInt(), random50bitBigInt(), random50bitBigInt()); - expect(command).to.not.eq(null); - }); }); describe("signature", () => { @@ -105,34 +101,10 @@ describe("Commands", () => { expect(c1.nonce.toString()).not.to.eq(c3.nonce.toString()); }); - - it("should produce a deep copy for TCommand", () => { - const c1: TCommand = new TCommand(BigInt(10), BigInt(0), BigInt(9)); - - // shallow copy - const c2 = c1; - c1.amount = BigInt(9999); - expect(c1.amount.toString()).to.eq(c2.amount.toString()); - - // deep copy - const c3 = c1.copy(); - c1.amount = BigInt(8888); - - expect(c1.amount.toString()).not.to.eq(c3.amount.toString()); - }); }); describe("deserialization/serialization", () => { describe("toJSON", () => { - it("should produce a JSON object with valid values", () => { - const c1: TCommand = new TCommand(BigInt(10), BigInt(0), BigInt(9)); - const json = c1.toJSON(); - expect(json).to.not.eq(null); - expect(json.cmdType).to.eq("2"); - expect(json.stateIndex).to.eq("10"); - expect(json.amount).to.eq("0"); - expect(json.pollId).to.eq("9"); - }); it("should produce a JSON object with valid values", () => { const c1: PCommand = new PCommand(BigInt(10), pubKey, BigInt(0), BigInt(9), BigInt(1), BigInt(123)); const json = c1.toJSON(); @@ -142,17 +114,10 @@ describe("Commands", () => { expect(json.newVoteWeight).to.eq("9"); expect(json.nonce).to.eq("1"); expect(json.pollId).to.eq("123"); - expect(json.cmdType).to.eq("1"); }); }); describe("fromJSON", () => { - it("should produce a TCommand from a JSON object", () => { - const c1: TCommand = new TCommand(BigInt(10), BigInt(0), BigInt(9)); - const json = c1.toJSON(); - const c2 = TCommand.fromJSON(json); - expect(c2.equals(c1)).to.eq(true); - }); it("should produce a PCommand from a JSON object", () => { const c1: PCommand = new PCommand(BigInt(10), pubKey, BigInt(0), BigInt(9), BigInt(1), BigInt(123)); const json = c1.toJSON(); diff --git a/domainobjs/ts/__tests__/message.test.ts b/domainobjs/ts/__tests__/message.test.ts index 5491e98074..ccd15adfac 100644 --- a/domainobjs/ts/__tests__/message.test.ts +++ b/domainobjs/ts/__tests__/message.test.ts @@ -5,35 +5,34 @@ import { Message, Keypair } from ".."; describe("message", () => { describe("constructor", () => { it("should create a new message", () => { - const msg = new Message(BigInt(0), Array(10).fill(BigInt(0))); + const msg = new Message(Array(10).fill(BigInt(0))); expect(msg).to.not.eq(null); }); it("should throw an error if the data length is not 10", () => { - expect(() => new Message(BigInt(0), Array(9).fill(BigInt(0)))).to.throw(); + expect(() => new Message(Array(9).fill(BigInt(0)))).to.throw(); }); }); describe("asCircuitInputs", () => { it("should produce an array", () => { - const msg = new Message(BigInt(0), Array(10).fill(BigInt(0))); + const msg = new Message(Array(10).fill(BigInt(0))); const arr = msg.asCircuitInputs(); expect(arr).to.be.instanceOf(Array); - expect(arr.length).to.eq(11); - expect(arr).to.deep.eq([BigInt(0), ...Array(10).fill(BigInt(0))]); + expect(arr.length).to.eq(10); + expect(arr).to.deep.eq([...Array(10).fill(BigInt(0))]); }); }); describe("asContractParam", () => { it("should produce an object", () => { - const msg = new Message(BigInt(0), Array(10).fill(BigInt(0))); + const msg = new Message(Array(10).fill(BigInt(0))); const obj = msg.asContractParam(); expect(obj).to.be.instanceOf(Object); - expect(Object.keys(obj)).to.deep.eq(["msgType", "data"]); + expect(Object.keys(obj)).to.deep.eq(["data"]); }); it("should produce an object with the correct values", () => { - const msg = new Message(BigInt(0), Array(10).fill(BigInt(0))); + const msg = new Message(Array(10).fill(BigInt(0))); const obj = msg.asContractParam(); - expect(obj.msgType).to.eq("0"); expect(obj.data).to.deep.eq(Array(10).fill("0")); }); }); @@ -41,13 +40,13 @@ describe("message", () => { describe("hash", () => { const keypair = new Keypair(); it("should produce a hash", () => { - const msg = new Message(BigInt(0), Array(10).fill(BigInt(0))); + const msg = new Message(Array(10).fill(BigInt(0))); const h = msg.hash(keypair.pubKey); expect(h).to.not.eq(null); }); it("should produce the same hash for the same ballot", () => { - const msg1 = new Message(BigInt(0), Array(10).fill(BigInt(0))); - const msg2 = new Message(BigInt(0), Array(10).fill(BigInt(0))); + const msg1 = new Message(Array(10).fill(BigInt(0))); + const msg2 = new Message(Array(10).fill(BigInt(0))); const h1 = msg1.hash(keypair.pubKey); const h2 = msg2.hash(keypair.pubKey); expect(h1).to.eq(h2); @@ -55,62 +54,55 @@ describe("message", () => { }); describe("copy", () => { it("should produce a deep copy", () => { - const msg1 = new Message(BigInt(0), Array(10).fill(BigInt(0))); + const msg1 = new Message(Array(10).fill(BigInt(0))); const msg2 = msg1.copy(); expect(msg1.equals(msg2)).to.eq(true); expect(msg1.data).to.deep.eq(msg2.data); - expect(msg1.msgType).to.eq(msg2.msgType); }); }); describe("equals", () => { it("should return false for messages that are not equal (different length)", () => { - const msg1 = new Message(BigInt(0), Array(10).fill(BigInt(0))); - const msg2 = new Message(BigInt(0), Array(10).fill(BigInt(0))); + const msg1 = new Message(Array(10).fill(BigInt(0))); + const msg2 = new Message(Array(10).fill(BigInt(0))); msg1.data[10] = BigInt(1); expect(msg1.equals(msg2)).to.eq(false); }); it("should return true for messages that are equal", () => { - const msg1 = new Message(BigInt(0), Array(10).fill(BigInt(0))); - const msg2 = new Message(BigInt(0), Array(10).fill(BigInt(0))); + const msg1 = new Message(Array(10).fill(BigInt(0))); + const msg2 = new Message(Array(10).fill(BigInt(0))); expect(msg1.equals(msg2)).to.eq(true); }); - it("should return false when the message type is not equal", () => { - const msg1 = new Message(BigInt(0), Array(10).fill(BigInt(0))); - const msg2 = new Message(BigInt(1), Array(10).fill(BigInt(0))); - expect(msg1.equals(msg2)).to.eq(false); - }); }); describe("serialization/deserialization", () => { describe("toJSON", () => { it("should produce a JSON object", () => { - const msg = new Message(BigInt(0), Array(10).fill(BigInt(0))); + const msg = new Message(Array(10).fill(BigInt(0))); const json = msg.toJSON(); expect(json).to.not.eq(null); }); it("should produce a JSON object with the correct keys", () => { - const msg = new Message(BigInt(0), Array(10).fill(BigInt(0))); + const msg = new Message(Array(10).fill(BigInt(0))); const json = msg.toJSON(); - expect(Object.keys(json)).to.deep.eq(["msgType", "data"]); + expect(Object.keys(json)).to.deep.eq(["data"]); }); it("should preserve the data correctly", () => { - const msg = new Message(BigInt(0), Array(10).fill(BigInt(0))); + const msg = new Message(Array(10).fill(BigInt(0))); const json = msg.toJSON(); - expect(msg.msgType.toString()).to.eq(json.msgType); expect(msg.data.map((x: bigint) => x.toString())).to.deep.eq(json.data); }); }); describe("fromJSON", () => { it("should produce a Message instance", () => { - const msg = new Message(BigInt(0), Array(10).fill(BigInt(0))); + const msg = new Message(Array(10).fill(BigInt(0))); const json = msg.toJSON(); const msg2 = Message.fromJSON(json); expect(msg2).to.be.instanceOf(Message); }); it("should preserve the data correctly", () => { - const msg = new Message(BigInt(0), Array(10).fill(BigInt(0))); + const msg = new Message(Array(10).fill(BigInt(0))); const json = msg.toJSON(); const msg2 = Message.fromJSON(json); expect(msg.equals(msg2)).to.eq(true); diff --git a/domainobjs/ts/commands/PCommand.ts b/domainobjs/ts/commands/PCommand.ts index 31534d9196..caa4420281 100644 --- a/domainobjs/ts/commands/PCommand.ts +++ b/domainobjs/ts/commands/PCommand.ts @@ -14,7 +14,7 @@ import { import assert from "assert"; -import type { ICommand, IJsonPCommand } from "./types"; +import type { IJsonPCommand } from "./types"; import type { PrivKey } from "../privateKey"; import { Message } from "../message"; @@ -29,9 +29,7 @@ export interface IDecryptMessage { * @notice Unencrypted data whose fields include the user's public key, vote etc. * This represents a Vote command. */ -export class PCommand implements ICommand { - cmdType: bigint; - +export class PCommand { stateIndex: bigint; newPubKey: PubKey; @@ -65,8 +63,6 @@ export class PCommand implements ICommand { pollId: bigint, salt: bigint = genRandomSalt(), ) { - this.cmdType = BigInt(1); - const limit50Bits = BigInt(2 ** 50); assert(limit50Bits >= stateIndex); assert(limit50Bits >= voteOptionIndex); @@ -166,7 +162,7 @@ export class PCommand implements ICommand { const ciphertext: Ciphertext = poseidonEncrypt(plaintext, sharedKey, BigInt(0)); - const message = new Message(BigInt(1), ciphertext as bigint[]); + const message = new Message(ciphertext as bigint[]); return message; }; @@ -234,7 +230,6 @@ export class PCommand implements ICommand { nonce: this.nonce.toString(), pollId: this.pollId.toString(), salt: this.salt.toString(), - cmdType: this.cmdType.toString(), }; } diff --git a/domainobjs/ts/commands/TCommand.ts b/domainobjs/ts/commands/TCommand.ts deleted file mode 100644 index 86f340556b..0000000000 --- a/domainobjs/ts/commands/TCommand.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { ICommand, IJsonTCommand } from "./types"; - -/** - * @notice Command for submitting a topup request - */ -export class TCommand implements ICommand { - cmdType: bigint; - - stateIndex: bigint; - - amount: bigint; - - pollId: bigint; - - /** - * Create a new TCommand - * @param stateIndex the state index of the user - * @param amount the amount of voice credits - * @param pollId the poll ID - */ - constructor(stateIndex: bigint, amount: bigint, pollId: bigint) { - this.cmdType = BigInt(2); - this.stateIndex = stateIndex; - this.amount = amount; - this.pollId = pollId; - } - - /** - * Create a deep clone of this TCommand - * @returns a copy of the TCommand - */ - copy = (): T => new TCommand(this.stateIndex, this.amount, this.pollId) as T; - - /** - * Check whether this command has deep equivalence to another command - * @param command the command to compare with - * @returns whether they are equal or not - */ - equals = (command: TCommand): boolean => - this.stateIndex === command.stateIndex && - this.amount === command.amount && - this.pollId === command.pollId && - this.cmdType === command.cmdType; - - /** - * Serialize into a JSON object - */ - toJSON(): IJsonTCommand { - return { - stateIndex: this.stateIndex.toString(), - amount: this.amount.toString(), - cmdType: this.cmdType.toString(), - pollId: this.pollId.toString(), - }; - } - - /** - * Deserialize into a TCommand object - * @param json - the json representation - * @returns the TCommand instance - */ - static fromJSON(json: IJsonTCommand): TCommand { - return new TCommand(BigInt(json.stateIndex), BigInt(json.amount), BigInt(json.pollId)); - } -} diff --git a/domainobjs/ts/commands/index.ts b/domainobjs/ts/commands/index.ts index 24323c43af..6e0fd2beb8 100644 --- a/domainobjs/ts/commands/index.ts +++ b/domainobjs/ts/commands/index.ts @@ -1,3 +1,2 @@ -export { TCommand } from "./TCommand"; export { PCommand } from "./PCommand"; -export type { ICommand, IJsonCommand, IJsonTCommand, IJsonPCommand } from "./types"; +export type { IJsonTCommand, IJsonPCommand } from "./types"; diff --git a/domainobjs/ts/commands/types.ts b/domainobjs/ts/commands/types.ts index 03a96de92b..8ee4def037 100644 --- a/domainobjs/ts/commands/types.ts +++ b/domainobjs/ts/commands/types.ts @@ -1,24 +1,7 @@ -/** - * @notice A parent interface for all the commands - */ -export interface ICommand { - cmdType: bigint; - copy: () => T; - equals: (command: T) => boolean; - toJSON: () => unknown; -} - -/** - * @notice An interface representing a generic json command - */ -export interface IJsonCommand { - cmdType: string; -} - /** * @notice An interface representing a json T command */ -export interface IJsonTCommand extends IJsonCommand { +export interface IJsonTCommand { stateIndex: string; amount: string; pollId: string; @@ -27,7 +10,7 @@ export interface IJsonTCommand extends IJsonCommand { /** * @notice An interface representing a json P command */ -export interface IJsonPCommand extends IJsonCommand { +export interface IJsonPCommand { stateIndex: string; newPubKey: string; voteOptionIndex: string; diff --git a/domainobjs/ts/index.ts b/domainobjs/ts/index.ts index 8d4a5ffb7f..ad8081b858 100644 --- a/domainobjs/ts/index.ts +++ b/domainobjs/ts/index.ts @@ -29,13 +29,6 @@ export type { IJsonBallot, } from "./types"; -export { - type ICommand, - type IJsonCommand, - type IJsonTCommand, - type IJsonPCommand, - TCommand, - PCommand, -} from "./commands"; +export { type IJsonTCommand, type IJsonPCommand, PCommand } from "./commands"; export { VerifyingKey } from "./verifyingKey"; diff --git a/domainobjs/ts/message.ts b/domainobjs/ts/message.ts index d563d9351d..08843dd4ce 100644 --- a/domainobjs/ts/message.ts +++ b/domainobjs/ts/message.ts @@ -1,4 +1,4 @@ -import { hash13 } from "maci-crypto"; +import { hash12 } from "maci-crypto"; import assert from "assert"; @@ -9,8 +9,6 @@ import type { IMessageContractParams } from "./types"; * @notice An encrypted command and signature. */ export class Message { - msgType: bigint; - data: bigint[]; static DATA_LENGTH = 10; @@ -20,9 +18,8 @@ export class Message { * @param msgType the type of the message * @param data the data of the message */ - constructor(msgType: bigint, data: bigint[]) { + constructor(data: bigint[]) { assert(data.length === Message.DATA_LENGTH); - this.msgType = msgType; this.data = data; } @@ -30,14 +27,13 @@ export class Message { * Return the message as an array of bigints * @returns the message as an array of bigints */ - private asArray = (): bigint[] => [this.msgType].concat(this.data); + private asArray = (): bigint[] => this.data; /** * Return the message as a contract param * @returns the message as a contract param */ asContractParam = (): IMessageContractParams => ({ - msgType: this.msgType.toString(), data: this.data.map((x: bigint) => x.toString()), }); @@ -52,17 +48,13 @@ export class Message { * @param encPubKey the public key that is used to encrypt this message * @returns the hash of the message data and the public key */ - hash = (encPubKey: PubKey): bigint => hash13([...[this.msgType], ...this.data, ...encPubKey.rawPubKey]); + hash = (encPubKey: PubKey): bigint => hash12([...this.data, ...encPubKey.rawPubKey]); /** * Create a copy of the message * @returns a copy of the message */ - copy = (): Message => - new Message( - BigInt(this.msgType.toString()), - this.data.map((x: bigint) => BigInt(x.toString())), - ); + copy = (): Message => new Message(this.data.map((x: bigint) => BigInt(x.toString()))); /** * Check if two messages are equal @@ -73,9 +65,6 @@ export class Message { if (this.data.length !== m.data.length) { return false; } - if (this.msgType !== m.msgType) { - return false; - } return this.data.every((data, index) => data === m.data[index]); }; @@ -93,9 +82,6 @@ export class Message { * @returns the deserialized object as a Message instance */ static fromJSON(json: IMessageContractParams): Message { - return new Message( - BigInt(json.msgType), - json.data.map((x) => BigInt(x)), - ); + return new Message(json.data.map((x) => BigInt(x))); } } diff --git a/domainobjs/ts/types.ts b/domainobjs/ts/types.ts index 99b313a6e1..1429c63d85 100644 --- a/domainobjs/ts/types.ts +++ b/domainobjs/ts/types.ts @@ -79,7 +79,6 @@ export interface IStateLeafContractParams { } export interface IMessageContractParams { - msgType: string; data: BigNumberish[]; } diff --git a/integrationTests/ts/__tests__/utils/utils.ts b/integrationTests/ts/__tests__/utils/utils.ts index 82a16ba13c..b99b5d7d0b 100644 --- a/integrationTests/ts/__tests__/utils/utils.ts +++ b/integrationTests/ts/__tests__/utils/utils.ts @@ -7,7 +7,6 @@ import { deployFreeForAllSignUpGatekeeper, deployMaci, deployMockVerifier, - deployTopupCredit, deployVkRegistry, Verifier, } from "maci-contracts"; @@ -186,18 +185,14 @@ export const deployTestContracts = async ( // VkRegistry const vkRegistryContract = await deployVkRegistry(signer, true); - const topupCreditContract = await deployTopupCredit(signer, true); - const [gatekeeperContractAddress, constantIntialVoiceCreditProxyContractAddress, topupCreditContractAddress] = - await Promise.all([ - gatekeeperContract.getAddress(), - constantIntialVoiceCreditProxyContract.getAddress(), - topupCreditContract.getAddress(), - ]); + const [gatekeeperContractAddress, constantIntialVoiceCreditProxyContractAddress] = await Promise.all([ + gatekeeperContract.getAddress(), + constantIntialVoiceCreditProxyContract.getAddress(), + ]); const { maciContract } = await deployMaci({ signUpTokenGatekeeperContractAddress: gatekeeperContractAddress, initialVoiceCreditBalanceAddress: constantIntialVoiceCreditProxyContractAddress, - topupCreditContractAddress, signer, stateTreeDepth, quiet,