From 14397568850f28448f52ab8ba889015e41444ab6 Mon Sep 17 00:00:00 2001 From: NicoSerranoP Date: Tue, 17 Dec 2024 14:24:55 -0500 Subject: [PATCH 01/17] feat(voice-credits): eth based voice credit contract --- .../ETHBasedInitialVoiceCreditProxy.sol | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 packages/contracts/contracts/initialVoiceCreditProxy/ETHBasedInitialVoiceCreditProxy.sol diff --git a/packages/contracts/contracts/initialVoiceCreditProxy/ETHBasedInitialVoiceCreditProxy.sol b/packages/contracts/contracts/initialVoiceCreditProxy/ETHBasedInitialVoiceCreditProxy.sol new file mode 100644 index 0000000000..a9896cb4c6 --- /dev/null +++ b/packages/contracts/contracts/initialVoiceCreditProxy/ETHBasedInitialVoiceCreditProxy.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import { InitialVoiceCreditProxy } from "./InitialVoiceCreditProxy.sol"; + +/// @title ETHBasedInitialVoiceCreditProxy +/// @notice This contract allows to set balances depending on the amount of ETH sent +/// for MACI's voters. +contract ETHBasedInitialVoiceCreditProxy is InitialVoiceCreditProxy { + /// @notice the address where the ETH will be sent + address payable public immutable receiver; + /// @notice the conversion rate between ETH and voice credits + uint256 internal immutable conversionRate; + mapping(address => uint256) public balances; + + /// @notice creates a new ETHBasedInitialVoiceCreditProxy + /// @param _receiver the address where the ETH will be sent + /// @param _conversionRate the conversion rate between ETH and voice credits + constructor(address payable _receiver, uint256 _conversionRate) payable { + receiver = _receiver; + conversionRate = _conversionRate; + } + + /// @notice Returns the voice credits based on the amount of ETH sent for any new MACI's voter + /// @return balance + function getVoiceCredits(address _user, bytes memory) public view override returns (uint256) { + // Calculate the voice credits based on the amount of ETH sent + uint256 voiceCredits = (balances[_user] * conversionRate) / 1 ether; + return voiceCredits; + } + + /// @notice Saves the amount of voice credits for any new MACI's voter + /// @dev The real amount is saved (no conversion here) to allow full withdrawals + /// @param _user the address of the voter + function registerVoiceCredits(address _user) public payable { + // set user's balanace + balances[_user] += msg.value; + // send ETH to the receiver address + receiver.transfer(msg.value); + } +} From 814108405ed991f2a02d7ecb889ed347b02cd2ed Mon Sep 17 00:00:00 2001 From: NicoSerranoP Date: Thu, 19 Dec 2024 16:46:09 -0500 Subject: [PATCH 02/17] feat(voice-credit): setup tests and change name --- ... => TokensSentInitialVoiceCreditProxy.sol} | 23 +++++++++++++------ .../TokensSentInitialVoiceCreditProxy.test.ts | 18 +++++++++++++++ 2 files changed, 34 insertions(+), 7 deletions(-) rename packages/contracts/contracts/initialVoiceCreditProxy/{ETHBasedInitialVoiceCreditProxy.sol => TokensSentInitialVoiceCreditProxy.sol} (61%) create mode 100644 packages/contracts/tests/initialvoicecredits/TokensSentInitialVoiceCreditProxy.test.ts diff --git a/packages/contracts/contracts/initialVoiceCreditProxy/ETHBasedInitialVoiceCreditProxy.sol b/packages/contracts/contracts/initialVoiceCreditProxy/TokensSentInitialVoiceCreditProxy.sol similarity index 61% rename from packages/contracts/contracts/initialVoiceCreditProxy/ETHBasedInitialVoiceCreditProxy.sol rename to packages/contracts/contracts/initialVoiceCreditProxy/TokensSentInitialVoiceCreditProxy.sol index a9896cb4c6..99c54272a2 100644 --- a/packages/contracts/contracts/initialVoiceCreditProxy/ETHBasedInitialVoiceCreditProxy.sol +++ b/packages/contracts/contracts/initialVoiceCreditProxy/TokensSentInitialVoiceCreditProxy.sol @@ -2,22 +2,26 @@ pragma solidity ^0.8.20; import { InitialVoiceCreditProxy } from "./InitialVoiceCreditProxy.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -/// @title ETHBasedInitialVoiceCreditProxy +/// @title TokensSentInitialVoiceCreditProxy /// @notice This contract allows to set balances depending on the amount of ETH sent /// for MACI's voters. -contract ETHBasedInitialVoiceCreditProxy is InitialVoiceCreditProxy { +contract TokensSentInitialVoiceCreditProxy is InitialVoiceCreditProxy { /// @notice the address where the ETH will be sent address payable public immutable receiver; + /// @notice the ERC20 token contract + IERC20 public immutable token; /// @notice the conversion rate between ETH and voice credits uint256 internal immutable conversionRate; mapping(address => uint256) public balances; - /// @notice creates a new ETHBasedInitialVoiceCreditProxy + /// @notice creates a new TokensSentInitialVoiceCreditProxy /// @param _receiver the address where the ETH will be sent /// @param _conversionRate the conversion rate between ETH and voice credits - constructor(address payable _receiver, uint256 _conversionRate) payable { + constructor(address payable _receiver, IERC20 _token, uint256 _conversionRate) payable { receiver = _receiver; + token = _token; conversionRate = _conversionRate; } @@ -32,10 +36,15 @@ contract ETHBasedInitialVoiceCreditProxy is InitialVoiceCreditProxy { /// @notice Saves the amount of voice credits for any new MACI's voter /// @dev The real amount is saved (no conversion here) to allow full withdrawals /// @param _user the address of the voter - function registerVoiceCredits(address _user) public payable { + /// @param _amount the amount of ERC-20 tokens (if ETH then the amount is passed as msg.value) + function registerVoiceCredits(address _user, uint256 _amount) public payable { // set user's balanace balances[_user] += msg.value; - // send ETH to the receiver address - receiver.transfer(msg.value); + // send tokens to the receiver address + if (address(token) == address(0)) { + receiver.transfer(msg.value); + } else { + require(token.transferFrom(msg.sender, receiver, _amount), "Transfer failed"); + } } } diff --git a/packages/contracts/tests/initialvoicecredits/TokensSentInitialVoiceCreditProxy.test.ts b/packages/contracts/tests/initialvoicecredits/TokensSentInitialVoiceCreditProxy.test.ts new file mode 100644 index 0000000000..112da38e0c --- /dev/null +++ b/packages/contracts/tests/initialvoicecredits/TokensSentInitialVoiceCreditProxy.test.ts @@ -0,0 +1,18 @@ +// import { Signer } from "ethers"; +// import { getDefaultSigner } from "../../ts/utils"; + +describe("Tokens Sent Initial Voice Credit Proxy", () => { + /* + let signer: Signer; + + before(async () => { + signer = await getDefaultSigner(); + }); + + describe("Deployment", () => { + it("The voice credit proxy should be deployed", async () => {}); + }); + describe("Receive tokens", () => {}); + describe("Send voice credits", () => {}); + */ +}); From bf0b877aeb5fb24859150a34442b6b494834b59e Mon Sep 17 00:00:00 2001 From: ctrlc03 <93448202+ctrlc03@users.noreply.github.com> Date: Wed, 18 Dec 2024 16:12:36 +0000 Subject: [PATCH 03/17] feat: use gatekeeper per poll (#1961) --- packages/cli/ts/commands/deployPoll.ts | 38 ++- packages/cli/ts/commands/joinPoll.ts | 6 +- packages/cli/ts/index.ts | 2 + packages/cli/ts/utils/interfaces.ts | 11 + packages/contracts/contracts/MACI.sol | 7 +- packages/contracts/contracts/Poll.sol | 18 +- .../contracts/contracts/interfaces/IPoll.sol | 3 +- .../interfaces/ISignUpGatekeeper.sol | 11 + .../contracts/contracts/utilities/Params.sol | 2 + packages/contracts/deploy-config-example.json | 33 +- .../tasks/deploy/poll/01-gatekeepers.ts | 298 ++++++++++++++++++ .../deploy/poll/{01-poll.ts => 02-poll.ts} | 6 + packages/contracts/tasks/helpers/constants.ts | 1 + packages/contracts/tests/MACI.test.ts | 14 +- .../contracts/tests/MessageProcessor.test.ts | 6 +- packages/contracts/tests/Poll.test.ts | 31 +- packages/contracts/tests/PollFactory.test.ts | 7 +- packages/contracts/tests/Tally.test.ts | 8 + packages/contracts/tests/TallyNonQv.test.ts | 4 + packages/contracts/tests/constants.ts | 1 + .../ts/__tests__/maci-keys.test.ts | 3 +- .../ts/__tests__/utils/interfaces.ts | 3 +- .../ts/__tests__/utils/utils.ts | 7 +- 23 files changed, 480 insertions(+), 40 deletions(-) create mode 100644 packages/contracts/contracts/interfaces/ISignUpGatekeeper.sol create mode 100644 packages/contracts/tasks/deploy/poll/01-gatekeepers.ts rename packages/contracts/tasks/deploy/poll/{01-poll.ts => 02-poll.ts} (93%) diff --git a/packages/cli/ts/commands/deployPoll.ts b/packages/cli/ts/commands/deployPoll.ts index bff6d257f2..b69fb1a631 100644 --- a/packages/cli/ts/commands/deployPoll.ts +++ b/packages/cli/ts/commands/deployPoll.ts @@ -1,4 +1,4 @@ -import { MACI__factory as MACIFactory, EMode } from "maci-contracts"; +import { MACI__factory as MACIFactory, EMode, deployFreeForAllSignUpGatekeeper } from "maci-contracts"; import { PubKey } from "maci-domainobjs"; import { @@ -26,6 +26,7 @@ export const deployPoll = async ({ coordinatorPubkey, maciAddress, vkRegistryAddress, + gatekeeperAddress, signer, quiet = true, useQuadraticVoting = false, @@ -49,6 +50,18 @@ export const deployPoll = async ({ const maci = maciAddress || maciContractAddress; + const maciContract = MACIFactory.connect(maci, signer); + const pollId = await maciContract.nextPollId(); + + // check if we have a signupGatekeeper already deployed or passed as arg + let signupGatekeeperContractAddress = + gatekeeperAddress || (await readContractAddress(`SignUpGatekeeper-${pollId.toString()}`, network?.name)); + + if (!signupGatekeeperContractAddress) { + const contract = await deployFreeForAllSignUpGatekeeper(signer, true); + signupGatekeeperContractAddress = await contract.getAddress(); + } + // required arg -> poll duration if (pollDuration <= 0) { logError("Duration cannot be <= 0"); @@ -83,8 +96,6 @@ export const deployPoll = async ({ // get the verifier contract const verifierContractAddress = await readContractAddress("Verifier", network?.name); - const maciContract = MACIFactory.connect(maci, signer); - // deploy the poll let pollAddr = ""; let messageProcessorContractAddress = ""; @@ -103,6 +114,7 @@ export const deployPoll = async ({ verifierContractAddress, vkRegistry, useQuadraticVoting ? EMode.QV : EMode.NON_QV, + signupGatekeeperContractAddress, { gasLimit: 10000000 }, ); @@ -130,8 +142,8 @@ export const deployPoll = async ({ } // eslint-disable-next-line no-underscore-dangle - const pollId = log.args._pollId; - const pollContracts = await maciContract.getPoll(pollId); + const eventPollId = log.args._pollId; + const pollContracts = await maciContract.getPoll(eventPollId); pollAddr = pollContracts.poll; messageProcessorContractAddress = pollContracts.messageProcessor; tallyContractAddress = pollContracts.tally; @@ -142,9 +154,18 @@ export const deployPoll = async ({ logGreen(quiet, info(`Tally contract: ${tallyContractAddress}`)); // store the address - await storeContractAddress(`MessageProcessor-${pollId.toString()}`, messageProcessorContractAddress, network?.name); - await storeContractAddress(`Tally-${pollId.toString()}`, tallyContractAddress, network?.name); - await storeContractAddress(`Poll-${pollId.toString()}`, pollAddr, network?.name); + await storeContractAddress( + `SignUpGatekeeper-${eventPollId.toString()}`, + signupGatekeeperContractAddress, + network?.name, + ); + await storeContractAddress( + `MessageProcessor-${eventPollId.toString()}`, + messageProcessorContractAddress, + network?.name, + ); + await storeContractAddress(`Tally-${eventPollId.toString()}`, tallyContractAddress, network?.name); + await storeContractAddress(`Poll-${eventPollId.toString()}`, pollAddr, network?.name); } catch (error) { logError((error as Error).message); } @@ -154,5 +175,6 @@ export const deployPoll = async ({ messageProcessor: messageProcessorContractAddress, tally: tallyContractAddress, poll: pollAddr, + signupGatekeeper: signupGatekeeperContractAddress, }; }; diff --git a/packages/cli/ts/commands/joinPoll.ts b/packages/cli/ts/commands/joinPoll.ts index c8dc02af6a..a78b52a6dc 100644 --- a/packages/cli/ts/commands/joinPoll.ts +++ b/packages/cli/ts/commands/joinPoll.ts @@ -10,7 +10,7 @@ import fs from "fs"; import type { IJoinPollArgs, IJoinedUserArgs, IParsePollJoinEventsArgs, IJoinPollData } from "../utils"; -import { contractExists, logError, logYellow, info, logGreen, success, BLOCKS_STEP } from "../utils"; +import { contractExists, logError, logYellow, info, logGreen, success, BLOCKS_STEP, DEFAULT_SG_DATA } from "../utils"; import { banner } from "../utils/banner"; /** @@ -195,6 +195,7 @@ export const joinPoll = async ({ rapidsnark, pollWitgen, pollWasm, + sgDataArg, quiet = true, }: IJoinPollArgs): Promise => { banner(quiet); @@ -332,6 +333,8 @@ export const joinPoll = async ({ let pollStateIndex = ""; let receipt: ContractTransactionReceipt | null = null; + const sgData = sgDataArg || DEFAULT_SG_DATA; + try { // generate the proof for this batch const proof = await generateAndVerifyProof( @@ -351,6 +354,7 @@ export const joinPoll = async ({ loadedCreditBalance!, currentStateRootIndex, proof, + sgData, ); receipt = await tx.wait(); logYellow(quiet, info(`Transaction hash: ${receipt!.hash}`)); diff --git a/packages/cli/ts/index.ts b/packages/cli/ts/index.ts index 6051a4f856..c40a5166e9 100644 --- a/packages/cli/ts/index.ts +++ b/packages/cli/ts/index.ts @@ -216,6 +216,7 @@ program .description("join the poll") .requiredOption("-sk, --priv-key ", "the private key") .option("-i, --state-index ", "the user's state index", BigInt) + .requiredOption("-s, --sg-data ", "the signup gateway data") .requiredOption("-esk, --poll-priv-key ", "the user ephemeral private key for the poll") .option( "-nv, --new-voice-credit-balance ", @@ -265,6 +266,7 @@ program useWasm: cmdObj.wasm, rapidsnark: cmdObj.rapidsnark, pollWitgen: cmdObj.pollWitnessgen, + sgDataArg: cmdObj.sgData, }); } catch (error) { program.error((error as Error).message, { exitCode: 1 }); diff --git a/packages/cli/ts/utils/interfaces.ts b/packages/cli/ts/utils/interfaces.ts index f1054c0b83..68467b9f7a 100644 --- a/packages/cli/ts/utils/interfaces.ts +++ b/packages/cli/ts/utils/interfaces.ts @@ -23,6 +23,7 @@ export interface PollContracts { poll: string; messageProcessor: string; tally: string; + signupGatekeeper: string; } /** @@ -318,6 +319,11 @@ export interface DeployPollArgs { * Whether to use quadratic voting or not */ useQuadraticVoting?: boolean; + + /** + * The address of the gatekeeper contract + */ + gatekeeperAddress?: string; } /** @@ -447,6 +453,11 @@ export interface IJoinPollArgs { * Poll private key for the poll */ pollPrivKey: string; + + /** + * The signup gatekeeper data + */ + sgDataArg?: string; } /** diff --git a/packages/contracts/contracts/MACI.sol b/packages/contracts/contracts/MACI.sol index 8a12ee01f3..3575d6a7cf 100644 --- a/packages/contracts/contracts/MACI.sol +++ b/packages/contracts/contracts/MACI.sol @@ -6,6 +6,7 @@ import { IMessageProcessorFactory } from "./interfaces/IMPFactory.sol"; import { ITallyFactory } from "./interfaces/ITallyFactory.sol"; import { IVerifier } from "./interfaces/IVerifier.sol"; import { IVkRegistry } from "./interfaces/IVkRegistry.sol"; +import { ISignUpGatekeeper } from "./interfaces/ISignUpGatekeeper.sol"; import { InitialVoiceCreditProxy } from "./initialVoiceCreditProxy/InitialVoiceCreditProxy.sol"; import { SignUpGatekeeper } from "./gatekeepers/SignUpGatekeeper.sol"; import { IMACI } from "./interfaces/IMACI.sol"; @@ -187,7 +188,8 @@ contract MACI is IMACI, DomainObjs, Params, Utilities { PubKey memory _coordinatorPubKey, address _verifier, address _vkRegistry, - Mode _mode + Mode _mode, + address _gatekeeper ) public virtual { // cache the poll to a local variable so we can increment it uint256 pollId = nextPollId; @@ -208,7 +210,8 @@ contract MACI is IMACI, DomainObjs, Params, Utilities { ExtContracts memory extContracts = ExtContracts({ maci: IMACI(address(this)), verifier: IVerifier(_verifier), - vkRegistry: IVkRegistry(_vkRegistry) + vkRegistry: IVkRegistry(_vkRegistry), + gatekeeper: ISignUpGatekeeper(_gatekeeper) }); address p = pollFactory.deploy( diff --git a/packages/contracts/contracts/Poll.sol b/packages/contracts/contracts/Poll.sol index a183f39e00..d620c03906 100644 --- a/packages/contracts/contracts/Poll.sol +++ b/packages/contracts/contracts/Poll.sol @@ -6,6 +6,7 @@ import { SnarkCommon } from "./crypto/SnarkCommon.sol"; import { LazyIMTData, InternalLazyIMT } from "./trees/LazyIMT.sol"; import { IMACI } from "./interfaces/IMACI.sol"; import { IPoll } from "./interfaces/IPoll.sol"; +import { ISignUpGatekeeper } from "./interfaces/ISignUpGatekeeper.sol"; import { Utilities } from "./utilities/Utilities.sol"; import { CurveBabyJubJub } from "./crypto/BabyJubJub.sol"; @@ -284,28 +285,31 @@ contract Poll is Params, Utilities, SnarkCommon, IPoll { PubKey calldata _pubKey, uint256 _newVoiceCreditBalance, uint256 _stateRootIndex, - uint256[8] calldata _proof + uint256[8] calldata _proof, + bytes memory _signUpGatekeeperData ) public virtual isWithinVotingDeadline { // Whether the user has already joined if (pollNullifier[_nullifier]) { revert UserAlreadyJoined(); } + // Set nullifier for user's private key + pollNullifier[_nullifier] = true; + // Verify user's proof if (!verifyPollProof(_nullifier, _newVoiceCreditBalance, _stateRootIndex, _pubKey, _proof)) { revert InvalidPollProof(); } + // Check if the user is eligible to join the poll + extContracts.gatekeeper.register(msg.sender, _signUpGatekeeperData); + // Store user in the pollStateTree - uint256 timestamp = block.timestamp; - uint256 stateLeaf = hashStateLeaf(StateLeaf(_pubKey, _newVoiceCreditBalance, timestamp)); + uint256 stateLeaf = hashStateLeaf(StateLeaf(_pubKey, _newVoiceCreditBalance, block.timestamp)); InternalLazyIMT._insert(pollStateTree, stateLeaf); - // Set nullifier for user's private key - pollNullifier[_nullifier] = true; - uint256 pollStateIndex = pollStateTree.numberOfLeaves - 1; - emit PollJoined(_pubKey.x, _pubKey.y, _newVoiceCreditBalance, timestamp, _nullifier, pollStateIndex); + emit PollJoined(_pubKey.x, _pubKey.y, _newVoiceCreditBalance, block.timestamp, _nullifier, pollStateIndex); } /// @notice Verify the proof for Poll diff --git a/packages/contracts/contracts/interfaces/IPoll.sol b/packages/contracts/contracts/interfaces/IPoll.sol index 50318db07f..b17491e6ad 100644 --- a/packages/contracts/contracts/interfaces/IPoll.sol +++ b/packages/contracts/contracts/interfaces/IPoll.sol @@ -13,7 +13,8 @@ interface IPoll { DomainObjs.PubKey calldata _pubKey, uint256 _newVoiceCreditBalance, uint256 _stateRootIndex, - uint256[8] calldata _proof + uint256[8] calldata _proof, + bytes memory _signUpGatekeeperData ) external; /// @notice The number of messages which have been processed and the number of signups diff --git a/packages/contracts/contracts/interfaces/ISignUpGatekeeper.sol b/packages/contracts/contracts/interfaces/ISignUpGatekeeper.sol new file mode 100644 index 0000000000..ded9df5cfd --- /dev/null +++ b/packages/contracts/contracts/interfaces/ISignUpGatekeeper.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +/// @title ISignUpGatekeeper +/// @notice SignUpGatekeeper interface +interface ISignUpGatekeeper { + /// @notice Register a user + /// @param _user User address + /// @param _data Data to register + function register(address _user, bytes memory _data) external; +} diff --git a/packages/contracts/contracts/utilities/Params.sol b/packages/contracts/contracts/utilities/Params.sol index bde214b17e..91d9fae8e0 100644 --- a/packages/contracts/contracts/utilities/Params.sol +++ b/packages/contracts/contracts/utilities/Params.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.20; import { IMACI } from "../interfaces/IMACI.sol"; import { IVerifier } from "../interfaces/IVerifier.sol"; import { IVkRegistry } from "../interfaces/IVkRegistry.sol"; +import { ISignUpGatekeeper } from "../interfaces/ISignUpGatekeeper.sol"; /// @title Params /// @notice This contracts contains a number of structures @@ -24,5 +25,6 @@ contract Params { IMACI maci; IVerifier verifier; IVkRegistry vkRegistry; + ISignUpGatekeeper gatekeeper; } } diff --git a/packages/contracts/deploy-config-example.json b/packages/contracts/deploy-config-example.json index eb3daf87e4..04ab0e3417 100644 --- a/packages/contracts/deploy-config-example.json +++ b/packages/contracts/deploy-config-example.json @@ -65,7 +65,8 @@ "Poll": { "pollDuration": 3600, "coordinatorPubkey": "macipk.9a59264310d95cfd8eb7083aebeba221b5c26e77427f12b7c0f50bc1cc35e621", - "useQuadraticVoting": false + "useQuadraticVoting": false, + "gatekeeper": "FreeForAllGatekeeper" } }, "scroll_sepolia": { @@ -133,7 +134,8 @@ "Poll": { "pollDuration": 10800, "coordinatorPubkey": "macipk.0a1ce79a43fa676ee3d2882c79d9164a24d4a22bb6190e3d8fa25d97bffc069a", - "useQuadraticVoting": false + "useQuadraticVoting": false, + "gatekeeper": "FreeForAllGatekeeper" } }, "optimism": { @@ -202,7 +204,8 @@ "Poll": { "pollDuration": 3600, "coordinatorPubkey": "macipk.9a59264310d95cfd8eb7083aebeba221b5c26e77427f12b7c0f50bc1cc35e621", - "useQuadraticVoting": false + "useQuadraticVoting": false, + "gatekeeper": "FreeForAllGatekeeper" } }, "arbitrum_sepolia": { @@ -271,7 +274,8 @@ "Poll": { "pollDuration": 3600, "coordinatorPubkey": "macipk.9a59264310d95cfd8eb7083aebeba221b5c26e77427f12b7c0f50bc1cc35e621", - "useQuadraticVoting": false + "useQuadraticVoting": false, + "gatekeeper": "FreeForAllGatekeeper" } }, "localhost": { @@ -340,7 +344,8 @@ "Poll": { "pollDuration": 30, "coordinatorPubkey": "macipk.29add77d27341c4cdfc2fb623175ecfd6527a286e3e7ded785d9fd7afbbdf399", - "useQuadraticVoting": false + "useQuadraticVoting": false, + "gatekeeper": "FreeForAllGatekeeper" } }, "base_sepolia": { @@ -409,7 +414,8 @@ "Poll": { "pollDuration": 3600, "coordinatorPubkey": "macipk.9a59264310d95cfd8eb7083aebeba221b5c26e77427f12b7c0f50bc1cc35e621", - "useQuadraticVoting": false + "useQuadraticVoting": false, + "gatekeeper": "FreeForAllGatekeeper" } }, "optimism_sepolia": { @@ -483,7 +489,8 @@ "Poll": { "pollDuration": 3600, "coordinatorPubkey": "macipk.9a59264310d95cfd8eb7083aebeba221b5c26e77427f12b7c0f50bc1cc35e621", - "useQuadraticVoting": false + "useQuadraticVoting": false, + "gatekeeper": "FreeForAllGatekeeper" } }, "gnosis_chiado": { @@ -557,7 +564,8 @@ "Poll": { "pollDuration": 3600, "coordinatorPubkey": "macipk.0a1ce79a43fa676ee3d2882c79d9164a24d4a22bb6190e3d8fa25d97bffc069a", - "useQuadraticVoting": false + "useQuadraticVoting": false, + "gatekeeper": "FreeForAllGatekeeper" } }, "gnosis": { @@ -631,7 +639,8 @@ "Poll": { "pollDuration": 3600, "coordinatorPubkey": "macipk.0a1ce79a43fa676ee3d2882c79d9164a24d4a22bb6190e3d8fa25d97bffc069a", - "useQuadraticVoting": false + "useQuadraticVoting": false, + "gatekeeper": "FreeForAllGatekeeper" } }, "polygon_amoy": { @@ -705,7 +714,8 @@ "Poll": { "pollDuration": 3600, "coordinatorPubkey": "macipk.0a1ce79a43fa676ee3d2882c79d9164a24d4a22bb6190e3d8fa25d97bffc069a", - "useQuadraticVoting": true + "useQuadraticVoting": true, + "gatekeeper": "FreeForAllGatekeeper" } }, "polygon": { @@ -779,7 +789,8 @@ "Poll": { "pollDuration": 3600, "coordinatorPubkey": "macipk.0a1ce79a43fa676ee3d2882c79d9164a24d4a22bb6190e3d8fa25d97bffc069a", - "useQuadraticVoting": true + "useQuadraticVoting": true, + "gatekeeper": "FreeForAllGatekeeper" } } } diff --git a/packages/contracts/tasks/deploy/poll/01-gatekeepers.ts b/packages/contracts/tasks/deploy/poll/01-gatekeepers.ts new file mode 100644 index 0000000000..856ebef3dc --- /dev/null +++ b/packages/contracts/tasks/deploy/poll/01-gatekeepers.ts @@ -0,0 +1,298 @@ +import { hexToBigInt, uuidToBigInt } from "@pcd/util"; + +import { HatsGatekeeperBase, MACI } from "../../../typechain-types"; +import { EDeploySteps, ESupportedChains } from "../../helpers/constants"; +import { ContractStorage } from "../../helpers/ContractStorage"; +import { Deployment } from "../../helpers/Deployment"; +import { EContracts, IDeployParams } from "../../helpers/types"; + +const deployment = Deployment.getInstance(); +const storage = ContractStorage.getInstance(); + +/** + * Deploy step registration and task itself + */ +deployment.deployTask(EDeploySteps.PollGatekeeper, "Deploy Poll gatekeepers").then((task) => + task.setAction(async ({ incremental }: IDeployParams, hre) => { + deployment.setHre(hre); + const deployer = await deployment.getDeployer(); + + const maciContract = await deployment.getContract({ name: EContracts.MACI }); + const pollId = await maciContract.nextPollId(); + + const freeForAllGatekeeperContractAddress = storage.getAddress( + EContracts.FreeForAllGatekeeper, + hre.network.name, + `poll-${pollId}`, + ); + const easGatekeeperContractAddress = storage.getAddress( + EContracts.EASGatekeeper, + hre.network.name, + `poll-${pollId}`, + ); + const hatsGatekeeperContractAddress = storage.getAddress( + EContracts.HatsGatekeeper, + hre.network.name, + `poll-${pollId}`, + ); + const gitcoinGatekeeperContractAddress = storage.getAddress( + EContracts.GitcoinPassportGatekeeper, + hre.network.name, + `poll-${pollId}`, + ); + const zupassGatekeeperContractAddress = storage.getAddress( + EContracts.ZupassGatekeeper, + hre.network.name, + `poll-${pollId}`, + ); + const semaphoreGatekeeperContractAddress = storage.getAddress( + EContracts.SemaphoreGatekeeper, + hre.network.name, + `poll-${pollId}`, + ); + const merkleProofGatekeeperContractAddress = storage.getAddress( + EContracts.MerkleProofGatekeeper, + hre.network.name, + `poll-${pollId}`, + ); + + const gatekeeperToDeploy = + deployment.getDeployConfigField(EContracts.Poll, "gatekeeper") || + EContracts.FreeForAllGatekeeper; + + const skipDeployFreeForAllGatekeeper = gatekeeperToDeploy !== EContracts.FreeForAllGatekeeper; + const skipDeployEASGatekeeper = gatekeeperToDeploy !== EContracts.EASGatekeeper; + const skipDeployGitcoinGatekeeper = gatekeeperToDeploy !== EContracts.GitcoinPassportGatekeeper; + const skipDeployZupassGatekeeper = gatekeeperToDeploy !== EContracts.ZupassGatekeeper; + const skipDeploySemaphoreGatekeeper = gatekeeperToDeploy !== EContracts.SemaphoreGatekeeper; + const skipDeployHatsGatekeeper = gatekeeperToDeploy !== EContracts.HatsGatekeeper; + const skipDeployMerkleProofGatekeeper = gatekeeperToDeploy !== EContracts.MerkleProofGatekeeper; + + const hasGatekeeperAddress = [ + freeForAllGatekeeperContractAddress, + easGatekeeperContractAddress, + gitcoinGatekeeperContractAddress, + zupassGatekeeperContractAddress, + semaphoreGatekeeperContractAddress, + hatsGatekeeperContractAddress, + merkleProofGatekeeperContractAddress, + ].some(Boolean); + + const isSkipable = [ + skipDeployFreeForAllGatekeeper, + skipDeployEASGatekeeper, + skipDeployGitcoinGatekeeper, + skipDeployZupassGatekeeper, + skipDeploySemaphoreGatekeeper, + skipDeployHatsGatekeeper, + skipDeployMerkleProofGatekeeper, + ].some((skip) => !skip); + + const canSkipDeploy = incremental && hasGatekeeperAddress && isSkipable; + + if (canSkipDeploy) { + // eslint-disable-next-line no-console + console.log(`Skipping deployment of the Gatekeeper contract`); + return; + } + + if (!skipDeployFreeForAllGatekeeper) { + const freeForAllGatekeeperContract = await deployment.deployContract({ + name: EContracts.FreeForAllGatekeeper, + signer: deployer, + }); + + await storage.register({ + id: EContracts.FreeForAllGatekeeper, + key: `poll-${pollId}`, + contract: freeForAllGatekeeperContract, + args: [], + network: hre.network.name, + }); + } + + const isSupportedEASGatekeeperNetwork = ![ESupportedChains.Hardhat, ESupportedChains.Coverage].includes( + hre.network.name as ESupportedChains, + ); + + if (!skipDeployEASGatekeeper && isSupportedEASGatekeeperNetwork) { + const easAddress = deployment.getDeployConfigField(EContracts.EASGatekeeper, "easAddress", true); + const encodedSchema = deployment.getDeployConfigField(EContracts.EASGatekeeper, "schema", true); + const attester = deployment.getDeployConfigField(EContracts.EASGatekeeper, "attester", true); + + const easGatekeeperContract = await deployment.deployContract( + { + name: EContracts.EASGatekeeper, + signer: deployer, + }, + easAddress, + attester, + encodedSchema, + ); + + await storage.register({ + id: EContracts.EASGatekeeper, + key: `poll-${pollId}`, + contract: easGatekeeperContract, + args: [easAddress, attester, encodedSchema], + network: hre.network.name, + }); + } + + const isSupportedGitcoinGatekeeperNetwork = ![ + ESupportedChains.Hardhat, + ESupportedChains.Coverage, + ESupportedChains.Sepolia, + ].includes(hre.network.name as ESupportedChains); + + if (!skipDeployGitcoinGatekeeper && isSupportedGitcoinGatekeeperNetwork) { + const gitcoinGatekeeperDecoderAddress = deployment.getDeployConfigField( + EContracts.GitcoinPassportGatekeeper, + "decoderAddress", + true, + ); + const gitcoinGatekeeperPassingScore = deployment.getDeployConfigField( + EContracts.GitcoinPassportGatekeeper, + "passingScore", + true, + ); + const gitcoinGatekeeperContract = await deployment.deployContract( + { + name: EContracts.GitcoinPassportGatekeeper, + signer: deployer, + }, + gitcoinGatekeeperDecoderAddress, + gitcoinGatekeeperPassingScore, + ); + + await storage.register({ + id: EContracts.GitcoinPassportGatekeeper, + key: `poll-${pollId}`, + contract: gitcoinGatekeeperContract, + args: [gitcoinGatekeeperDecoderAddress, gitcoinGatekeeperPassingScore], + network: hre.network.name, + }); + } + + if (!skipDeployZupassGatekeeper) { + const eventId = deployment.getDeployConfigField(EContracts.ZupassGatekeeper, "eventId", true); + const validEventId = uuidToBigInt(eventId); + const signer1 = deployment.getDeployConfigField(EContracts.ZupassGatekeeper, "signer1", true); + const validSigner1 = hexToBigInt(signer1); + const signer2 = deployment.getDeployConfigField(EContracts.ZupassGatekeeper, "signer2", true); + const validSigner2 = hexToBigInt(signer2); + let verifier = deployment.getDeployConfigField(EContracts.ZupassGatekeeper, "zupassVerifier"); + + if (!verifier) { + const verifierContract = await deployment.deployContract({ + name: EContracts.ZupassGroth16Verifier, + signer: deployer, + }); + verifier = await verifierContract.getAddress(); + } + + const ZupassGatekeeperContract = await deployment.deployContract( + { + name: EContracts.ZupassGatekeeper, + signer: deployer, + }, + validEventId, + validSigner1, + validSigner2, + verifier, + ); + await storage.register({ + id: EContracts.ZupassGatekeeper, + key: `poll-${pollId}`, + contract: ZupassGatekeeperContract, + args: [validEventId.toString(), validSigner1.toString(), validSigner2.toString(), verifier], + network: hre.network.name, + }); + } + + if (!skipDeploySemaphoreGatekeeper) { + const semaphoreContractAddress = deployment.getDeployConfigField( + EContracts.SemaphoreGatekeeper, + "semaphoreContract", + true, + ); + const groupId = deployment.getDeployConfigField(EContracts.SemaphoreGatekeeper, "groupId", true); + + const semaphoreGatekeeperContract = await deployment.deployContract( + { + name: EContracts.SemaphoreGatekeeper, + signer: deployer, + }, + semaphoreContractAddress, + groupId, + ); + + await storage.register({ + id: EContracts.SemaphoreGatekeeper, + key: `poll-${pollId}`, + contract: semaphoreGatekeeperContract, + args: [semaphoreContractAddress, groupId.toString()], + network: hre.network.name, + }); + } + + if (!skipDeployHatsGatekeeper) { + // get args + const criterionHats = deployment.getDeployConfigField(EContracts.HatsGatekeeper, "criterionHats", true); + const hatsProtocolAddress = deployment.getDeployConfigField( + EContracts.HatsGatekeeper, + "hatsProtocolAddress", + true, + ); + + let hatsGatekeeperContract: HatsGatekeeperBase; + // if we have one we use the single gatekeeper + if (criterionHats.length === 1) { + hatsGatekeeperContract = await deployment.deployContract( + { + name: EContracts.HatsGatekeeperSingle, + signer: deployer, + }, + hatsProtocolAddress, + criterionHats[0], + ); + } else { + hatsGatekeeperContract = await deployment.deployContract( + { + name: EContracts.HatsGatekeeperMultiple, + signer: deployer, + }, + hatsProtocolAddress, + criterionHats, + ); + } + + await storage.register({ + id: EContracts.HatsGatekeeper, + key: `poll-${pollId}`, + contract: hatsGatekeeperContract, + args: [hatsProtocolAddress, criterionHats.length === 1 ? criterionHats[0] : criterionHats], + network: hre.network.name, + }); + } + + if (!skipDeployMerkleProofGatekeeper) { + const root = deployment.getDeployConfigField(EContracts.MerkleProofGatekeeper, "root", true); + + const MerkleProofGatekeeperContract = await deployment.deployContract( + { + name: EContracts.MerkleProofGatekeeper, + signer: deployer, + }, + root, + ); + await storage.register({ + id: EContracts.MerkleProofGatekeeper, + key: `poll-${pollId}`, + contract: MerkleProofGatekeeperContract, + args: [root], + network: hre.network.name, + }); + } + }), +); diff --git a/packages/contracts/tasks/deploy/poll/01-poll.ts b/packages/contracts/tasks/deploy/poll/02-poll.ts similarity index 93% rename from packages/contracts/tasks/deploy/poll/01-poll.ts rename to packages/contracts/tasks/deploy/poll/02-poll.ts index 4a6459019a..98b48ee5b8 100644 --- a/packages/contracts/tasks/deploy/poll/01-poll.ts +++ b/packages/contracts/tasks/deploy/poll/02-poll.ts @@ -49,6 +49,11 @@ deployment.deployTask(EDeploySteps.Poll, "Deploy poll").then((task) => const unserializedKey = PubKey.deserialize(coordinatorPubkey); const mode = useQuadraticVoting ? EMode.QV : EMode.NON_QV; + const gatekeeper = + deployment.getDeployConfigField(EContracts.Poll, "gatekeeper") || + EContracts.FreeForAllGatekeeper; + const gatekeeperContractAddress = storage.mustGetAddress(gatekeeper, hre.network.name, `poll-${pollId}`); + const tx = await maciContract.deployPoll( pollDuration, { @@ -60,6 +65,7 @@ deployment.deployTask(EDeploySteps.Poll, "Deploy poll").then((task) => verifierContractAddress, vkRegistryContractAddress, mode, + gatekeeperContractAddress, ); const receipt = await tx.wait(); diff --git a/packages/contracts/tasks/helpers/constants.ts b/packages/contracts/tasks/helpers/constants.ts index 76e580ec17..f8bcfec6c2 100644 --- a/packages/contracts/tasks/helpers/constants.ts +++ b/packages/contracts/tasks/helpers/constants.ts @@ -11,6 +11,7 @@ export enum EDeploySteps { TallyFactory = "full:deploy-tally-factory", Maci = "full:deploy-maci", VkRegistry = "full:deploy-vk-registry", + PollGatekeeper = "poll:deploy-gatekeeper", Poll = "poll:deploy-poll", } diff --git a/packages/contracts/tests/MACI.test.ts b/packages/contracts/tests/MACI.test.ts index 19bd9d7b14..8c8d6a03ae 100644 --- a/packages/contracts/tests/MACI.test.ts +++ b/packages/contracts/tests/MACI.test.ts @@ -8,7 +8,14 @@ import { Keypair, PubKey, Message } from "maci-domainobjs"; import { EMode } from "../ts/constants"; import { getDefaultSigner, getSigners } from "../ts/utils"; -import { MACI, Poll as PollContract, Poll__factory as PollFactory, Verifier, VkRegistry } from "../typechain-types"; +import { + MACI, + Poll as PollContract, + Poll__factory as PollFactory, + Verifier, + VkRegistry, + SignUpGatekeeper, +} from "../typechain-types"; import { STATE_TREE_DEPTH, duration, initialVoiceCreditBalance, messageBatchSize, treeDepths } from "./constants"; import { timeTravel, deployTestContracts } from "./utils"; @@ -19,6 +26,7 @@ describe("MACI", function test() { let maciContract: MACI; let vkRegistryContract: VkRegistry; let verifierContract: Verifier; + let signupGatekeeperContract: SignUpGatekeeper; let pollId: bigint; const coordinator = new Keypair(); @@ -40,6 +48,7 @@ describe("MACI", function test() { maciContract = r.maciContract; vkRegistryContract = r.vkRegistryContract; verifierContract = r.mockVerifierContract as Verifier; + signupGatekeeperContract = r.gatekeeperContract; }); it("should have set the correct stateTreeDepth", async () => { @@ -218,6 +227,7 @@ describe("MACI", function test() { verifierContract, vkRegistryContract, EMode.QV, + signupGatekeeperContract, ); const receipt = await tx.wait(); @@ -252,6 +262,7 @@ describe("MACI", function test() { verifierContract, vkRegistryContract, EMode.QV, + signupGatekeeperContract, ); const receipt = await tx.wait(); expect(receipt?.status).to.eq(1); @@ -270,6 +281,7 @@ describe("MACI", function test() { verifierContract, vkRegistryContract, EMode.QV, + signupGatekeeperContract, ); const receipt = await tx.wait(); expect(receipt?.status).to.eq(1); diff --git a/packages/contracts/tests/MessageProcessor.test.ts b/packages/contracts/tests/MessageProcessor.test.ts index 598558d1af..6702b30619 100644 --- a/packages/contracts/tests/MessageProcessor.test.ts +++ b/packages/contracts/tests/MessageProcessor.test.ts @@ -15,6 +15,7 @@ import { MessageProcessor__factory as MessageProcessorFactory, Verifier, VkRegistry, + SignUpGatekeeper, } from "../typechain-types"; import { @@ -34,7 +35,7 @@ describe("MessageProcessor", () => { let verifierContract: Verifier; let vkRegistryContract: VkRegistry; let mpContract: MessageProcessor; - + let signupGatekeeperContract: SignUpGatekeeper; let pollId: bigint; // local poll and maci state @@ -57,7 +58,7 @@ describe("MessageProcessor", () => { signer = await getDefaultSigner(); verifierContract = r.mockVerifierContract as Verifier; vkRegistryContract = r.vkRegistryContract; - + signupGatekeeperContract = r.gatekeeperContract; // deploy on chain poll const tx = await maciContract.deployPoll( duration, @@ -67,6 +68,7 @@ describe("MessageProcessor", () => { verifierContract, vkRegistryContract, EMode.QV, + signupGatekeeperContract, ); let receipt = await tx.wait(); diff --git a/packages/contracts/tests/Poll.test.ts b/packages/contracts/tests/Poll.test.ts index 1bd6b5b4b0..935a731807 100644 --- a/packages/contracts/tests/Poll.test.ts +++ b/packages/contracts/tests/Poll.test.ts @@ -10,7 +10,14 @@ import { Keypair, Message, PCommand, PubKey } from "maci-domainobjs"; import { EMode } from "../ts/constants"; import { IVerifyingKeyStruct } from "../ts/types"; import { getDefaultSigner } from "../ts/utils"; -import { Poll__factory as PollFactory, MACI, Poll as PollContract, Verifier, VkRegistry } from "../typechain-types"; +import { + Poll__factory as PollFactory, + MACI, + Poll as PollContract, + Verifier, + VkRegistry, + SignUpGatekeeper, +} from "../typechain-types"; import { STATE_TREE_DEPTH, @@ -30,6 +37,7 @@ describe("Poll", () => { let pollContract: PollContract; let verifierContract: Verifier; let vkRegistryContract: VkRegistry; + let signupGatekeeperContract: SignUpGatekeeper; let signer: Signer; let deployTime: number; const coordinator = new Keypair(); @@ -51,6 +59,7 @@ describe("Poll", () => { maciContract = r.maciContract; verifierContract = r.mockVerifierContract as Verifier; vkRegistryContract = r.vkRegistryContract; + signupGatekeeperContract = r.gatekeeperContract; for (let i = 0; i < NUM_USERS; i += 1) { const timestamp = Math.floor(Date.now() / 1000); @@ -74,6 +83,7 @@ describe("Poll", () => { verifierContract, vkRegistryContract, EMode.QV, + signupGatekeeperContract, ); const receipt = await tx.wait(); @@ -177,6 +187,7 @@ describe("Poll", () => { r.mockVerifierContract as Verifier, r.vkRegistryContract, EMode.QV, + signupGatekeeperContract, ), ).to.be.revertedWithCustomError(testMaciContract, "InvalidPubKey"); }); @@ -192,7 +203,14 @@ describe("Poll", () => { const mockNullifier = AbiCoder.defaultAbiCoder().encode(["uint256"], [i]); const voiceCreditBalance = AbiCoder.defaultAbiCoder().encode(["uint256"], [i]); - const response = await pollContract.joinPoll(mockNullifier, pubkey, voiceCreditBalance, i, mockProof); + const response = await pollContract.joinPoll( + mockNullifier, + pubkey, + voiceCreditBalance, + i, + mockProof, + AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), + ); const receipt = await response.wait(); const logs = receipt!.logs[0]; const event = iface.parseLog(logs as unknown as { topics: string[]; data: string }) as unknown as { @@ -226,7 +244,14 @@ describe("Poll", () => { const mockProof = [0, 0, 0, 0, 0, 0, 0, 0]; await expect( - pollContract.joinPoll(mockNullifier, pubkey, voiceCreditBalance, 0, mockProof), + pollContract.joinPoll( + mockNullifier, + pubkey, + voiceCreditBalance, + 0, + mockProof, + AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), + ), ).to.be.revertedWithCustomError(pollContract, "UserAlreadyJoined"); }); }); diff --git a/packages/contracts/tests/PollFactory.test.ts b/packages/contracts/tests/PollFactory.test.ts index 89d4565101..55c3586818 100644 --- a/packages/contracts/tests/PollFactory.test.ts +++ b/packages/contracts/tests/PollFactory.test.ts @@ -33,7 +33,12 @@ describe("pollFactory", () => { maciContract = r.maciContract; verifierContract = r.mockVerifierContract as Verifier; vkRegistryContract = r.vkRegistryContract; - extContracts = { maci: maciContract, verifier: verifierContract, vkRegistry: vkRegistryContract }; + extContracts = { + maci: maciContract, + verifier: verifierContract, + vkRegistry: vkRegistryContract, + gatekeeper: r.gatekeeperContract, + }; pollFactory = (await deployPollFactory(signer, undefined, true)) as BaseContract as PollFactory; }); diff --git a/packages/contracts/tests/Tally.test.ts b/packages/contracts/tests/Tally.test.ts index ed76475005..d8a25fd2de 100644 --- a/packages/contracts/tests/Tally.test.ts +++ b/packages/contracts/tests/Tally.test.ts @@ -19,6 +19,7 @@ import { MessageProcessor__factory as MessageProcessorFactory, Poll__factory as PollFactory, Tally__factory as TallyFactory, + SignUpGatekeeper, } from "../typechain-types"; import { @@ -41,6 +42,7 @@ describe("TallyVotes", () => { let mpContract: MessageProcessor; let verifierContract: Verifier; let vkRegistryContract: VkRegistry; + let signupGatekeeperContract: SignUpGatekeeper; const coordinator = new Keypair(); let users: Keypair[]; @@ -63,6 +65,7 @@ describe("TallyVotes", () => { maciContract = r.maciContract; verifierContract = r.mockVerifierContract as Verifier; vkRegistryContract = r.vkRegistryContract; + signupGatekeeperContract = r.gatekeeperContract; // deploy a poll // deploy on chain poll @@ -74,6 +77,7 @@ describe("TallyVotes", () => { verifierContract, vkRegistryContract, EMode.QV, + signupGatekeeperContract, ); const receipt = await tx.wait(); @@ -231,6 +235,7 @@ describe("TallyVotes", () => { verifierContract, vkRegistryContract, EMode.QV, + signupGatekeeperContract, ); const receipt = await tx.wait(); @@ -308,6 +313,7 @@ describe("TallyVotes", () => { BigInt(initialVoiceCreditBalance), i, [0, 0, 0, 0, 0, 0, 0, 0], + AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), ); } @@ -538,6 +544,7 @@ describe("TallyVotes", () => { verifierContract, vkRegistryContract, EMode.QV, + signupGatekeeperContract, ); const receipt = await tx.wait(); @@ -616,6 +623,7 @@ describe("TallyVotes", () => { BigInt(initialVoiceCreditBalance), i, [0, 0, 0, 0, 0, 0, 0, 0], + AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), ); } diff --git a/packages/contracts/tests/TallyNonQv.test.ts b/packages/contracts/tests/TallyNonQv.test.ts index 7d4e218e40..9187925de8 100644 --- a/packages/contracts/tests/TallyNonQv.test.ts +++ b/packages/contracts/tests/TallyNonQv.test.ts @@ -19,6 +19,7 @@ import { MessageProcessor__factory as MessageProcessorFactory, Poll__factory as PollFactory, Tally__factory as TallyFactory, + SignUpGatekeeper, } from "../typechain-types"; import { STATE_TREE_DEPTH, duration, messageBatchSize, testProcessVk, testTallyVk, treeDepths } from "./constants"; @@ -32,6 +33,7 @@ describe("TallyVotesNonQv", () => { let mpContract: MessageProcessor; let verifierContract: Verifier; let vkRegistryContract: VkRegistry; + let gatekeeperContract: SignUpGatekeeper; const coordinator = new Keypair(); let maciState: MaciState; @@ -50,6 +52,7 @@ describe("TallyVotesNonQv", () => { maciContract = r.maciContract; verifierContract = r.mockVerifierContract as Verifier; vkRegistryContract = r.vkRegistryContract; + gatekeeperContract = r.gatekeeperContract; // deploy a poll // deploy on chain poll @@ -61,6 +64,7 @@ describe("TallyVotesNonQv", () => { verifierContract, vkRegistryContract, EMode.NON_QV, + gatekeeperContract, ); const receipt = await tx.wait(); diff --git a/packages/contracts/tests/constants.ts b/packages/contracts/tests/constants.ts index 855b0e102e..ac2b747dcf 100644 --- a/packages/contracts/tests/constants.ts +++ b/packages/contracts/tests/constants.ts @@ -7,6 +7,7 @@ export interface ExtContractsStruct { maci: AddressLike; verifier: AddressLike; vkRegistry: AddressLike; + gatekeeper: AddressLike; } export const duration = 2_000; diff --git a/packages/integrationTests/ts/__tests__/maci-keys.test.ts b/packages/integrationTests/ts/__tests__/maci-keys.test.ts index 52a86fcfb4..081553e52f 100644 --- a/packages/integrationTests/ts/__tests__/maci-keys.test.ts +++ b/packages/integrationTests/ts/__tests__/maci-keys.test.ts @@ -72,7 +72,7 @@ describe("integration tests private/public/keypair", () => { before(async () => { signer = await getDefaultSigner(); - const { maci, verifier, vkRegistry } = await deployTestContracts( + const { maci, verifier, vkRegistry, gatekeeper } = await deployTestContracts( initialVoiceCredits, STATE_TREE_DEPTH, signer, @@ -91,6 +91,7 @@ describe("integration tests private/public/keypair", () => { verifier, vkRegistry, EMode.NON_QV, + gatekeeper, ); // we know it's the first poll so id is 0 diff --git a/packages/integrationTests/ts/__tests__/utils/interfaces.ts b/packages/integrationTests/ts/__tests__/utils/interfaces.ts index 9bfd6297ce..647a0b6ee5 100644 --- a/packages/integrationTests/ts/__tests__/utils/interfaces.ts +++ b/packages/integrationTests/ts/__tests__/utils/interfaces.ts @@ -1,4 +1,4 @@ -import { MACI, Verifier, VkRegistry } from "maci-contracts"; +import { MACI, Verifier, VkRegistry, FreeForAllGatekeeper } from "maci-contracts"; /** * A util interface that represents a vote object @@ -47,4 +47,5 @@ export interface IDeployedTestContracts { maci: MACI; verifier: Verifier; vkRegistry: VkRegistry; + gatekeeper: FreeForAllGatekeeper; } diff --git a/packages/integrationTests/ts/__tests__/utils/utils.ts b/packages/integrationTests/ts/__tests__/utils/utils.ts index 2859b7ecf1..5b59cb923b 100644 --- a/packages/integrationTests/ts/__tests__/utils/utils.ts +++ b/packages/integrationTests/ts/__tests__/utils/utils.ts @@ -198,5 +198,10 @@ export const deployTestContracts = async ( quiet, }); - return { maci: maciContract, verifier: mockVerifierContract as Verifier, vkRegistry: vkRegistryContract }; + return { + maci: maciContract, + verifier: mockVerifierContract as Verifier, + vkRegistry: vkRegistryContract, + gatekeeper: gatekeeperContract, + }; }; From b7199e7f44681daf823e422492e94f8acbdead9e Mon Sep 17 00:00:00 2001 From: ctrlc03 <93448202+ctrlc03@users.noreply.github.com> Date: Fri, 20 Dec 2024 22:12:48 +0000 Subject: [PATCH 04/17] docs: update contribution guidelines (#1975) --- .../version-v2.x/contributing/contributing.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/apps/website/versioned_docs/version-v2.x/contributing/contributing.md b/apps/website/versioned_docs/version-v2.x/contributing/contributing.md index 2225542f9e..424a57d31d 100644 --- a/apps/website/versioned_docs/version-v2.x/contributing/contributing.md +++ b/apps/website/versioned_docs/version-v2.x/contributing/contributing.md @@ -15,10 +15,26 @@ All members of our community are expected to follow our [Code of Conduct](/docs/ We're really glad you're reading this, because we need volunteer developers to help this project come to fruition. There is a lot we want to achieve, and this can only be made possible thanks to your support. 👏 +**Disclaimer**: We do not accept minor grammatical fixes (e.g., correcting typos, rewording sentences) unless they significantly improve clarity in technical documentation. These contributions, while appreciated, are not a priority for merging. If there is a grammatical error feel free to message the team [here](https://discord.gg/akDcCB69). + +## How You Can Contribute + +1. **Report Bugs**: Identify and describe issues. +2. **Suggest Features**: Share your ideas for improvements. +3. **Code Contributions**: Fix bugs, add features, or refactor existing code. +4. **Improve Documentation**: Help us keep the docs clear and up to date. +5. **Engage with the Community**: Help answer questions or participate in discussions. + ## Issues The best way to contribute to our projects is by opening a [new issue](https://github.com/privacy-scaling-explorations/maci/issues) or tackling one of the issues listed [here](https://github.com/privacy-scaling-explorations/maci/contribute). +Before submitting an issue: + +- Search existing issues to avoid duplicates +- Check documentation/FAQ +- Test with the latest version + :::info If you pick up an issue and are assigned to it by the maintaining team, please be advised that from time to time the team will reach out to check on the progress of the work. If you are working on the issue you are assigned but need more time or help, please let us know and we will be happy to assist you. We understand that contributors have other commitments too, and we appreciate every contribution, no matter the pace. If you fail to respond after 2 weeks, we will gently remind you to provide an update. If there is still no activity after that, we may reassign the issue to ensure project momentum, but we also welcome you to reengage with the project at any time when you are more available. ::: From b4799068b7047378afc73c2fcd701cee45e194a2 Mon Sep 17 00:00:00 2001 From: ctrlc03 <93448202+ctrlc03@users.noreply.github.com> Date: Mon, 23 Dec 2024 10:07:06 +0000 Subject: [PATCH 05/17] feat: make nullifier not leak identity between polls (#1974) --- packages/circuits/circom/anon/pollJoining.circom | 9 ++++----- packages/circuits/circom/circuits.json | 2 +- .../circuits/ts/__tests__/PollJoining.test.ts | 1 + packages/circuits/ts/types.ts | 1 + packages/cli/ts/commands/joinPoll.ts | 16 ++++++++++------ packages/contracts/contracts/MACI.sol | 3 ++- packages/contracts/contracts/Poll.sol | 12 ++++++++++-- packages/contracts/contracts/PollFactory.sol | 6 ++++-- .../contracts/interfaces/IPollFactory.sol | 4 +++- packages/contracts/tests/PollFactory.test.ts | 1 + packages/core/ts/Poll.ts | 4 +++- packages/core/ts/utils/types.ts | 1 + 12 files changed, 41 insertions(+), 19 deletions(-) diff --git a/packages/circuits/circom/anon/pollJoining.circom b/packages/circuits/circom/anon/pollJoining.circom index b66513bac0..323a3d1535 100644 --- a/packages/circuits/circom/anon/pollJoining.circom +++ b/packages/circuits/circom/anon/pollJoining.circom @@ -41,8 +41,11 @@ template PollJoining(stateTreeDepth) { signal input stateRoot; // The actual tree depth (might be <= stateTreeDepth) Used in BinaryMerkleRoot signal input actualStateTreeDepth; + // The poll id + signal input pollId; - var computedNullifier = PoseidonHasher(1)([privKey]); + // Compute the nullifier (hash of private key and poll id) + var computedNullifier = PoseidonHasher(2)([privKey, pollId]); nullifier === computedNullifier; // User private to public key @@ -69,8 +72,4 @@ template PollJoining(stateTreeDepth) { // Check credits var isCreditsValid = SafeLessEqThan(N_BITS)([credits, stateLeaf[STATE_LEAF_VOICE_CREDIT_BALANCE_IDX]]); isCreditsValid === 1; - - // Check nullifier - var hashedPrivKey = PoseidonHasher(1)([privKey]); - hashedPrivKey === nullifier; } diff --git a/packages/circuits/circom/circuits.json b/packages/circuits/circom/circuits.json index bcf56fbade..d9a9328410 100644 --- a/packages/circuits/circom/circuits.json +++ b/packages/circuits/circom/circuits.json @@ -3,7 +3,7 @@ "file": "./anon/pollJoining", "template": "PollJoining", "params": [10], - "pubs": ["nullifier", "credits", "stateRoot", "pollPubKey"] + "pubs": ["nullifier", "credits", "stateRoot", "pollPubKey", "pollId"] }, "ProcessMessages_10-20-2_test": { "file": "./core/qv/processMessages", diff --git a/packages/circuits/ts/__tests__/PollJoining.test.ts b/packages/circuits/ts/__tests__/PollJoining.test.ts index 5bfedadd8e..eb68e305e8 100644 --- a/packages/circuits/ts/__tests__/PollJoining.test.ts +++ b/packages/circuits/ts/__tests__/PollJoining.test.ts @@ -26,6 +26,7 @@ describe("Poll Joining circuit", function test() { "credits", "stateRoot", "actualStateTreeDepth", + "pollId", ]; let circuit: WitnessTester; diff --git a/packages/circuits/ts/types.ts b/packages/circuits/ts/types.ts index 1ac9ba3038..2d9bdba101 100644 --- a/packages/circuits/ts/types.ts +++ b/packages/circuits/ts/types.ts @@ -54,6 +54,7 @@ export interface IPollJoiningInputs { credits: bigint; stateRoot: bigint; actualStateTreeDepth: bigint; + pollId: bigint; } /** diff --git a/packages/cli/ts/commands/joinPoll.ts b/packages/cli/ts/commands/joinPoll.ts index a78b52a6dc..ab9fa3e131 100644 --- a/packages/cli/ts/commands/joinPoll.ts +++ b/packages/cli/ts/commands/joinPoll.ts @@ -101,6 +101,7 @@ const generateAndVerifyProof = async ( * @param credits Credits for voting * @param pollPrivKey Poll's private key for the poll joining * @param pollPubKey Poll's public key for the poll joining + * @param pollId Poll's id * @returns stringified circuit inputs */ const joiningCircuitInputs = ( @@ -111,6 +112,7 @@ const joiningCircuitInputs = ( credits: bigint, pollPrivKey: PrivKey, pollPubKey: PubKey, + pollId: bigint, ): IPollJoiningCircuitInputs => { // Get the state leaf on the index position const { signUpTree: stateTree, stateLeaves } = signUpData; @@ -146,7 +148,7 @@ const joiningCircuitInputs = ( // Create nullifier from private key const inputNullifier = BigInt(maciPrivKey.asCircuitInputs()); - const nullifier = poseidon([inputNullifier]); + const nullifier = poseidon([inputNullifier, pollId]); // Get pll state tree's root const stateRoot = stateTree.root; @@ -167,6 +169,7 @@ const joiningCircuitInputs = ( credits, stateRoot, actualStateTreeDepth, + pollId, }; return stringifyBigInts(circuitInputs) as unknown as IPollJoiningCircuitInputs; @@ -208,19 +211,19 @@ export const joinPoll = async ({ logError("Invalid MACI private key"); } + if (pollId < 0) { + logError("Invalid poll id"); + } + const userMaciPrivKey = PrivKey.deserialize(privateKey); const userMaciPubKey = new Keypair(userMaciPrivKey).pubKey; - const nullifier = poseidon([BigInt(userMaciPrivKey.asCircuitInputs())]); + const nullifier = poseidon([BigInt(userMaciPrivKey.asCircuitInputs()), pollId]); // Create poll public key from poll private key const pollPrivKeyDeserialized = PrivKey.deserialize(pollPrivKey); const pollKeyPair = new Keypair(pollPrivKeyDeserialized); const pollPubKey = pollKeyPair.pubKey; - if (pollId < 0) { - logError("Invalid poll id"); - } - const maciContract = MACIFactory.connect(maciAddress, signer); const pollContracts = await maciContract.getPoll(pollId); @@ -325,6 +328,7 @@ export const joinPoll = async ({ loadedCreditBalance!, pollPrivKeyDeserialized, pollPubKey, + pollId, ) as unknown as CircuitInputs; } diff --git a/packages/contracts/contracts/MACI.sol b/packages/contracts/contracts/MACI.sol index 3575d6a7cf..d25eff7053 100644 --- a/packages/contracts/contracts/MACI.sol +++ b/packages/contracts/contracts/MACI.sol @@ -220,7 +220,8 @@ contract MACI is IMACI, DomainObjs, Params, Utilities { _messageBatchSize, _coordinatorPubKey, extContracts, - emptyBallotRoots[voteOptionTreeDepth - 1] + emptyBallotRoots[voteOptionTreeDepth - 1], + pollId ); address mp = messageProcessorFactory.deploy(_verifier, _vkRegistry, p, msg.sender, _mode); diff --git a/packages/contracts/contracts/Poll.sol b/packages/contracts/contracts/Poll.sol index d620c03906..fe44303073 100644 --- a/packages/contracts/contracts/Poll.sol +++ b/packages/contracts/contracts/Poll.sol @@ -93,6 +93,9 @@ contract Poll is Params, Utilities, SnarkCommon, IPoll { /// @notice Poll voting nullifier mapping(uint256 => bool) private pollNullifier; + /// @notice The Id of this poll + uint256 public immutable pollId; + error VotingPeriodOver(); error VotingPeriodNotOver(); error PollAlreadyInit(); @@ -125,13 +128,15 @@ contract Poll is Params, Utilities, SnarkCommon, IPoll { /// @param _coordinatorPubKey The coordinator's public key /// @param _extContracts The external contracts /// @param _emptyBallotRoot The root of the empty ballot tree + /// @param _pollId The poll id constructor( uint256 _duration, TreeDepths memory _treeDepths, uint8 _messageBatchSize, PubKey memory _coordinatorPubKey, ExtContracts memory _extContracts, - uint256 _emptyBallotRoot + uint256 _emptyBallotRoot, + uint256 _pollId ) payable { // check that the coordinator public key is valid if (!CurveBabyJubJub.isOnCurve(_coordinatorPubKey.x, _coordinatorPubKey.y)) { @@ -156,6 +161,8 @@ contract Poll is Params, Utilities, SnarkCommon, IPoll { deployTime = block.timestamp; // store the empty ballot root emptyBallotRoot = _emptyBallotRoot; + // store the poll id + pollId = _pollId; } /// @notice A modifier that causes the function to revert if the voting period is @@ -350,13 +357,14 @@ contract Poll is Params, Utilities, SnarkCommon, IPoll { uint256 _index, PubKey calldata _pubKey ) public view returns (uint256[] memory publicInputs) { - publicInputs = new uint256[](5); + publicInputs = new uint256[](6); publicInputs[0] = _pubKey.x; publicInputs[1] = _pubKey.y; publicInputs[2] = _nullifier; publicInputs[3] = _voiceCreditBalance; publicInputs[4] = extContracts.maci.getStateRootOnIndexedSignUp(_index); + publicInputs[5] = pollId; } /// @inheritdoc IPoll diff --git a/packages/contracts/contracts/PollFactory.sol b/packages/contracts/contracts/PollFactory.sol index 903a5e211c..e2ce4d27a2 100644 --- a/packages/contracts/contracts/PollFactory.sol +++ b/packages/contracts/contracts/PollFactory.sol @@ -21,7 +21,8 @@ contract PollFactory is Params, DomainObjs, IPollFactory { uint8 _messageBatchSize, DomainObjs.PubKey calldata _coordinatorPubKey, Params.ExtContracts calldata _extContracts, - uint256 _emptyBallotRoot + uint256 _emptyBallotRoot, + uint256 _pollId ) public virtual returns (address pollAddr) { // deploy the poll Poll poll = new Poll( @@ -30,7 +31,8 @@ contract PollFactory is Params, DomainObjs, IPollFactory { _messageBatchSize, _coordinatorPubKey, _extContracts, - _emptyBallotRoot + _emptyBallotRoot, + _pollId ); // init Poll diff --git a/packages/contracts/contracts/interfaces/IPollFactory.sol b/packages/contracts/contracts/interfaces/IPollFactory.sol index 8e2fce385f..c52a8f1642 100644 --- a/packages/contracts/contracts/interfaces/IPollFactory.sol +++ b/packages/contracts/contracts/interfaces/IPollFactory.sol @@ -14,6 +14,7 @@ interface IPollFactory { /// @param _coordinatorPubKey The coordinator's public key /// @param _extContracts The external contracts interface references /// @param _emptyBallotRoot The root of the empty ballot tree + /// @param _pollId The poll id /// @return The deployed Poll contract function deploy( uint256 _duration, @@ -21,6 +22,7 @@ interface IPollFactory { uint8 _messageBatchSize, DomainObjs.PubKey calldata _coordinatorPubKey, Params.ExtContracts calldata _extContracts, - uint256 _emptyBallotRoot + uint256 _emptyBallotRoot, + uint256 _pollId ) external returns (address); } diff --git a/packages/contracts/tests/PollFactory.test.ts b/packages/contracts/tests/PollFactory.test.ts index 55c3586818..e7d08468ba 100644 --- a/packages/contracts/tests/PollFactory.test.ts +++ b/packages/contracts/tests/PollFactory.test.ts @@ -52,6 +52,7 @@ describe("pollFactory", () => { coordinatorPubKey.asContractParam(), extContracts, emptyBallotRoot, + 0n, ); const receipt = await tx.wait(); expect(receipt?.status).to.eq(1); diff --git a/packages/core/ts/Poll.ts b/packages/core/ts/Poll.ts index 1511410425..e1292e0039 100644 --- a/packages/core/ts/Poll.ts +++ b/packages/core/ts/Poll.ts @@ -142,6 +142,7 @@ export class Poll implements IPoll { * @param treeDepths - The depths of the trees used in the poll. * @param batchSizes - The sizes of the batches used in the poll. * @param maciStateRef - The reference to the MACI state. + * @param pollId - The poll id */ constructor( pollEndTimestamp: bigint, @@ -471,7 +472,7 @@ export class Poll implements IPoll { // Create nullifier from private key const inputNullifier = BigInt(maciPrivKey.asCircuitInputs()); - const nullifier = poseidon([inputNullifier]); + const nullifier = poseidon([inputNullifier, this.pollId]); // Get pll state tree's root const stateRoot = this.stateTree!.root; @@ -490,6 +491,7 @@ export class Poll implements IPoll { credits, stateRoot, actualStateTreeDepth, + pollId: this.pollId, }; return stringifyBigInts(circuitInputs) as unknown as IPollJoiningCircuitInputs; diff --git a/packages/core/ts/utils/types.ts b/packages/core/ts/utils/types.ts index d1b9a79708..d2a7e7a586 100644 --- a/packages/core/ts/utils/types.ts +++ b/packages/core/ts/utils/types.ts @@ -156,6 +156,7 @@ export interface IPollJoiningCircuitInputs { credits: string; stateRoot: string; actualStateTreeDepth: string; + pollId: string; } /** * An interface describing the circuit inputs to the ProcessMessage circuit From b0abf59dd813d22352c0e0dfe654601f3ec4b8f0 Mon Sep 17 00:00:00 2001 From: ctrlc03 <93448202+ctrlc03@users.noreply.github.com> Date: Tue, 7 Jan 2025 17:12:47 +0000 Subject: [PATCH 06/17] feat: voice credits per poll (#1967) --- apps/subgraph/src/maci.ts | 2 +- .../subgraph/templates/subgraph.template.yaml | 2 +- .../circuits/circom/anon/pollJoining.circom | 33 ++----- packages/circuits/circom/circuits.json | 2 +- .../circom/trees/incrementalMerkleTree.circom | 2 + .../ts/__tests__/CeremonyParams.test.ts | 8 +- .../circuits/ts/__tests__/PollJoining.test.ts | 20 +--- .../ts/__tests__/ProcessMessages.test.ts | 58 +++++------- .../circuits/ts/__tests__/TallyVotes.test.ts | 12 +-- packages/cli/.gitignore | 3 + packages/cli/tests/constants.ts | 4 +- packages/cli/tests/e2e/e2e.test.ts | 15 --- packages/cli/tests/e2e/keyChange.test.ts | 3 - packages/cli/tests/unit/joinPoll.test.ts | 5 - packages/cli/ts/commands/deploy.ts | 1 - packages/cli/ts/commands/deployPoll.ts | 22 ++++- packages/cli/ts/commands/genProofs.ts | 2 +- packages/cli/ts/commands/joinPoll.ts | 89 ++++++------------ packages/cli/ts/commands/signup.ts | 26 +++--- packages/cli/ts/index.ts | 7 +- packages/cli/ts/utils/interfaces.ts | 29 +++--- packages/contracts/contracts/MACI.sol | 62 ++++--------- packages/contracts/contracts/Poll.sol | 38 ++++---- .../contracts/crypto/SnarkConstants.sol | 2 - .../interfaces/IInitialVoiceCreditProxy.sol | 11 +++ .../contracts/contracts/interfaces/IPoll.sol | 4 +- .../contracts/contracts/trees/LeanIMT.sol | 2 - .../contracts/contracts/utilities/Params.sol | 2 + packages/contracts/deploy-config-example.json | 33 ++++--- .../{02-gatekeepers.ts => 01-gatekeepers.ts} | 0 .../maci/{03-verifier.ts => 02-verifier.ts} | 0 .../maci/{04-poseidon.ts => 03-poseidon.ts} | 0 .../{05-pollFactory.ts => 04-pollFactory.ts} | 0 ...ctory.ts => 05-messageProcessorFactory.ts} | 0 ...{07-tallyFactory.ts => 06-tallyFactory.ts} | 0 .../deploy/maci/{08-maci.ts => 07-maci.ts} | 6 -- .../{09-vkRegistry.ts => 08-vkRegistry.ts} | 0 .../01-constantInitialVoiceCreditProxy.ts | 0 .../{01-gatekeepers.ts => 02-gatekeepers.ts} | 0 .../deploy/poll/{02-poll.ts => 03-poll.ts} | 7 ++ .../contracts/tasks/helpers/ProofGenerator.ts | 2 +- packages/contracts/tasks/helpers/constants.ts | 2 +- packages/contracts/tests/MACI.test.ts | 91 +++---------------- .../contracts/tests/MessageProcessor.test.ts | 7 +- packages/contracts/tests/Poll.test.ts | 40 ++++---- packages/contracts/tests/PollFactory.test.ts | 1 + packages/contracts/tests/Tally.test.ts | 24 ++--- packages/contracts/tests/TallyNonQv.test.ts | 7 +- packages/contracts/tests/constants.ts | 1 + .../gatekeepers/AnonAadhaarGatekeeper.test.ts | 40 +++----- .../tests/gatekeepers/EASGatekeeper.test.ts | 19 ++-- .../GitcoinPassportGatekeeper.test.ts | 6 +- .../tests/gatekeepers/HatsGatekeeper.test.ts | 48 ++-------- .../gatekeepers/MerkleProofGatekeeper.test.ts | 2 - .../gatekeepers/SemaphoreGatekeeper.test.ts | 29 ++---- .../gatekeepers/SignUpGatekeeper.test.ts | 7 +- .../gatekeepers/ZupassGatekeeper.test.ts | 21 ++--- packages/contracts/tests/utils.ts | 6 +- packages/contracts/ts/deploy.ts | 2 - packages/contracts/ts/genMaciState.ts | 10 +- packages/contracts/ts/genSignUpTree.ts | 17 ++-- packages/contracts/ts/types.ts | 9 +- packages/core/ts/MaciState.ts | 37 +++----- packages/core/ts/Poll.ts | 32 +++---- packages/core/ts/__benchmarks__/index.ts | 4 +- packages/core/ts/__tests__/MaciState.test.ts | 11 +-- packages/core/ts/__tests__/Poll.test.ts | 26 +++--- packages/core/ts/__tests__/e2e.test.ts | 51 +++++------ packages/core/ts/__tests__/utils/utils.ts | 10 +- packages/core/ts/utils/types.ts | 7 +- packages/crypto/ts/constants.ts | 2 + packages/crypto/ts/index.ts | 2 +- packages/domainobjs/ts/constants.ts | 2 + packages/domainobjs/ts/index.ts | 2 +- packages/domainobjs/ts/publicKey.ts | 17 ++++ packages/integrationTests/.gitignore | 4 +- .../ts/__tests__/integration.test.ts | 6 +- .../ts/__tests__/maci-keys.test.ts | 3 +- .../ts/__tests__/utils/interfaces.ts | 2 + .../ts/__tests__/utils/utils.ts | 7 +- 80 files changed, 438 insertions(+), 690 deletions(-) create mode 100644 packages/contracts/contracts/interfaces/IInitialVoiceCreditProxy.sol rename packages/contracts/tasks/deploy/maci/{02-gatekeepers.ts => 01-gatekeepers.ts} (100%) rename packages/contracts/tasks/deploy/maci/{03-verifier.ts => 02-verifier.ts} (100%) rename packages/contracts/tasks/deploy/maci/{04-poseidon.ts => 03-poseidon.ts} (100%) rename packages/contracts/tasks/deploy/maci/{05-pollFactory.ts => 04-pollFactory.ts} (100%) rename packages/contracts/tasks/deploy/maci/{06-messageProcessorFactory.ts => 05-messageProcessorFactory.ts} (100%) rename packages/contracts/tasks/deploy/maci/{07-tallyFactory.ts => 06-tallyFactory.ts} (100%) rename packages/contracts/tasks/deploy/maci/{08-maci.ts => 07-maci.ts} (93%) rename packages/contracts/tasks/deploy/maci/{09-vkRegistry.ts => 08-vkRegistry.ts} (100%) rename packages/contracts/tasks/deploy/{maci => poll}/01-constantInitialVoiceCreditProxy.ts (100%) rename packages/contracts/tasks/deploy/poll/{01-gatekeepers.ts => 02-gatekeepers.ts} (100%) rename packages/contracts/tasks/deploy/poll/{02-poll.ts => 03-poll.ts} (94%) diff --git a/apps/subgraph/src/maci.ts b/apps/subgraph/src/maci.ts index 45d1aacf6b..5e3d572bf2 100644 --- a/apps/subgraph/src/maci.ts +++ b/apps/subgraph/src/maci.ts @@ -51,7 +51,7 @@ export function handleDeployPoll(event: DeployPollEvent): void { export function handleSignUp(event: SignUpEvent): void { const user = createOrLoadUser(event.params._userPubKeyX, event.params._userPubKeyY, event); - createOrLoadAccount(event.params._stateIndex, event, user.id, event.params._voiceCreditBalance); + createOrLoadAccount(event.params._stateIndex, event, user.id); const maci = createOrLoadMACI(event); maci.numSignUps = maci.numSignUps.plus(ONE_BIG_INT); diff --git a/apps/subgraph/templates/subgraph.template.yaml b/apps/subgraph/templates/subgraph.template.yaml index a5a5b0e768..9742d913c1 100644 --- a/apps/subgraph/templates/subgraph.template.yaml +++ b/apps/subgraph/templates/subgraph.template.yaml @@ -33,7 +33,7 @@ dataSources: eventHandlers: - event: DeployPoll(uint256,indexed uint256,indexed uint256,uint8) handler: handleDeployPoll - - event: SignUp(uint256,indexed uint256,indexed uint256,uint256,uint256,uint256) + - event: SignUp(uint256,uint256,indexed uint256,indexed uint256) handler: handleSignUp file: ./src/maci.ts templates: diff --git a/packages/circuits/circom/anon/pollJoining.circom b/packages/circuits/circom/anon/pollJoining.circom index 323a3d1535..29358356b5 100644 --- a/packages/circuits/circom/anon/pollJoining.circom +++ b/packages/circuits/circom/anon/pollJoining.circom @@ -1,42 +1,26 @@ pragma circom 2.0.0; -// circomlib import -include "./mux1.circom"; -// zk-kit imports -include "./safe-comparators.circom"; // local imports include "../utils/hashers.circom"; include "../utils/privToPubKey.circom"; include "../trees/incrementalMerkleTree.circom"; template PollJoining(stateTreeDepth) { - // Constants defining the structure and size of state. - var STATE_LEAF_LENGTH = 4; + // Constants defining the tree structure var STATE_TREE_ARITY = 2; - // Public key IDs. - var STATE_LEAF_PUB_X_IDX = 0; - var STATE_LEAF_PUB_Y_IDX = 1; - // Voice Credit balance id - var STATE_LEAF_VOICE_CREDIT_BALANCE_IDX = 2; - var N_BITS = 252; - // User's private key signal input privKey; // Poll's private key signal input pollPrivKey; // Poll's public key signal input pollPubKey[2]; - // The state leaf and related path elements. - signal input stateLeaf[STATE_LEAF_LENGTH]; // Siblings signal input siblings[stateTreeDepth][STATE_TREE_ARITY - 1]; // Indices signal input indices[stateTreeDepth]; // User's hashed private key signal input nullifier; - // User's credits for poll joining (might be <= oldCredits) - signal input credits; // MACI State tree root which proves the user is signed up signal input stateRoot; // The actual tree depth (might be <= stateTreeDepth) Used in BinaryMerkleRoot @@ -50,26 +34,21 @@ template PollJoining(stateTreeDepth) { // User private to public key var derivedPubKey[2] = PrivToPubKey()(privKey); - derivedPubKey[0] === stateLeaf[STATE_LEAF_PUB_X_IDX]; - derivedPubKey[1] === stateLeaf[STATE_LEAF_PUB_Y_IDX]; - - // Poll private to public key + // Hash the public key + var pubKeyHash = PoseidonHasher(2)([derivedPubKey[0], derivedPubKey[1]]); + + // Poll private to public key to verify the correct one is used to join the poll (public input) var derivedPollPubKey[2] = PrivToPubKey()(pollPrivKey); derivedPollPubKey[0] === pollPubKey[0]; derivedPollPubKey[1] === pollPubKey[1]; // Inclusion proof - var stateLeafHash = PoseidonHasher(4)(stateLeaf); var stateLeafQip = BinaryMerkleRoot(stateTreeDepth)( - stateLeafHash, + pubKeyHash, actualStateTreeDepth, indices, siblings ); stateLeafQip === stateRoot; - - // Check credits - var isCreditsValid = SafeLessEqThan(N_BITS)([credits, stateLeaf[STATE_LEAF_VOICE_CREDIT_BALANCE_IDX]]); - isCreditsValid === 1; } diff --git a/packages/circuits/circom/circuits.json b/packages/circuits/circom/circuits.json index d9a9328410..d043cc1916 100644 --- a/packages/circuits/circom/circuits.json +++ b/packages/circuits/circom/circuits.json @@ -3,7 +3,7 @@ "file": "./anon/pollJoining", "template": "PollJoining", "params": [10], - "pubs": ["nullifier", "credits", "stateRoot", "pollPubKey", "pollId"] + "pubs": ["nullifier", "stateRoot", "pollPubKey", "pollId"] }, "ProcessMessages_10-20-2_test": { "file": "./core/qv/processMessages", diff --git a/packages/circuits/circom/trees/incrementalMerkleTree.circom b/packages/circuits/circom/trees/incrementalMerkleTree.circom index 36fcd05012..e67e052783 100644 --- a/packages/circuits/circom/trees/incrementalMerkleTree.circom +++ b/packages/circuits/circom/trees/incrementalMerkleTree.circom @@ -1,5 +1,7 @@ pragma circom 2.0.0; +// zk-kit imports +include "./safe-comparators.circom"; // circomlib import include "./mux1.circom"; include "./comparators.circom"; diff --git a/packages/circuits/ts/__tests__/CeremonyParams.test.ts b/packages/circuits/ts/__tests__/CeremonyParams.test.ts index d8a705056b..1bcbe8b9fd 100644 --- a/packages/circuits/ts/__tests__/CeremonyParams.test.ts +++ b/packages/circuits/ts/__tests__/CeremonyParams.test.ts @@ -78,7 +78,7 @@ describe("Ceremony param tests", () => { before(() => { // Sign up and publish const userKeypair = new Keypair(new PrivKey(BigInt(1))); - maciState.signUp(userKeypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(userKeypair.pubKey); pollId = maciState.deployPoll( BigInt(Math.floor(Date.now() / 1000) + duration), @@ -90,7 +90,7 @@ describe("Ceremony param tests", () => { poll = maciState.polls.get(pollId)!; // update the state - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); // Join the poll const { privKey } = userKeypair; @@ -221,7 +221,7 @@ describe("Ceremony param tests", () => { const commands: PCommand[] = []; // Sign up and publish const userKeypair = new Keypair(); - maciState.signUp(userKeypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(userKeypair.pubKey); pollId = maciState.deployPoll( BigInt(Math.floor(Date.now() / 1000) + duration), @@ -233,7 +233,7 @@ describe("Ceremony param tests", () => { poll = maciState.polls.get(pollId)!; // update the state - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); // Join the poll const { privKey } = userKeypair; diff --git a/packages/circuits/ts/__tests__/PollJoining.test.ts b/packages/circuits/ts/__tests__/PollJoining.test.ts index eb68e305e8..5161ab3881 100644 --- a/packages/circuits/ts/__tests__/PollJoining.test.ts +++ b/packages/circuits/ts/__tests__/PollJoining.test.ts @@ -1,4 +1,3 @@ -import { expect } from "chai"; import { type WitnessTester } from "circomkit"; import { MaciState, Poll } from "maci-core"; import { poseidon } from "maci-crypto"; @@ -23,7 +22,6 @@ describe("Poll Joining circuit", function test() { "siblings", "indices", "nullifier", - "credits", "stateRoot", "actualStateTreeDepth", "pollId", @@ -53,7 +51,7 @@ describe("Poll Joining circuit", function test() { users = new Array(NUM_USERS).fill(0).map(() => new Keypair()); users.forEach((userKeypair) => { - maciState.signUp(userKeypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(userKeypair.pubKey); }); pollId = maciState.deployPoll( @@ -64,7 +62,7 @@ describe("Poll Joining circuit", function test() { ); poll = maciState.polls.get(pollId)!; - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); // Join the poll const { privKey } = users[0]; @@ -101,12 +99,10 @@ describe("Poll Joining circuit", function test() { it("should produce a proof", async () => { const privateKey = users[0].privKey; const stateLeafIndex = BigInt(1); - const credits = BigInt(10); const inputs = poll.joiningCircuitInputs({ maciPrivKey: privateKey, stateLeafIndex, - credits, pollPrivKey, pollPubKey, }) as unknown as IPollJoiningInputs; @@ -117,12 +113,10 @@ describe("Poll Joining circuit", function test() { it("should fail for fake witness", async () => { const privateKey = users[0].privKey; const stateLeafIndex = BigInt(1); - const credits = BigInt(10); const inputs = poll.joiningCircuitInputs({ maciPrivKey: privateKey, stateLeafIndex, - credits, pollPrivKey, pollPubKey, }) as unknown as IPollJoiningInputs; @@ -131,15 +125,5 @@ describe("Poll Joining circuit", function test() { const fakeWitness = Array(witness.length).fill(1n) as bigint[]; await circuit.expectConstraintFail(fakeWitness); }); - - it("should fail for improper credits", () => { - const privateKey = users[0].privKey; - const stateLeafIndex = BigInt(1); - const credits = BigInt(105); - - expect(() => - poll.joiningCircuitInputs({ maciPrivKey: privateKey, stateLeafIndex, credits, pollPrivKey, pollPubKey }), - ).to.throw("Credits must be lower than signed up credits"); - }); }); }); diff --git a/packages/circuits/ts/__tests__/ProcessMessages.test.ts b/packages/circuits/ts/__tests__/ProcessMessages.test.ts index 21e810435f..d252a86e31 100644 --- a/packages/circuits/ts/__tests__/ProcessMessages.test.ts +++ b/packages/circuits/ts/__tests__/ProcessMessages.test.ts @@ -71,7 +71,7 @@ describe("ProcessMessage circuit", function test() { const pollKeys: Keypair[] = []; users.forEach((userKeypair) => { - maciState.signUp(userKeypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(userKeypair.pubKey); pollKeys.push(new Keypair()); }); @@ -83,7 +83,7 @@ describe("ProcessMessage circuit", function test() { ); poll = maciState.polls.get(pollId)!; - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); // Join the poll for (let i = 0; i < users.length; i += 1) { @@ -159,7 +159,7 @@ describe("ProcessMessage circuit", function test() { before(() => { // Sign up and publish const userKeypair = new Keypair(new PrivKey(BigInt(1))); - maciState.signUp(userKeypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(userKeypair.pubKey); pollId = maciState.deployPoll( BigInt(Math.floor(Date.now() / 1000) + duration), @@ -169,7 +169,7 @@ describe("ProcessMessage circuit", function test() { ); poll = maciState.polls.get(pollId)!; - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); // Join the poll const { privKey } = userKeypair; @@ -227,7 +227,7 @@ describe("ProcessMessage circuit", function test() { ballotTree.insert(emptyBallot.hash()); - poll.stateLeaves.forEach(() => { + poll.pubKeys.forEach(() => { ballotTree.insert(emptyBallotHash); }); @@ -262,16 +262,8 @@ describe("ProcessMessage circuit", function test() { const userKeypair = new Keypair(new PrivKey(BigInt(123))); const userKeypair2 = new Keypair(new PrivKey(BigInt(456))); - maciState.signUp( - userKeypair.pubKey, - voiceCreditBalance, - BigInt(1), // BigInt(Math.floor(Date.now() / 1000)), - ); - maciState.signUp( - userKeypair2.pubKey, - voiceCreditBalance, - BigInt(1), // BigInt(Math.floor(Date.now() / 1000)), - ); + maciState.signUp(userKeypair.pubKey); + maciState.signUp(userKeypair2.pubKey); pollId = maciState.deployPoll( BigInt(2 + duration), // BigInt(Math.floor(Date.now() / 1000) + duration), @@ -282,7 +274,7 @@ describe("ProcessMessage circuit", function test() { poll = maciState.polls.get(pollId)!; - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); // Join the poll const { privKey } = userKeypair; @@ -321,7 +313,7 @@ describe("ProcessMessage circuit", function test() { ballotTree.insert(emptyBallot.hash()); - poll.stateLeaves.forEach(() => { + poll.pubKeys.forEach(() => { ballotTree.insert(emptyBallotHash); }); @@ -355,11 +347,7 @@ describe("ProcessMessage circuit", function test() { // Sign up and publish const userKeypair = new Keypair(new PrivKey(BigInt(123))); - maciState.signUp( - userKeypair.pubKey, - voiceCreditBalance, - BigInt(1), // BigInt(Math.floor(Date.now() / 1000)), - ); + maciState.signUp(userKeypair.pubKey); pollId = maciState.deployPoll( BigInt(2 + duration), // BigInt(Math.floor(Date.now() / 1000) + duration), @@ -370,7 +358,7 @@ describe("ProcessMessage circuit", function test() { poll = maciState.polls.get(pollId)!; - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); const { privKey } = userKeypair; const { privKey: pollPrivKey, pubKey: pollPubKey } = new Keypair(); @@ -448,7 +436,7 @@ describe("ProcessMessage circuit", function test() { ballotTree.insert(emptyBallot.hash()); - poll.stateLeaves.forEach(() => { + poll.pubKeys.forEach(() => { ballotTree.insert(emptyBallotHash); }); @@ -480,7 +468,7 @@ describe("ProcessMessage circuit", function test() { before(() => { const userKeypair = new Keypair(new PrivKey(BigInt(1))); - maciState.signUp(userKeypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(userKeypair.pubKey); // Sign up and publish pollId = maciState.deployPoll( @@ -492,7 +480,7 @@ describe("ProcessMessage circuit", function test() { poll = maciState.polls.get(pollId)!; - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); // Join the poll const { privKey } = userKeypair; @@ -547,7 +535,7 @@ describe("ProcessMessage circuit", function test() { before(() => { // Sign up and publish const userKeypair = new Keypair(new PrivKey(BigInt(1))); - maciState.signUp(userKeypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(userKeypair.pubKey); pollId = maciState.deployPoll( BigInt(Math.floor(Date.now() / 1000) + duration), treeDepths, @@ -556,7 +544,7 @@ describe("ProcessMessage circuit", function test() { ); poll = maciState.polls.get(pollId)!; - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); // Join the poll const { privKey } = userKeypair; @@ -634,7 +622,7 @@ describe("ProcessMessage circuit", function test() { ballotTree.insert(emptyBallot.hash()); - poll.stateLeaves.forEach(() => { + poll.pubKeys.forEach(() => { ballotTree.insert(emptyBallotHash); }); @@ -669,7 +657,7 @@ describe("ProcessMessage circuit", function test() { before(() => { // Sign up and publish const userKeypair = new Keypair(new PrivKey(BigInt(1))); - maciState.signUp(userKeypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(userKeypair.pubKey); pollId = maciState.deployPoll( BigInt(Math.floor(Date.now() / 1000) + duration), @@ -679,7 +667,7 @@ describe("ProcessMessage circuit", function test() { ); poll = maciState.polls.get(pollId)!; - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); // Join the poll const { privKey } = userKeypair; @@ -762,7 +750,7 @@ describe("ProcessMessage circuit", function test() { ballotTree.insert(emptyBallot.hash()); - poll.stateLeaves.forEach(() => { + poll.pubKeys.forEach(() => { ballotTree.insert(emptyBallotHash); }); @@ -800,7 +788,7 @@ describe("ProcessMessage circuit", function test() { before(() => { // Sign up and publish const userKeypair = new Keypair(new PrivKey(BigInt(1))); - maciState.signUp(userKeypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(userKeypair.pubKey); pollId = maciState.deployPoll( BigInt(Math.floor(Date.now() / 1000) + duration), treeDepths, @@ -809,7 +797,7 @@ describe("ProcessMessage circuit", function test() { ); poll = maciState.polls.get(pollId)!; - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); // Join the poll const { privKey } = userKeypair; @@ -911,7 +899,7 @@ describe("ProcessMessage circuit", function test() { ballotTree.insert(emptyBallot.hash()); - poll.stateLeaves.forEach(() => { + poll.pubKeys.forEach(() => { ballotTree.insert(emptyBallotHash); }); diff --git a/packages/circuits/ts/__tests__/TallyVotes.test.ts b/packages/circuits/ts/__tests__/TallyVotes.test.ts index 24fc8eaa05..d9ae595eea 100644 --- a/packages/circuits/ts/__tests__/TallyVotes.test.ts +++ b/packages/circuits/ts/__tests__/TallyVotes.test.ts @@ -73,7 +73,7 @@ describe("TallyVotes circuit", function test() { const commands: PCommand[] = []; // Sign up and publish const userKeypair = new Keypair(); - maciState.signUp(userKeypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(userKeypair.pubKey); pollId = maciState.deployPoll( BigInt(Math.floor(Date.now() / 1000) + duration), @@ -83,7 +83,7 @@ describe("TallyVotes circuit", function test() { ); poll = maciState.polls.get(pollId)!; - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); // Join the poll const { privKey } = userKeypair; @@ -153,7 +153,7 @@ describe("TallyVotes circuit", function test() { const commands: PCommand[] = []; // Sign up and publish const userKeypair = new Keypair(); - maciState.signUp(userKeypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(userKeypair.pubKey); pollId = maciState.deployPoll( BigInt(Math.floor(Date.now() / 1000) + duration), @@ -163,7 +163,7 @@ describe("TallyVotes circuit", function test() { ); poll = maciState.polls.get(pollId)!; - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); // Join the poll const { privKey } = userKeypair; @@ -234,7 +234,7 @@ describe("TallyVotes circuit", function test() { const k = new Keypair(); userKeypairs.push(k); pollKeypairs.push(new Keypair()); - maciState.signUp(k.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000) + duration)); + maciState.signUp(k.pubKey); } // Deploy poll @@ -246,7 +246,7 @@ describe("TallyVotes circuit", function test() { ); const poll = maciState.polls.get(pollId)!; - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); // Join the poll for (let i = 0; i < x; i += 1) { diff --git a/packages/cli/.gitignore b/packages/cli/.gitignore index d195e77ec3..a122a02e0d 100644 --- a/packages/cli/.gitignore +++ b/packages/cli/.gitignore @@ -4,3 +4,6 @@ contractAddress.old contractAddress.txt localState.json zkeys +state.json +deployed-contracts.json +deploy-config.json diff --git a/packages/cli/tests/constants.ts b/packages/cli/tests/constants.ts index 14397f0067..053f77a49f 100644 --- a/packages/cli/tests/constants.ts +++ b/packages/cli/tests/constants.ts @@ -46,13 +46,13 @@ export const testProcessMessagesWasmPath = export const testTallyVotesWasmPath = "./zkeys/TallyVotes_10-1-2_test/TallyVotes_10-1-2_test_js/TallyVotes_10-1-2_test.wasm"; export const testRapidsnarkPath = `${homedir()}/rapidsnark/build/prover`; -export const ceremonyPollJoiningZkeyPath = "./zkeys/PollJoining_10/pollJoining_10.zkey"; +export const ceremonyPollJoiningZkeyPath = "./zkeys/PollJoining_10_test/PollJoining_10_test.0.zkey"; export const ceremonyProcessMessagesZkeyPath = "./zkeys/ProcessMessages_6-9-2-3/processMessages_6-9-2-3.zkey"; export const ceremonyProcessMessagesNonQvZkeyPath = "./zkeys/ProcessMessagesNonQv_6-9-2-3/processMessagesNonQv_6-9-2-3.zkey"; export const ceremonyTallyVotesZkeyPath = "./zkeys/TallyVotes_6-2-3/tallyVotes_6-2-3.zkey"; export const ceremonyTallyVotesNonQvZkeyPath = "./zkeys/TallyVotesNonQv_6-2-3/tallyVotesNonQv_6-2-3.zkey"; -export const ceremonyPollJoiningWitnessPath = "./zkeys/PollJoining/PollJoining_10_cpp/PollJoining_10"; +export const ceremonyPollJoiningWitnessPath = "./zkeys/PollJoining_10_test/PollJoining_10_test_cpp/PollJoining_10_test"; export const ceremonyProcessMessagesWitnessPath = "./zkeys/ProcessMessages_14-9-2-3/ProcessMessages_14-9-2-3_cpp/ProcessMessages_14-9-2-3"; export const ceremonyProcessMessagesNonQvWitnessPath = diff --git a/packages/cli/tests/e2e/e2e.test.ts b/packages/cli/tests/e2e/e2e.test.ts index 4508fd8743..bc9e1fa347 100644 --- a/packages/cli/tests/e2e/e2e.test.ts +++ b/packages/cli/tests/e2e/e2e.test.ts @@ -138,7 +138,6 @@ describe("e2e tests", function test() { pollWitgen: testPollJoiningWitnessPath, rapidsnark: testRapidsnarkPath, signer, - newVoiceCreditBalance: 10n, quiet: true, }); }); @@ -203,7 +202,6 @@ describe("e2e tests", function test() { pollWitgen: testPollJoiningWitnessPath, rapidsnark: testRapidsnarkPath, signer, - newVoiceCreditBalance: 10n, quiet: true, }); }); @@ -277,7 +275,6 @@ describe("e2e tests", function test() { pollWitgen: testPollJoiningWitnessPath, rapidsnark: testRapidsnarkPath, signer, - newVoiceCreditBalance: 1n, quiet: true, }); } @@ -451,7 +448,6 @@ describe("e2e tests", function test() { pollWitgen: testPollJoiningWitnessPath, rapidsnark: testRapidsnarkPath, signer, - newVoiceCreditBalance: 1n, quiet: true, }); } @@ -517,7 +513,6 @@ describe("e2e tests", function test() { pollWitgen: testPollJoiningWitnessPath, rapidsnark: testRapidsnarkPath, signer, - newVoiceCreditBalance: 1n, quiet: true, }); }); @@ -588,7 +583,6 @@ describe("e2e tests", function test() { pollWitgen: testPollJoiningWitnessPath, rapidsnark: testRapidsnarkPath, signer, - newVoiceCreditBalance: 1n, quiet: true, }); } @@ -696,7 +690,6 @@ describe("e2e tests", function test() { pollWitgen: testPollJoiningWitnessPath, rapidsnark: testRapidsnarkPath, signer, - newVoiceCreditBalance: 1n, quiet: true, }); // publish @@ -740,7 +733,6 @@ describe("e2e tests", function test() { pollWitgen: testPollJoiningWitnessPath, rapidsnark: testRapidsnarkPath, signer, - newVoiceCreditBalance: 1n, quiet: true, }); }); @@ -797,7 +789,6 @@ describe("e2e tests", function test() { pollWitgen: testPollJoiningWitnessPath, rapidsnark: testRapidsnarkPath, signer, - newVoiceCreditBalance: 1n, quiet: true, }); @@ -832,7 +823,6 @@ describe("e2e tests", function test() { pollWitgen: testPollJoiningWitnessPath, rapidsnark: testRapidsnarkPath, signer, - newVoiceCreditBalance: 1n, quiet: true, }); @@ -871,7 +861,6 @@ describe("e2e tests", function test() { pollWitgen: testPollJoiningWitnessPath, rapidsnark: testRapidsnarkPath, signer, - newVoiceCreditBalance: 1n, quiet: true, }); // joinPoll @@ -887,7 +876,6 @@ describe("e2e tests", function test() { pollWitgen: testPollJoiningWitnessPath, rapidsnark: testRapidsnarkPath, signer, - newVoiceCreditBalance: 1n, quiet: true, }); }); @@ -997,7 +985,6 @@ describe("e2e tests", function test() { pollWitgen: testPollJoiningWitnessPath, rapidsnark: testRapidsnarkPath, signer, - newVoiceCreditBalance: 1n, quiet: true, }); // eslint-disable-next-line no-await-in-loop @@ -1061,7 +1048,6 @@ describe("e2e tests", function test() { pollWitgen: testPollJoiningWitnessPath, rapidsnark: testRapidsnarkPath, signer, - newVoiceCreditBalance: 1n, quiet: true, }); // eslint-disable-next-line no-await-in-loop @@ -1240,7 +1226,6 @@ describe("e2e tests", function test() { pollWitgen: testPollJoiningWitnessPath, rapidsnark: testRapidsnarkPath, signer, - newVoiceCreditBalance: 1n, quiet: true, }); }); diff --git a/packages/cli/tests/e2e/keyChange.test.ts b/packages/cli/tests/e2e/keyChange.test.ts index 7fc5441f0e..4513607dfe 100644 --- a/packages/cli/tests/e2e/keyChange.test.ts +++ b/packages/cli/tests/e2e/keyChange.test.ts @@ -124,7 +124,6 @@ describe("keyChange tests", function test() { pollWitgen: testPollJoiningWitnessPath, rapidsnark: testRapidsnarkPath, signer, - newVoiceCreditBalance: 99n, quiet: true, }); await publish({ @@ -214,7 +213,6 @@ describe("keyChange tests", function test() { pollWitgen: testPollJoiningWitnessPath, rapidsnark: testRapidsnarkPath, signer, - newVoiceCreditBalance: 99n, quiet: true, }); await publish({ @@ -304,7 +302,6 @@ describe("keyChange tests", function test() { pollWitgen: testPollJoiningWitnessPath, rapidsnark: testRapidsnarkPath, signer, - newVoiceCreditBalance: 99n, quiet: true, }); diff --git a/packages/cli/tests/unit/joinPoll.test.ts b/packages/cli/tests/unit/joinPoll.test.ts index 6e70e4cff7..a20c86c413 100644 --- a/packages/cli/tests/unit/joinPoll.test.ts +++ b/packages/cli/tests/unit/joinPoll.test.ts @@ -31,7 +31,6 @@ describe("joinPoll", function test() { const userPublicKey = user.pubKey.serialize(); const { privKey: pollPrivateKey, pubKey: pollPublicKey } = new Keypair(); - const mockNewVoiceCreditBalance = 10n; const mockStateIndex = 1n; const mockPollId = 9000n; @@ -71,7 +70,6 @@ describe("joinPoll", function test() { pollWasm: testPollJoiningWasmPath, pollWitgen: testPollJoiningWitnessPath, rapidsnark: testRapidsnarkPath, - newVoiceCreditBalance: mockNewVoiceCreditBalance, quiet: true, }); @@ -98,7 +96,6 @@ describe("joinPoll", function test() { pollId: mockPollId, pollPrivKey: pollPrivateKey.serialize(), pollJoiningZkey: pollJoiningTestZkeyPath, - newVoiceCreditBalance: mockNewVoiceCreditBalance, quiet: true, }), ).eventually.rejectedWith("PollDoesNotExist(9000)"); @@ -114,7 +111,6 @@ describe("joinPoll", function test() { pollId: 0n, pollPrivKey: pollPrivateKey.serialize(), pollJoiningZkey: pollJoiningTestZkeyPath, - newVoiceCreditBalance: mockNewVoiceCreditBalance, quiet: true, }), ).eventually.rejectedWith("Invalid state index"); @@ -130,7 +126,6 @@ describe("joinPoll", function test() { pollId: -1n, pollPrivKey: pollPrivateKey.serialize(), pollJoiningZkey: pollJoiningTestZkeyPath, - newVoiceCreditBalance: mockNewVoiceCreditBalance, quiet: true, }), ).eventually.rejectedWith("Invalid poll id"); diff --git a/packages/cli/ts/commands/deploy.ts b/packages/cli/ts/commands/deploy.ts index 1ae2983b3e..2e8bacead0 100644 --- a/packages/cli/ts/commands/deploy.ts +++ b/packages/cli/ts/commands/deploy.ts @@ -78,7 +78,6 @@ export const deploy = async ({ // deploy MACI, PollFactory and poseidon const { maciContract, pollFactoryContract, poseidonAddrs } = await deployMaci({ signUpTokenGatekeeperContractAddress: signupGatekeeperContractAddress, - initialVoiceCreditBalanceAddress: initialVoiceCreditProxyContractAddress, poseidonAddresses: { poseidonT3, poseidonT4, diff --git a/packages/cli/ts/commands/deployPoll.ts b/packages/cli/ts/commands/deployPoll.ts index b69fb1a631..774c19e94c 100644 --- a/packages/cli/ts/commands/deployPoll.ts +++ b/packages/cli/ts/commands/deployPoll.ts @@ -1,4 +1,9 @@ -import { MACI__factory as MACIFactory, EMode, deployFreeForAllSignUpGatekeeper } from "maci-contracts"; +import { + MACI__factory as MACIFactory, + EMode, + deployFreeForAllSignUpGatekeeper, + deployConstantInitialVoiceCreditProxy, +} from "maci-contracts"; import { PubKey } from "maci-domainobjs"; import { @@ -11,6 +16,7 @@ import { logGreen, type DeployPollArgs, type PollContracts, + DEFAULT_INITIAL_VOICE_CREDITS, } from "../utils"; /** @@ -27,6 +33,8 @@ export const deployPoll = async ({ maciAddress, vkRegistryAddress, gatekeeperAddress, + voiceCreditProxyAddress, + initialVoiceCreditsBalance, signer, quiet = true, useQuadraticVoting = false, @@ -62,6 +70,17 @@ export const deployPoll = async ({ signupGatekeeperContractAddress = await contract.getAddress(); } + let initialVoiceCreditProxyAddress = + voiceCreditProxyAddress || (await readContractAddress("VoiceCreditProxy", network?.name)); + if (!initialVoiceCreditProxyAddress) { + const contract = await deployConstantInitialVoiceCreditProxy( + initialVoiceCreditsBalance ?? DEFAULT_INITIAL_VOICE_CREDITS, + signer, + true, + ); + initialVoiceCreditProxyAddress = await contract.getAddress(); + } + // required arg -> poll duration if (pollDuration <= 0) { logError("Duration cannot be <= 0"); @@ -115,6 +134,7 @@ export const deployPoll = async ({ vkRegistry, useQuadraticVoting ? EMode.QV : EMode.NON_QV, signupGatekeeperContractAddress, + initialVoiceCreditProxyAddress, { gasLimit: 10000000 }, ); diff --git a/packages/cli/ts/commands/genProofs.ts b/packages/cli/ts/commands/genProofs.ts index e302a10c63..8415577757 100644 --- a/packages/cli/ts/commands/genProofs.ts +++ b/packages/cli/ts/commands/genProofs.ts @@ -272,7 +272,7 @@ export const genProofs = async ({ const tallyStartTime = Date.now(); const { tallyBatchSize } = poll.batchSizes; - const numStateLeaves = poll.stateLeaves.length; + const numStateLeaves = poll.pubKeys.length; let totalTallyBatches = numStateLeaves <= tallyBatchSize ? 1 : Math.floor(numStateLeaves / tallyBatchSize); if (numStateLeaves > tallyBatchSize && numStateLeaves % tallyBatchSize > 0) { totalTallyBatches += 1; diff --git a/packages/cli/ts/commands/joinPoll.ts b/packages/cli/ts/commands/joinPoll.ts index ab9fa3e131..4eb1e3bb2c 100644 --- a/packages/cli/ts/commands/joinPoll.ts +++ b/packages/cli/ts/commands/joinPoll.ts @@ -4,53 +4,44 @@ import { formatProofForVerifierContract, genSignUpTree, IGenSignUpTree } from "m import { MACI__factory as MACIFactory, Poll__factory as PollFactory } from "maci-contracts/typechain-types"; import { CircuitInputs, IJsonMaciState, MaciState, IPollJoiningCircuitInputs } from "maci-core"; import { poseidon, stringifyBigInts } from "maci-crypto"; -import { IVkObjectParams, Keypair, PrivKey, PubKey, StateLeaf } from "maci-domainobjs"; +import { IVkObjectParams, Keypair, PrivKey, PubKey } from "maci-domainobjs"; import fs from "fs"; import type { IJoinPollArgs, IJoinedUserArgs, IParsePollJoinEventsArgs, IJoinPollData } from "../utils"; -import { contractExists, logError, logYellow, info, logGreen, success, BLOCKS_STEP, DEFAULT_SG_DATA } from "../utils"; +import { + contractExists, + logError, + logYellow, + info, + logGreen, + success, + BLOCKS_STEP, + DEFAULT_SG_DATA, + DEFAULT_IVCP_DATA, +} from "../utils"; import { banner } from "../utils/banner"; /** * Get state index and credit balance * either from command line or * from maci state leaves or from sign up leaves - * @param stateIndex State index from the command - * @param newVoiceCreditBalance Credit balance from the command - * @param stateLeaves State leaves from maci state or sign up tree + * @param pubKeys Public keys from maci state or sign up tree * @param userMaciPubKey Public key of the maci user - * @returns State index and credit balance + * @param stateIndex State index from the command + * @returns State index */ -const getStateIndexAndCreditBalance = ( - stateIndex: bigint | null, - newVoiceCreditBalance: bigint | null, - stateLeaves: StateLeaf[], - userMaciPubKey: PubKey, -): [bigint | null, bigint | null] => { - let loadedStateIndex = stateIndex; - let loadedCreditBalance = newVoiceCreditBalance; - +const getStateIndex = (pubKeys: PubKey[], userMaciPubKey: PubKey, stateIndex?: bigint): bigint | undefined => { if (!stateIndex) { - const index = stateLeaves.findIndex((leaf) => leaf.pubKey.equals(userMaciPubKey)); + const index = pubKeys.findIndex((key) => key.equals(userMaciPubKey)); if (index > 0) { - loadedStateIndex = BigInt(index); - } else { - logError("State leaf not found"); + return BigInt(index); } + logError("State leaf not found"); } - if (!newVoiceCreditBalance) { - const balance = stateLeaves[Number(loadedStateIndex!)].voiceCreditBalance; - if (balance) { - loadedCreditBalance = balance; - } else { - logError("Voice credit balance not found"); - } - } - - return [loadedStateIndex, loadedCreditBalance]; + return stateIndex; }; /** @@ -98,7 +89,6 @@ const generateAndVerifyProof = async ( * @param stateTreeDepth Maci state tree depth * @param maciPrivKey User's private key for signing up * @param stateLeafIndex Index where the user is stored in the state leaves - * @param credits Credits for voting * @param pollPrivKey Poll's private key for the poll joining * @param pollPubKey Poll's public key for the poll joining * @param pollId Poll's id @@ -109,21 +99,12 @@ const joiningCircuitInputs = ( stateTreeDepth: bigint, maciPrivKey: PrivKey, stateLeafIndex: bigint, - credits: bigint, pollPrivKey: PrivKey, pollPubKey: PubKey, pollId: bigint, ): IPollJoiningCircuitInputs => { // Get the state leaf on the index position - const { signUpTree: stateTree, stateLeaves } = signUpData; - const stateLeaf = stateLeaves[Number(stateLeafIndex)]; - const { pubKey, voiceCreditBalance, timestamp } = stateLeaf; - const [pubKeyX, pubKeyY] = pubKey.asArray(); - const stateLeafArray = [pubKeyX, pubKeyY, voiceCreditBalance, timestamp]; - - if (credits > voiceCreditBalance) { - logError("Credits must be lower than signed up credits"); - } + const { signUpTree: stateTree } = signUpData; // calculate the path elements for the state tree given the original state tree const { siblings, index } = stateTree.generateProof(Number(stateLeafIndex)); @@ -162,11 +143,9 @@ const joiningCircuitInputs = ( privKey: maciPrivKey.asCircuitInputs(), pollPrivKey: pollPrivKey.asCircuitInputs(), pollPubKey: pollPubKey.asCircuitInputs(), - stateLeaf: stateLeafArray, siblings: siblingsArray, indices, nullifier, - credits, stateRoot, actualStateTreeDepth, pollId, @@ -185,7 +164,6 @@ export const joinPoll = async ({ privateKey, pollPrivKey, stateIndex, - newVoiceCreditBalance, stateFile, pollId, signer, @@ -199,6 +177,7 @@ export const joinPoll = async ({ pollWitgen, pollWasm, sgDataArg, + ivcpDataArg, quiet = true, }: IJoinPollArgs): Promise => { banner(quiet); @@ -233,8 +212,7 @@ export const joinPoll = async ({ const pollContract = PollFactory.connect(pollContracts.poll, signer); - let loadedStateIndex: bigint | null; - let loadedCreditBalance: bigint | null; + let loadedStateIndex: bigint | undefined; let maciState: MaciState | undefined; let signUpData: IGenSignUpTree | undefined; let currentStateRootIndex: number; @@ -254,12 +232,7 @@ export const joinPoll = async ({ throw new Error("User the given nullifier has already joined"); } - [loadedStateIndex, loadedCreditBalance] = getStateIndexAndCreditBalance( - stateIndex, - newVoiceCreditBalance, - maciState!.stateLeaves, - userMaciPubKey, - ); + loadedStateIndex = getStateIndex(maciState!.pubKeys, userMaciPubKey, stateIndex); // check < 1 cause index zero is a blank state leaf if (loadedStateIndex! < 1) { @@ -268,12 +241,11 @@ export const joinPoll = async ({ currentStateRootIndex = poll.maciStateRef.numSignUps - 1; - poll.updatePoll(BigInt(maciState!.stateLeaves.length)); + poll.updatePoll(BigInt(maciState!.pubKeys.length)); circuitInputs = poll.joiningCircuitInputs({ maciPrivKey: userMaciPrivKey, stateLeafIndex: loadedStateIndex!, - credits: loadedCreditBalance!, pollPrivKey: pollPrivKeyDeserialized, pollPubKey, }) as unknown as CircuitInputs; @@ -308,12 +280,7 @@ export const joinPoll = async ({ currentStateRootIndex = Number(numSignups) - 1; - [loadedStateIndex, loadedCreditBalance] = getStateIndexAndCreditBalance( - stateIndex, - newVoiceCreditBalance, - signUpData.stateLeaves, - userMaciPubKey, - ); + loadedStateIndex = getStateIndex(signUpData.pubKeys, userMaciPubKey, stateIndex); // check < 1 cause index zero is a blank state leaf if (loadedStateIndex! < 1) { @@ -325,7 +292,6 @@ export const joinPoll = async ({ stateTreeDepth, userMaciPrivKey, loadedStateIndex!, - loadedCreditBalance!, pollPrivKeyDeserialized, pollPubKey, pollId, @@ -338,6 +304,7 @@ export const joinPoll = async ({ let receipt: ContractTransactionReceipt | null = null; const sgData = sgDataArg || DEFAULT_SG_DATA; + const ivcpData = ivcpDataArg || DEFAULT_IVCP_DATA; try { // generate the proof for this batch @@ -355,10 +322,10 @@ export const joinPoll = async ({ const tx = await pollContract.joinPoll( nullifier, pollPubKey.asContractParam(), - loadedCreditBalance!, currentStateRootIndex, proof, sgData, + ivcpData, ); receipt = await tx.wait(); logYellow(quiet, info(`Transaction hash: ${receipt!.hash}`)); diff --git a/packages/cli/ts/commands/signup.ts b/packages/cli/ts/commands/signup.ts index f7e3aa1859..357e3458c9 100644 --- a/packages/cli/ts/commands/signup.ts +++ b/packages/cli/ts/commands/signup.ts @@ -26,7 +26,7 @@ import type { import { banner } from "../utils/banner"; import { contractExists } from "../utils/contracts"; -import { DEFAULT_IVCP_DATA, DEFAULT_SG_DATA } from "../utils/defaults"; +import { DEFAULT_SG_DATA } from "../utils/defaults"; import { GatekeeperTrait } from "../utils/interfaces"; import { info, logError, logGreen, logYellow, success } from "../utils/theme"; @@ -39,7 +39,6 @@ export const signup = async ({ maciPubKey, maciAddress, sgDataArg, - ivcpDataArg, signer, quiet = true, }: SignupArgs): Promise => { @@ -57,17 +56,12 @@ export const signup = async ({ } const sgData = sgDataArg || DEFAULT_SG_DATA; - const ivcpData = ivcpDataArg || DEFAULT_IVCP_DATA; // we validate that the signup data and voice credit data is valid if (!isBytesLike(sgData)) { logError("invalid signup gateway data"); } - if (!isBytesLike(ivcpData)) { - logError("invalid initial voice credit proxy data"); - } - const maciContract = MACIFactory.connect(maciAddress, signer); let stateIndex = ""; @@ -76,7 +70,7 @@ export const signup = async ({ try { // sign up to the MACI contract - const tx = await maciContract.signUp(userMaciPubKey.asContractParam(), sgData, ivcpData); + const tx = await maciContract.signUp(userMaciPubKey.asContractParam(), sgData); receipt = await tx.wait(); logYellow(quiet, info(`Transaction hash: ${tx.hash}`)); @@ -110,13 +104,18 @@ export const signup = async ({ /** * Parse the signup events from the MACI contract */ -const parseSignupEvents = async ({ maciContract, startBlock, currentBlock, publicKey }: IParseSignupEventsArgs) => { +const parseSignupEvents = async ({ + maciContract, + startBlock, + currentBlock, + publicKey, +}: IParseSignupEventsArgs): Promise<{ stateIndex?: string }> => { // 1000 blocks at a time for (let block = startBlock; block <= currentBlock; block += 1000) { const toBlock = Math.min(block + 999, currentBlock); // eslint-disable-next-line no-await-in-loop const newEvents = await maciContract.queryFilter( - maciContract.filters.SignUp(undefined, publicKey.rawPubKey[0], publicKey.rawPubKey[1]), + maciContract.filters.SignUp(undefined, undefined, publicKey.rawPubKey[0], publicKey.rawPubKey[1]), block, toBlock, ); @@ -126,14 +125,12 @@ const parseSignupEvents = async ({ maciContract, startBlock, currentBlock, publi return { stateIndex: event.args[0].toString(), - voiceCredits: event.args[3].toString(), }; } } return { stateIndex: undefined, - voiceCredits: undefined, }; }; @@ -148,7 +145,7 @@ export const isRegisteredUser = async ({ signer, startBlock, quiet = true, -}: IRegisteredUserArgs): Promise<{ isRegistered: boolean; stateIndex?: string; voiceCredits?: string }> => { +}: IRegisteredUserArgs): Promise<{ isRegistered: boolean; stateIndex?: string }> => { banner(quiet); const maciContract = MACIFactory.connect(maciAddress, signer); @@ -156,7 +153,7 @@ export const isRegisteredUser = async ({ const startBlockNumber = startBlock || 0; const currentBlock = await signer.provider!.getBlockNumber(); - const { stateIndex, voiceCredits } = await parseSignupEvents({ + const { stateIndex } = await parseSignupEvents({ maciContract, startBlock: startBlockNumber, currentBlock, @@ -168,7 +165,6 @@ export const isRegisteredUser = async ({ return { isRegistered: stateIndex !== undefined, stateIndex, - voiceCredits, }; }; diff --git a/packages/cli/ts/index.ts b/packages/cli/ts/index.ts index c40a5166e9..fd2318f84c 100644 --- a/packages/cli/ts/index.ts +++ b/packages/cli/ts/index.ts @@ -218,6 +218,7 @@ program .option("-i, --state-index ", "the user's state index", BigInt) .requiredOption("-s, --sg-data ", "the signup gateway data") .requiredOption("-esk, --poll-priv-key ", "the user ephemeral private key for the poll") + .option("-iv, --ivcp-data ", "the initial voice credit proxy data") .option( "-nv, --new-voice-credit-balance ", "the voice credit balance of the user for the poll", @@ -251,8 +252,7 @@ program maciAddress, privateKey, pollPrivKey: cmdObj.pollPrivKey, - stateIndex: cmdObj.stateIndex || null, - newVoiceCreditBalance: cmdObj.newVoiceCreditBalance || null, + stateIndex: cmdObj.stateIndex || undefined, stateFile: cmdObj.stateFile, pollId: cmdObj.pollId, signer, @@ -267,6 +267,7 @@ program rapidsnark: cmdObj.rapidsnark, pollWitgen: cmdObj.pollWitnessgen, sgDataArg: cmdObj.sgData, + ivcpDataArg: cmdObj.ivcpData, }); } catch (error) { program.error((error as Error).message, { exitCode: 1 }); @@ -456,7 +457,6 @@ program .requiredOption("-p, --pubkey ", "the MACI public key") .option("-x, --maci-address ", "the MACI contract address") .option("-s, --sg-data ", "the signup gateway data") - .option("-i, --ivcp-data ", "the initial voice credit proxy data") .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) => { @@ -470,7 +470,6 @@ program maciPubKey: cmdObj.pubkey, maciAddress, sgDataArg: cmdObj.sgData, - ivcpDataArg: cmdObj.ivcpData, quiet: cmdObj.quiet, signer, }); diff --git a/packages/cli/ts/utils/interfaces.ts b/packages/cli/ts/utils/interfaces.ts index 68467b9f7a..36c746df2a 100644 --- a/packages/cli/ts/utils/interfaces.ts +++ b/packages/cli/ts/utils/interfaces.ts @@ -324,6 +324,16 @@ export interface DeployPollArgs { * The address of the gatekeeper contract */ gatekeeperAddress?: string; + + /** + * The address of the initial voice credit proxy contract + */ + voiceCreditProxyAddress?: string; + + /** + * The initial voice credits balance + */ + initialVoiceCreditsBalance?: number; } /** @@ -374,20 +384,15 @@ export interface IJoinPollArgs { */ privateKey: string; - /** - * User's credit balance for voting within this poll - */ - newVoiceCreditBalance: bigint | null; - /** * The id of the poll */ pollId: bigint; /** - * The index of the state leaf + * The index of the public key in the state tree */ - stateIndex: bigint | null; + stateIndex?: bigint; /** * Whether to log the output @@ -458,6 +463,11 @@ export interface IJoinPollArgs { * The signup gatekeeper data */ sgDataArg?: string; + + /** + * The initial voice credit proxy data + */ + ivcpDataArg?: string; } /** @@ -945,11 +955,6 @@ export interface SignupArgs { */ sgDataArg?: string; - /** - * The initial voice credit proxy data - */ - ivcpDataArg?: string; - /** * Whether to log the output */ diff --git a/packages/contracts/contracts/MACI.sol b/packages/contracts/contracts/MACI.sol index d25eff7053..dca425a050 100644 --- a/packages/contracts/contracts/MACI.sol +++ b/packages/contracts/contracts/MACI.sol @@ -7,18 +7,18 @@ import { ITallyFactory } from "./interfaces/ITallyFactory.sol"; import { IVerifier } from "./interfaces/IVerifier.sol"; import { IVkRegistry } from "./interfaces/IVkRegistry.sol"; import { ISignUpGatekeeper } from "./interfaces/ISignUpGatekeeper.sol"; -import { InitialVoiceCreditProxy } from "./initialVoiceCreditProxy/InitialVoiceCreditProxy.sol"; +import { IInitialVoiceCreditProxy } from "./interfaces/IInitialVoiceCreditProxy.sol"; import { SignUpGatekeeper } from "./gatekeepers/SignUpGatekeeper.sol"; import { IMACI } from "./interfaces/IMACI.sol"; import { Params } from "./utilities/Params.sol"; -import { Utilities } from "./utilities/Utilities.sol"; import { DomainObjs } from "./utilities/DomainObjs.sol"; import { CurveBabyJubJub } from "./crypto/BabyJubJub.sol"; +import { Hasher } from "./crypto/Hasher.sol"; import { InternalLeanIMT, LeanIMTData } from "./trees/LeanIMT.sol"; /// @title MACI - Minimum Anti-Collusion Infrastructure Version 1 /// @notice A contract which allows users to sign up, and deploy new polls -contract MACI is IMACI, DomainObjs, Params, Utilities { +contract MACI is IMACI, DomainObjs, Params, Hasher { /// @notice The state tree depth is fixed. As such it should be as large as feasible /// so that there can be as many users as possible. i.e. 2 ** 23 = 8388608 /// this should also match the parameter of the circom circuits. @@ -31,9 +31,8 @@ contract MACI is IMACI, DomainObjs, Params, Utilities { uint8 internal constant STATE_TREE_ARITY = 2; - /// @notice The hash of a blank state leaf - uint256 internal constant BLANK_STATE_LEAF_HASH = - uint256(6769006970205099520508948723718471724660867171122235270773600567925038008762); + /// @notice This is the poseidon hash of the pad key + uint256 internal constant PAD_KEY_HASH = 1309255631273308531193241901289907343161346846555918942743921933037802809814; /// @notice The roots of the empty ballot trees uint256[5] public emptyBallotRoots; @@ -53,18 +52,13 @@ contract MACI is IMACI, DomainObjs, Params, Utilities { /// @notice Factory contract that deploy a Tally contract ITallyFactory public immutable tallyFactory; - /// @notice The state tree. Represents a mapping between each user's public key - /// and their voice credit balance. + /// @notice The state tree. Stores users' public keys LeanIMTData public leanIMTData; /// @notice Address of the SignUpGatekeeper, a contract which determines whether a /// user may sign up to vote SignUpGatekeeper public immutable signUpGatekeeper; - /// @notice The contract which provides the values of the initial voice credit - /// balance per user - InitialVoiceCreditProxy public immutable initialVoiceCreditProxy; - /// @notice The array of the state tree roots for each sign up /// For the N'th sign up, the state tree root will be stored at the index N uint256[] public stateRootsOnSignUp; @@ -77,14 +71,7 @@ contract MACI is IMACI, DomainObjs, Params, Utilities { } // Events - event SignUp( - uint256 _stateIndex, - uint256 indexed _userPubKeyX, - uint256 indexed _userPubKeyY, - uint256 _voiceCreditBalance, - uint256 _timestamp, - uint256 _stateLeaf - ); + event SignUp(uint256 _stateIndex, uint256 _timestamp, uint256 indexed _userPubKeyX, uint256 indexed _userPubKeyY); event DeployPoll( uint256 _pollId, uint256 indexed _coordinatorPubKeyX, @@ -103,7 +90,6 @@ contract MACI is IMACI, DomainObjs, Params, Utilities { /// @param _messageProcessorFactory The MessageProcessorFactory contract /// @param _tallyFactory The TallyFactory contract /// @param _signUpGatekeeper The SignUpGatekeeper contract - /// @param _initialVoiceCreditProxy The InitialVoiceCreditProxy contract /// @param _stateTreeDepth The depth of the state tree /// @param _emptyBallotRoots The roots of the empty ballot trees constructor( @@ -111,19 +97,17 @@ contract MACI is IMACI, DomainObjs, Params, Utilities { IMessageProcessorFactory _messageProcessorFactory, ITallyFactory _tallyFactory, SignUpGatekeeper _signUpGatekeeper, - InitialVoiceCreditProxy _initialVoiceCreditProxy, uint8 _stateTreeDepth, uint256[5] memory _emptyBallotRoots ) payable { // initialize and insert the blank leaf - InternalLeanIMT._insert(leanIMTData, BLANK_STATE_LEAF_HASH); - stateRootsOnSignUp.push(BLANK_STATE_LEAF_HASH); + InternalLeanIMT._insert(leanIMTData, PAD_KEY_HASH); + stateRootsOnSignUp.push(PAD_KEY_HASH); pollFactory = _pollFactory; messageProcessorFactory = _messageProcessorFactory; tallyFactory = _tallyFactory; signUpGatekeeper = _signUpGatekeeper; - initialVoiceCreditProxy = _initialVoiceCreditProxy; stateTreeDepth = _stateTreeDepth; maxSignups = uint256(STATE_TREE_ARITY) ** uint256(_stateTreeDepth); emptyBallotRoots = _emptyBallotRoots; @@ -140,14 +124,7 @@ contract MACI is IMACI, DomainObjs, Params, Utilities { /// register() function. For instance, the POAPGatekeeper or /// SignUpTokenGatekeeper requires this value to be the ABI-encoded /// token ID. - /// @param _initialVoiceCreditProxyData Data to pass to the - /// InitialVoiceCreditProxy, which allows it to determine how many voice - /// credits this user should have. - function signUp( - PubKey memory _pubKey, - bytes memory _signUpGatekeeperData, - bytes memory _initialVoiceCreditProxyData - ) public virtual { + function signUp(PubKey memory _pubKey, bytes memory _signUpGatekeeperData) public virtual { // ensure we do not have more signups than what the circuits support if (leanIMTData.size >= maxSignups) revert TooManySignups(); @@ -160,17 +137,14 @@ contract MACI is IMACI, DomainObjs, Params, Utilities { // throw if the user has already registered or if ineligible to do so. signUpGatekeeper.register(msg.sender, _signUpGatekeeperData); - // Get the user's voice credit balance. - uint256 voiceCreditBalance = initialVoiceCreditProxy.getVoiceCredits(msg.sender, _initialVoiceCreditProxyData); - - // Create a state leaf and insert it into the tree. - uint256 stateLeaf = hashStateLeaf(StateLeaf(_pubKey, voiceCreditBalance, block.timestamp)); - uint256 stateRoot = InternalLeanIMT._insert(leanIMTData, stateLeaf); + // Hash the public key and insert it into the tree. + uint256 pubKeyHash = hashLeftRight(_pubKey.x, _pubKey.y); + uint256 stateRoot = InternalLeanIMT._insert(leanIMTData, pubKeyHash); // Store the current state tree root in the array stateRootsOnSignUp.push(stateRoot); - emit SignUp(leanIMTData.size - 1, _pubKey.x, _pubKey.y, voiceCreditBalance, block.timestamp, stateLeaf); + emit SignUp(leanIMTData.size - 1, block.timestamp, _pubKey.x, _pubKey.y); } /// @notice Deploy a new Poll contract. @@ -181,6 +155,8 @@ contract MACI is IMACI, DomainObjs, Params, Utilities { /// @param _verifier The Verifier Contract /// @param _vkRegistry The VkRegistry Contract /// @param _mode Voting mode + /// @param _gatekeeper The gatekeeper contract + /// @param _initialVoiceCreditProxy The initial voice credit proxy contract function deployPoll( uint256 _duration, TreeDepths memory _treeDepths, @@ -189,7 +165,8 @@ contract MACI is IMACI, DomainObjs, Params, Utilities { address _verifier, address _vkRegistry, Mode _mode, - address _gatekeeper + address _gatekeeper, + address _initialVoiceCreditProxy ) public virtual { // cache the poll to a local variable so we can increment it uint256 pollId = nextPollId; @@ -211,7 +188,8 @@ contract MACI is IMACI, DomainObjs, Params, Utilities { maci: IMACI(address(this)), verifier: IVerifier(_verifier), vkRegistry: IVkRegistry(_vkRegistry), - gatekeeper: ISignUpGatekeeper(_gatekeeper) + gatekeeper: ISignUpGatekeeper(_gatekeeper), + initialVoiceCreditProxy: IInitialVoiceCreditProxy(_initialVoiceCreditProxy) }); address p = pollFactory.deploy( diff --git a/packages/contracts/contracts/Poll.sol b/packages/contracts/contracts/Poll.sol index fe44303073..e90d025b16 100644 --- a/packages/contracts/contracts/Poll.sol +++ b/packages/contracts/contracts/Poll.sol @@ -112,7 +112,7 @@ contract Poll is Params, Utilities, SnarkCommon, IPoll { event PollJoined( uint256 indexed _pollPubKeyX, uint256 indexed _pollPubKeyY, - uint256 _newVoiceCreditBalance, + uint256 _voiceCreditBalance, uint256 _timestamp, uint256 _nullifier, uint256 _pollStateIndex @@ -284,17 +284,18 @@ contract Poll is Params, Utilities, SnarkCommon, IPoll { /// @notice Join the poll for voting /// @param _nullifier Hashed user's private key to check whether user has already voted /// @param _pubKey Poll user's public key - /// @param _newVoiceCreditBalance User's credit balance for voting within this poll - /// @param _stateRootIndex Index of the MACI's stateRootOnSignUp when the user signed up + /// @param _stateRootIndex Index of the MACI's stateRootOnSignUp for which the inclusion proof is generated /// @param _proof The zk-SNARK proof + /// @param _signUpGatekeeperData Data to pass to the SignUpGatekeeper + /// @param _initialVoiceCreditProxyData Data to pass to the InitialVoiceCreditProxy function joinPoll( uint256 _nullifier, PubKey calldata _pubKey, - uint256 _newVoiceCreditBalance, uint256 _stateRootIndex, uint256[8] calldata _proof, - bytes memory _signUpGatekeeperData - ) public virtual isWithinVotingDeadline { + bytes memory _signUpGatekeeperData, + bytes memory _initialVoiceCreditProxyData + ) external virtual isWithinVotingDeadline { // Whether the user has already joined if (pollNullifier[_nullifier]) { revert UserAlreadyJoined(); @@ -304,31 +305,35 @@ contract Poll is Params, Utilities, SnarkCommon, IPoll { pollNullifier[_nullifier] = true; // Verify user's proof - if (!verifyPollProof(_nullifier, _newVoiceCreditBalance, _stateRootIndex, _pubKey, _proof)) { + if (!verifyPollProof(_nullifier, _stateRootIndex, _pubKey, _proof)) { revert InvalidPollProof(); } // Check if the user is eligible to join the poll extContracts.gatekeeper.register(msg.sender, _signUpGatekeeperData); + // Get the user's voice credit balance. + uint256 voiceCreditBalance = extContracts.initialVoiceCreditProxy.getVoiceCredits( + msg.sender, + _initialVoiceCreditProxyData + ); + // Store user in the pollStateTree - uint256 stateLeaf = hashStateLeaf(StateLeaf(_pubKey, _newVoiceCreditBalance, block.timestamp)); + uint256 stateLeaf = hashStateLeaf(StateLeaf(_pubKey, voiceCreditBalance, block.timestamp)); InternalLazyIMT._insert(pollStateTree, stateLeaf); uint256 pollStateIndex = pollStateTree.numberOfLeaves - 1; - emit PollJoined(_pubKey.x, _pubKey.y, _newVoiceCreditBalance, block.timestamp, _nullifier, pollStateIndex); + emit PollJoined(_pubKey.x, _pubKey.y, voiceCreditBalance, block.timestamp, _nullifier, pollStateIndex); } /// @notice Verify the proof for Poll /// @param _nullifier Hashed user's private key to check whether user has already voted - /// @param _voiceCreditBalance User's credit balance for voting /// @param _index Index of the MACI's stateRootOnSignUp when the user signed up /// @param _pubKey Poll user's public key /// @param _proof The zk-SNARK proof /// @return isValid Whether the proof is valid function verifyPollProof( uint256 _nullifier, - uint256 _voiceCreditBalance, uint256 _index, PubKey calldata _pubKey, uint256[8] memory _proof @@ -340,31 +345,28 @@ contract Poll is Params, Utilities, SnarkCommon, IPoll { ); // Generate the circuit public input - uint256[] memory circuitPublicInputs = getPublicCircuitInputs(_nullifier, _voiceCreditBalance, _index, _pubKey); + uint256[] memory circuitPublicInputs = getPublicCircuitInputs(_nullifier, _index, _pubKey); isValid = extContracts.verifier.verify(_proof, vk, circuitPublicInputs); } /// @notice Get public circuit inputs for poll joining circuit /// @param _nullifier Hashed user's private key to check whether user has already voted - /// @param _voiceCreditBalance User's credit balance for voting /// @param _index Index of the MACI's stateRootOnSignUp when the user signed up /// @param _pubKey Poll user's public key /// @return publicInputs Public circuit inputs function getPublicCircuitInputs( uint256 _nullifier, - uint256 _voiceCreditBalance, uint256 _index, PubKey calldata _pubKey ) public view returns (uint256[] memory publicInputs) { - publicInputs = new uint256[](6); + publicInputs = new uint256[](5); publicInputs[0] = _pubKey.x; publicInputs[1] = _pubKey.y; publicInputs[2] = _nullifier; - publicInputs[3] = _voiceCreditBalance; - publicInputs[4] = extContracts.maci.getStateRootOnIndexedSignUp(_index); - publicInputs[5] = pollId; + publicInputs[3] = extContracts.maci.getStateRootOnIndexedSignUp(_index); + publicInputs[4] = pollId; } /// @inheritdoc IPoll diff --git a/packages/contracts/contracts/crypto/SnarkConstants.sol b/packages/contracts/contracts/crypto/SnarkConstants.sol index dd0075b680..782b5fa2b0 100644 --- a/packages/contracts/contracts/crypto/SnarkConstants.sol +++ b/packages/contracts/contracts/crypto/SnarkConstants.sol @@ -15,8 +15,6 @@ contract SnarkConstants { /// confident that no-one knows the private key associated with this /// public key. See: /// https://github.com/iden3/circomlib/blob/d5ed1c3ce4ca137a6b3ca48bec4ac12c1b38957a/src/pedersen_printbases.js - /// Its hash should equal - /// 6769006970205099520508948723718471724660867171122235270773600567925038008762. uint256 internal constant PAD_PUBKEY_X = 10457101036533406547632367118273992217979173478358440826365724437999023779287; uint256 internal constant PAD_PUBKEY_Y = diff --git a/packages/contracts/contracts/interfaces/IInitialVoiceCreditProxy.sol b/packages/contracts/contracts/interfaces/IInitialVoiceCreditProxy.sol new file mode 100644 index 0000000000..546e0e9b6f --- /dev/null +++ b/packages/contracts/contracts/interfaces/IInitialVoiceCreditProxy.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +/// @title IInitialVoiceCreditProxy +/// @notice InitialVoiceCreditProxy interface +interface IInitialVoiceCreditProxy { + /// @notice Get the voice credits of a user + /// @param _user User address + /// @param _data Data to get voice credits + function getVoiceCredits(address _user, bytes memory _data) external view returns (uint256); +} diff --git a/packages/contracts/contracts/interfaces/IPoll.sol b/packages/contracts/contracts/interfaces/IPoll.sol index b17491e6ad..2deeb5e9c5 100644 --- a/packages/contracts/contracts/interfaces/IPoll.sol +++ b/packages/contracts/contracts/interfaces/IPoll.sol @@ -11,10 +11,10 @@ interface IPoll { function joinPoll( uint256 _nullifier, DomainObjs.PubKey calldata _pubKey, - uint256 _newVoiceCreditBalance, uint256 _stateRootIndex, uint256[8] calldata _proof, - bytes memory _signUpGatekeeperData + bytes memory _signUpGatekeeperData, + bytes memory _initialVoiceCreditProxyData ) external; /// @notice The number of messages which have been processed and the number of signups diff --git a/packages/contracts/contracts/trees/LeanIMT.sol b/packages/contracts/contracts/trees/LeanIMT.sol index cc3fe22448..c376f80521 100644 --- a/packages/contracts/contracts/trees/LeanIMT.sol +++ b/packages/contracts/contracts/trees/LeanIMT.sol @@ -45,8 +45,6 @@ library InternalLeanIMT { revert LeafGreaterThanSnarkScalarField(); } else if (leaf == 0) { revert LeafCannotBeZero(); - } else if (_has(self, leaf)) { - revert LeafAlreadyExists(); } uint256 index = self.size; diff --git a/packages/contracts/contracts/utilities/Params.sol b/packages/contracts/contracts/utilities/Params.sol index 91d9fae8e0..b6195451a2 100644 --- a/packages/contracts/contracts/utilities/Params.sol +++ b/packages/contracts/contracts/utilities/Params.sol @@ -5,6 +5,7 @@ import { IMACI } from "../interfaces/IMACI.sol"; import { IVerifier } from "../interfaces/IVerifier.sol"; import { IVkRegistry } from "../interfaces/IVkRegistry.sol"; import { ISignUpGatekeeper } from "../interfaces/ISignUpGatekeeper.sol"; +import { IInitialVoiceCreditProxy } from "../interfaces/IInitialVoiceCreditProxy.sol"; /// @title Params /// @notice This contracts contains a number of structures @@ -26,5 +27,6 @@ contract Params { IVerifier verifier; IVkRegistry vkRegistry; ISignUpGatekeeper gatekeeper; + IInitialVoiceCreditProxy initialVoiceCreditProxy; } } diff --git a/packages/contracts/deploy-config-example.json b/packages/contracts/deploy-config-example.json index 04ab0e3417..136f2888da 100644 --- a/packages/contracts/deploy-config-example.json +++ b/packages/contracts/deploy-config-example.json @@ -66,7 +66,8 @@ "pollDuration": 3600, "coordinatorPubkey": "macipk.9a59264310d95cfd8eb7083aebeba221b5c26e77427f12b7c0f50bc1cc35e621", "useQuadraticVoting": false, - "gatekeeper": "FreeForAllGatekeeper" + "gatekeeper": "FreeForAllGatekeeper", + "initialVoiceCreditProxy": "ConstantInitialVoiceCreditProxy" } }, "scroll_sepolia": { @@ -135,7 +136,8 @@ "pollDuration": 10800, "coordinatorPubkey": "macipk.0a1ce79a43fa676ee3d2882c79d9164a24d4a22bb6190e3d8fa25d97bffc069a", "useQuadraticVoting": false, - "gatekeeper": "FreeForAllGatekeeper" + "gatekeeper": "FreeForAllGatekeeper", + "initialVoiceCreditProxy": "ConstantInitialVoiceCreditProxy" } }, "optimism": { @@ -205,7 +207,8 @@ "pollDuration": 3600, "coordinatorPubkey": "macipk.9a59264310d95cfd8eb7083aebeba221b5c26e77427f12b7c0f50bc1cc35e621", "useQuadraticVoting": false, - "gatekeeper": "FreeForAllGatekeeper" + "gatekeeper": "FreeForAllGatekeeper", + "initialVoiceCreditProxy": "ConstantInitialVoiceCreditProxy" } }, "arbitrum_sepolia": { @@ -275,7 +278,8 @@ "pollDuration": 3600, "coordinatorPubkey": "macipk.9a59264310d95cfd8eb7083aebeba221b5c26e77427f12b7c0f50bc1cc35e621", "useQuadraticVoting": false, - "gatekeeper": "FreeForAllGatekeeper" + "gatekeeper": "FreeForAllGatekeeper", + "initialVoiceCreditProxy": "ConstantInitialVoiceCreditProxy" } }, "localhost": { @@ -345,7 +349,8 @@ "pollDuration": 30, "coordinatorPubkey": "macipk.29add77d27341c4cdfc2fb623175ecfd6527a286e3e7ded785d9fd7afbbdf399", "useQuadraticVoting": false, - "gatekeeper": "FreeForAllGatekeeper" + "gatekeeper": "FreeForAllGatekeeper", + "initialVoiceCreditProxy": "ConstantInitialVoiceCreditProxy" } }, "base_sepolia": { @@ -415,7 +420,8 @@ "pollDuration": 3600, "coordinatorPubkey": "macipk.9a59264310d95cfd8eb7083aebeba221b5c26e77427f12b7c0f50bc1cc35e621", "useQuadraticVoting": false, - "gatekeeper": "FreeForAllGatekeeper" + "gatekeeper": "FreeForAllGatekeeper", + "initialVoiceCreditProxy": "ConstantInitialVoiceCreditProxy" } }, "optimism_sepolia": { @@ -490,7 +496,8 @@ "pollDuration": 3600, "coordinatorPubkey": "macipk.9a59264310d95cfd8eb7083aebeba221b5c26e77427f12b7c0f50bc1cc35e621", "useQuadraticVoting": false, - "gatekeeper": "FreeForAllGatekeeper" + "gatekeeper": "FreeForAllGatekeeper", + "initialVoiceCreditProxy": "ConstantInitialVoiceCreditProxy" } }, "gnosis_chiado": { @@ -565,7 +572,8 @@ "pollDuration": 3600, "coordinatorPubkey": "macipk.0a1ce79a43fa676ee3d2882c79d9164a24d4a22bb6190e3d8fa25d97bffc069a", "useQuadraticVoting": false, - "gatekeeper": "FreeForAllGatekeeper" + "gatekeeper": "FreeForAllGatekeeper", + "initialVoiceCreditProxy": "ConstantInitialVoiceCreditProxy" } }, "gnosis": { @@ -640,7 +648,8 @@ "pollDuration": 3600, "coordinatorPubkey": "macipk.0a1ce79a43fa676ee3d2882c79d9164a24d4a22bb6190e3d8fa25d97bffc069a", "useQuadraticVoting": false, - "gatekeeper": "FreeForAllGatekeeper" + "gatekeeper": "FreeForAllGatekeeper", + "initialVoiceCreditProxy": "ConstantInitialVoiceCreditProxy" } }, "polygon_amoy": { @@ -715,7 +724,8 @@ "pollDuration": 3600, "coordinatorPubkey": "macipk.0a1ce79a43fa676ee3d2882c79d9164a24d4a22bb6190e3d8fa25d97bffc069a", "useQuadraticVoting": true, - "gatekeeper": "FreeForAllGatekeeper" + "gatekeeper": "FreeForAllGatekeeper", + "initialVoiceCreditProxy": "ConstantInitialVoiceCreditProxy" } }, "polygon": { @@ -790,7 +800,8 @@ "pollDuration": 3600, "coordinatorPubkey": "macipk.0a1ce79a43fa676ee3d2882c79d9164a24d4a22bb6190e3d8fa25d97bffc069a", "useQuadraticVoting": true, - "gatekeeper": "FreeForAllGatekeeper" + "gatekeeper": "FreeForAllGatekeeper", + "initialVoiceCreditProxy": "ConstantInitialVoiceCreditProxy" } } } diff --git a/packages/contracts/tasks/deploy/maci/02-gatekeepers.ts b/packages/contracts/tasks/deploy/maci/01-gatekeepers.ts similarity index 100% rename from packages/contracts/tasks/deploy/maci/02-gatekeepers.ts rename to packages/contracts/tasks/deploy/maci/01-gatekeepers.ts diff --git a/packages/contracts/tasks/deploy/maci/03-verifier.ts b/packages/contracts/tasks/deploy/maci/02-verifier.ts similarity index 100% rename from packages/contracts/tasks/deploy/maci/03-verifier.ts rename to packages/contracts/tasks/deploy/maci/02-verifier.ts diff --git a/packages/contracts/tasks/deploy/maci/04-poseidon.ts b/packages/contracts/tasks/deploy/maci/03-poseidon.ts similarity index 100% rename from packages/contracts/tasks/deploy/maci/04-poseidon.ts rename to packages/contracts/tasks/deploy/maci/03-poseidon.ts diff --git a/packages/contracts/tasks/deploy/maci/05-pollFactory.ts b/packages/contracts/tasks/deploy/maci/04-pollFactory.ts similarity index 100% rename from packages/contracts/tasks/deploy/maci/05-pollFactory.ts rename to packages/contracts/tasks/deploy/maci/04-pollFactory.ts diff --git a/packages/contracts/tasks/deploy/maci/06-messageProcessorFactory.ts b/packages/contracts/tasks/deploy/maci/05-messageProcessorFactory.ts similarity index 100% rename from packages/contracts/tasks/deploy/maci/06-messageProcessorFactory.ts rename to packages/contracts/tasks/deploy/maci/05-messageProcessorFactory.ts diff --git a/packages/contracts/tasks/deploy/maci/07-tallyFactory.ts b/packages/contracts/tasks/deploy/maci/06-tallyFactory.ts similarity index 100% rename from packages/contracts/tasks/deploy/maci/07-tallyFactory.ts rename to packages/contracts/tasks/deploy/maci/06-tallyFactory.ts diff --git a/packages/contracts/tasks/deploy/maci/08-maci.ts b/packages/contracts/tasks/deploy/maci/07-maci.ts similarity index 93% rename from packages/contracts/tasks/deploy/maci/08-maci.ts rename to packages/contracts/tasks/deploy/maci/07-maci.ts index 81d687775b..c403a7284e 100644 --- a/packages/contracts/tasks/deploy/maci/08-maci.ts +++ b/packages/contracts/tasks/deploy/maci/07-maci.ts @@ -42,10 +42,6 @@ deployment.deployTask(EDeploySteps.Maci, "Deploy MACI contract").then((task) => }, }); - const constantInitialVoiceCreditProxyContractAddress = storage.mustGetAddress( - EContracts.ConstantInitialVoiceCreditProxy, - hre.network.name, - ); const gatekeeper = deployment.getDeployConfigField(EContracts.MACI, "gatekeeper") || EContracts.FreeForAllGatekeeper; @@ -68,7 +64,6 @@ deployment.deployTask(EDeploySteps.Maci, "Deploy MACI contract").then((task) => messageProcessorFactoryContractAddress, tallyFactoryContractAddress, gatekeeperContractAddress, - constantInitialVoiceCreditProxyContractAddress, stateTreeDepth, emptyBallotRoots, ); @@ -90,7 +85,6 @@ deployment.deployTask(EDeploySteps.Maci, "Deploy MACI contract").then((task) => messageProcessorFactoryContractAddress, tallyFactoryContractAddress, gatekeeperContractAddress, - constantInitialVoiceCreditProxyContractAddress, stateTreeDepth, emptyBallotRoots.map((root) => root.toString()), ], diff --git a/packages/contracts/tasks/deploy/maci/09-vkRegistry.ts b/packages/contracts/tasks/deploy/maci/08-vkRegistry.ts similarity index 100% rename from packages/contracts/tasks/deploy/maci/09-vkRegistry.ts rename to packages/contracts/tasks/deploy/maci/08-vkRegistry.ts diff --git a/packages/contracts/tasks/deploy/maci/01-constantInitialVoiceCreditProxy.ts b/packages/contracts/tasks/deploy/poll/01-constantInitialVoiceCreditProxy.ts similarity index 100% rename from packages/contracts/tasks/deploy/maci/01-constantInitialVoiceCreditProxy.ts rename to packages/contracts/tasks/deploy/poll/01-constantInitialVoiceCreditProxy.ts diff --git a/packages/contracts/tasks/deploy/poll/01-gatekeepers.ts b/packages/contracts/tasks/deploy/poll/02-gatekeepers.ts similarity index 100% rename from packages/contracts/tasks/deploy/poll/01-gatekeepers.ts rename to packages/contracts/tasks/deploy/poll/02-gatekeepers.ts diff --git a/packages/contracts/tasks/deploy/poll/02-poll.ts b/packages/contracts/tasks/deploy/poll/03-poll.ts similarity index 94% rename from packages/contracts/tasks/deploy/poll/02-poll.ts rename to packages/contracts/tasks/deploy/poll/03-poll.ts index 98b48ee5b8..f280b04566 100644 --- a/packages/contracts/tasks/deploy/poll/02-poll.ts +++ b/packages/contracts/tasks/deploy/poll/03-poll.ts @@ -53,6 +53,10 @@ deployment.deployTask(EDeploySteps.Poll, "Deploy poll").then((task) => deployment.getDeployConfigField(EContracts.Poll, "gatekeeper") || EContracts.FreeForAllGatekeeper; const gatekeeperContractAddress = storage.mustGetAddress(gatekeeper, hre.network.name, `poll-${pollId}`); + const initialVoiceCreditProxyContractAddress = storage.mustGetAddress( + EContracts.ConstantInitialVoiceCreditProxy, + hre.network.name, + ); const tx = await maciContract.deployPoll( pollDuration, @@ -66,6 +70,7 @@ deployment.deployTask(EDeploySteps.Poll, "Deploy poll").then((task) => vkRegistryContractAddress, mode, gatekeeperContractAddress, + initialVoiceCreditProxyContractAddress, ); const receipt = await tx.wait(); @@ -110,6 +115,8 @@ deployment.deployTask(EDeploySteps.Poll, "Deploy poll").then((task) => unserializedKey.asContractParam(), extContracts, emptyBallotRoot.toString(), + gatekeeperContractAddress, + initialVoiceCreditProxyContractAddress, ], network: hre.network.name, }), diff --git a/packages/contracts/tasks/helpers/ProofGenerator.ts b/packages/contracts/tasks/helpers/ProofGenerator.ts index 7583a0c550..ac1bd3e313 100644 --- a/packages/contracts/tasks/helpers/ProofGenerator.ts +++ b/packages/contracts/tasks/helpers/ProofGenerator.ts @@ -252,7 +252,7 @@ export class ProofGenerator { console.log(`Generating proofs of vote tallying...`); const { tallyBatchSize } = this.poll.batchSizes; - const numStateLeaves = this.poll.stateLeaves.length; + const numStateLeaves = this.poll.pollStateLeaves.length; let totalTallyBatches = numStateLeaves <= tallyBatchSize ? 1 : Math.floor(numStateLeaves / tallyBatchSize); if (numStateLeaves > tallyBatchSize && numStateLeaves % tallyBatchSize > 0) { totalTallyBatches += 1; diff --git a/packages/contracts/tasks/helpers/constants.ts b/packages/contracts/tasks/helpers/constants.ts index f8bcfec6c2..e0bbbbeac7 100644 --- a/packages/contracts/tasks/helpers/constants.ts +++ b/packages/contracts/tasks/helpers/constants.ts @@ -2,7 +2,6 @@ * Deploy steps */ export enum EDeploySteps { - ConstantInitialVoiceCreditProxy = "full:deploy-constant-initial-voice-credit-proxy", Gatekeepers = "full:deploy-gatekeepers", Verifier = "full:deploy-verifier", Poseidon = "full:deploy-poseidon", @@ -11,6 +10,7 @@ export enum EDeploySteps { TallyFactory = "full:deploy-tally-factory", Maci = "full:deploy-maci", VkRegistry = "full:deploy-vk-registry", + ConstantInitialVoiceCreditProxy = "poll:deploy-constant-initial-voice-credit-proxy", PollGatekeeper = "poll:deploy-gatekeeper", Poll = "poll:deploy-poll", } diff --git a/packages/contracts/tests/MACI.test.ts b/packages/contracts/tests/MACI.test.ts index 8c8d6a03ae..d92f27c74b 100644 --- a/packages/contracts/tests/MACI.test.ts +++ b/packages/contracts/tests/MACI.test.ts @@ -1,24 +1,16 @@ /* eslint-disable no-underscore-dangle */ import { expect } from "chai"; import { AbiCoder, BigNumberish, Signer, ZeroAddress } from "ethers"; -import { EthereumProvider } from "hardhat/types"; import { MaciState } from "maci-core"; import { NOTHING_UP_MY_SLEEVE } from "maci-crypto"; import { Keypair, PubKey, Message } from "maci-domainobjs"; import { EMode } from "../ts/constants"; import { getDefaultSigner, getSigners } from "../ts/utils"; -import { - MACI, - Poll as PollContract, - Poll__factory as PollFactory, - Verifier, - VkRegistry, - SignUpGatekeeper, -} from "../typechain-types"; +import { MACI, Verifier, VkRegistry, SignUpGatekeeper, ConstantInitialVoiceCreditProxy } from "../typechain-types"; import { STATE_TREE_DEPTH, duration, initialVoiceCreditBalance, messageBatchSize, treeDepths } from "./constants"; -import { timeTravel, deployTestContracts } from "./utils"; +import { deployTestContracts } from "./utils"; describe("MACI", function test() { this.timeout(90000); @@ -27,6 +19,7 @@ describe("MACI", function test() { let vkRegistryContract: VkRegistry; let verifierContract: Verifier; let signupGatekeeperContract: SignUpGatekeeper; + let initialVoiceCreditProxy: ConstantInitialVoiceCreditProxy; let pollId: bigint; const coordinator = new Keypair(); @@ -49,6 +42,7 @@ describe("MACI", function test() { vkRegistryContract = r.vkRegistryContract; verifierContract = r.mockVerifierContract as Verifier; signupGatekeeperContract = r.gatekeeperContract; + initialVoiceCreditProxy = r.constantInitialVoiceCreditProxyContract; }); it("should have set the correct stateTreeDepth", async () => { @@ -83,7 +77,6 @@ describe("MACI", function test() { const tx = await maciContract.signUp( user.pubKey.asContractParam(), AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [0]), ); // eslint-disable-next-line no-await-in-loop const receipt = await tx.wait(); @@ -101,11 +94,7 @@ describe("MACI", function test() { expect(event.args._stateIndex.toString()).to.eq((index + 1).toString()); - maciState.signUp( - user.pubKey, - BigInt(event.args._voiceCreditBalance.toString()), - BigInt(event.args._timestamp.toString()), - ); + maciState.signUp(user.pubKey); } }); @@ -117,7 +106,6 @@ describe("MACI", function test() { y: "0", }, AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [0]), ), ).to.be.revertedWithCustomError(maciContract, "InvalidPubKey"); }); @@ -130,7 +118,6 @@ describe("MACI", function test() { y: "21888242871839275222246405745257275088548364400416034343698204186575808495617", }, AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [0]), ), ).to.be.revertedWithCustomError(maciContract, "InvalidPubKey"); }); @@ -143,7 +130,6 @@ describe("MACI", function test() { y: "21888242871839275222246405745257275088548364400416034343698204186575808495617", }, AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [0]), ), ).to.be.revertedWithCustomError(maciContract, "InvalidPubKey"); }); @@ -156,7 +142,6 @@ describe("MACI", function test() { y: "1", }, AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [0]), ), ).to.be.revertedWithCustomError(maciContract, "InvalidPubKey"); }); @@ -175,20 +160,12 @@ describe("MACI", function test() { // start from one as we already have one signup (blank state leaf) for (let i = 1; i < maxUsers; i += 1) { // eslint-disable-next-line no-await-in-loop - await maci.signUp( - keypair.pubKey.asContractParam(), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [0]), - ); + await maci.signUp(keypair.pubKey.asContractParam(), AbiCoder.defaultAbiCoder().encode(["uint256"], [1])); } // the next signup should fail await expect( - maci.signUp( - keypair.pubKey.asContractParam(), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [0]), - ), + maci.signUp(keypair.pubKey.asContractParam(), AbiCoder.defaultAbiCoder().encode(["uint256"], [1])), ).to.be.revertedWithCustomError(maciContract, "TooManySignups"); }); @@ -205,11 +182,7 @@ describe("MACI", function test() { // start from one as we already have one signup (blank state leaf) for (let i = 1; i < maxUsers; i += 1) { // eslint-disable-next-line no-await-in-loop - await maci.signUp( - keypair.pubKey.asContractParam(), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [0]), - ); + await maci.signUp(keypair.pubKey.asContractParam(), AbiCoder.defaultAbiCoder().encode(["uint256"], [1])); } }); }); @@ -228,6 +201,7 @@ describe("MACI", function test() { vkRegistryContract, EMode.QV, signupGatekeeperContract, + initialVoiceCreditProxy, ); const receipt = await tx.wait(); @@ -263,6 +237,7 @@ describe("MACI", function test() { vkRegistryContract, EMode.QV, signupGatekeeperContract, + initialVoiceCreditProxy, ); const receipt = await tx.wait(); expect(receipt?.status).to.eq(1); @@ -282,6 +257,7 @@ describe("MACI", function test() { vkRegistryContract, EMode.QV, signupGatekeeperContract, + initialVoiceCreditProxy, ); const receipt = await tx.wait(); expect(receipt?.status).to.eq(1); @@ -289,51 +265,6 @@ describe("MACI", function test() { }); }); - describe("Merge sign-ups", () => { - let pollContract: PollContract; - - before(async () => { - const pollContracts = await maciContract.getPoll(pollId); - pollContract = PollFactory.connect(pollContracts.poll, signer); - }); - - it("should allow a Poll contract to merge the state tree (calculate the state root)", async () => { - await timeTravel(signer.provider as unknown as EthereumProvider, Number(duration) + 1); - - const tx = await pollContract.mergeState(); - const receipt = await tx.wait(); - expect(receipt?.status).to.eq(1); - }); - - it("should allow a user to signup after the state tree root was calculated", async () => { - const tx = await maciContract.signUp( - users[0].pubKey.asContractParam(), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [0]), - ); - const receipt = await tx.wait(); - expect(receipt?.status).to.eq(1); - - const iface = maciContract.interface; - - // Store the state index - const log = receipt!.logs[receipt!.logs.length - 1]; - const event = iface.parseLog(log as unknown as { topics: string[]; data: string }) as unknown as { - args: { - _stateIndex: BigNumberish; - _voiceCreditBalance: BigNumberish; - _timestamp: BigNumberish; - }; - }; - - maciState.signUp( - users[0].pubKey, - BigInt(event.args._voiceCreditBalance.toString()), - BigInt(event.args._timestamp.toString()), - ); - }); - }); - describe("getPoll", () => { it("should return an object for a valid id", async () => { const pollContracts = await maciContract.getPoll(pollId); diff --git a/packages/contracts/tests/MessageProcessor.test.ts b/packages/contracts/tests/MessageProcessor.test.ts index 6702b30619..1060b17d03 100644 --- a/packages/contracts/tests/MessageProcessor.test.ts +++ b/packages/contracts/tests/MessageProcessor.test.ts @@ -16,6 +16,7 @@ import { Verifier, VkRegistry, SignUpGatekeeper, + ConstantInitialVoiceCreditProxy, } from "../typechain-types"; import { @@ -36,6 +37,7 @@ describe("MessageProcessor", () => { let vkRegistryContract: VkRegistry; let mpContract: MessageProcessor; let signupGatekeeperContract: SignUpGatekeeper; + let initialVoiceCreditProxyContract: ConstantInitialVoiceCreditProxy; let pollId: bigint; // local poll and maci state @@ -59,6 +61,8 @@ describe("MessageProcessor", () => { verifierContract = r.mockVerifierContract as Verifier; vkRegistryContract = r.vkRegistryContract; signupGatekeeperContract = r.gatekeeperContract; + initialVoiceCreditProxyContract = r.constantInitialVoiceCreditProxyContract; + // deploy on chain poll const tx = await maciContract.deployPoll( duration, @@ -69,6 +73,7 @@ describe("MessageProcessor", () => { vkRegistryContract, EMode.QV, signupGatekeeperContract, + initialVoiceCreditProxyContract, ); let receipt = await tx.wait(); @@ -107,7 +112,7 @@ describe("MessageProcessor", () => { } // update the poll state - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); generatedInputs = poll.processMessages(pollId); diff --git a/packages/contracts/tests/Poll.test.ts b/packages/contracts/tests/Poll.test.ts index 935a731807..5b156e313c 100644 --- a/packages/contracts/tests/Poll.test.ts +++ b/packages/contracts/tests/Poll.test.ts @@ -17,6 +17,7 @@ import { Verifier, VkRegistry, SignUpGatekeeper, + ConstantInitialVoiceCreditProxy, } from "../typechain-types"; import { @@ -38,6 +39,7 @@ describe("Poll", () => { let verifierContract: Verifier; let vkRegistryContract: VkRegistry; let signupGatekeeperContract: SignUpGatekeeper; + let initialVoiceCreditProxyContract: ConstantInitialVoiceCreditProxy; let signer: Signer; let deployTime: number; const coordinator = new Keypair(); @@ -46,7 +48,7 @@ describe("Poll", () => { const keypair = new Keypair(); - const NUM_USERS = 2; + const NUM_USERS = 3; describe("deployment", () => { before(async () => { @@ -60,18 +62,14 @@ describe("Poll", () => { verifierContract = r.mockVerifierContract as Verifier; vkRegistryContract = r.vkRegistryContract; signupGatekeeperContract = r.gatekeeperContract; + initialVoiceCreditProxyContract = r.constantInitialVoiceCreditProxyContract; for (let i = 0; i < NUM_USERS; i += 1) { - const timestamp = Math.floor(Date.now() / 1000); const user = new Keypair(); - maciState.signUp(user.pubKey, BigInt(initialVoiceCreditBalance), BigInt(timestamp), BigInt(0)); + maciState.signUp(user.pubKey); // eslint-disable-next-line no-await-in-loop - await maciContract.signUp( - user.pubKey.asContractParam(), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [0]), - ); + await maciContract.signUp(user.pubKey.asContractParam(), AbiCoder.defaultAbiCoder().encode(["uint256"], [1])); } // deploy on chain poll @@ -84,6 +82,7 @@ describe("Poll", () => { vkRegistryContract, EMode.QV, signupGatekeeperContract, + initialVoiceCreditProxyContract, ); const receipt = await tx.wait(); @@ -188,35 +187,36 @@ describe("Poll", () => { r.vkRegistryContract, EMode.QV, signupGatekeeperContract, + initialVoiceCreditProxyContract, ), ).to.be.revertedWithCustomError(testMaciContract, "InvalidPubKey"); }); }); describe("Poll join", () => { - it("The users have joined the poll", async () => { + it("should let users join the poll", async () => { const iface = pollContract.interface; const pubkey = keypair.pubKey.asContractParam(); const mockProof = [0, 0, 0, 0, 0, 0, 0, 0]; for (let i = 0; i < NUM_USERS; i += 1) { const mockNullifier = AbiCoder.defaultAbiCoder().encode(["uint256"], [i]); - const voiceCreditBalance = AbiCoder.defaultAbiCoder().encode(["uint256"], [i]); const response = await pollContract.joinPoll( mockNullifier, pubkey, - voiceCreditBalance, i, mockProof, AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), + AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), ); const receipt = await response.wait(); const logs = receipt!.logs[0]; const event = iface.parseLog(logs as unknown as { topics: string[]; data: string }) as unknown as { - args: { _pollStateIndex: bigint }; + args: { _pollStateIndex: bigint; _voiceCreditBalance: bigint }; }; const index = event.args._pollStateIndex; + const voiceCredits = event.args._voiceCreditBalance; expect(receipt!.status).to.eq(1); @@ -225,32 +225,31 @@ describe("Poll", () => { const expectedIndex = maciState.polls .get(pollId) - ?.joinPoll(BigInt(mockNullifier), keypair.pubKey, BigInt(voiceCreditBalance), BigInt(timestamp)); + ?.joinPoll(BigInt(mockNullifier), keypair.pubKey, BigInt(voiceCredits), BigInt(timestamp)); expect(index).to.eq(expectedIndex); } }); - it("Poll state tree size after user's joining", async () => { + it("should have the correct tree size", async () => { const pollStateTree = await pollContract.pollStateTree(); const size = Number(pollStateTree.numberOfLeaves); expect(size).to.eq(maciState.polls.get(pollId)?.pollStateLeaves.length); }); - it("The first user has been rejected for the second join", async () => { + it("should not allow a user to join twice", async () => { const mockNullifier = AbiCoder.defaultAbiCoder().encode(["uint256"], [0]); const pubkey = keypair.pubKey.asContractParam(); - const voiceCreditBalance = AbiCoder.defaultAbiCoder().encode(["uint256"], [0]); const mockProof = [0, 0, 0, 0, 0, 0, 0, 0]; await expect( pollContract.joinPoll( mockNullifier, pubkey, - voiceCreditBalance, 0, mockProof, AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), + AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), ), ).to.be.revertedWithCustomError(pollContract, "UserAlreadyJoined"); }); @@ -380,12 +379,12 @@ describe("Poll", () => { it("should allow a Poll contract to merge the state tree (calculate the state root)", async () => { await timeTravel(signer.provider as unknown as EthereumProvider, Number(duration) + 1); - const tx = await pollContract.mergeState({ - gasLimit: 3000000, - }); + const tx = await pollContract.mergeState(); const receipt = await tx.wait(); expect(receipt?.status).to.eq(1); + + expect(await pollContract.stateMerged()).to.eq(true); }); it("should get the correct numSignUps", async () => { @@ -396,6 +395,7 @@ describe("Poll", () => { it("should get the correct mergedStateRoot", async () => { const mergedStateRoot = await pollContract.mergedStateRoot(); + expect(mergedStateRoot.toString()).to.eq(maciState.polls.get(pollId)?.pollStateTree?.root.toString()); }); }); diff --git a/packages/contracts/tests/PollFactory.test.ts b/packages/contracts/tests/PollFactory.test.ts index e7d08468ba..59a9cf5b1e 100644 --- a/packages/contracts/tests/PollFactory.test.ts +++ b/packages/contracts/tests/PollFactory.test.ts @@ -38,6 +38,7 @@ describe("pollFactory", () => { verifier: verifierContract, vkRegistry: vkRegistryContract, gatekeeper: r.gatekeeperContract, + initialVoiceCreditProxy: r.constantInitialVoiceCreditProxyContract, }; pollFactory = (await deployPollFactory(signer, undefined, true)) as BaseContract as PollFactory; diff --git a/packages/contracts/tests/Tally.test.ts b/packages/contracts/tests/Tally.test.ts index d8a25fd2de..7024dc9178 100644 --- a/packages/contracts/tests/Tally.test.ts +++ b/packages/contracts/tests/Tally.test.ts @@ -20,6 +20,7 @@ import { Poll__factory as PollFactory, Tally__factory as TallyFactory, SignUpGatekeeper, + ConstantInitialVoiceCreditProxy, } from "../typechain-types"; import { @@ -43,6 +44,7 @@ describe("TallyVotes", () => { let verifierContract: Verifier; let vkRegistryContract: VkRegistry; let signupGatekeeperContract: SignUpGatekeeper; + let initialVoiceCreditProxyContract: ConstantInitialVoiceCreditProxy; const coordinator = new Keypair(); let users: Keypair[]; @@ -66,6 +68,7 @@ describe("TallyVotes", () => { verifierContract = r.mockVerifierContract as Verifier; vkRegistryContract = r.vkRegistryContract; signupGatekeeperContract = r.gatekeeperContract; + initialVoiceCreditProxyContract = r.constantInitialVoiceCreditProxyContract; // deploy a poll // deploy on chain poll @@ -78,6 +81,7 @@ describe("TallyVotes", () => { vkRegistryContract, EMode.QV, signupGatekeeperContract, + initialVoiceCreditProxyContract, ); const receipt = await tx.wait(); @@ -113,7 +117,7 @@ describe("TallyVotes", () => { poll.publishMessage(message, padKey); // update the poll state - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); // process messages locally generatedInputs = poll.processMessages(pollId); @@ -209,16 +213,14 @@ describe("TallyVotes", () => { // signup all users // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let i = 0; i < users.length; i += 1) { - const timestamp = Math.floor(Date.now() / 1000); // signup locally - maciState.signUp(users[i].pubKey, BigInt(initialVoiceCreditBalance), BigInt(timestamp)); + maciState.signUp(users[i].pubKey); // signup on chain // eslint-disable-next-line no-await-in-loop await maciContract.signUp( users[i].pubKey.asContractParam(), AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [0]), ); } @@ -236,6 +238,7 @@ describe("TallyVotes", () => { vkRegistryContract, EMode.QV, signupGatekeeperContract, + initialVoiceCreditProxyContract, ); const receipt = await tx.wait(); @@ -279,7 +282,7 @@ describe("TallyVotes", () => { poll.publishMessage(message, padKey); // update the poll state - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); await vkRegistryContract.setPollVkKey( STATE_TREE_DEPTH, @@ -310,10 +313,10 @@ describe("TallyVotes", () => { await pollContract.joinPoll( nullifier, pollKeys[i].pubKey.asContractParam(), - BigInt(initialVoiceCreditBalance), i, [0, 0, 0, 0, 0, 0, 0, 0], AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), + AbiCoder.defaultAbiCoder().encode(["uint256"], [0]), ); } @@ -518,16 +521,14 @@ describe("TallyVotes", () => { // signup all users // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let i = 0; i < users.length; i += 1) { - const timestamp = Math.floor(Date.now() / 1000); // signup locally - maciState.signUp(users[i].pubKey, BigInt(initialVoiceCreditBalance), BigInt(timestamp)); + maciState.signUp(users[i].pubKey); // signup on chain // eslint-disable-next-line no-await-in-loop await maciContract.signUp( users[i].pubKey.asContractParam(), AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [0]), ); } @@ -545,6 +546,7 @@ describe("TallyVotes", () => { vkRegistryContract, EMode.QV, signupGatekeeperContract, + initialVoiceCreditProxyContract, ); const receipt = await tx.wait(); @@ -588,7 +590,7 @@ describe("TallyVotes", () => { poll.publishMessage(message, padKey); // update the poll state - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); // set the verification keys on the vk smart contract await vkRegistryContract.setPollVkKey( @@ -620,10 +622,10 @@ describe("TallyVotes", () => { await pollContract.joinPoll( nullifier, pollKeys[i].pubKey.asContractParam(), - BigInt(initialVoiceCreditBalance), i, [0, 0, 0, 0, 0, 0, 0, 0], AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), + AbiCoder.defaultAbiCoder().encode(["uint256"], [0]), ); } diff --git a/packages/contracts/tests/TallyNonQv.test.ts b/packages/contracts/tests/TallyNonQv.test.ts index 9187925de8..3148e18805 100644 --- a/packages/contracts/tests/TallyNonQv.test.ts +++ b/packages/contracts/tests/TallyNonQv.test.ts @@ -20,6 +20,7 @@ import { Poll__factory as PollFactory, Tally__factory as TallyFactory, SignUpGatekeeper, + ConstantInitialVoiceCreditProxy, } from "../typechain-types"; import { STATE_TREE_DEPTH, duration, messageBatchSize, testProcessVk, testTallyVk, treeDepths } from "./constants"; @@ -34,7 +35,7 @@ describe("TallyVotesNonQv", () => { let verifierContract: Verifier; let vkRegistryContract: VkRegistry; let gatekeeperContract: SignUpGatekeeper; - + let initialVoiceCreditProxyContract: ConstantInitialVoiceCreditProxy; const coordinator = new Keypair(); let maciState: MaciState; @@ -53,6 +54,7 @@ describe("TallyVotesNonQv", () => { verifierContract = r.mockVerifierContract as Verifier; vkRegistryContract = r.vkRegistryContract; gatekeeperContract = r.gatekeeperContract; + initialVoiceCreditProxyContract = r.constantInitialVoiceCreditProxyContract; // deploy a poll // deploy on chain poll @@ -65,6 +67,7 @@ describe("TallyVotesNonQv", () => { vkRegistryContract, EMode.NON_QV, gatekeeperContract, + initialVoiceCreditProxyContract, ); const receipt = await tx.wait(); @@ -100,7 +103,7 @@ describe("TallyVotesNonQv", () => { poll.publishMessage(message, padKey); // update the poll state - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); // process messages locally generatedInputs = poll.processMessages(pollId, false); diff --git a/packages/contracts/tests/constants.ts b/packages/contracts/tests/constants.ts index ac2b747dcf..7b543b9b24 100644 --- a/packages/contracts/tests/constants.ts +++ b/packages/contracts/tests/constants.ts @@ -8,6 +8,7 @@ export interface ExtContractsStruct { verifier: AddressLike; vkRegistry: AddressLike; gatekeeper: AddressLike; + initialVoiceCreditProxy: AddressLike; } export const duration = 2_000; diff --git a/packages/contracts/tests/gatekeepers/AnonAadhaarGatekeeper.test.ts b/packages/contracts/tests/gatekeepers/AnonAadhaarGatekeeper.test.ts index 815ba7d0aa..213f9418af 100644 --- a/packages/contracts/tests/gatekeepers/AnonAadhaarGatekeeper.test.ts +++ b/packages/contracts/tests/gatekeepers/AnonAadhaarGatekeeper.test.ts @@ -118,11 +118,7 @@ describe("AnonAadhaar Gatekeeper", () => { ); await expect( - maciContract.signUp( - user.pubKey.asContractParam(), - encodedInvalidNullifierSeedProof, - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ), + maciContract.signUp(user.pubKey.asContractParam(), encodedInvalidNullifierSeedProof), ).to.be.revertedWithCustomError(anonAadhaarGatekeeper, "InvalidNullifierSeed"); }); @@ -139,32 +135,21 @@ describe("AnonAadhaar Gatekeeper", () => { ], ); await expect( - maciContract.signUp( - user.pubKey.asContractParam(), - encodedInvalidProof, - AbiCoder.defaultAbiCoder().encode(["uint256"], [0]), - ), + maciContract.signUp(user.pubKey.asContractParam(), encodedInvalidProof), ).to.be.revertedWithCustomError(anonAadhaarGatekeeper, "InvalidSignal"); }); it("should revert if the proof is invalid (mock)", async () => { await mockAnonAadhaar.flipValid(); - await expect( - maciContract.signUp( - user.pubKey.asContractParam(), - encodedProof, - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ), - ).to.be.revertedWithCustomError(anonAadhaarGatekeeper, "InvalidProof"); + await expect(maciContract.signUp(user.pubKey.asContractParam(), encodedProof)).to.be.revertedWithCustomError( + anonAadhaarGatekeeper, + "InvalidProof", + ); await mockAnonAadhaar.flipValid(); }); it("should register a user if the register function is called with the valid data", async () => { - const tx = await maciContract.signUp( - user.pubKey.asContractParam(), - encodedProof, - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ); + const tx = await maciContract.signUp(user.pubKey.asContractParam(), encodedProof); const receipt = await tx.wait(); @@ -172,13 +157,10 @@ describe("AnonAadhaar Gatekeeper", () => { }); it("should prevent signing up twice", async () => { - await expect( - maciContract.signUp( - user.pubKey.asContractParam(), - encodedProof, - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ), - ).to.be.revertedWithCustomError(anonAadhaarGatekeeper, "AlreadyRegistered"); + await expect(maciContract.signUp(user.pubKey.asContractParam(), encodedProof)).to.be.revertedWithCustomError( + anonAadhaarGatekeeper, + "AlreadyRegistered", + ); }); }); }); diff --git a/packages/contracts/tests/gatekeepers/EASGatekeeper.test.ts b/packages/contracts/tests/gatekeepers/EASGatekeeper.test.ts index eddd1cff0a..d56c3b7d41 100644 --- a/packages/contracts/tests/gatekeepers/EASGatekeeper.test.ts +++ b/packages/contracts/tests/gatekeepers/EASGatekeeper.test.ts @@ -1,5 +1,5 @@ import { expect } from "chai"; -import { AbiCoder, Signer, ZeroAddress, toBeArray } from "ethers"; +import { Signer, ZeroAddress, toBeArray } from "ethers"; import { Keypair } from "maci-domainobjs"; import { deployContract } from "../../ts/deploy"; @@ -124,11 +124,7 @@ describe("EAS Gatekeeper", () => { await easGatekeeper.setMaciInstance(await maciContract.getAddress()).then((tx) => tx.wait()); // signup via MACI - const tx = await maciContract.signUp( - user.pubKey.asContractParam(), - attestation, - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ); + const tx = await maciContract.signUp(user.pubKey.asContractParam(), attestation); const receipt = await tx.wait(); @@ -136,13 +132,10 @@ describe("EAS Gatekeeper", () => { }); it("should prevent signing up twice", async () => { - await expect( - maciContract.signUp( - user.pubKey.asContractParam(), - attestation, - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ), - ).to.be.revertedWithCustomError(easGatekeeper, "AlreadyRegistered"); + await expect(maciContract.signUp(user.pubKey.asContractParam(), attestation)).to.be.revertedWithCustomError( + easGatekeeper, + "AlreadyRegistered", + ); }); }); }); diff --git a/packages/contracts/tests/gatekeepers/GitcoinPassportGatekeeper.test.ts b/packages/contracts/tests/gatekeepers/GitcoinPassportGatekeeper.test.ts index 797e8c26c0..9fd0178716 100644 --- a/packages/contracts/tests/gatekeepers/GitcoinPassportGatekeeper.test.ts +++ b/packages/contracts/tests/gatekeepers/GitcoinPassportGatekeeper.test.ts @@ -103,11 +103,7 @@ describe("GitcoinPassport Gatekeeper", () => { const tx = await maciContract .connect(secondSigner) - .signUp( - user.pubKey.asContractParam(), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ); + .signUp(user.pubKey.asContractParam(), AbiCoder.defaultAbiCoder().encode(["uint256"], [1])); const receipt = await tx.wait(); diff --git a/packages/contracts/tests/gatekeepers/HatsGatekeeper.test.ts b/packages/contracts/tests/gatekeepers/HatsGatekeeper.test.ts index 02a03020d9..99d0cddb69 100644 --- a/packages/contracts/tests/gatekeepers/HatsGatekeeper.test.ts +++ b/packages/contracts/tests/gatekeepers/HatsGatekeeper.test.ts @@ -94,11 +94,7 @@ describe("HatsProtocol Gatekeeper", () => { await expect( maciContract .connect(signer) - .signUp( - user.pubKey.asContractParam(), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ), + .signUp(user.pubKey.asContractParam(), AbiCoder.defaultAbiCoder().encode(["uint256"], [1])), ).to.be.revertedWithCustomError(hatsGatekeeperSingle, "OnlyMACI"); }); @@ -108,11 +104,7 @@ describe("HatsProtocol Gatekeeper", () => { // signup via MACI const tx = await maciContract .connect(voter) - .signUp( - user.pubKey.asContractParam(), - AbiCoder.defaultAbiCoder().encode(["uint256"], [hatId]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ); + .signUp(user.pubKey.asContractParam(), AbiCoder.defaultAbiCoder().encode(["uint256"], [hatId])); const receipt = await tx.wait(); @@ -123,11 +115,7 @@ describe("HatsProtocol Gatekeeper", () => { await expect( maciContract .connect(voter) - .signUp( - user.pubKey.asContractParam(), - AbiCoder.defaultAbiCoder().encode(["uint256"], [hatId]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ), + .signUp(user.pubKey.asContractParam(), AbiCoder.defaultAbiCoder().encode(["uint256"], [hatId])), ).to.be.revertedWithCustomError(hatsGatekeeperSingle, "AlreadyRegistered"); }); }); @@ -186,11 +174,7 @@ describe("HatsProtocol Gatekeeper", () => { await expect( maciContract .connect(signer) - .signUp( - user.pubKey.asContractParam(), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ), + .signUp(user.pubKey.asContractParam(), AbiCoder.defaultAbiCoder().encode(["uint256"], [1])), ).to.be.revertedWithCustomError(hatsGatekeeperMultiple, "OnlyMACI"); }); @@ -200,11 +184,7 @@ describe("HatsProtocol Gatekeeper", () => { // signup via MACI const tx = await maciContract .connect(signer) - .signUp( - user.pubKey.asContractParam(), - AbiCoder.defaultAbiCoder().encode(["uint256"], [hatId]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ); + .signUp(user.pubKey.asContractParam(), AbiCoder.defaultAbiCoder().encode(["uint256"], [hatId])); const receipt = await tx.wait(); @@ -215,11 +195,7 @@ describe("HatsProtocol Gatekeeper", () => { await expect( maciContract .connect(voter) - .signUp( - user.pubKey.asContractParam(), - AbiCoder.defaultAbiCoder().encode(["uint256"], [secondHatId]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ), + .signUp(user.pubKey.asContractParam(), AbiCoder.defaultAbiCoder().encode(["uint256"], [secondHatId])), ).to.be.revertedWithCustomError(hatsGatekeeperMultiple, "NotCriterionHat"); }); @@ -230,11 +206,7 @@ describe("HatsProtocol Gatekeeper", () => { await expect( maciContract .connect(another) - .signUp( - user.pubKey.asContractParam(), - AbiCoder.defaultAbiCoder().encode(["uint256"], [thirdHatId]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ), + .signUp(user.pubKey.asContractParam(), AbiCoder.defaultAbiCoder().encode(["uint256"], [thirdHatId])), ).to.be.revertedWithCustomError(hatsGatekeeperMultiple, "NotWearingCriterionHat"); }); @@ -242,11 +214,7 @@ describe("HatsProtocol Gatekeeper", () => { await expect( maciContract .connect(signer) - .signUp( - user.pubKey.asContractParam(), - AbiCoder.defaultAbiCoder().encode(["uint256"], [hatId]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ), + .signUp(user.pubKey.asContractParam(), AbiCoder.defaultAbiCoder().encode(["uint256"], [hatId])), ).to.be.revertedWithCustomError(hatsGatekeeperMultiple, "AlreadyRegistered"); }); }); diff --git a/packages/contracts/tests/gatekeepers/MerkleProofGatekeeper.test.ts b/packages/contracts/tests/gatekeepers/MerkleProofGatekeeper.test.ts index bf3200b830..db340b0d8f 100644 --- a/packages/contracts/tests/gatekeepers/MerkleProofGatekeeper.test.ts +++ b/packages/contracts/tests/gatekeepers/MerkleProofGatekeeper.test.ts @@ -102,7 +102,6 @@ describe("MerkleProof Gatekeeper", () => { const tx = await maciContract.signUp( user.pubKey.asContractParam(), AbiCoder.defaultAbiCoder().encode(["bytes32[]"], [validProof]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), ); const receipt = await tx.wait(); @@ -115,7 +114,6 @@ describe("MerkleProof Gatekeeper", () => { maciContract.signUp( user.pubKey.asContractParam(), AbiCoder.defaultAbiCoder().encode(["bytes32[]"], [validProof]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), ), ).to.be.revertedWithCustomError(merkleProofGatekeeper, "AlreadyRegistered"); }); diff --git a/packages/contracts/tests/gatekeepers/SemaphoreGatekeeper.test.ts b/packages/contracts/tests/gatekeepers/SemaphoreGatekeeper.test.ts index 05d8a7fc4f..afc60c612d 100644 --- a/packages/contracts/tests/gatekeepers/SemaphoreGatekeeper.test.ts +++ b/packages/contracts/tests/gatekeepers/SemaphoreGatekeeper.test.ts @@ -112,32 +112,20 @@ describe("Semaphore Gatekeeper", () => { await semaphoreGatekeeper.setMaciInstance(await maciContract.getAddress()).then((tx) => tx.wait()); await expect( - maciContract.signUp( - user.pubKey.asContractParam(), - encodedProofInvalidGroupId, - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ), + maciContract.signUp(user.pubKey.asContractParam(), encodedProofInvalidGroupId), ).to.be.revertedWithCustomError(semaphoreGatekeeper, "InvalidGroup"); }); it("should revert if the proof is invalid (mock)", async () => { await mockSemaphore.flipValid(); await expect( - maciContract.signUp( - user.pubKey.asContractParam(), - encodedInvalidProof, - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ), + maciContract.signUp(user.pubKey.asContractParam(), encodedInvalidProof), ).to.be.revertedWithCustomError(semaphoreGatekeeper, "InvalidProof"); await mockSemaphore.flipValid(); }); it("should register a user if the register function is called with the valid data", async () => { - const tx = await maciContract.signUp( - user.pubKey.asContractParam(), - encodedProof, - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ); + const tx = await maciContract.signUp(user.pubKey.asContractParam(), encodedProof); const receipt = await tx.wait(); @@ -145,13 +133,10 @@ describe("Semaphore Gatekeeper", () => { }); it("should prevent signing up twice", async () => { - await expect( - maciContract.signUp( - user.pubKey.asContractParam(), - encodedProof, - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ), - ).to.be.revertedWithCustomError(semaphoreGatekeeper, "AlreadyRegistered"); + await expect(maciContract.signUp(user.pubKey.asContractParam(), encodedProof)).to.be.revertedWithCustomError( + semaphoreGatekeeper, + "AlreadyRegistered", + ); }); }); }); diff --git a/packages/contracts/tests/gatekeepers/SignUpGatekeeper.test.ts b/packages/contracts/tests/gatekeepers/SignUpGatekeeper.test.ts index 8b69986c20..024b088b0f 100644 --- a/packages/contracts/tests/gatekeepers/SignUpGatekeeper.test.ts +++ b/packages/contracts/tests/gatekeepers/SignUpGatekeeper.test.ts @@ -64,11 +64,7 @@ describe("SignUpGatekeeper", () => { await signUpToken.giveToken(await signer.getAddress(), 0); await expect( - maciContract.signUp( - user.pubKey.asContractParam(), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [0]), - ), + maciContract.signUp(user.pubKey.asContractParam(), AbiCoder.defaultAbiCoder().encode(["uint256"], [1])), ).to.be.revertedWithCustomError(signUpTokenGatekeeperContract, "OnlyMACI"); }); @@ -82,7 +78,6 @@ describe("SignUpGatekeeper", () => { const tx = await maciContract.signUp( user.pubKey.asContractParam(), AbiCoder.defaultAbiCoder().encode(["uint256"], [0]), - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), ); const receipt = await tx.wait(); diff --git a/packages/contracts/tests/gatekeepers/ZupassGatekeeper.test.ts b/packages/contracts/tests/gatekeepers/ZupassGatekeeper.test.ts index 6d766a973a..058564b036 100644 --- a/packages/contracts/tests/gatekeepers/ZupassGatekeeper.test.ts +++ b/packages/contracts/tests/gatekeepers/ZupassGatekeeper.test.ts @@ -1,5 +1,5 @@ import { expect } from "chai"; -import { AbiCoder, Signer, ZeroAddress } from "ethers"; +import { Signer, ZeroAddress } from "ethers"; import { Keypair } from "maci-domainobjs"; import { deployContract } from "../../ts/deploy"; @@ -92,20 +92,12 @@ describe("Zupass Gatekeeper", () => { await zupassGatekeeper.setMaciInstance(await maciContract.getAddress()).then((tx) => tx.wait()); await expect( - maciContract.signUp( - user.pubKey.asContractParam(), - dataWithInvalidWatermark, - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ), + maciContract.signUp(user.pubKey.asContractParam(), dataWithInvalidWatermark), ).to.be.revertedWithCustomError(zupassGatekeeper, "InvalidWatermark"); }); it("should register a user if the register function is called with the valid data", async () => { - const tx = await maciContract.signUp( - user.pubKey.asContractParam(), - data, - AbiCoder.defaultAbiCoder().encode(["uint256"], [1]), - ); + const tx = await maciContract.signUp(user.pubKey.asContractParam(), data); const receipt = await tx.wait(); @@ -113,9 +105,10 @@ describe("Zupass Gatekeeper", () => { }); it("should prevent signing up twice", async () => { - await expect( - maciContract.signUp(user.pubKey.asContractParam(), data, AbiCoder.defaultAbiCoder().encode(["uint256"], [1])), - ).to.be.revertedWithCustomError(zupassGatekeeper, "AlreadyRegistered"); + await expect(maciContract.signUp(user.pubKey.asContractParam(), data)).to.be.revertedWithCustomError( + zupassGatekeeper, + "AlreadyRegistered", + ); }); }); }); diff --git a/packages/contracts/tests/utils.ts b/packages/contracts/tests/utils.ts index 035d559402..5d4081ab3e 100644 --- a/packages/contracts/tests/utils.ts +++ b/packages/contracts/tests/utils.ts @@ -86,14 +86,10 @@ export const deployTestContracts = async ({ // VkRegistry const vkRegistryContract = await deployVkRegistry(signer, true); - const [gatekeeperContractAddress, constantInitialVoiceCreditProxyContractAddress] = await Promise.all([ - gatekeeperContract.getAddress(), - constantInitialVoiceCreditProxyContract.getAddress(), - ]); + const [gatekeeperContractAddress] = await Promise.all([gatekeeperContract.getAddress()]); const { maciContract } = await deployMaci({ signUpTokenGatekeeperContractAddress: gatekeeperContractAddress, - initialVoiceCreditBalanceAddress: constantInitialVoiceCreditProxyContractAddress, signer, stateTreeDepth, factories, diff --git a/packages/contracts/ts/deploy.ts b/packages/contracts/ts/deploy.ts index 7b652912ff..1f40edf7c3 100644 --- a/packages/contracts/ts/deploy.ts +++ b/packages/contracts/ts/deploy.ts @@ -294,7 +294,6 @@ export const deployPollFactory = async ( */ export const deployMaci = async ({ signUpTokenGatekeeperContractAddress, - initialVoiceCreditBalanceAddress, signer, poseidonAddresses, stateTreeDepth = 10, @@ -360,7 +359,6 @@ export const deployMaci = async ({ messageProcessorAddress, tallyAddress, signUpTokenGatekeeperContractAddress, - initialVoiceCreditBalanceAddress, stateTreeDepth, emptyBallotRoots, ); diff --git a/packages/contracts/ts/genMaciState.ts b/packages/contracts/ts/genMaciState.ts index 3e0bfb6120..60df574527 100644 --- a/packages/contracts/ts/genMaciState.ts +++ b/packages/contracts/ts/genMaciState.ts @@ -78,9 +78,7 @@ export const genMaciStateFromContract = async ( data: { stateIndex: Number(event.args._stateIndex), pubKey: new PubKey([BigInt(event.args._userPubKeyX), BigInt(event.args._userPubKeyY)]), - voiceCreditBalance: Number(event.args._voiceCreditBalance), timestamp: Number(event.args._timestamp), - stateLeaf: BigInt(event.args._stateLeaf), }, }); }); @@ -156,7 +154,7 @@ export const genMaciStateFromContract = async ( const pubKeyY = BigInt(event.args._pollPubKeyY); const timestamp = Number(event.args._timestamp); - const newVoiceCreditBalance = BigInt(event.args._newVoiceCreditBalance); + const voiceCreditBalance = BigInt(event.args._voiceCreditBalance); actions.push({ type: "PollJoined", @@ -164,7 +162,7 @@ export const genMaciStateFromContract = async ( transactionIndex: event.transactionIndex, data: { pubKey: new PubKey([pubKeyX, pubKeyY]), - newVoiceCreditBalance, + newVoiceCreditBalance: voiceCreditBalance, timestamp, nullifier, }, @@ -245,9 +243,9 @@ export const genMaciStateFromContract = async ( sortActions(actions).forEach((action) => { switch (true) { case action.type === "SignUp": { - const { pubKey, voiceCreditBalance, timestamp, stateLeaf } = action.data; + const { pubKey } = action.data; - maciState.signUp(pubKey!, BigInt(voiceCreditBalance!), BigInt(timestamp!), stateLeaf); + maciState.signUp(pubKey!); break; } diff --git a/packages/contracts/ts/genSignUpTree.ts b/packages/contracts/ts/genSignUpTree.ts index 598c47b795..c16b8241d2 100644 --- a/packages/contracts/ts/genSignUpTree.ts +++ b/packages/contracts/ts/genSignUpTree.ts @@ -1,7 +1,7 @@ /* eslint-disable no-underscore-dangle */ import { LeanIMT, LeanIMTHashFunction } from "@zk-kit/lean-imt"; -import { hashLeanIMT } from "maci-crypto"; -import { PubKey, StateLeaf, blankStateLeaf, blankStateLeafHash } from "maci-domainobjs"; +import { hashLeanIMT, hashLeftRight, PAD_KEY_HASH } from "maci-crypto"; +import { PubKey } from "maci-domainobjs"; import { assert } from "console"; @@ -32,8 +32,8 @@ export const genSignUpTree = async ({ const maciContract = MACIFactory.connect(address, provider); const signUpTree = new LeanIMT(hashLeanIMT as LeanIMTHashFunction); - signUpTree.insert(blankStateLeafHash); - const stateLeaves: StateLeaf[] = [blankStateLeaf]; + signUpTree.insert(PAD_KEY_HASH); + const pubKeys: PubKey[] = []; // Fetch event logs in batches (lastBlock inclusive) for (let i = fromBlock; i <= lastBlock; i += blocksPerRequest + 1) { @@ -47,14 +47,11 @@ export const genSignUpTree = async ({ assert(!!event); const pubKeyX = event.args._userPubKeyX; const pubKeyY = event.args._userPubKeyY; - const voiceCreditBalance = event.args._voiceCreditBalance; - const timestamp = event.args._timestamp; const pubKey = new PubKey([pubKeyX, pubKeyY]); - const stateLeaf = new StateLeaf(pubKey, voiceCreditBalance, timestamp); - stateLeaves.push(stateLeaf); - signUpTree.insert(event.args._stateLeaf); + pubKeys.push(pubKey); + signUpTree.insert(hashLeftRight(pubKeyX, pubKeyY)); }); if (sleepAmount) { @@ -64,6 +61,6 @@ export const genSignUpTree = async ({ } return { signUpTree, - stateLeaves, + pubKeys, }; }; diff --git a/packages/contracts/ts/types.ts b/packages/contracts/ts/types.ts index 505054a970..aa14b57385 100644 --- a/packages/contracts/ts/types.ts +++ b/packages/contracts/ts/types.ts @@ -14,7 +14,7 @@ import type { } from "../typechain-types"; import type { BigNumberish, Provider, Signer, ContractFactory } from "ethers"; import type { CircuitInputs } from "maci-core"; -import type { Message, PubKey, StateLeaf } from "maci-domainobjs"; +import type { Message, PubKey } from "maci-domainobjs"; import type { PublicSignals } from "snarkjs"; /** @@ -141,11 +141,6 @@ export interface IDeployMaciArgs { */ signUpTokenGatekeeperContractAddress: string; - /** - * The address of the ConstantInitialVoiceCreditProxy contract - */ - initialVoiceCreditBalanceAddress: string; - /** * The signer to use to deploy the contract */ @@ -238,5 +233,5 @@ export interface IGenSignUpTree { /** * State leaves */ - stateLeaves: StateLeaf[]; + pubKeys: PubKey[]; } diff --git a/packages/core/ts/MaciState.ts b/packages/core/ts/MaciState.ts index 506c51fbb1..c676837980 100644 --- a/packages/core/ts/MaciState.ts +++ b/packages/core/ts/MaciState.ts @@ -1,5 +1,5 @@ -import { hash4, IncrementalQuinTree } from "maci-crypto"; -import { type PubKey, type Keypair, StateLeaf, blankStateLeaf } from "maci-domainobjs"; +import { IncrementalQuinTree } from "maci-crypto"; +import { PubKey, type Keypair, padKey } from "maci-domainobjs"; import type { IJsonMaciState, IJsonPoll, IMaciState, TreeDepths } from "./utils/types"; @@ -13,8 +13,8 @@ export class MaciState implements IMaciState { // a MaciState can hold multiple polls polls: Map = new Map(); - // the leaves of the state tree - stateLeaves: StateLeaf[] = []; + // the public keys of the users + pubKeys: PubKey[] = []; // how deep the state tree is stateTreeDepth: number; @@ -37,29 +37,22 @@ export class MaciState implements IMaciState { this.stateTreeDepth = stateTreeDepth; // we put a blank state leaf to prevent a DoS attack - this.stateLeaves.push(blankStateLeaf); + this.pubKeys.push(padKey); // we need to increase the number of signups by one given // that we already added the blank leaf this.numSignUps += 1; } /** - * Sign up a user with the given public key, initial voice credit balance, and timestamp. + * Sign up a user with the given public key. * @param pubKey - The public key of the user. - * @param initialVoiceCreditBalance - The initial voice credit balance of the user. - * @param timestamp - The timestamp of the sign-up. - * @param stateLeaf - The hash state leaf. * @returns The index of the newly signed-up user in the state tree. */ - signUp(pubKey: PubKey, initialVoiceCreditBalance: bigint, timestamp: bigint, stateLeaf?: bigint): number { + signUp(pubKey: PubKey): number { this.numSignUps += 1; - const stateLeafObj = new StateLeaf(pubKey, initialVoiceCreditBalance, timestamp); - const pubKeyAsArray = pubKey.asArray(); - const stateLeafHash = - stateLeaf || hash4([pubKeyAsArray[0], pubKeyAsArray[1], initialVoiceCreditBalance, timestamp]); - this.stateTree?.insert(stateLeafHash); - return this.stateLeaves.push(stateLeafObj.copy()) - 1; + this.stateTree?.insert(pubKey.hash()); + return this.pubKeys.push(pubKey.copy()) - 1; } /** @@ -105,7 +98,7 @@ export class MaciState implements IMaciState { copy = (): MaciState => { const copied = new MaciState(this.stateTreeDepth); - copied.stateLeaves = this.stateLeaves.map((x: StateLeaf) => x.copy()); + copied.pubKeys = this.pubKeys.map((x: PubKey) => x.copy()); copied.polls = new Map(Array.from(this.polls, ([key, value]) => [key, value.copy()])); @@ -121,7 +114,7 @@ export class MaciState implements IMaciState { const result = this.stateTreeDepth === m.stateTreeDepth && this.polls.size === m.polls.size && - this.stateLeaves.length === m.stateLeaves.length; + this.pubKeys.length === m.pubKeys.length; if (!result) { return false; @@ -132,8 +125,8 @@ export class MaciState implements IMaciState { return false; } } - for (let i = 0; i < this.stateLeaves.length; i += 1) { - if (!this.stateLeaves[i].equals(m.stateLeaves[i])) { + for (let i = 0; i < this.pubKeys.length; i += 1) { + if (!this.pubKeys[i].equals(m.pubKeys[i])) { return false; } } @@ -149,7 +142,7 @@ export class MaciState implements IMaciState { return { stateTreeDepth: this.stateTreeDepth, polls: Array.from(this.polls.values()).map((poll) => poll.toJSON()), - stateLeaves: this.stateLeaves.map((leaf) => leaf.toJSON()), + pubKeys: this.pubKeys.map((pubKey) => pubKey.toJSON()), pollBeingProcessed: Boolean(this.pollBeingProcessed), currentPollBeingProcessed: this.currentPollBeingProcessed ? this.currentPollBeingProcessed.toString() : "", numSignUps: this.numSignUps, @@ -165,7 +158,7 @@ export class MaciState implements IMaciState { const maciState = new MaciState(json.stateTreeDepth); // assign the json values to the new instance - maciState.stateLeaves = json.stateLeaves.map((leaf) => StateLeaf.fromJSON(leaf)); + maciState.pubKeys = json.pubKeys.map((pubKey) => PubKey.fromJSON(pubKey)); maciState.pollBeingProcessed = json.pollBeingProcessed; maciState.currentPollBeingProcessed = BigInt(json.currentPollBeingProcessed); maciState.numSignUps = json.numSignUps; diff --git a/packages/core/ts/Poll.ts b/packages/core/ts/Poll.ts index e1292e0039..8e87fe88f6 100644 --- a/packages/core/ts/Poll.ts +++ b/packages/core/ts/Poll.ts @@ -25,6 +25,7 @@ import { type IMessageContractParams, type IJsonPCommand, blankStateLeafHash, + padKey, } from "maci-domainobjs"; import assert from "assert"; @@ -81,7 +82,7 @@ export class Poll implements IPoll { stateCopied = false; - stateLeaves: StateLeaf[] = [blankStateLeaf]; + pubKeys: PubKey[] = [padKey]; stateTree?: LeanIMT; @@ -203,6 +204,9 @@ export class Poll implements IPoll { * Update a Poll with data from MaciState. * This is the step where we copy the state from the MaciState instance, * and set the number of signups we have so far. + * @note It should be called to generate the state for poll joining with numSignups set as + * the number of signups in the MaciState. For message processing, you should set numSignups as + * the number of users who joined the poll. */ updatePoll = (numSignups: bigint): void => { // there might be occasions where we fetch logs after new signups have been made @@ -216,14 +220,15 @@ export class Poll implements IPoll { // start by setting the number of signups this.setNumSignups(numSignups); // copy up to numSignups state leaves - this.stateLeaves = this.maciStateRef.stateLeaves.slice(0, Number(this.numSignups)).map((x) => x.copy()); + this.pubKeys = this.maciStateRef.pubKeys.slice(0, Number(this.numSignups)).map((x) => x.copy()); // ensure we have the correct actual state tree depth value this.actualStateTreeDepth = Math.max(1, Math.ceil(Math.log2(Number(this.numSignups)))); this.stateTree = new LeanIMT(hashLeanIMT as LeanIMTHashFunction); + // add all leaves - this.stateLeaves.forEach((stateLeaf) => { - this.stateTree?.insert(stateLeaf.hash()); + this.pubKeys.forEach((pubKey) => { + this.stateTree?.insert(pubKey.hash()); }); // create a poll state tree @@ -244,7 +249,7 @@ export class Poll implements IPoll { this.ballotTree.insert(this.emptyBallotHash); // we fill the ballotTree with empty ballots hashes to match the number of signups in the tree - while (this.ballots.length < this.stateLeaves.length) { + while (this.ballots.length < this.pubKeys.length) { this.ballotTree.insert(this.emptyBallotHash); this.ballots.push(this.emptyBallot); } @@ -429,7 +434,6 @@ export class Poll implements IPoll { * Create circuit input for pollJoining * @param maciPrivKey User's private key for signing up * @param stateLeafIndex Index where the user is stored in the state leaves - * @param credits Credits for voting * @param pollPrivKey Poll's private key for the poll joining * @param pollPubKey Poll's public key for the poll joining * @returns stringified circuit inputs @@ -437,19 +441,9 @@ export class Poll implements IPoll { joiningCircuitInputs = ({ maciPrivKey, stateLeafIndex, - credits, pollPrivKey, pollPubKey, }: IJoiningCircuitArgs): IPollJoiningCircuitInputs => { - // Get the state leaf on the index position - const stateLeaf = this.stateLeaves[Number(stateLeafIndex)]; - const { pubKey, voiceCreditBalance, timestamp } = stateLeaf; - const pubKeyX = pubKey.asArray()[0]; - const pubKeyY = pubKey.asArray()[1]; - const stateLeafArray = [pubKeyX, pubKeyY, voiceCreditBalance, timestamp]; - - assert(credits <= voiceCreditBalance, "Credits must be lower than signed up credits"); - // calculate the path elements for the state tree given the original state tree const { siblings, index } = this.stateTree!.generateProof(Number(stateLeafIndex)); const siblingsLength = siblings.length; @@ -484,11 +478,9 @@ export class Poll implements IPoll { privKey: maciPrivKey.asCircuitInputs(), pollPrivKey: pollPrivKey.asCircuitInputs(), pollPubKey: pollPubKey.asCircuitInputs(), - stateLeaf: stateLeafArray, siblings: siblingsArray, indices, nullifier, - credits, stateRoot, actualStateTreeDepth, pollId: this.pollId, @@ -1305,7 +1297,7 @@ export class Poll implements IPoll { this.maciStateRef, ); - copied.stateLeaves = this.stateLeaves.map((x) => x.copy()); + copied.pubKeys = this.pubKeys.map((x) => x.copy()); copied.pollStateLeaves = this.pollStateLeaves.map((x) => x.copy()); copied.messages = this.messages.map((x) => x.copy()); copied.commands = this.commands.map((x) => x.copy()); @@ -1402,7 +1394,7 @@ export class Poll implements IPoll { ballots: this.ballots.map((ballot) => ballot.toJSON()), encPubKeys: this.encPubKeys.map((encPubKey) => encPubKey.serialize()), currentMessageBatchIndex: this.currentMessageBatchIndex, - stateLeaves: this.stateLeaves.map((leaf) => leaf.toJSON()), + pubKeys: this.pubKeys.map((leaf) => leaf.toJSON()), pollStateLeaves: this.pollStateLeaves.map((leaf) => leaf.toJSON()), results: this.tallyResult.map((result) => result.toString()), numBatchesProcessed: this.numBatchesProcessed, diff --git a/packages/core/ts/__benchmarks__/index.ts b/packages/core/ts/__benchmarks__/index.ts index ef9bb44ccf..4e92a12ef8 100644 --- a/packages/core/ts/__benchmarks__/index.ts +++ b/packages/core/ts/__benchmarks__/index.ts @@ -29,7 +29,7 @@ export default function runCore(): void { const userKeypair = new Keypair(); users.push(userKeypair); - maciState.signUp(userKeypair.pubKey, VOICE_CREDIT_BALANCE, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(userKeypair.pubKey); } const pollId = maciState.deployPoll( @@ -40,7 +40,7 @@ export default function runCore(): void { ); const poll = maciState.polls.get(pollId)!; - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); // 4 valid votes for (let i = 0; i < MESSAGE_BATCH_SIZE - 1; i += 1) { diff --git a/packages/core/ts/__tests__/MaciState.test.ts b/packages/core/ts/__tests__/MaciState.test.ts index 1c6ce09c10..b41d7bcbef 100644 --- a/packages/core/ts/__tests__/MaciState.test.ts +++ b/packages/core/ts/__tests__/MaciState.test.ts @@ -7,7 +7,7 @@ import { MaciState } from "../MaciState"; import { STATE_TREE_DEPTH } from "../utils/constants"; import { IJsonMaciState } from "../utils/types"; -import { coordinatorKeypair, duration, messageBatchSize, treeDepths, voiceCreditBalance } from "./utils/constants"; +import { coordinatorKeypair, duration, messageBatchSize, treeDepths } from "./utils/constants"; describe("MaciState", function test() { this.timeout(100000); @@ -26,7 +26,7 @@ describe("MaciState", function test() { before(() => { m1 = new MaciState(STATE_TREE_DEPTH); - m1.signUp(userKeypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + m1.signUp(userKeypair.pubKey); pollId = m1.deployPoll( BigInt(Math.floor(Date.now() / 1000) + duration), treeDepths, @@ -53,14 +53,9 @@ describe("MaciState", function test() { // modify user.pubKey const m3 = m1.copy(); - m3.stateLeaves[0].pubKey = new Keypair().pubKey; + m3.pubKeys[0] = new Keypair().pubKey; expect(m1.equals(m3)).not.to.eq(true); - // modify user.voiceCreditBalance - const m4 = m1.copy(); - m4.stateLeaves[0].voiceCreditBalance = BigInt(m4.stateLeaves[0].voiceCreditBalance) + 1n; - expect(m1.equals(m4)).not.to.eq(true); - // modify poll.coordinatorKeypair const m6 = m1.copy(); m6.polls.get(pollId)!.coordinatorKeypair = new Keypair(); diff --git a/packages/core/ts/__tests__/Poll.test.ts b/packages/core/ts/__tests__/Poll.test.ts index 2be83d427f..955c4d2774 100644 --- a/packages/core/ts/__tests__/Poll.test.ts +++ b/packages/core/ts/__tests__/Poll.test.ts @@ -24,10 +24,10 @@ describe("Poll", function test() { const user1Keypair = new Keypair(); // signup the user - maciState.signUp(user1Keypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(user1Keypair.pubKey); // copy the state from the MaciState ref - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); const { privKey } = user1Keypair; const { privKey: pollPrivKey, pubKey: pollPubKey } = new Keypair(); @@ -244,11 +244,11 @@ describe("Poll", function test() { ); const poll = maciState.polls.get(pollId)!; - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); const user1Keypair = new Keypair(); // signup the user - maciState.signUp(user1Keypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(user1Keypair.pubKey); const { privKey } = user1Keypair; const { privKey: pollPrivKey, pubKey: pollPubKey } = new Keypair(); @@ -291,7 +291,7 @@ describe("Poll", function test() { poll.publishMessage(message, ecdhKeypair.pubKey); poll.publishMessage(message, ecdhKeypair.pubKey); - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); expect(() => { poll.processMessage(message, ecdhKeypair.pubKey); @@ -323,9 +323,9 @@ describe("Poll", function test() { const user1Keypair = new Keypair(); // signup the user - maciState.signUp(user1Keypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(user1Keypair.pubKey); - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); const { privKey } = user1Keypair; const { privKey: pollPrivKey, pubKey: pollPubKey } = new Keypair(); @@ -418,11 +418,11 @@ describe("Poll", function test() { const user2Keypair = new Keypair(); // signup the user - maciState.signUp(user1Keypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(user1Keypair.pubKey); - maciState.signUp(user2Keypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(user2Keypair.pubKey); - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); const { privKey: privKey1 } = user1Keypair; const { privKey: pollPrivKey1, pubKey: pollPubKey1 } = new Keypair(); @@ -481,7 +481,7 @@ describe("Poll", function test() { ); const secondPoll = maciState.polls.get(secondPollId)!; - secondPoll.updatePoll(BigInt(maciState.stateLeaves.length)); + secondPoll.updatePoll(BigInt(maciState.pubKeys.length)); const stateIndex2 = secondPoll.joinPoll(nullifier2, pollPubKey2, voiceCreditBalance, timestamp2); @@ -548,11 +548,11 @@ describe("Poll", function test() { coordinatorKeypair, ); - maciState.signUp(new Keypair().pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(new Keypair().pubKey); const poll = maciState.polls.get(pollId)!; - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); expect(poll.getNumSignups()).to.eq(2n); diff --git a/packages/core/ts/__tests__/e2e.test.ts b/packages/core/ts/__tests__/e2e.test.ts index 3827ed5feb..8cd30e7d73 100644 --- a/packages/core/ts/__tests__/e2e.test.ts +++ b/packages/core/ts/__tests__/e2e.test.ts @@ -1,6 +1,7 @@ +import { LeanIMT, LeanIMTHashFunction } from "@zk-kit/lean-imt"; import { expect } from "chai"; -import { hash5, IncrementalQuinTree, hash2, poseidon } from "maci-crypto"; -import { PCommand, Keypair, StateLeaf, blankStateLeafHash } from "maci-domainobjs"; +import { hash5, IncrementalQuinTree, poseidon, PAD_KEY_HASH, hashLeanIMT } from "maci-crypto"; +import { PCommand, Keypair, blankStateLeafHash } from "maci-domainobjs"; import { MaciState } from "../MaciState"; import { Poll } from "../Poll"; @@ -46,8 +47,8 @@ describe("MaciState/Poll e2e", function test() { before(() => { // Sign up - maciState.signUp(user1Keypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); - maciState.signUp(user2Keypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(user1Keypair.pubKey); + maciState.signUp(user2Keypair.pubKey); // deploy a poll pollId = maciState.deployPoll( @@ -57,7 +58,7 @@ describe("MaciState/Poll e2e", function test() { coordinatorKeypair, ); - maciState.polls.get(pollId)?.updatePoll(BigInt(maciState.stateLeaves.length)); + maciState.polls.get(pollId)?.updatePoll(BigInt(maciState.pubKeys.length)); }); it("should submit a vote for each user", () => { const poll = maciState.polls.get(pollId)!; @@ -141,8 +142,8 @@ describe("MaciState/Poll e2e", function test() { before(() => { // Sign up - maciState.signUp(user1Keypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); - maciState.signUp(user2Keypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(user1Keypair.pubKey); + maciState.signUp(user2Keypair.pubKey); // deploy a poll pollId = maciState.deployPoll( @@ -153,7 +154,7 @@ describe("MaciState/Poll e2e", function test() { ); poll = maciState.polls.get(pollId)!; - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); }); it("should submit a vote for each user", () => { user1StateIndex = poll.joinPoll(nullifier1, pollPubKey1, voiceCreditBalance, timestamp1); @@ -252,7 +253,7 @@ describe("MaciState/Poll e2e", function test() { before(() => { // Sign up - maciState.signUp(user1Keypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(user1Keypair.pubKey); // deploy a poll pollId = maciState.deployPoll( @@ -263,7 +264,7 @@ describe("MaciState/Poll e2e", function test() { ); poll = maciState.polls.get(pollId)!; - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); }); it("should submit a vote for one user in one batch", () => { @@ -357,16 +358,13 @@ describe("MaciState/Poll e2e", function test() { // The end result should be that option 0 gets 3 votes // because the user spends 9 voice credits on it it("the state root should be correct", () => { - const timestamp = BigInt(Math.floor(Date.now() / 1000)); - const stateLeaf = new StateLeaf(userKeypair.pubKey, voiceCreditBalance, timestamp); + stateIndex = maciState.signUp(userKeypair.pubKey); + poll.updatePoll(BigInt(maciState.pubKeys.length)); - stateIndex = maciState.signUp(userKeypair.pubKey, voiceCreditBalance, timestamp); - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + const stateTree = new LeanIMT(hashLeanIMT as LeanIMTHashFunction); - const stateTree = new IncrementalQuinTree(poll.actualStateTreeDepth, blankStateLeafHash, STATE_TREE_ARITY, hash2); - - stateTree.insert(blankStateLeafHash); - stateTree.insert(stateLeaf.hash()); + stateTree.insert(PAD_KEY_HASH); + stateTree.insert(userKeypair.pubKey.hash()); expect(stateIndex.toString()).to.eq("1"); expect(stateTree.root.toString()).to.eq(poll.stateTree?.root.toString()); @@ -434,7 +432,7 @@ describe("MaciState/Poll e2e", function test() { const pollKeypair = new Keypair(); pollKeys.push(pollKeypair); - maciState.signUp(userKeypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000))); + maciState.signUp(userKeypair.pubKey); } pollId = maciState.deployPoll( @@ -444,7 +442,7 @@ describe("MaciState/Poll e2e", function test() { coordinatorKeypair, ); poll = maciState.polls.get(pollId)!; - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); for (let i = 0; i < messageBatchSize - 1; i += 1) { const nullifier = poseidon([BigInt(pollKeys[i].privKey.rawPrivKey.toString())]); @@ -592,14 +590,11 @@ describe("MaciState/Poll e2e", function test() { poll = maciState.polls.get(pollId)!; - const timestamp = BigInt(Math.floor(Date.now() / 1000)); - const stateLeaf = new StateLeaf(userKeypair.pubKey, voiceCreditBalance, timestamp); - - maciState.signUp(userKeypair.pubKey, voiceCreditBalance, timestamp); - stateTree.insert(blankStateLeafHash); - stateTree.insert(stateLeaf.hash()); + maciState.signUp(userKeypair.pubKey); + stateTree.insert(PAD_KEY_HASH); + stateTree.insert(userKeypair.pubKey.hash()); - poll.updatePoll(BigInt(maciState.stateLeaves.length)); + poll.updatePoll(BigInt(maciState.pubKeys.length)); const { privKey } = userKeypair; const { privKey: pollPrivKey, pubKey: pollPubKey } = new Keypair(); @@ -697,7 +692,7 @@ describe("MaciState/Poll e2e", function test() { const pollStateIndex = testHarness.joinPoll(nullifier, pollKeypair.pubKey, voiceCreditBalance, timestamp); testHarness.vote(pollKeypair, pollStateIndex, voteOptionIndex, voteWeight, nonce); - poll.updatePoll(BigInt(testHarness.maciState.stateLeaves.length)); + poll.updatePoll(BigInt(testHarness.maciState.pubKeys.length)); poll.processMessages(testHarness.pollId); expect(() => { diff --git a/packages/core/ts/__tests__/utils/utils.ts b/packages/core/ts/__tests__/utils/utils.ts index 85f86ffb15..c31b356cae 100644 --- a/packages/core/ts/__tests__/utils/utils.ts +++ b/packages/core/ts/__tests__/utils/utils.ts @@ -5,7 +5,7 @@ import { MaciState } from "../../MaciState"; import { Poll } from "../../Poll"; import { STATE_TREE_DEPTH } from "../../utils/constants"; -import { duration, messageBatchSize, treeDepths, voiceCreditBalance } from "./constants"; +import { duration, messageBatchSize, treeDepths } from "./constants"; /** * Calculates the total of a tally result @@ -63,11 +63,7 @@ export class TestHarness { * @param user - The keypair of the user. * @returns The index of the newly signed-up user in the state tree. */ - signup = (user: Keypair): number => { - const timestamp = BigInt(Math.floor(Date.now() / 1000)); - const stateIndex = this.maciState.signUp(user.pubKey, voiceCreditBalance, timestamp); - return stateIndex; - }; + signup = (user: Keypair): number => this.maciState.signUp(user.pubKey); joinPoll = (nullifier: bigint, pubKey: PubKey, newVoiceCreditBalance: bigint, timestamp: bigint): number => this.poll.joinPoll(nullifier, pubKey, newVoiceCreditBalance, timestamp); @@ -142,7 +138,7 @@ export class TestHarness { * This should be called after all votes have been cast. */ finalizePoll = (): void => { - this.poll.updatePoll(BigInt(this.maciState.stateLeaves.length)); + this.poll.updatePoll(BigInt(this.maciState.pubKeys.length)); this.poll.processMessages(this.pollId); this.poll.tallyVotes(); }; diff --git a/packages/core/ts/utils/types.ts b/packages/core/ts/utils/types.ts index d2a7e7a586..ad6139992a 100644 --- a/packages/core/ts/utils/types.ts +++ b/packages/core/ts/utils/types.ts @@ -5,6 +5,7 @@ import type { Ballot, IJsonBallot, IJsonPCommand, + IJsonPublicKey, IJsonStateLeaf, Keypair, Message, @@ -95,7 +96,7 @@ export interface IJsonPoll { ballots: IJsonBallot[]; encPubKeys: string[]; currentMessageBatchIndex: number; - stateLeaves: IJsonStateLeaf[]; + pubKeys: IJsonPublicKey[]; pollStateLeaves: IJsonStateLeaf[]; results: string[]; numBatchesProcessed: number; @@ -110,7 +111,7 @@ export interface IJsonPoll { export interface IJsonMaciState { stateTreeDepth: number; polls: IJsonPoll[]; - stateLeaves: IJsonStateLeaf[]; + pubKeys: IJsonPublicKey[]; pollBeingProcessed: boolean; currentPollBeingProcessed: string; numSignUps: number; @@ -138,7 +139,6 @@ export interface IProcessMessagesOutput { export interface IJoiningCircuitArgs { maciPrivKey: PrivKey; stateLeafIndex: bigint; - credits: bigint; pollPrivKey: PrivKey; pollPubKey: PubKey; } @@ -153,7 +153,6 @@ export interface IPollJoiningCircuitInputs { siblings: string[][]; indices: string[]; nullifier: string; - credits: string; stateRoot: string; actualStateTreeDepth: string; pollId: string; diff --git a/packages/crypto/ts/constants.ts b/packages/crypto/ts/constants.ts index ce10528f2f..3118f7a65b 100644 --- a/packages/crypto/ts/constants.ts +++ b/packages/crypto/ts/constants.ts @@ -10,3 +10,5 @@ export const SNARK_FIELD_SIZE = r; export const NOTHING_UP_MY_SLEEVE = BigInt(keccak256(toUtf8Bytes("Maci"))) % SNARK_FIELD_SIZE; assert(NOTHING_UP_MY_SLEEVE === BigInt("8370432830353022751713833565135785980866757267633941821328460903436894336785")); + +export const PAD_KEY_HASH = BigInt("1309255631273308531193241901289907343161346846555918942743921933037802809814"); diff --git a/packages/crypto/ts/index.ts b/packages/crypto/ts/index.ts index bfaf8e003c..8ed437e972 100644 --- a/packages/crypto/ts/index.ts +++ b/packages/crypto/ts/index.ts @@ -4,7 +4,7 @@ export { IncrementalQuinTree } from "./quinTree"; export { bigInt2Buffer, stringifyBigInts, unstringifyBigInts, deepCopyBigIntArray } from "./bigIntUtils"; -export { NOTHING_UP_MY_SLEEVE, SNARK_FIELD_SIZE } from "./constants"; +export { NOTHING_UP_MY_SLEEVE, SNARK_FIELD_SIZE, PAD_KEY_HASH } from "./constants"; export { genPrivKey, diff --git a/packages/domainobjs/ts/constants.ts b/packages/domainobjs/ts/constants.ts index aae4709cb1..bc727d7b03 100644 --- a/packages/domainobjs/ts/constants.ts +++ b/packages/domainobjs/ts/constants.ts @@ -1,4 +1,6 @@ +import { PubKey } from "./publicKey"; import { StateLeaf } from "./stateLeaf"; export const blankStateLeaf = StateLeaf.genBlankLeaf(); export const blankStateLeafHash = blankStateLeaf.hash(); +export const padKey = PubKey.genPadKey(); diff --git a/packages/domainobjs/ts/index.ts b/packages/domainobjs/ts/index.ts index ad8081b858..6aabb2e6dc 100644 --- a/packages/domainobjs/ts/index.ts +++ b/packages/domainobjs/ts/index.ts @@ -10,7 +10,7 @@ export { Keypair } from "./keyPair"; export { StateLeaf } from "./stateLeaf"; -export { blankStateLeaf, blankStateLeafHash } from "./constants"; +export { blankStateLeaf, blankStateLeafHash, padKey } from "./constants"; export type { Proof, diff --git a/packages/domainobjs/ts/publicKey.ts b/packages/domainobjs/ts/publicKey.ts index 905107975f..92b4e707ee 100644 --- a/packages/domainobjs/ts/publicKey.ts +++ b/packages/domainobjs/ts/publicKey.ts @@ -135,4 +135,21 @@ export class PubKey { static fromJSON(json: IJsonPublicKey): PubKey { return PubKey.deserialize(json.pubKey); } + + /** + * Generate a default pad key + * @returns a default pad key + */ + static genPadKey(): PubKey { + // This public key is the first Pedersen base + // point from iden3's circomlib implementation of the Pedersen hash. + // Since it is generated using a hash-to-curve function, we are + // confident that no-one knows the private key associated with this + // public key. See: + // https://github.com/iden3/circomlib/blob/d5ed1c3ce4ca137a6b3ca48bec4ac12c1b38957a/src/pedersen_printbases.js + return new PubKey([ + BigInt("10457101036533406547632367118273992217979173478358440826365724437999023779287"), + BigInt("19824078218392094440610104313265183977899662750282163392862422243483260492317"), + ]); + } } diff --git a/packages/integrationTests/.gitignore b/packages/integrationTests/.gitignore index 1e52b58973..1ac4dd5602 100644 --- a/packages/integrationTests/.gitignore +++ b/packages/integrationTests/.gitignore @@ -1,2 +1,4 @@ !ts/__tests__/data/ -cache \ No newline at end of file +cache +deploy-config.json +deployed-contracts.json diff --git a/packages/integrationTests/ts/__tests__/integration.test.ts b/packages/integrationTests/ts/__tests__/integration.test.ts index c3666f40f5..d17fc2a659 100644 --- a/packages/integrationTests/ts/__tests__/integration.test.ts +++ b/packages/integrationTests/ts/__tests__/integration.test.ts @@ -34,7 +34,6 @@ import { VOTE_OPTION_TREE_DEPTH, duration, initialVoiceCredits, - ivcpData, maxMessages, } from "./utils/constants"; import { ITestSuite } from "./utils/interfaces"; @@ -113,6 +112,7 @@ describe("Integration tests", function test() { maciAddress: contracts.maciAddress, signer, useQuadraticVoting: true, + initialVoiceCreditsBalance: initialVoiceCredits, }); const treeDepths: TreeDepths = { @@ -168,7 +168,6 @@ describe("Integration tests", function test() { maciPubKey: user.keypair.pubKey.serialize(), maciAddress: contracts.maciAddress, sgDataArg: SG_DATA, - ivcpDataArg: ivcpData, signer, }).then((result) => result.stateIndex), ); @@ -191,12 +190,11 @@ describe("Integration tests", function test() { ), rapidsnark: `${homedir()}/rapidsnark/build/prover`, signer, - newVoiceCreditBalance: BigInt(initialVoiceCredits), quiet: true, }); // signup on local maci state - maciState.signUp(user.keypair.pubKey, BigInt(initialVoiceCredits), BigInt(timestamp)); + maciState.signUp(user.keypair.pubKey); // join the poll on local const inputNullifier = BigInt(user.keypair.privKey.asCircuitInputs()); diff --git a/packages/integrationTests/ts/__tests__/maci-keys.test.ts b/packages/integrationTests/ts/__tests__/maci-keys.test.ts index 081553e52f..97d59a8b97 100644 --- a/packages/integrationTests/ts/__tests__/maci-keys.test.ts +++ b/packages/integrationTests/ts/__tests__/maci-keys.test.ts @@ -72,7 +72,7 @@ describe("integration tests private/public/keypair", () => { before(async () => { signer = await getDefaultSigner(); - const { maci, verifier, vkRegistry, gatekeeper } = await deployTestContracts( + const { maci, verifier, vkRegistry, gatekeeper, initialVoiceCreditProxy } = await deployTestContracts( initialVoiceCredits, STATE_TREE_DEPTH, signer, @@ -92,6 +92,7 @@ describe("integration tests private/public/keypair", () => { vkRegistry, EMode.NON_QV, gatekeeper, + initialVoiceCreditProxy, ); // we know it's the first poll so id is 0 diff --git a/packages/integrationTests/ts/__tests__/utils/interfaces.ts b/packages/integrationTests/ts/__tests__/utils/interfaces.ts index 647a0b6ee5..abaf203580 100644 --- a/packages/integrationTests/ts/__tests__/utils/interfaces.ts +++ b/packages/integrationTests/ts/__tests__/utils/interfaces.ts @@ -1,4 +1,5 @@ import { MACI, Verifier, VkRegistry, FreeForAllGatekeeper } from "maci-contracts"; +import { ConstantInitialVoiceCreditProxy } from "maci-contracts/typechain-types"; /** * A util interface that represents a vote object @@ -48,4 +49,5 @@ export interface IDeployedTestContracts { verifier: Verifier; vkRegistry: VkRegistry; gatekeeper: FreeForAllGatekeeper; + initialVoiceCreditProxy: ConstantInitialVoiceCreditProxy; } diff --git a/packages/integrationTests/ts/__tests__/utils/utils.ts b/packages/integrationTests/ts/__tests__/utils/utils.ts index 5b59cb923b..63d97966d1 100644 --- a/packages/integrationTests/ts/__tests__/utils/utils.ts +++ b/packages/integrationTests/ts/__tests__/utils/utils.ts @@ -185,14 +185,10 @@ export const deployTestContracts = async ( // VkRegistry const vkRegistryContract = await deployVkRegistry(signer, true); - const [gatekeeperContractAddress, constantInitialVoiceCreditProxyContractAddress] = await Promise.all([ - gatekeeperContract.getAddress(), - constantInitialVoiceCreditProxyContract.getAddress(), - ]); + const [gatekeeperContractAddress] = await Promise.all([gatekeeperContract.getAddress()]); const { maciContract } = await deployMaci({ signUpTokenGatekeeperContractAddress: gatekeeperContractAddress, - initialVoiceCreditBalanceAddress: constantInitialVoiceCreditProxyContractAddress, signer, stateTreeDepth, quiet, @@ -203,5 +199,6 @@ export const deployTestContracts = async ( verifier: mockVerifierContract as Verifier, vkRegistry: vkRegistryContract, gatekeeper: gatekeeperContract, + initialVoiceCreditProxy: constantInitialVoiceCreditProxyContract, }; }; From 06db2d7b8459431af881660d9935a577828e98b6 Mon Sep 17 00:00:00 2001 From: Anton <14254374+0xmad@users.noreply.github.com> Date: Mon, 6 Jan 2025 12:45:08 -0600 Subject: [PATCH 07/17] feat(relayer): add relayer service boilerplate - [x] Add relayer package - [x] Add boilerplate package for relayer --- .github/workflows/relayer-build.yml | 51 + apps/relayer/.env.example | 15 + apps/relayer/.eslintrc.cjs | 32 + apps/relayer/.gitignore | 3 + apps/relayer/README.md | 5 + apps/relayer/hardhat.config.cjs | 33 + apps/relayer/nest-cli.json | 8 + apps/relayer/package.json | 102 + apps/relayer/tests/app.test.ts | 38 + apps/relayer/ts/app.module.ts | 14 + apps/relayer/ts/jest/setup.ts | 9 + apps/relayer/ts/jest/transform.js | 11 + apps/relayer/ts/main.ts | 55 + apps/relayer/tsconfig.build.json | 19 + apps/relayer/tsconfig.json | 19 + pnpm-lock.yaml | 2847 +++++++++++++++++++++++++-- 16 files changed, 3145 insertions(+), 116 deletions(-) create mode 100644 .github/workflows/relayer-build.yml create mode 100644 apps/relayer/.env.example create mode 100644 apps/relayer/.eslintrc.cjs create mode 100644 apps/relayer/.gitignore create mode 100644 apps/relayer/README.md create mode 100644 apps/relayer/hardhat.config.cjs create mode 100644 apps/relayer/nest-cli.json create mode 100644 apps/relayer/package.json create mode 100644 apps/relayer/tests/app.test.ts create mode 100644 apps/relayer/ts/app.module.ts create mode 100644 apps/relayer/ts/jest/setup.ts create mode 100644 apps/relayer/ts/jest/transform.js create mode 100644 apps/relayer/ts/main.ts create mode 100644 apps/relayer/tsconfig.build.json create mode 100644 apps/relayer/tsconfig.json diff --git a/.github/workflows/relayer-build.yml b/.github/workflows/relayer-build.yml new file mode 100644 index 0000000000..143484ed04 --- /dev/null +++ b/.github/workflows/relayer-build.yml @@ -0,0 +1,51 @@ +name: Relayer + +on: + push: + branches: [dev] + pull_request: + +env: + RPC_URL: "http://localhost:8545" + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: 9 + + - name: Use Node.js 20 + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "pnpm" + + - name: Install + run: | + pnpm install --frozen-lockfile --prefer-offline + + - name: Build + run: | + pnpm run build + + - name: Run hardhat + run: | + pnpm run hardhat & + sleep 5 + working-directory: apps/relayer + + - name: Test + run: pnpm run test:coverage + working-directory: apps/relayer + + - name: Stop Hardhat + if: always() + run: kill $(lsof -t -i:8545) diff --git a/apps/relayer/.env.example b/apps/relayer/.env.example new file mode 100644 index 0000000000..a6389442ae --- /dev/null +++ b/apps/relayer/.env.example @@ -0,0 +1,15 @@ +# Rate limit configuation +TTL=60000 +LIMIT=10 + +# Coordinator RPC url +RELAYER_RPC_URL=http://localhost:8545 + +# Allowed origin host, use comma to separate each of them +ALLOWED_ORIGINS= + +# Specify port for coordinator service (optional) +PORT= + +# Mnemonic phrase +MNEMONIC="" diff --git a/apps/relayer/.eslintrc.cjs b/apps/relayer/.eslintrc.cjs new file mode 100644 index 0000000000..9d837bea44 --- /dev/null +++ b/apps/relayer/.eslintrc.cjs @@ -0,0 +1,32 @@ +const path = require("path"); + +module.exports = { + root: true, + env: { + node: true, + jest: true, + }, + extends: ["../../.eslintrc.js"], + parser: "@typescript-eslint/parser", + parserOptions: { + project: path.resolve(__dirname, "./tsconfig.json"), + sourceType: "module", + typescript: true, + ecmaVersion: 2022, + experimentalDecorators: true, + requireConfigFile: false, + ecmaFeatures: { + classes: true, + impliedStrict: true, + }, + warnOnUnsupportedTypeScriptVersion: true, + }, + overrides: [ + { + files: ["./ts/**/*.module.ts"], + rules: { + "@typescript-eslint/no-extraneous-class": "off", + }, + }, + ], +}; diff --git a/apps/relayer/.gitignore b/apps/relayer/.gitignore new file mode 100644 index 0000000000..801ee0564b --- /dev/null +++ b/apps/relayer/.gitignore @@ -0,0 +1,3 @@ +build/ +coverage/ +.env diff --git a/apps/relayer/README.md b/apps/relayer/README.md new file mode 100644 index 0000000000..8d4082b4d0 --- /dev/null +++ b/apps/relayer/README.md @@ -0,0 +1,5 @@ +# Relayer service + +## Instructions + +1. Add `.env` file (see `.env.example`). diff --git a/apps/relayer/hardhat.config.cjs b/apps/relayer/hardhat.config.cjs new file mode 100644 index 0000000000..4c2978010b --- /dev/null +++ b/apps/relayer/hardhat.config.cjs @@ -0,0 +1,33 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +require("@nomicfoundation/hardhat-toolbox"); +const dotenv = require("dotenv"); + +const path = require("path"); + +dotenv.config(); + +const parentDir = __dirname.includes("build") ? ".." : ""; +const TEST_MNEMONIC = "test test test test test test test test test test test junk"; + +module.exports = { + defaultNetwork: "hardhat", + networks: { + localhost: { + url: process.env.RELAYER_RPC_URL || "", + accounts: { + mnemonic: process.env.MNEMONIC || TEST_MNEMONIC, + path: "m/44'/60'/0'/0", + initialIndex: 0, + count: 20, + }, + loggingEnabled: false, + }, + hardhat: { + loggingEnabled: false, + }, + }, + paths: { + sources: path.resolve(__dirname, parentDir, "./node_modules/maci-contracts/contracts"), + artifacts: path.resolve(__dirname, parentDir, "./node_modules/maci-contracts/build/artifacts"), + }, +}; diff --git a/apps/relayer/nest-cli.json b/apps/relayer/nest-cli.json new file mode 100644 index 0000000000..bfeb2a1c90 --- /dev/null +++ b/apps/relayer/nest-cli.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/nest-cli", + "collection": "@nestjs/schematics", + "sourceRoot": "ts", + "compilerOptions": { + "deleteOutDir": true + } +} diff --git a/apps/relayer/package.json b/apps/relayer/package.json new file mode 100644 index 0000000000..649a03e07a --- /dev/null +++ b/apps/relayer/package.json @@ -0,0 +1,102 @@ +{ + "name": "maci-relayer", + "version": "0.1.0", + "private": true, + "description": "Relayer service for MACI", + "main": "build/ts/main.js", + "type": "module", + "exports": { + ".": "./build/ts/main.js" + }, + "files": [ + "build", + "CHANGELOG.md", + "README.md" + ], + "scripts": { + "hardhat": "hardhat node", + "build": "nest build", + "run:node": "node --import 'data:text/javascript,import { register } from \"node:module\"; import { pathToFileURL } from \"node:url\"; register(\"ts-node/esm\", pathToFileURL(\"./\"));'", + "start": "pnpm run run:node ./ts/main.ts", + "start:prod": "pnpm run run:node build/ts/main.js", + "test": "jest --forceExit", + "test:coverage": "jest --coverage --forceExit", + "types": "tsc -p tsconfig.json --noEmit" + }, + "dependencies": { + "@nestjs/common": "^10.4.7", + "@nestjs/core": "^10.4.7", + "@nestjs/platform-express": "^10.4.7", + "@nestjs/platform-socket.io": "^10.3.10", + "@nestjs/swagger": "^8.0.3", + "@nestjs/throttler": "^6.3.0", + "@nestjs/websockets": "^10.4.7", + "@nomicfoundation/hardhat-ethers": "^3.0.8", + "@nomicfoundation/hardhat-toolbox": "^5.0.0", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.1", + "date-fns": "^4.1.0", + "dotenv": "^16.4.5", + "ethers": "^6.13.4", + "hardhat": "^2.22.15", + "helmet": "^8.0.0", + "maci-contracts": "workspace:^2.5.0", + "mustache": "^4.2.0", + "reflect-metadata": "^0.2.0", + "rxjs": "^7.8.1", + "ts-node": "^10.9.1" + }, + "devDependencies": { + "@nestjs/cli": "^10.4.2", + "@nestjs/schematics": "^10.1.2", + "@nestjs/testing": "^10.4.15", + "@types/express": "^5.0.0", + "@types/jest": "^29.5.2", + "@types/node": "^22.10.5", + "@types/supertest": "^6.0.2", + "fast-check": "^3.23.1", + "jest": "^29.5.0", + "supertest": "^7.0.0", + "ts-jest": "^29.2.5", + "typescript": "^5.7.2" + }, + "jest": { + "testTimeout": 900000, + "moduleFileExtensions": [ + "js", + "json", + "ts" + ], + "rootDir": ".", + "roots": [ + "/ts", + "/tests" + ], + "testRegex": ".*\\.test\\.ts$", + "transform": { + "^.+\\.js$": [ + "/ts/jest/transform.js", + { + "useESM": true + } + ], + "^.+\\.(t|j)s$": [ + "ts-jest", + { + "useESM": true + } + ] + }, + "collectCoverageFrom": [ + "**/*.(t|j)s", + "!/ts/main.ts", + "!/ts/jest/*.js", + "!/hardhat.config.js" + ], + "coveragePathIgnorePatterns": [ + "/ts/sessionKeys/__tests__/utils.ts" + ], + "coverageDirectory": "/coverage", + "testEnvironment": "node" + } +} diff --git a/apps/relayer/tests/app.test.ts b/apps/relayer/tests/app.test.ts new file mode 100644 index 0000000000..26c6a977de --- /dev/null +++ b/apps/relayer/tests/app.test.ts @@ -0,0 +1,38 @@ +import { HttpStatus, ValidationPipe, type INestApplication } from "@nestjs/common"; +import { Test } from "@nestjs/testing"; +import request from "supertest"; + +import type { App } from "supertest/types"; + +import { AppModule } from "../ts/app.module"; + +describe("e2e", () => { + let app: INestApplication; + + beforeAll(async () => { + const moduleFixture = await Test.createTestingModule({ + imports: [AppModule], + }).compile(); + + app = moduleFixture.createNestApplication(); + app.useGlobalPipes(new ValidationPipe({ transform: true })); + await app.listen(3000); + }); + + afterAll(async () => { + await app.close(); + }); + + test("should throw an error if api is not found", async () => { + const result = await request(app.getHttpServer() as App) + .get("/unknown") + .send() + .expect(404); + + expect(result.body).toStrictEqual({ + error: "Not Found", + statusCode: HttpStatus.NOT_FOUND, + message: "Cannot GET /unknown", + }); + }); +}); diff --git a/apps/relayer/ts/app.module.ts b/apps/relayer/ts/app.module.ts new file mode 100644 index 0000000000..b1a9046774 --- /dev/null +++ b/apps/relayer/ts/app.module.ts @@ -0,0 +1,14 @@ +import { Module } from "@nestjs/common"; +import { ThrottlerModule } from "@nestjs/throttler"; + +@Module({ + imports: [ + ThrottlerModule.forRoot([ + { + ttl: Number(process.env.TTL), + limit: Number(process.env.LIMIT), + }, + ]), + ], +}) +export class AppModule {} diff --git a/apps/relayer/ts/jest/setup.ts b/apps/relayer/ts/jest/setup.ts new file mode 100644 index 0000000000..bcc226d412 --- /dev/null +++ b/apps/relayer/ts/jest/setup.ts @@ -0,0 +1,9 @@ +import type { HardhatEthersHelpers } from "@nomicfoundation/hardhat-ethers/types"; +import type { ethers } from "ethers"; + +declare module "hardhat/types/runtime" { + interface HardhatRuntimeEnvironment { + // We omit the ethers field because it is redundant. + ethers: typeof ethers & HardhatEthersHelpers; + } +} diff --git a/apps/relayer/ts/jest/transform.js b/apps/relayer/ts/jest/transform.js new file mode 100644 index 0000000000..dd33c84103 --- /dev/null +++ b/apps/relayer/ts/jest/transform.js @@ -0,0 +1,11 @@ +/* eslint-disable */ + +export function process(sourceText) { + return { + code: sourceText.replace("#!/usr/bin/env node", ""), + }; +} + +export default { + process, +}; diff --git a/apps/relayer/ts/main.ts b/apps/relayer/ts/main.ts new file mode 100644 index 0000000000..18f65b40bb --- /dev/null +++ b/apps/relayer/ts/main.ts @@ -0,0 +1,55 @@ +import { ValidationPipe } from "@nestjs/common"; +import { NestFactory } from "@nestjs/core"; +import { SwaggerModule, DocumentBuilder } from "@nestjs/swagger"; +import dotenv from "dotenv"; +import helmet from "helmet"; + +import path from "path"; +import url from "url"; + +/* eslint-disable no-underscore-dangle */ +/* eslint-disable @typescript-eslint/no-shadow */ +const __filename = url.fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +/* eslint-enable no-underscore-dangle */ +/* eslint-disable @typescript-eslint/no-shadow */ + +dotenv.config({ + path: [path.resolve(__dirname, "../.env"), path.resolve(__dirname, "../.env.example")], +}); + +async function bootstrap() { + const { AppModule } = await import("./app.module"); + const app = await NestFactory.create(AppModule, { + logger: ["log", "fatal", "error", "warn"], + }); + + app.useGlobalPipes(new ValidationPipe({ transform: true })); + app.use( + helmet({ + contentSecurityPolicy: { + directives: { + defaultSrc: [`'self'`], + styleSrc: [`'self'`, `'unsafe-inline'`], + imgSrc: [`'self'`, "data:", "validator.swagger.io"], + scriptSrc: [`'self'`, `https: 'unsafe-inline'`], + }, + }, + }), + ); + app.enableCors({ origin: process.env.ALLOWED_ORIGINS?.split(",") }); + + const config = new DocumentBuilder() + .setTitle("Relayer service") + .setDescription("Relayer service API methods") + .setVersion("1.0") + .addTag("relayer") + .addBearerAuth() + .build(); + const document = SwaggerModule.createDocument(app, config); + SwaggerModule.setup("api", app, document); + + await app.listen(process.env.PORT || 3000); +} + +bootstrap(); diff --git a/apps/relayer/tsconfig.build.json b/apps/relayer/tsconfig.build.json new file mode 100644 index 0000000000..f0be7d9d8b --- /dev/null +++ b/apps/relayer/tsconfig.build.json @@ -0,0 +1,19 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./build", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": ["ES2023"], + "module": "ESNext", + "moduleResolution": "Bundler", + "target": "ES2022", + "forceConsistentCasingInFileNames": true + }, + "ts-node": { + "esm": true, + "experimentalSpecifierResolution": "node" + }, + "include": ["./ts", "./scripts", "./tests"], + "files": ["./hardhat.config.cjs"] +} diff --git a/apps/relayer/tsconfig.json b/apps/relayer/tsconfig.json new file mode 100644 index 0000000000..f0be7d9d8b --- /dev/null +++ b/apps/relayer/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./build", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": ["ES2023"], + "module": "ESNext", + "moduleResolution": "Bundler", + "target": "ES2022", + "forceConsistentCasingInFileNames": true + }, + "ts-node": { + "esm": true, + "experimentalSpecifierResolution": "node" + }, + "include": ["./ts", "./scripts", "./tests"], + "files": ["./hardhat.config.cjs"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 72daac53d1..ca2d6a5b67 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ importers: devDependencies: '@commitlint/cli': specifier: ^19.5.0 - version: 19.5.0(@types/node@22.9.0)(typescript@5.6.3) + version: 19.5.0(@types/node@22.10.5)(typescript@5.6.3) '@commitlint/config-conventional': specifier: ^19.5.0 version: 19.5.0 @@ -25,7 +25,7 @@ importers: version: 7.0.2 cz-conventional-changelog: specifier: ^3.3.0 - version: 3.3.0(@types/node@22.9.0)(typescript@5.6.3) + version: 3.3.0(@types/node@22.10.5)(typescript@5.6.3) eslint: specifier: ^8.57.0 version: 8.57.0 @@ -85,7 +85,7 @@ importers: version: 7.4.3 ts-node: specifier: ^10.9.1 - version: 10.9.2(@types/node@22.9.0)(typescript@5.6.3) + version: 10.9.2(@types/node@22.10.5)(typescript@5.6.3) typedoc: specifier: ^0.26.11 version: 0.26.11(typescript@5.6.3) @@ -96,11 +96,114 @@ importers: specifier: ^5.6.3 version: 5.6.3 + apps/relayer: + dependencies: + '@nestjs/common': + specifier: ^10.4.7 + version: 10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': + specifier: ^10.4.7 + version: 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/platform-express': + specifier: ^10.4.7 + version: 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15) + '@nestjs/platform-socket.io': + specifier: ^10.3.10 + version: 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@10.4.15)(rxjs@7.8.1) + '@nestjs/swagger': + specifier: ^8.0.3 + version: 8.1.0(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2) + '@nestjs/throttler': + specifier: ^6.3.0 + version: 6.3.0(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2) + '@nestjs/websockets': + specifier: ^10.4.7 + version: 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15)(@nestjs/platform-socket.io@10.4.15)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nomicfoundation/hardhat-ethers': + specifier: ^3.0.8 + version: 3.0.8(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)) + '@nomicfoundation/hardhat-toolbox': + specifier: ^5.0.0 + version: 5.0.0(zw7zqps7ouu5cvynqyf6kamiou) + class-transformer: + specifier: ^0.5.1 + version: 0.5.1 + class-validator: + specifier: ^0.14.1 + version: 0.14.1 + date-fns: + specifier: ^4.1.0 + version: 4.1.0 + dotenv: + specifier: ^16.4.5 + version: 16.4.5 + ethers: + specifier: ^6.13.4 + version: 6.13.4 + hardhat: + specifier: ^2.22.15 + version: 2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2) + helmet: + specifier: ^8.0.0 + version: 8.0.0 + maci-contracts: + specifier: workspace:^2.5.0 + version: link:../../packages/contracts + mustache: + specifier: ^4.2.0 + version: 4.2.0 + reflect-metadata: + specifier: ^0.2.0 + version: 0.2.2 + rxjs: + specifier: ^7.8.1 + version: 7.8.1 + ts-node: + specifier: ^10.9.1 + version: 10.9.2(@types/node@22.10.5)(typescript@5.7.2) + devDependencies: + '@nestjs/cli': + specifier: ^10.4.2 + version: 10.4.9 + '@nestjs/schematics': + specifier: ^10.1.2 + version: 10.2.3(chokidar@3.6.0)(typescript@5.7.2) + '@nestjs/testing': + specifier: ^10.4.15 + version: 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15)) + '@types/express': + specifier: ^5.0.0 + version: 5.0.0 + '@types/jest': + specifier: ^29.5.2 + version: 29.5.14 + '@types/node': + specifier: ^22.10.5 + version: 22.10.5 + '@types/supertest': + specifier: ^6.0.2 + version: 6.0.2 + fast-check: + specifier: ^3.23.1 + version: 3.23.1 + jest: + specifier: ^29.5.0 + version: 29.7.0(@types/node@22.10.5)(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2)) + supertest: + specifier: ^7.0.0 + version: 7.0.0 + ts-jest: + specifier: ^29.2.5 + version: 29.2.5(@babel/core@7.24.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@29.7.0(@types/node@22.10.5)(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2)))(typescript@5.7.2) + typescript: + specifier: ^5.7.2 + version: 5.7.2 + apps/subgraph: dependencies: '@graphprotocol/graph-cli': specifier: ^0.88.0 - version: 0.88.0(@types/node@22.9.0)(encoding@0.1.13)(node-fetch@2.7.0(encoding@0.1.13))(typescript@5.6.3) + version: 0.88.0(@types/node@22.10.5)(encoding@0.1.13)(node-fetch@2.7.0(encoding@0.1.13))(typescript@5.7.2) '@graphprotocol/graph-ts': specifier: ^0.35.1 version: 0.35.1 @@ -695,6 +798,24 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} + '@angular-devkit/core@17.3.11': + resolution: {integrity: sha512-vTNDYNsLIWpYk2I969LMQFH29GTsLzxNk/0cLw5q56ARF0v5sIWfHYwGTS88jdDqIpuuettcSczbxeA7EuAmqQ==} + engines: {node: ^18.13.0 || >=20.9.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + peerDependencies: + chokidar: ^3.5.2 + peerDependenciesMeta: + chokidar: + optional: true + + '@angular-devkit/schematics-cli@17.3.11': + resolution: {integrity: sha512-kcOMqp+PHAKkqRad7Zd7PbpqJ0LqLaNZdY1+k66lLWmkEBozgq8v4ASn/puPWf9Bo0HpCiK+EzLf0VHE8Z/y6Q==} + engines: {node: ^18.13.0 || >=20.9.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + hasBin: true + + '@angular-devkit/schematics@17.3.11': + resolution: {integrity: sha512-I5wviiIqiFwar9Pdk30Lujk8FczEEc18i22A5c6Z9lbmhPQdTroDnEQdsfXjy404wPe8H62s0I15o4pmMGfTYQ==} + engines: {node: ^18.13.0 || >=20.9.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + '@arrows/array@1.4.1': resolution: {integrity: sha512-MGYS8xi3c4tTy1ivhrVntFvufoNzje0PchjEz6G/SsWRgUKxL4tKwS6iPdO8vsaJYldagAeWMd5KRD0aX3Q39g==} @@ -877,6 +998,11 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-bigint@7.8.3': + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-class-properties@7.12.13': resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: @@ -1356,6 +1482,9 @@ packages: resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==} engines: {node: '>=6.9.0'} + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} @@ -1853,10 +1982,68 @@ packages: resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} engines: {node: '>=8'} + '@jest/console@29.7.0': + resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/core@29.7.0': + resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/environment@29.7.0': + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect-utils@29.7.0': + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect@29.7.0': + resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/fake-timers@29.7.0': + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/globals@29.7.0': + resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/reporters@29.7.0': + resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + '@jest/schemas@29.6.3': resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/source-map@29.6.3': + resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-result@29.7.0': + resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-sequencer@29.7.0': + resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/transform@29.7.0': + resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/types@29.6.3': resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -1892,6 +2079,14 @@ packages: resolution: {integrity: sha512-DPnl5lPX4v49eVxEbJnAizrpMdMTBz1qykZrAbBul9rfgk531v8oAt+Pm6O/rpAleRombNM7FJb5rYGzBJatOQ==} engines: {node: '>=18.0.0'} + '@ljharb/through@2.3.13': + resolution: {integrity: sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==} + engines: {node: '>= 0.4'} + + '@lukeed/csprng@1.1.0': + resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} + engines: {node: '>=8'} + '@mdx-js/mdx@3.0.1': resolution: {integrity: sha512-eIQ4QTrOWyL3LWEe/bu6Taqzq2HQvHcyTMaOrI95P2/LmJE7AsfPfgJGuFLPVqBUE1BC1rik3VIhU+s9u72arA==} @@ -1905,9 +2100,135 @@ packages: resolution: {integrity: sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==} engines: {node: '>=12.0.0'} + '@microsoft/tsdoc@0.15.1': + resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==} + '@napi-rs/wasm-runtime@0.2.4': resolution: {integrity: sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==} + '@nestjs/cli@10.4.9': + resolution: {integrity: sha512-s8qYd97bggqeK7Op3iD49X2MpFtW4LVNLAwXFkfbRxKME6IYT7X0muNTJ2+QfI8hpbNx9isWkrLWIp+g5FOhiA==} + engines: {node: '>= 16.14'} + hasBin: true + peerDependencies: + '@swc/cli': ^0.1.62 || ^0.3.0 || ^0.4.0 || ^0.5.0 + '@swc/core': ^1.3.62 + peerDependenciesMeta: + '@swc/cli': + optional: true + '@swc/core': + optional: true + + '@nestjs/common@10.4.15': + resolution: {integrity: sha512-vaLg1ZgwhG29BuLDxPA9OAcIlgqzp9/N8iG0wGapyUNTf4IY4O6zAHgN6QalwLhFxq7nOI021vdRojR1oF3bqg==} + peerDependencies: + class-transformer: '*' + class-validator: '*' + reflect-metadata: ^0.1.12 || ^0.2.0 + rxjs: ^7.1.0 + peerDependenciesMeta: + class-transformer: + optional: true + class-validator: + optional: true + + '@nestjs/core@10.4.15': + resolution: {integrity: sha512-UBejmdiYwaH6fTsz2QFBlC1cJHM+3UDeLZN+CiP9I1fRv2KlBZsmozGLbV5eS1JAVWJB4T5N5yQ0gjN8ZvcS2w==} + peerDependencies: + '@nestjs/common': ^10.0.0 + '@nestjs/microservices': ^10.0.0 + '@nestjs/platform-express': ^10.0.0 + '@nestjs/websockets': ^10.0.0 + reflect-metadata: ^0.1.12 || ^0.2.0 + rxjs: ^7.1.0 + peerDependenciesMeta: + '@nestjs/microservices': + optional: true + '@nestjs/platform-express': + optional: true + '@nestjs/websockets': + optional: true + + '@nestjs/mapped-types@2.0.6': + resolution: {integrity: sha512-84ze+CPfp1OWdpRi1/lOu59hOhTz38eVzJvRKrg9ykRFwDz+XleKfMsG0gUqNZYFa6v53XYzeD+xItt8uDW7NQ==} + peerDependencies: + '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 + class-transformer: ^0.4.0 || ^0.5.0 + class-validator: ^0.13.0 || ^0.14.0 + reflect-metadata: ^0.1.12 || ^0.2.0 + peerDependenciesMeta: + class-transformer: + optional: true + class-validator: + optional: true + + '@nestjs/platform-express@10.4.15': + resolution: {integrity: sha512-63ZZPkXHjoDyO7ahGOVcybZCRa7/Scp6mObQKjcX/fTEq1YJeU75ELvMsuQgc8U2opMGOBD7GVuc4DV0oeDHoA==} + peerDependencies: + '@nestjs/common': ^10.0.0 + '@nestjs/core': ^10.0.0 + + '@nestjs/platform-socket.io@10.4.15': + resolution: {integrity: sha512-KZAxNEADPwoORixh3NJgGYWMVGORVPKeTqjD7hbF8TPDLKWWxru9yasBQwEz2/wXH/WgpkQbbaYwx4nUjCIVpw==} + peerDependencies: + '@nestjs/common': ^10.0.0 + '@nestjs/websockets': ^10.0.0 + rxjs: ^7.1.0 + + '@nestjs/schematics@10.2.3': + resolution: {integrity: sha512-4e8gxaCk7DhBxVUly2PjYL4xC2ifDFexCqq1/u4TtivLGXotVk0wHdYuPYe1tHTHuR1lsOkRbfOCpkdTnigLVg==} + peerDependencies: + typescript: '>=4.8.2' + + '@nestjs/swagger@8.1.0': + resolution: {integrity: sha512-8hzH+r/31XshzXHC9vww4T0xjDAxMzvOaT1xAOvvY1LtXTWyNRCUP2iQsCYJOnnMrR+vydWjvRZiuB3hdvaHxA==} + peerDependencies: + '@fastify/static': ^6.0.0 || ^7.0.0 + '@nestjs/common': ^9.0.0 || ^10.0.0 + '@nestjs/core': ^9.0.0 || ^10.0.0 + class-transformer: '*' + class-validator: '*' + reflect-metadata: ^0.1.12 || ^0.2.0 + peerDependenciesMeta: + '@fastify/static': + optional: true + class-transformer: + optional: true + class-validator: + optional: true + + '@nestjs/testing@10.4.15': + resolution: {integrity: sha512-eGlWESkACMKti+iZk1hs6FUY/UqObmMaa8HAN9JLnaYkoLf1Jeh+EuHlGnfqo/Rq77oznNLIyaA3PFjrFDlNUg==} + peerDependencies: + '@nestjs/common': ^10.0.0 + '@nestjs/core': ^10.0.0 + '@nestjs/microservices': ^10.0.0 + '@nestjs/platform-express': ^10.0.0 + peerDependenciesMeta: + '@nestjs/microservices': + optional: true + '@nestjs/platform-express': + optional: true + + '@nestjs/throttler@6.3.0': + resolution: {integrity: sha512-IqTMbl5Iyxjts7NwbVriDND0Cnr8rwNqAPpF5HJE+UV+2VrVUBwCfDXKEiXu47vzzaQLlWPYegBsGO9OXxa+oQ==} + peerDependencies: + '@nestjs/common': ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 + '@nestjs/core': ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 + reflect-metadata: ^0.1.13 || ^0.2.0 + + '@nestjs/websockets@10.4.15': + resolution: {integrity: sha512-OmCUJwvtagzXfMVko595O98UI3M9zg+URL+/HV7vd3QPMCZ3uGCKSq15YYJ99LHJn9NyK4e4Szm2KnHtUg2QzA==} + peerDependencies: + '@nestjs/common': ^10.0.0 + '@nestjs/core': ^10.0.0 + '@nestjs/platform-socket.io': ^10.0.0 + reflect-metadata: ^0.1.12 || ^0.2.0 + rxjs: ^7.1.0 + peerDependenciesMeta: + '@nestjs/platform-socket.io': + optional: true + '@noble/curves@1.2.0': resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} @@ -1925,9 +2246,9 @@ packages: resolution: {integrity: sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==} engines: {node: '>= 16'} - '@noble/hashes@1.4.0': - resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} - engines: {node: '>= 16'} + '@noble/hashes@1.6.1': + resolution: {integrity: sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w==} + engines: {node: ^14.21.3 || >=16} '@noble/secp256k1@1.7.1': resolution: {integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==} @@ -2289,6 +2610,11 @@ packages: resolution: {integrity: sha512-9AOwbY/E7OlLCFu+6jhJGUIs+qurE2/3Pldooe7cJPqQmSQeJuVZuL6A2xHtbSG7VsXTq5Yj8dVvK1KmT45SIA==} hasBin: true + '@nuxtjs/opencollective@0.3.2': + resolution: {integrity: sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA==} + engines: {node: '>=8.0.0', npm: '>=5.0.0'} + hasBin: true + '@nx/devkit@19.2.0': resolution: {integrity: sha512-fK3zRUE2SLp9BUomFiyCuAX2E1yfWYE/hKimniscsvM34/u/xLZYVmmZ0/jfpGPbyaonXKZr2KTb7RimX/hyqg==} peerDependencies: @@ -2517,6 +2843,9 @@ packages: '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + '@scarf/scarf@1.4.0': + resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==} + '@scure/base@1.1.6': resolution: {integrity: sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g==} @@ -2610,9 +2939,18 @@ packages: resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==} engines: {node: '>=14.16'} + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@10.3.0': + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + '@slorber/remark-comment@1.0.0': resolution: {integrity: sha512-RCE24n7jsOj1M0UPvIQCHTe7fI0sFL4S2nwKVWwHyVr/wI/H8GosgsJGyhnsZoGFnD/P2hLf1mSbrrgSLN93NA==} + '@socket.io/component-emitter@3.1.2': + resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} + '@solidity-parser/parser@0.14.5': resolution: {integrity: sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==} @@ -2746,6 +3084,18 @@ packages: '@types/acorn@4.0.6': resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==} + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.6.8': + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.20.6': + resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} + '@types/bn.js@4.11.6': resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==} @@ -2782,6 +3132,15 @@ packages: '@types/conventional-commits-parser@5.0.0': resolution: {integrity: sha512-loB369iXNmAZglwWATL+WRe+CRMmmBPtpolYzIebFaX4YA3x+BEfLqhUAV9WanycKI3TG1IMr5bMJDajDKLlUQ==} + '@types/cookie@0.4.1': + resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==} + + '@types/cookiejar@2.1.5': + resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} + + '@types/cors@2.8.17': + resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} + '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} @@ -2797,18 +3156,30 @@ packages: '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/express-serve-static-core@4.19.3': resolution: {integrity: sha512-KOzM7MhcBFlmnlr/fzISFF5vGWVSvN6fTd4T+ExOt08bA/dA5kpSzY52nMsI1KDFmUREpJelPYyuslLRSjjgCg==} + '@types/express-serve-static-core@5.0.3': + resolution: {integrity: sha512-JEhMNwUJt7bw728CydvYzntD0XJeTmDnvwLlbfbAhE7Tbslm/ax6bdIiUwTgeVlZTsJQPwZwKpAkyDtIjsvx3g==} + '@types/express@4.17.21': resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} + '@types/express@5.0.0': + resolution: {integrity: sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ==} + '@types/form-data@0.0.33': resolution: {integrity: sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==} '@types/glob@7.2.0': resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} + '@types/graceful-fs@4.1.9': + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + '@types/gtag.js@0.0.12': resolution: {integrity: sha512-YQV9bUsemkzG81Ea295/nF/5GijnD2Af7QhEofh7xu+kvCN6RdodgNwwGWXB5GMI3NoyvQo0odNctoH/qLMIpg==} @@ -2839,6 +3210,9 @@ packages: '@types/istanbul-reports@3.0.4': resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + '@types/jest@29.5.14': + resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -2866,6 +3240,9 @@ packages: '@types/mdx@2.0.13': resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==} + '@types/methods@1.1.4': + resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==} + '@types/mime@1.3.5': resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} @@ -2896,6 +3273,9 @@ packages: '@types/node@17.0.45': resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} + '@types/node@22.10.5': + resolution: {integrity: sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==} + '@types/node@22.7.5': resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} @@ -2971,6 +3351,15 @@ packages: '@types/sockjs@0.3.36': resolution: {integrity: sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==} + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/superagent@8.1.9': + resolution: {integrity: sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==} + + '@types/supertest@6.0.2': + resolution: {integrity: sha512-137ypx2lk/wTQbW6An6safu9hXmajAifU/s7szAHLN/FeIm5w7yR0Wkl9fdJMRSHwOn4HLAI0DaB2TOORuhPDg==} + '@types/unist@2.0.10': resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==} @@ -2980,6 +3369,9 @@ packages: '@types/uuid@10.0.0': resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + '@types/validator@13.12.2': + resolution: {integrity: sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA==} + '@types/ws@7.4.7': resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} @@ -3056,48 +3448,93 @@ packages: '@webassemblyjs/ast@1.12.1': resolution: {integrity: sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==} + '@webassemblyjs/ast@1.14.1': + resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} + '@webassemblyjs/floating-point-hex-parser@1.11.6': resolution: {integrity: sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==} + '@webassemblyjs/floating-point-hex-parser@1.13.2': + resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} + '@webassemblyjs/helper-api-error@1.11.6': resolution: {integrity: sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==} + '@webassemblyjs/helper-api-error@1.13.2': + resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} + '@webassemblyjs/helper-buffer@1.12.1': resolution: {integrity: sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==} + '@webassemblyjs/helper-buffer@1.14.1': + resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} + '@webassemblyjs/helper-numbers@1.11.6': resolution: {integrity: sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==} + '@webassemblyjs/helper-numbers@1.13.2': + resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} + '@webassemblyjs/helper-wasm-bytecode@1.11.6': resolution: {integrity: sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==} + '@webassemblyjs/helper-wasm-bytecode@1.13.2': + resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} + '@webassemblyjs/helper-wasm-section@1.12.1': resolution: {integrity: sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==} + '@webassemblyjs/helper-wasm-section@1.14.1': + resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} + '@webassemblyjs/ieee754@1.11.6': resolution: {integrity: sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==} + '@webassemblyjs/ieee754@1.13.2': + resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} + '@webassemblyjs/leb128@1.11.6': resolution: {integrity: sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==} + '@webassemblyjs/leb128@1.13.2': + resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} + '@webassemblyjs/utf8@1.11.6': resolution: {integrity: sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==} + '@webassemblyjs/utf8@1.13.2': + resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} + '@webassemblyjs/wasm-edit@1.12.1': resolution: {integrity: sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==} + '@webassemblyjs/wasm-edit@1.14.1': + resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} + '@webassemblyjs/wasm-gen@1.12.1': resolution: {integrity: sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==} + '@webassemblyjs/wasm-gen@1.14.1': + resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} + '@webassemblyjs/wasm-opt@1.12.1': resolution: {integrity: sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==} + '@webassemblyjs/wasm-opt@1.14.1': + resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} + '@webassemblyjs/wasm-parser@1.12.1': resolution: {integrity: sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==} + '@webassemblyjs/wasm-parser@1.14.1': + resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} + '@webassemblyjs/wast-printer@1.12.1': resolution: {integrity: sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==} + '@webassemblyjs/wast-printer@1.14.1': + resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + '@whatwg-node/events@0.0.3': resolution: {integrity: sha512-IqnKIDWfXBJkvy/k6tzskWTc2NK3LcqHlb+KHGCrjOCH4jfQckRX0NAiIcC/vIqQkzLYw2r2CTSwAxcrtcD6lA==} @@ -3187,6 +3624,11 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + add-stream@1.0.0: resolution: {integrity: sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==} @@ -3237,6 +3679,9 @@ packages: ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@8.12.0: + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + ajv@8.16.0: resolution: {integrity: sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==} @@ -3334,6 +3779,9 @@ packages: app-module-path@2.2.0: resolution: {integrity: sha512-gkco+qxENJV+8vFcDiiFhuoSvRXb2a/QPqpSoWhVz829VNJfOTnELbBmPmNKFxf3xdNnw4DWCkzkDaavcX/1YQ==} + append-field@1.0.0: + resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} + append-transform@2.0.0: resolution: {integrity: sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==} engines: {node: '>=8'} @@ -3386,6 +3834,9 @@ packages: resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} engines: {node: '>= 0.4'} + array-timsort@1.0.3: + resolution: {integrity: sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==} + array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} @@ -3505,6 +3956,12 @@ packages: b4a@1.6.6: resolution: {integrity: sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==} + babel-jest@29.7.0: + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + babel-loader@9.1.3: resolution: {integrity: sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==} engines: {node: '>= 14.15.0'} @@ -3515,6 +3972,14 @@ packages: babel-plugin-dynamic-import-node@2.3.3: resolution: {integrity: sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==} + babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + + babel-plugin-jest-hoist@29.6.3: + resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-plugin-polyfill-corejs2@0.4.11: resolution: {integrity: sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==} peerDependencies: @@ -3530,6 +3995,17 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-preset-current-node-syntax@1.1.0: + resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==} + peerDependencies: + '@babel/core': ^7.0.0 + + babel-preset-jest@29.6.3: + resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} @@ -3542,6 +4018,10 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + base64id@2.0.0: + resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} + engines: {node: ^4.5.0 || >= 5.9} + batch@0.6.1: resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} @@ -3623,6 +4103,10 @@ packages: resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + body-parser@1.20.3: + resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + bonjour-service@1.2.1: resolution: {integrity: sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==} @@ -3668,12 +4152,24 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + browserslist@4.24.3: + resolution: {integrity: sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bs-logger@0.2.6: + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} + bs58@4.0.1: resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} bs58check@2.1.2: resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==} + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + buffer-alloc-unsafe@1.1.0: resolution: {integrity: sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==} @@ -3764,6 +4260,9 @@ packages: caniuse-lite@1.0.30001628: resolution: {integrity: sha512-S3BnR4Kh26TBxbi5t5kpbcUlLJb9lhtDXISDPwOfI+JoC+ik0QksvkZtUVyikw3hjnkgkMPSJ8oIM9yMm9vflA==} + caniuse-lite@1.0.30001690: + resolution: {integrity: sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==} + cardinal@2.1.1: resolution: {integrity: sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==} hasBin: true @@ -3923,6 +4422,15 @@ packages: circomlibjs@0.1.7: resolution: {integrity: sha512-GRAUoAlKAsiiTa+PA725G9RmEmJJRc8tRFxw/zKktUxlQISGznT4hH4ESvW8FNTsrGg/nNd06sGP/Wlx0LUHVg==} + cjs-module-lexer@1.4.1: + resolution: {integrity: sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==} + + class-transformer@0.5.1: + resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==} + + class-validator@0.14.1: + resolution: {integrity: sha512-2VEG9JICxIqTpoK1eMzZqaV+u/EiwEJkMGzTrZf6sU/fwsnOITVgYJ8yojSy6CaXtO9V0Cc6ZQZ8h8m4UBuLwQ==} + clean-css@5.3.3: resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==} engines: {node: '>= 10.0'} @@ -3983,6 +4491,10 @@ packages: resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} engines: {node: '>= 10'} + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + cliui@6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} @@ -4013,9 +4525,16 @@ packages: resolution: {integrity: sha512-FMabTRlc5t5zjdenF6mS0MBeFZm0XqHqeOkcskKFb/LYCcRQ5fVgLOHVc4Lq9CqABd9zhjwPjMBCJvMCziSVtA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + collapse-white-space@2.1.0: resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} + collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -4084,6 +4603,10 @@ packages: commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + commander@5.1.0: resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} engines: {node: '>= 6'} @@ -4100,6 +4623,10 @@ packages: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} + comment-json@4.2.5: + resolution: {integrity: sha512-bKw/r35jR3HGt5PEPm1ljsQQGyCrR8sFGNiN5L+ykDHdpO8Smxkrkla9Yi6NkQyUrb8V54PGhfMs6NrIwtxtdw==} + engines: {node: '>= 6'} + commitizen@4.3.0: resolution: {integrity: sha512-H0iNtClNEhT0fotHvGV3E9tDejDeS04sN1veIebsKYGMuGscFaswRoYJKmT3eW85eIJAs0F28bG2+a/9wCOfPw==} engines: {node: '>= 12'} @@ -4121,6 +4648,9 @@ packages: compare-func@2.0.0: resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} + component-emitter@1.3.1: + resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} + compressible@2.0.18: resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} engines: {node: '>= 0.6'} @@ -4232,6 +4762,17 @@ packages: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} + cookie@0.7.1: + resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} + engines: {node: '>= 0.6'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + cookiejar@2.1.4: + resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==} + copy-text-to-clipboard@3.2.0: resolution: {integrity: sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q==} engines: {node: '>=12'} @@ -4254,6 +4795,10 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cors@2.8.5: + resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + engines: {node: '>= 0.10'} + cosmiconfig-typescript-loader@5.0.0: resolution: {integrity: sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==} engines: {node: '>=v16'} @@ -4294,6 +4839,11 @@ packages: create-hmac@1.1.7: resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + create-jest@29.7.0: + resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} @@ -4436,6 +4986,9 @@ packages: resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} engines: {node: '>= 0.4'} + date-fns@4.1.0: + resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + dateformat@3.0.3: resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==} @@ -4612,6 +5165,10 @@ packages: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} + detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + detect-node@2.1.0: resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} @@ -4628,6 +5185,9 @@ packages: devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + dezalgo@1.0.4: + resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} + diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -4764,6 +5324,9 @@ packages: electron-to-chromium@1.4.790: resolution: {integrity: sha512-eVGeQxpaBYbomDBa/Mehrs28MdvCXfJmEFzaMFsv8jH/MJDLIylJN81eTJ5kvx7B7p18OiPK0BkC06lydEy63A==} + electron-to-chromium@1.5.76: + resolution: {integrity: sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ==} + elliptic@6.5.4: resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} @@ -4774,6 +5337,10 @@ packages: resolution: {integrity: sha512-gYCwo7kh5S3IDyZPLZf6hSS0MnZT8QmJFqYvbqlDZSbwdZlY6QZWxJ4i/6UhITOJ4XzyI647Bm2MXKCLqnJ4nQ==} engines: {node: '>4.0'} + emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + emoji-regex@10.3.0: resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==} @@ -4797,6 +5364,10 @@ packages: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + encoding-sniffer@0.2.0: resolution: {integrity: sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==} @@ -4806,10 +5377,22 @@ packages: end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + engine.io-parser@5.2.3: + resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} + engines: {node: '>=10.0.0'} + + engine.io@6.6.2: + resolution: {integrity: sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw==} + engines: {node: '>=10.2.0'} + enhanced-resolve@5.17.0: resolution: {integrity: sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==} engines: {node: '>=10.13.0'} + enhanced-resolve@5.18.0: + resolution: {integrity: sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ==} + engines: {node: '>=10.13.0'} + enquirer@2.3.6: resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} engines: {node: '>=8.6'} @@ -4894,6 +5477,10 @@ packages: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + escape-goat@4.0.0: resolution: {integrity: sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==} engines: {node: '>=12'} @@ -4905,6 +5492,10 @@ packages: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -5228,10 +5819,18 @@ packages: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} + exit@0.1.2: + resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + engines: {node: '>= 0.8.0'} + expand-tilde@2.0.2: resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} engines: {node: '>=0.10.0'} + expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + exponential-backoff@3.1.1: resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==} @@ -5239,6 +5838,10 @@ packages: resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} engines: {node: '>= 0.10.0'} + express@4.21.2: + resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} + engines: {node: '>= 0.10.0'} + extend-shallow@2.0.1: resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} engines: {node: '>=0.10.0'} @@ -5286,6 +5889,9 @@ packages: fast-querystring@1.1.2: resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + fast-url-parser@1.1.3: resolution: {integrity: sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==} @@ -5306,6 +5912,9 @@ packages: resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} engines: {node: '>=0.8.0'} + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + feed@4.2.2: resolution: {integrity: sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==} engines: {node: '>=0.4.0'} @@ -5351,6 +5960,10 @@ packages: resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} engines: {node: '>= 0.8'} + finalhandler@1.3.1: + resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} + engines: {node: '>= 0.8'} + find-cache-dir@3.3.2: resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} engines: {node: '>=8'} @@ -5449,6 +6062,13 @@ packages: vue-template-compiler: optional: true + fork-ts-checker-webpack-plugin@9.0.2: + resolution: {integrity: sha512-Uochze2R8peoN1XqlSi/rGUkDQpRogtLFocP9+PGu68zk1BDAKXfdeCdyVZpgTk8V8WFVQXdEz426VKjXLO1Gg==} + engines: {node: '>=12.13.0', yarn: '>=1.0.0'} + peerDependencies: + typescript: '>3.6.0' + webpack: ^5.11.0 + form-data-encoder@2.1.4: resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} engines: {node: '>= 14.17'} @@ -5465,6 +6085,9 @@ packages: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} + formidable@3.5.2: + resolution: {integrity: sha512-Jqc1btCy3QzRbJaICGwKcBfGWuLADRerLzDqi2NwSt/UkXLsHJw2TVResiaoBufHVHy9aSgClOHCeJsSsFLTbg==} + forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} @@ -5655,6 +6278,10 @@ packages: engines: {node: '>=16 || 14 >=14.18'} hasBin: true + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + glob@11.0.0: resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==} engines: {node: 20 || >=22} @@ -5828,6 +6455,10 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-own-prop@2.0.0: + resolution: {integrity: sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==} + engines: {node: '>=8'} + has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} @@ -5911,6 +6542,14 @@ packages: heap@0.2.7: resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==} + helmet@8.0.0: + resolution: {integrity: sha512-VyusHLEIIO5mjQPUI1wpOAEu+wl6Q0998jzTxqUYGE45xCIcAxy3MsbEK/yyJUJ3ADeMoB6MornPH6GMWAf+Pw==} + engines: {node: '>=18.0.0'} + + hexoid@2.0.0: + resolution: {integrity: sha512-qlspKUK7IlSQv2o+5I7yhUd7TxlOG2Vr5LTa3ve2XSNVKAL/n/u/7KLvKmFNimomDIKvZFXWHv0T12mv7rT8Aw==} + engines: {node: '>=8'} + history@4.10.1: resolution: {integrity: sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==} @@ -6172,6 +6811,10 @@ packages: resolution: {integrity: sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==} engines: {node: '>=12.0.0'} + inquirer@9.2.15: + resolution: {integrity: sha512-vI2w4zl/mDluHt9YEQ/543VTCwPKWiHzKtm9dM2V0NdFcqEexDAjUHzO1oA60HRNaVifGXXM1tRRNluLVHa0Kg==} + engines: {node: '>=18'} + interface-datastore@6.1.1: resolution: {integrity: sha512-AmCS+9CT34pp2u0QQVXjKztkuq3y5T+BIciuiHDDtDZucZD8VudosnSdUyXJV6IsRkN5jc4RFDhCk1O6Q3Gxjg==} @@ -6322,6 +6965,10 @@ packages: resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==} engines: {node: '>=18'} + is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + is-generator-function@1.0.10: resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} engines: {node: '>= 0.4'} @@ -6550,6 +7197,10 @@ packages: resolution: {integrity: sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==} engines: {node: '>=8'} + istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + istanbul-lib-instrument@6.0.2: resolution: {integrity: sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==} engines: {node: '>=10'} @@ -6591,6 +7242,10 @@ packages: it-to-stream@1.0.0: resolution: {integrity: sha512-pLULMZMAB/+vbdvbZtebC0nWBTbG581lk6w8P7DfIIIKUfa8FbY7Oi0FxZcFPbxvISs7A9E+cMpLDBc1XhpAOA==} + iterare@1.2.1: + resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==} + engines: {node: '>=6'} + iterator.prototype@1.1.3: resolution: {integrity: sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==} engines: {node: '>= 0.4'} @@ -6613,18 +7268,121 @@ packages: engines: {node: '>=8'} hasBin: true + jest-changed-files@29.7.0: + resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-circus@29.7.0: + resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-cli@29.7.0: + resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jest-config@29.7.0: + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + jest-diff@29.7.0: resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-docblock@29.7.0: + resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-each@29.7.0: + resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-environment-node@29.7.0: + resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-get-type@29.6.3: resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-haste-map@29.7.0: + resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-leak-detector@29.7.0: + resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-pnp-resolver@1.2.3: + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + + jest-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve-dependencies@29.7.0: + resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve@29.7.0: + resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runner@29.7.0: + resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runtime@29.7.0: + resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-snapshot@29.7.0: + resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-util@29.7.0: resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-watcher@29.7.0: + resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-worker@27.5.1: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} @@ -6633,6 +7391,16 @@ packages: resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest@29.7.0: + resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + jiti@1.21.3: resolution: {integrity: sha512-uy2bNX5zQ+tESe+TiC7ilGRz8AtRGmnJH55NC5S0nSUjvvvM2hJHmefHErugGXN4pNv4Qx7vLsnNw9qJ9mtIsw==} hasBin: true @@ -6719,6 +7487,9 @@ packages: jsonc-parser@3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + jsonc-parser@3.2.1: + resolution: {integrity: sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==} + jsonc-parser@3.3.1: resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} @@ -6813,6 +7584,9 @@ packages: resolution: {integrity: sha512-26zzwoBNAvX9AWOPiqqF6FG4HrSCPsHFkQm7nT+xU1ggAujL/eae81RnCv4CJ2In9q9fh10B88sYSzKCUh/Ghg==} engines: {node: ^16.14.0 || >=18.0.0} + libphonenumber-js@1.11.17: + resolution: {integrity: sha512-Jr6v8thd5qRlOlc6CslSTzGzzQW03uiscab7KHQZX1Dfo4R6n6FDhZ0Hri6/X7edLIDv9gl4VMZXhxTjLnl0VQ==} + lilconfig@3.1.2: resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} engines: {node: '>=14'} @@ -7041,6 +7815,10 @@ packages: lunr@2.3.9: resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} + magic-string@0.30.8: + resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==} + engines: {node: '>=12'} + make-dir@2.1.0: resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} engines: {node: '>=6'} @@ -7060,6 +7838,9 @@ packages: resolution: {integrity: sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==} engines: {node: ^16.14.0 || >=18.0.0} + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + map-obj@1.0.1: resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} engines: {node: '>=0.10.0'} @@ -7183,6 +7964,9 @@ packages: merge-descriptors@1.0.1: resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} + merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + merge-options@3.0.4: resolution: {integrity: sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==} engines: {node: '>=10'} @@ -7359,6 +8143,11 @@ packages: engines: {node: '>=4'} hasBin: true + mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -7514,6 +8303,10 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + multer@1.4.4-lts.1: + resolution: {integrity: sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==} + engines: {node: '>= 6.0.0'} + multiaddr-to-uri@8.0.0: resolution: {integrity: sha512-dq4p/vsOOUdVEd1J1gl+R2GFrXJQH8yjLtz4hodqdVbieg39LvBOdMQRdQnfbg5LSM/q1BYNVf5CBbwZFFqBgA==} deprecated: This module is deprecated, please upgrade to @multiformats/multiaddr-to-uri @@ -7583,6 +8376,9 @@ packages: no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + node-abort-controller@3.1.1: + resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} + node-addon-api@2.0.2: resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} @@ -7627,6 +8423,9 @@ packages: engines: {node: ^16.14.0 || >=18.0.0} hasBin: true + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + node-machine-id@1.1.12: resolution: {integrity: sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==} @@ -7637,6 +8436,9 @@ packages: node-releases@2.0.14: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + nofilter@3.1.0: resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} engines: {node: '>=12.19'} @@ -7740,6 +8542,10 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} @@ -8052,6 +8858,9 @@ packages: resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} engines: {node: 20 || >=22} + path-to-regexp@0.1.12: + resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} + path-to-regexp@0.1.7: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} @@ -8061,6 +8870,9 @@ packages: path-to-regexp@2.2.1: resolution: {integrity: sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==} + path-to-regexp@3.3.0: + resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==} + path-type@3.0.0: resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} engines: {node: '>=4'} @@ -8082,10 +8894,17 @@ packages: picocolors@1.0.1: resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + picomatch@4.0.1: + resolution: {integrity: sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==} + engines: {node: '>=12'} + pidtree@0.6.0: resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} engines: {node: '>=0.10'} @@ -8107,6 +8926,10 @@ packages: resolution: {integrity: sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==} engines: {node: '>=10'} + pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} @@ -8530,8 +9353,8 @@ packages: resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} engines: {node: '>=0.6'} - qs@6.12.1: - resolution: {integrity: sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==} + qs@6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} engines: {node: '>=0.6'} queue-microtask@1.2.3: @@ -8722,6 +9545,9 @@ packages: resolution: {integrity: sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==} engines: {node: '>=6'} + reflect-metadata@0.2.2: + resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + reflect.getprototypeof@1.0.6: resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} engines: {node: '>= 0.4'} @@ -8804,6 +9630,10 @@ packages: renderkid@3.0.0: resolution: {integrity: sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==} + repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + req-cwd@2.0.0: resolution: {integrity: sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==} engines: {node: '>=4'} @@ -8862,6 +9692,10 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve.exports@2.0.3: + resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} + engines: {node: '>=10'} + resolve@1.1.7: resolution: {integrity: sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==} @@ -8949,6 +9783,10 @@ packages: resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} engines: {node: '>=0.12.0'} + run-async@3.0.0: + resolution: {integrity: sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==} + engines: {node: '>=0.12.0'} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -9054,6 +9892,10 @@ packages: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} engines: {node: '>= 0.8.0'} + send@0.19.0: + resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} + engines: {node: '>= 0.8.0'} + serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} @@ -9068,6 +9910,10 @@ packages: resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} engines: {node: '>= 0.8.0'} + serve-static@1.16.2: + resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} + engines: {node: '>= 0.8.0'} + set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} @@ -9187,6 +10033,17 @@ packages: resolution: {integrity: sha512-h+3c4rXZKLhLuHk4LHydZCk/h5GcNvk5GjVKRRkHmfb6Ntf8gHOA9zea3g656iclRuhqQ3iKDWFgiD9ypLrKiA==} hasBin: true + socket.io-adapter@2.5.5: + resolution: {integrity: sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==} + + socket.io-parser@4.2.4: + resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} + engines: {node: '>=10.0.0'} + + socket.io@4.8.1: + resolution: {integrity: sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==} + engines: {node: '>=10.2.0'} + sockjs@0.3.24: resolution: {integrity: sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==} @@ -9233,6 +10090,9 @@ packages: resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} engines: {node: '>=0.10.0'} + source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} @@ -9304,6 +10164,10 @@ packages: stack-trace@0.0.10: resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + stacktrace-parser@0.1.10: resolution: {integrity: sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==} engines: {node: '>=6'} @@ -9339,6 +10203,10 @@ packages: string-format@2.0.0: resolution: {integrity: sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==} + string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + string-width@2.1.1: resolution: {integrity: sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==} engines: {node: '>=4'} @@ -9462,6 +10330,14 @@ packages: peerDependencies: postcss: ^8.4.31 + superagent@9.0.2: + resolution: {integrity: sha512-xuW7dzkUpcJq7QnhOsnNUgtYp3xRwpt2F7abdRYIpCsAt0hhUqia0EdxyXZQQpNmGtsCzYHryaKSV3q3GJnq7w==} + engines: {node: '>=14.18.0'} + + supertest@7.0.0: + resolution: {integrity: sha512-qlsr7fIC0lSddmA3tzojvzubYxvlGtzumcdHgPwbFWMISQwL22MhM2Y3LNt+6w9Yyx7559VW5ab70dgphm8qQA==} + engines: {node: '>=14.18.0'} + supports-color@3.2.3: resolution: {integrity: sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==} engines: {node: '>=0.8.0'} @@ -9494,6 +10370,13 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + swagger-ui-dist@5.18.2: + resolution: {integrity: sha512-J+y4mCw/zXh1FOj5wGJvnAajq6XgHOyywsa9yITmwxIlJbMqITq3gYRZHaeqLVH/eV/HOPphE6NjF+nbSNC5Zw==} + + symbol-observable@4.0.0: + resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} + engines: {node: '>=0.10'} + sync-request@6.1.0: resolution: {integrity: sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==} engines: {node: '>=8.0.0'} @@ -9619,6 +10502,9 @@ packages: resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} engines: {node: '>=14.14'} + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + to-buffer@1.1.1: resolution: {integrity: sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==} @@ -9641,6 +10527,10 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + treeverse@3.0.0: resolution: {integrity: sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -9673,6 +10563,30 @@ packages: peerDependencies: typescript: '>=3.7.0' + ts-jest@29.2.5: + resolution: {integrity: sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==} + engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/transform': ^29.0.0 + '@jest/types': ^29.0.0 + babel-jest: ^29.0.0 + esbuild: '*' + jest: ^29.0.0 + typescript: '>=4.3 <6' + peerDependenciesMeta: + '@babel/core': + optional: true + '@jest/transform': + optional: true + '@jest/types': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + ts-mocha@10.0.0: resolution: {integrity: sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw==} engines: {node: '>= 6.X.X'} @@ -9699,6 +10613,10 @@ packages: engines: {node: '>=4.2.0'} hasBin: true + tsconfig-paths-webpack-plugin@4.2.0: + resolution: {integrity: sha512-zbem3rfRS8BgeNK50Zz5SIQgXzLafiHjOwUAvk/38/o1jHn/V5QAgVUcz884or7WYcPaH3N2CIfUc2u0ul7UcA==} + engines: {node: '>=10.13.0'} + tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} @@ -9715,6 +10633,9 @@ packages: tslib@2.7.0: resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsort@0.0.1: resolution: {integrity: sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==} @@ -9829,6 +10750,11 @@ packages: engines: {node: '>=14.17'} hasBin: true + typescript@5.7.2: + resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} + engines: {node: '>=14.17'} + hasBin: true + typical@4.0.0: resolution: {integrity: sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==} engines: {node: '>=8'} @@ -9845,6 +10771,10 @@ packages: engines: {node: '>=0.8.0'} hasBin: true + uid@2.0.2: + resolution: {integrity: sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==} + engines: {node: '>=8'} + uint8arrays@3.1.1: resolution: {integrity: sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==} @@ -9857,6 +10787,9 @@ packages: undici-types@6.19.8: resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + undici-types@6.20.0: + resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + undici@5.28.4: resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} engines: {node: '>=14.0'} @@ -9953,6 +10886,12 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + update-browserslist-db@1.1.1: + resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + update-notifier@6.0.2: resolution: {integrity: sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==} engines: {node: '>=14.16'} @@ -10012,6 +10951,10 @@ packages: v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + v8-to-istanbul@9.3.0: + resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} + engines: {node: '>=10.12.0'} + validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} @@ -10023,6 +10966,10 @@ packages: resolution: {integrity: sha512-8X1OWlERjiUY6P6tdeU9E0EwO8RA3bahoOVG7ulOZT5MqgNDUO/BQoVjYiHPcNe+v8glsboZRIw9iToMAA2zAA==} engines: {node: '>= 12'} + validator@13.12.0: + resolution: {integrity: sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==} + engines: {node: '>= 0.10'} + value-equal@1.0.1: resolution: {integrity: sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==} @@ -10068,6 +11015,9 @@ packages: walk-up-path@3.0.1: resolution: {integrity: sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==} + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + wasmbuilder@0.0.16: resolution: {integrity: sha512-Qx3lEFqaVvp1cEYW7Bfi+ebRJrOiwz2Ieu7ZG2l7YyeSJIok/reEQCQCuicj/Y32ITIJuGIM9xZQppGx5LrQdA==} @@ -10146,6 +11096,10 @@ packages: resolution: {integrity: sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==} engines: {node: '>=10.0.0'} + webpack-node-externals@3.0.0: + resolution: {integrity: sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==} + engines: {node: '>=6'} + webpack-sources@3.2.3: resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} engines: {node: '>=10.13.0'} @@ -10160,6 +11114,16 @@ packages: webpack-cli: optional: true + webpack@5.97.1: + resolution: {integrity: sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + webpackbar@5.0.2: resolution: {integrity: sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==} engines: {node: '>=12'} @@ -10274,6 +11238,10 @@ packages: write-file-atomic@3.0.3: resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} + write-file-atomic@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + write-file-atomic@5.0.1: resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -10522,6 +11490,38 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 + '@angular-devkit/core@17.3.11(chokidar@3.6.0)': + dependencies: + ajv: 8.12.0 + ajv-formats: 2.1.1(ajv@8.12.0) + jsonc-parser: 3.2.1 + picomatch: 4.0.1 + rxjs: 7.8.1 + source-map: 0.7.4 + optionalDependencies: + chokidar: 3.6.0 + + '@angular-devkit/schematics-cli@17.3.11(chokidar@3.6.0)': + dependencies: + '@angular-devkit/core': 17.3.11(chokidar@3.6.0) + '@angular-devkit/schematics': 17.3.11(chokidar@3.6.0) + ansi-colors: 4.1.3 + inquirer: 9.2.15 + symbol-observable: 4.0.0 + yargs-parser: 21.1.1 + transitivePeerDependencies: + - chokidar + + '@angular-devkit/schematics@17.3.11(chokidar@3.6.0)': + dependencies: + '@angular-devkit/core': 17.3.11(chokidar@3.6.0) + jsonc-parser: 3.2.1 + magic-string: 0.30.8 + ora: 5.4.1 + rxjs: 7.8.1 + transitivePeerDependencies: + - chokidar + '@arrows/array@1.4.1': dependencies: '@arrows/composition': 1.2.2 @@ -10773,6 +11773,11 @@ snapshots: '@babel/core': 7.24.7 '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.7)': + dependencies: + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.7)': dependencies: '@babel/core': 7.24.7 @@ -11403,17 +12408,19 @@ snapshots: '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 + '@bcoe/v8-coverage@0.2.3': {} + '@colors/colors@1.5.0': {} '@commander-js/extra-typings@12.1.0(commander@12.1.0)': dependencies: commander: 12.1.0 - '@commitlint/cli@19.5.0(@types/node@22.9.0)(typescript@5.6.3)': + '@commitlint/cli@19.5.0(@types/node@22.10.5)(typescript@5.6.3)': dependencies: '@commitlint/format': 19.5.0 '@commitlint/lint': 19.5.0 - '@commitlint/load': 19.5.0(@types/node@22.9.0)(typescript@5.6.3) + '@commitlint/load': 19.5.0(@types/node@22.10.5)(typescript@5.6.3) '@commitlint/read': 19.5.0 '@commitlint/types': 19.5.0 tinyexec: 0.3.0 @@ -11469,7 +12476,7 @@ snapshots: '@commitlint/rules': 19.5.0 '@commitlint/types': 19.5.0 - '@commitlint/load@19.2.0(@types/node@22.9.0)(typescript@5.6.3)': + '@commitlint/load@19.2.0(@types/node@22.10.5)(typescript@5.6.3)': dependencies: '@commitlint/config-validator': 19.0.3 '@commitlint/execute-rule': 19.0.0 @@ -11477,7 +12484,7 @@ snapshots: '@commitlint/types': 19.5.0 chalk: 5.3.0 cosmiconfig: 9.0.0(typescript@5.6.3) - cosmiconfig-typescript-loader: 5.0.0(@types/node@22.9.0)(cosmiconfig@9.0.0(typescript@5.6.3))(typescript@5.6.3) + cosmiconfig-typescript-loader: 5.0.0(@types/node@22.10.5)(cosmiconfig@9.0.0(typescript@5.6.3))(typescript@5.6.3) lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 @@ -11486,7 +12493,7 @@ snapshots: - typescript optional: true - '@commitlint/load@19.5.0(@types/node@22.9.0)(typescript@5.6.3)': + '@commitlint/load@19.5.0(@types/node@22.10.5)(typescript@5.6.3)': dependencies: '@commitlint/config-validator': 19.5.0 '@commitlint/execute-rule': 19.5.0 @@ -11494,7 +12501,7 @@ snapshots: '@commitlint/types': 19.5.0 chalk: 5.3.0 cosmiconfig: 9.0.0(typescript@5.6.3) - cosmiconfig-typescript-loader: 5.0.0(@types/node@22.9.0)(cosmiconfig@9.0.0(typescript@5.6.3))(typescript@5.6.3) + cosmiconfig-typescript-loader: 5.0.0(@types/node@22.10.5)(cosmiconfig@9.0.0(typescript@5.6.3))(typescript@5.6.3) lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 @@ -11766,12 +12773,12 @@ snapshots: cssnano-preset-advanced: 6.1.2(postcss@8.4.38) postcss: 8.4.38 postcss-sort-media-queries: 5.2.0(postcss@8.4.38) - tslib: 2.6.3 + tslib: 2.7.0 '@docusaurus/logger@3.5.2': dependencies: chalk: 4.1.2 - tslib: 2.6.3 + tslib: 2.7.0 '@docusaurus/mdx-loader@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: @@ -11795,7 +12802,7 @@ snapshots: remark-frontmatter: 5.0.0 remark-gfm: 4.0.0 stringify-object: 3.3.0 - tslib: 2.6.3 + tslib: 2.7.0 unified: 11.0.4 unist-util-visit: 5.0.0 url-loader: 4.1.1(file-loader@6.2.0(webpack@5.92.1))(webpack@5.92.1) @@ -11847,7 +12854,7 @@ snapshots: react-dom: 18.3.1(react@18.3.1) reading-time: 1.5.0 srcset: 4.0.0 - tslib: 2.6.3 + tslib: 2.7.0 unist-util-visit: 5.0.0 utility-types: 3.11.0 webpack: 5.92.1 @@ -11888,7 +12895,7 @@ snapshots: lodash: 4.17.21 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.6.3 + tslib: 2.7.0 utility-types: 3.11.0 webpack: 5.92.1 transitivePeerDependencies: @@ -11928,7 +12935,7 @@ snapshots: lodash: 4.17.21 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.6.3 + tslib: 2.7.0 utility-types: 3.11.0 webpack: 5.92.1 transitivePeerDependencies: @@ -11960,7 +12967,7 @@ snapshots: fs-extra: 11.2.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.6.3 + tslib: 2.7.0 webpack: 5.92.1 transitivePeerDependencies: - '@mdx-js/react' @@ -11990,7 +12997,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) react-json-view-lite: 1.4.0(react@18.3.1) - tslib: 2.6.3 + tslib: 2.7.0 transitivePeerDependencies: - '@mdx-js/react' - '@parcel/css' @@ -12017,7 +13024,7 @@ snapshots: '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.3) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.6.3 + tslib: 2.7.0 transitivePeerDependencies: - '@mdx-js/react' - '@parcel/css' @@ -12045,7 +13052,7 @@ snapshots: '@types/gtag.js': 0.0.12 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.6.3 + tslib: 2.7.0 transitivePeerDependencies: - '@mdx-js/react' - '@parcel/css' @@ -12072,7 +13079,7 @@ snapshots: '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.3) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.6.3 + tslib: 2.7.0 transitivePeerDependencies: - '@mdx-js/react' - '@parcel/css' @@ -12104,7 +13111,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) sitemap: 7.1.2 - tslib: 2.6.3 + tslib: 2.7.0 transitivePeerDependencies: - '@mdx-js/react' - '@parcel/css' @@ -12286,7 +13293,7 @@ snapshots: lodash: 4.17.21 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.6.3 + tslib: 2.7.0 utility-types: 3.11.0 transitivePeerDependencies: - '@algolia/client-search' @@ -12314,7 +13321,7 @@ snapshots: '@docusaurus/theme-translations@3.5.2': dependencies: fs-extra: 11.2.0 - tslib: 2.6.3 + tslib: 2.7.0 '@docusaurus/tsconfig@3.5.2': {} @@ -12340,7 +13347,7 @@ snapshots: '@docusaurus/utils-common@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))': dependencies: - tslib: 2.6.3 + tslib: 2.7.0 optionalDependencies: '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -12353,7 +13360,7 @@ snapshots: joi: 17.13.1 js-yaml: 4.1.0 lodash: 4.17.21 - tslib: 2.6.3 + tslib: 2.7.0 transitivePeerDependencies: - '@docusaurus/types' - '@swc/core' @@ -12381,7 +13388,7 @@ snapshots: prompts: 2.4.2 resolve-pathname: 3.0.0 shelljs: 0.8.5 - tslib: 2.6.3 + tslib: 2.7.0 url-loader: 4.1.1(file-loader@6.2.0(webpack@5.92.1))(webpack@5.92.1) utility-types: 3.11.0 webpack: 5.92.1 @@ -12771,12 +13778,12 @@ snapshots: graphql-import-node: 0.0.5(graphql@16.8.1) js-yaml: 4.1.0 - '@graphprotocol/graph-cli@0.88.0(@types/node@22.9.0)(encoding@0.1.13)(node-fetch@2.7.0(encoding@0.1.13))(typescript@5.6.3)': + '@graphprotocol/graph-cli@0.88.0(@types/node@22.10.5)(encoding@0.1.13)(node-fetch@2.7.0(encoding@0.1.13))(typescript@5.7.2)': dependencies: '@float-capital/float-subgraph-uncrashable': 0.0.0-internal-testing.5 - '@oclif/core': 2.8.6(@types/node@22.9.0)(typescript@5.6.3) - '@oclif/plugin-autocomplete': 2.3.10(@types/node@22.9.0)(typescript@5.6.3) - '@oclif/plugin-not-found': 2.4.3(@types/node@22.9.0)(typescript@5.6.3) + '@oclif/core': 2.8.6(@types/node@22.10.5)(typescript@5.7.2) + '@oclif/plugin-autocomplete': 2.3.10(@types/node@22.10.5)(typescript@5.7.2) + '@oclif/plugin-not-found': 2.4.3(@types/node@22.10.5)(typescript@5.7.2) '@oclif/plugin-warn-if-update-available': 3.1.21 '@whatwg-node/fetch': 0.8.8 assemblyscript: 0.19.23 @@ -12888,37 +13895,186 @@ snapshots: '@istanbuljs/schema@0.1.3': {} - '@jest/schemas@29.6.3': + '@jest/console@29.7.0': dependencies: - '@sinclair/typebox': 0.27.8 + '@jest/types': 29.6.3 + '@types/node': 22.10.5 + chalk: 4.1.2 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 - '@jest/types@29.6.3': + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))': dependencies: - '@jest/schemas': 29.6.3 - '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-reports': 3.0.4 - '@types/node': 22.9.0 - '@types/yargs': 17.0.32 + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.10.5 + ansi-escapes: 4.3.2 chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@22.10.5)(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2)) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node - '@jridgewell/gen-mapping@0.3.5': + '@jest/environment@29.7.0': dependencies: - '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.25 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/set-array@1.2.1': {} + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.10.5 + jest-mock: 29.7.0 - '@jridgewell/source-map@0.3.6': + '@jest/expect-utils@29.7.0': dependencies: - '@jridgewell/gen-mapping': 0.3.5 - '@jridgewell/trace-mapping': 0.3.25 + jest-get-type: 29.6.3 - '@jridgewell/sourcemap-codec@1.4.15': {} + '@jest/expect@29.7.0': + dependencies: + expect: 29.7.0 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color - '@jridgewell/trace-mapping@0.3.25': + '@jest/fake-timers@29.7.0': + dependencies: + '@jest/types': 29.6.3 + '@sinonjs/fake-timers': 10.3.0 + '@types/node': 22.10.5 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + '@jest/globals@29.7.0': + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/types': 29.6.3 + jest-mock: 29.7.0 + transitivePeerDependencies: + - supports-color + + '@jest/reporters@29.7.0': + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.25 + '@types/node': 22.10.5 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2 + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.7 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + jest-worker: 29.7.0 + slash: 3.0.0 + string-length: 4.0.2 + strip-ansi: 6.0.1 + v8-to-istanbul: 9.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.8 + + '@jest/source-map@29.6.3': + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + callsites: 3.1.0 + graceful-fs: 4.2.11 + + '@jest/test-result@29.7.0': + dependencies: + '@jest/console': 29.7.0 + '@jest/types': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + collect-v8-coverage: 1.0.2 + + '@jest/test-sequencer@29.7.0': + dependencies: + '@jest/test-result': 29.7.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + slash: 3.0.0 + + '@jest/transform@29.7.0': + dependencies: + '@babel/core': 7.24.7 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.25 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + micromatch: 4.0.8 + pirates: 4.0.6 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 22.10.5 + '@types/yargs': 17.0.32 + chalk: 4.1.2 + + '@jridgewell/gen-mapping@0.3.5': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/source-map@0.3.6': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/sourcemap-codec@1.4.15': {} + + '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 @@ -12930,7 +14086,7 @@ snapshots: '@leichtgewicht/ip-codec@2.0.5': {} - '@lerna/create@8.1.9(encoding@0.1.13)(typescript@5.6.3)': + '@lerna/create@8.1.9(encoding@0.1.13)(typescript@5.7.2)': dependencies: '@npmcli/arborist': 7.5.4 '@npmcli/package-json': 5.2.0 @@ -12948,7 +14104,7 @@ snapshots: console-control-strings: 1.1.0 conventional-changelog-core: 5.0.1 conventional-recommended-bump: 7.0.1 - cosmiconfig: 9.0.0(typescript@5.6.3) + cosmiconfig: 9.0.0(typescript@5.7.2) dedent: 1.5.3 execa: 5.0.0 fs-extra: 11.2.0 @@ -13013,6 +14169,12 @@ snapshots: - supports-color - typescript + '@ljharb/through@2.3.13': + dependencies: + call-bind: 1.0.7 + + '@lukeed/csprng@1.1.0': {} + '@mdx-js/mdx@3.0.1': dependencies: '@types/estree': 1.0.5 @@ -13055,6 +14217,8 @@ snapshots: tweetnacl: 1.0.3 tweetnacl-util: 0.15.1 + '@microsoft/tsdoc@0.15.1': {} + '@napi-rs/wasm-runtime@0.2.4': dependencies: '@emnapi/core': 1.2.0 @@ -13062,6 +14226,144 @@ snapshots: '@tybys/wasm-util': 0.9.0 optional: true + '@nestjs/cli@10.4.9': + dependencies: + '@angular-devkit/core': 17.3.11(chokidar@3.6.0) + '@angular-devkit/schematics': 17.3.11(chokidar@3.6.0) + '@angular-devkit/schematics-cli': 17.3.11(chokidar@3.6.0) + '@nestjs/schematics': 10.2.3(chokidar@3.6.0)(typescript@5.7.2) + chalk: 4.1.2 + chokidar: 3.6.0 + cli-table3: 0.6.5 + commander: 4.1.1 + fork-ts-checker-webpack-plugin: 9.0.2(typescript@5.7.2)(webpack@5.97.1) + glob: 10.4.5 + inquirer: 8.2.6 + node-emoji: 1.11.0 + ora: 5.4.1 + tree-kill: 1.2.2 + tsconfig-paths: 4.2.0 + tsconfig-paths-webpack-plugin: 4.2.0 + typescript: 5.7.2 + webpack: 5.97.1 + webpack-node-externals: 3.0.0 + transitivePeerDependencies: + - esbuild + - uglify-js + - webpack-cli + + '@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)': + dependencies: + iterare: 1.2.1 + reflect-metadata: 0.2.2 + rxjs: 7.8.1 + tslib: 2.8.1 + uid: 2.0.2 + optionalDependencies: + class-transformer: 0.5.1 + class-validator: 0.14.1 + + '@nestjs/core@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)': + dependencies: + '@nestjs/common': 10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nuxtjs/opencollective': 0.3.2(encoding@0.1.13) + fast-safe-stringify: 2.1.1 + iterare: 1.2.1 + path-to-regexp: 3.3.0 + reflect-metadata: 0.2.2 + rxjs: 7.8.1 + tslib: 2.8.1 + uid: 2.0.2 + optionalDependencies: + '@nestjs/platform-express': 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15) + '@nestjs/websockets': 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15)(@nestjs/platform-socket.io@10.4.15)(reflect-metadata@0.2.2)(rxjs@7.8.1) + transitivePeerDependencies: + - encoding + + '@nestjs/mapped-types@2.0.6(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)': + dependencies: + '@nestjs/common': 10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + reflect-metadata: 0.2.2 + optionalDependencies: + class-transformer: 0.5.1 + class-validator: 0.14.1 + + '@nestjs/platform-express@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15)': + dependencies: + '@nestjs/common': 10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + body-parser: 1.20.3 + cors: 2.8.5 + express: 4.21.2 + multer: 1.4.4-lts.1 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@nestjs/platform-socket.io@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@10.4.15)(rxjs@7.8.1)': + dependencies: + '@nestjs/common': 10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/websockets': 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15)(@nestjs/platform-socket.io@10.4.15)(reflect-metadata@0.2.2)(rxjs@7.8.1) + rxjs: 7.8.1 + socket.io: 4.8.1 + tslib: 2.8.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@nestjs/schematics@10.2.3(chokidar@3.6.0)(typescript@5.7.2)': + dependencies: + '@angular-devkit/core': 17.3.11(chokidar@3.6.0) + '@angular-devkit/schematics': 17.3.11(chokidar@3.6.0) + comment-json: 4.2.5 + jsonc-parser: 3.3.1 + pluralize: 8.0.0 + typescript: 5.7.2 + transitivePeerDependencies: + - chokidar + + '@nestjs/swagger@8.1.0(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)': + dependencies: + '@microsoft/tsdoc': 0.15.1 + '@nestjs/common': 10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/mapped-types': 2.0.6(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2) + js-yaml: 4.1.0 + lodash: 4.17.21 + path-to-regexp: 3.3.0 + reflect-metadata: 0.2.2 + swagger-ui-dist: 5.18.2 + optionalDependencies: + class-transformer: 0.5.1 + class-validator: 0.14.1 + + '@nestjs/testing@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15))': + dependencies: + '@nestjs/common': 10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + tslib: 2.8.1 + optionalDependencies: + '@nestjs/platform-express': 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15) + + '@nestjs/throttler@6.3.0(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)': + dependencies: + '@nestjs/common': 10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + reflect-metadata: 0.2.2 + + '@nestjs/websockets@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15)(@nestjs/platform-socket.io@10.4.15)(reflect-metadata@0.2.2)(rxjs@7.8.1)': + dependencies: + '@nestjs/common': 10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + iterare: 1.2.1 + object-hash: 3.0.0 + reflect-metadata: 0.2.2 + rxjs: 7.8.1 + tslib: 2.8.1 + optionalDependencies: + '@nestjs/platform-socket.io': 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@10.4.15)(rxjs@7.8.1) + '@noble/curves@1.2.0': dependencies: '@noble/hashes': 1.3.2 @@ -13076,7 +14378,7 @@ snapshots: '@noble/hashes@1.3.3': {} - '@noble/hashes@1.4.0': {} + '@noble/hashes@1.6.1': {} '@noble/secp256k1@1.7.1': {} @@ -13199,6 +14501,17 @@ snapshots: '@nomicfoundation/ethereumjs-rlp': 5.0.4 ethereum-cryptography: 0.1.3 + '@nomicfoundation/hardhat-chai-matchers@2.0.7(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)))(chai@4.4.1)(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2))': + dependencies: + '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)) + '@types/chai-as-promised': 7.1.8 + chai: 4.4.1 + chai-as-promised: 7.1.2(chai@4.4.1) + deep-eql: 4.1.4 + ethers: 6.13.4 + hardhat: 2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2) + ordinal: 1.0.3 + '@nomicfoundation/hardhat-chai-matchers@2.0.7(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3)))(chai@4.4.1)(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3))': dependencies: '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3)) @@ -13210,6 +14523,15 @@ snapshots: hardhat: 2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3) ordinal: 1.0.3 + '@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2))': + dependencies: + debug: 4.3.6(supports-color@8.1.1) + ethers: 6.13.4 + hardhat: 2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2) + lodash.isequal: 4.5.0 + transitivePeerDependencies: + - supports-color + '@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3))': dependencies: debug: 4.3.6(supports-color@8.1.1) @@ -13219,6 +14541,14 @@ snapshots: transitivePeerDependencies: - supports-color + '@nomicfoundation/hardhat-ignition-ethers@0.15.4(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)))(@nomicfoundation/hardhat-ignition@0.15.4(@nomicfoundation/hardhat-verify@2.0.8(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)))(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)))(@nomicfoundation/ignition-core@0.15.4)(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2))': + dependencies: + '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)) + '@nomicfoundation/hardhat-ignition': 0.15.4(@nomicfoundation/hardhat-verify@2.0.8(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)))(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)) + '@nomicfoundation/ignition-core': 0.15.4 + ethers: 6.13.4 + hardhat: 2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2) + '@nomicfoundation/hardhat-ignition-ethers@0.15.4(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3)))(@nomicfoundation/hardhat-ignition@0.15.4(@nomicfoundation/hardhat-verify@2.0.8(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3)))(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3)))(@nomicfoundation/ignition-core@0.15.4)(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3))': dependencies: '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3)) @@ -13227,6 +14557,21 @@ snapshots: ethers: 6.13.4 hardhat: 2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3) + '@nomicfoundation/hardhat-ignition@0.15.4(@nomicfoundation/hardhat-verify@2.0.8(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)))(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2))': + dependencies: + '@nomicfoundation/hardhat-verify': 2.0.8(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)) + '@nomicfoundation/ignition-core': 0.15.4 + '@nomicfoundation/ignition-ui': 0.15.4 + chalk: 4.1.2 + debug: 4.3.7(supports-color@8.1.1) + fs-extra: 10.1.0 + hardhat: 2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2) + prompts: 2.4.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + '@nomicfoundation/hardhat-ignition@0.15.4(@nomicfoundation/hardhat-verify@2.0.8(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3)))(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3))': dependencies: '@nomicfoundation/hardhat-verify': 2.0.8(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3)) @@ -13242,6 +14587,11 @@ snapshots: - supports-color - utf-8-validate + '@nomicfoundation/hardhat-network-helpers@1.0.11(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2))': + dependencies: + ethereumjs-util: 7.1.5 + hardhat: 2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2) + '@nomicfoundation/hardhat-network-helpers@1.0.11(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3))': dependencies: ethereumjs-util: 7.1.5 @@ -13268,6 +14618,42 @@ snapshots: typechain: 8.3.2(typescript@5.6.3) typescript: 5.6.3 + '@nomicfoundation/hardhat-toolbox@5.0.0(zw7zqps7ouu5cvynqyf6kamiou)': + dependencies: + '@nomicfoundation/hardhat-chai-matchers': 2.0.7(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)))(chai@4.4.1)(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)) + '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)) + '@nomicfoundation/hardhat-ignition-ethers': 0.15.4(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)))(@nomicfoundation/hardhat-ignition@0.15.4(@nomicfoundation/hardhat-verify@2.0.8(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)))(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)))(@nomicfoundation/ignition-core@0.15.4)(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)) + '@nomicfoundation/hardhat-network-helpers': 1.0.11(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)) + '@nomicfoundation/hardhat-verify': 2.0.8(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)) + '@typechain/ethers-v6': 0.5.1(ethers@6.13.4)(typechain@8.3.2(typescript@5.7.2))(typescript@5.7.2) + '@typechain/hardhat': 9.1.0(@typechain/ethers-v6@0.5.1(ethers@6.13.4)(typechain@8.3.2(typescript@5.7.2))(typescript@5.7.2))(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2))(typechain@8.3.2(typescript@5.7.2)) + '@types/chai': 4.3.16 + '@types/mocha': 10.0.8 + '@types/node': 22.10.5 + chai: 4.4.1 + ethers: 6.13.4 + hardhat: 2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2) + hardhat-gas-reporter: 1.0.10(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)) + solidity-coverage: 0.8.12(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)) + ts-node: 10.9.2(@types/node@22.10.5)(typescript@5.7.2) + typechain: 8.3.2(typescript@5.7.2) + typescript: 5.7.2 + + '@nomicfoundation/hardhat-verify@2.0.8(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2))': + dependencies: + '@ethersproject/abi': 5.7.0 + '@ethersproject/address': 5.7.0 + cbor: 8.1.0 + chalk: 2.4.2 + debug: 4.3.7(supports-color@8.1.1) + hardhat: 2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2) + lodash.clonedeep: 4.5.0 + semver: 6.3.1 + table: 6.8.2 + undici: 5.28.4 + transitivePeerDependencies: + - supports-color + '@nomicfoundation/hardhat-verify@2.0.8(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3))': dependencies: '@ethersproject/abi': 5.7.0 @@ -13488,6 +14874,14 @@ snapshots: - '@swc/core' - debug + '@nuxtjs/opencollective@0.3.2(encoding@0.1.13)': + dependencies: + chalk: 4.1.2 + consola: 2.15.3 + node-fetch: 2.7.0(encoding@0.1.13) + transitivePeerDependencies: + - encoding + '@nx/devkit@19.2.0(nx@19.2.0)': dependencies: '@nrwl/devkit': 19.2.0(nx@19.2.0) @@ -13531,7 +14925,7 @@ snapshots: '@nx/nx-win32-x64-msvc@19.2.0': optional: true - '@oclif/core@2.16.0(@types/node@22.9.0)(typescript@5.6.3)': + '@oclif/core@2.16.0(@types/node@22.10.5)(typescript@5.7.2)': dependencies: '@types/cli-progress': 3.11.5 ansi-escapes: 4.3.2 @@ -13556,7 +14950,7 @@ snapshots: strip-ansi: 6.0.1 supports-color: 8.1.1 supports-hyperlinks: 2.3.0 - ts-node: 10.9.2(@types/node@22.9.0)(typescript@5.6.3) + ts-node: 10.9.2(@types/node@22.10.5)(typescript@5.7.2) tslib: 2.7.0 widest-line: 3.1.0 wordwrap: 1.0.0 @@ -13567,7 +14961,7 @@ snapshots: - '@types/node' - typescript - '@oclif/core@2.8.6(@types/node@22.9.0)(typescript@5.6.3)': + '@oclif/core@2.8.6(@types/node@22.10.5)(typescript@5.7.2)': dependencies: '@types/cli-progress': 3.11.5 ansi-escapes: 4.3.2 @@ -13593,7 +14987,7 @@ snapshots: strip-ansi: 6.0.1 supports-color: 8.1.1 supports-hyperlinks: 2.3.0 - ts-node: 10.9.2(@types/node@22.9.0)(typescript@5.6.3) + ts-node: 10.9.2(@types/node@22.10.5)(typescript@5.7.2) tslib: 2.6.3 widest-line: 3.1.0 wordwrap: 1.0.0 @@ -13625,9 +15019,9 @@ snapshots: wordwrap: 1.0.0 wrap-ansi: 7.0.0 - '@oclif/plugin-autocomplete@2.3.10(@types/node@22.9.0)(typescript@5.6.3)': + '@oclif/plugin-autocomplete@2.3.10(@types/node@22.10.5)(typescript@5.7.2)': dependencies: - '@oclif/core': 2.16.0(@types/node@22.9.0)(typescript@5.6.3) + '@oclif/core': 2.16.0(@types/node@22.10.5)(typescript@5.7.2) chalk: 4.1.2 debug: 4.3.7(supports-color@8.1.1) transitivePeerDependencies: @@ -13637,9 +15031,9 @@ snapshots: - supports-color - typescript - '@oclif/plugin-not-found@2.4.3(@types/node@22.9.0)(typescript@5.6.3)': + '@oclif/plugin-not-found@2.4.3(@types/node@22.10.5)(typescript@5.7.2)': dependencies: - '@oclif/core': 2.16.0(@types/node@22.9.0)(typescript@5.6.3) + '@oclif/core': 2.16.0(@types/node@22.10.5)(typescript@5.7.2) chalk: 4.1.2 fast-levenshtein: 3.0.0 transitivePeerDependencies: @@ -13823,6 +15217,8 @@ snapshots: '@rtsao/scc@1.1.0': {} + '@scarf/scarf@1.4.0': {} + '@scure/base@1.1.6': {} '@scure/bip32@1.1.5': @@ -13949,12 +15345,22 @@ snapshots: '@sindresorhus/is@5.6.0': {} + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@10.3.0': + dependencies: + '@sinonjs/commons': 3.0.1 + '@slorber/remark-comment@1.0.0': dependencies: micromark-factory-space: 1.1.0 micromark-util-character: 1.2.0 micromark-util-symbol: 1.1.0 + '@socket.io/component-emitter@3.1.2': {} + '@solidity-parser/parser@0.14.5': dependencies: antlr4ts: 0.5.0-alpha.4 @@ -14088,6 +15494,14 @@ snapshots: typechain: 8.3.2(typescript@5.6.3) typescript: 5.6.3 + '@typechain/ethers-v6@0.5.1(ethers@6.13.4)(typechain@8.3.2(typescript@5.7.2))(typescript@5.7.2)': + dependencies: + ethers: 6.13.4 + lodash: 4.17.21 + ts-essentials: 7.0.3(typescript@5.7.2) + typechain: 8.3.2(typescript@5.7.2) + typescript: 5.7.2 + '@typechain/hardhat@9.1.0(@typechain/ethers-v6@0.5.1(ethers@6.13.4)(typechain@8.3.2(typescript@5.6.3))(typescript@5.6.3))(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3))(typechain@8.3.2(typescript@5.6.3))': dependencies: '@typechain/ethers-v6': 0.5.1(ethers@6.13.4)(typechain@8.3.2(typescript@5.6.3))(typescript@5.6.3) @@ -14096,22 +15510,51 @@ snapshots: hardhat: 2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3) typechain: 8.3.2(typescript@5.6.3) + '@typechain/hardhat@9.1.0(@typechain/ethers-v6@0.5.1(ethers@6.13.4)(typechain@8.3.2(typescript@5.7.2))(typescript@5.7.2))(ethers@6.13.4)(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2))(typechain@8.3.2(typescript@5.7.2))': + dependencies: + '@typechain/ethers-v6': 0.5.1(ethers@6.13.4)(typechain@8.3.2(typescript@5.7.2))(typescript@5.7.2) + ethers: 6.13.4 + fs-extra: 9.1.0 + hardhat: 2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2) + typechain: 8.3.2(typescript@5.7.2) + '@types/acorn@4.0.6': dependencies: '@types/estree': 1.0.5 + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.24.7 + '@babel/types': 7.24.7 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.6 + + '@types/babel__generator@7.6.8': + dependencies: + '@babel/types': 7.24.7 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.24.7 + '@babel/types': 7.24.7 + + '@types/babel__traverse@7.20.6': + dependencies: + '@babel/types': 7.24.7 + '@types/bn.js@4.11.6': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.5 '@types/bn.js@5.1.5': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.5 '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 - '@types/node': 22.9.0 + '@types/node': 22.10.5 '@types/bonjour@3.5.13': dependencies: @@ -14131,7 +15574,7 @@ snapshots: '@types/concat-stream@1.6.1': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.5 '@types/connect-history-api-fallback@1.5.4': dependencies: @@ -14140,12 +15583,20 @@ snapshots: '@types/connect@3.4.38': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.5 '@types/conventional-commits-parser@5.0.0': dependencies: '@types/node': 22.9.0 + '@types/cookie@0.4.1': {} + + '@types/cookiejar@2.1.5': {} + + '@types/cors@2.8.17': + dependencies: + '@types/node': 22.10.5 + '@types/debug@4.1.12': dependencies: '@types/ms': 0.7.34 @@ -14166,9 +15617,18 @@ snapshots: '@types/estree@1.0.5': {} + '@types/estree@1.0.6': {} + '@types/express-serve-static-core@4.19.3': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.5 + '@types/qs': 6.9.15 + '@types/range-parser': 1.2.7 + '@types/send': 0.17.4 + + '@types/express-serve-static-core@5.0.3': + dependencies: + '@types/node': 22.10.5 '@types/qs': 6.9.15 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 @@ -14180,14 +15640,25 @@ snapshots: '@types/qs': 6.9.15 '@types/serve-static': 1.15.7 - '@types/form-data@0.0.33': + '@types/express@5.0.0': dependencies: - '@types/node': 22.9.0 + '@types/body-parser': 1.19.5 + '@types/express-serve-static-core': 5.0.3 + '@types/qs': 6.9.15 + '@types/serve-static': 1.15.7 + + '@types/form-data@0.0.33': + dependencies: + '@types/node': 22.10.5 '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 22.9.0 + '@types/node': 22.10.5 + + '@types/graceful-fs@4.1.9': + dependencies: + '@types/node': 22.10.5 '@types/gtag.js@0.0.12': {} @@ -14205,7 +15676,7 @@ snapshots: '@types/http-proxy@1.17.14': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.5 '@types/istanbul-lib-coverage@2.0.6': {} @@ -14217,6 +15688,11 @@ snapshots: dependencies: '@types/istanbul-lib-report': 3.0.3 + '@types/jest@29.5.14': + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} @@ -14239,6 +15715,8 @@ snapshots: '@types/mdx@2.0.13': {} + '@types/methods@1.1.4': {} + '@types/mime@1.3.5': {} '@types/minimatch@3.0.5': {} @@ -14253,7 +15731,7 @@ snapshots: '@types/node-forge@1.3.11': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.5 '@types/node@10.17.60': {} @@ -14261,6 +15739,10 @@ snapshots: '@types/node@17.0.45': {} + '@types/node@22.10.5': + dependencies: + undici-types: 6.20.0 + '@types/node@22.7.5': dependencies: undici-types: 6.19.8 @@ -14277,7 +15759,7 @@ snapshots: '@types/pbkdf2@3.1.2': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.5 '@types/prettier@2.7.3': {} @@ -14322,16 +15804,16 @@ snapshots: '@types/sax@1.2.7': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.5 '@types/secp256k1@4.0.6': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.5 '@types/send@0.17.4': dependencies: '@types/mime': 1.3.5 - '@types/node': 22.9.0 + '@types/node': 22.10.5 '@types/serve-index@1.9.4': dependencies: @@ -14340,7 +15822,7 @@ snapshots: '@types/serve-static@1.15.7': dependencies: '@types/http-errors': 2.0.4 - '@types/node': 22.9.0 + '@types/node': 22.10.5 '@types/send': 0.17.4 '@types/snarkjs@0.7.8': {} @@ -14349,12 +15831,28 @@ snapshots: dependencies: '@types/node': 22.9.0 + '@types/stack-utils@2.0.3': {} + + '@types/superagent@8.1.9': + dependencies: + '@types/cookiejar': 2.1.5 + '@types/methods': 1.1.4 + '@types/node': 22.10.5 + form-data: 4.0.0 + + '@types/supertest@6.0.2': + dependencies: + '@types/methods': 1.1.4 + '@types/superagent': 8.1.9 + '@types/unist@2.0.10': {} '@types/unist@3.0.2': {} '@types/uuid@10.0.0': {} + '@types/validator@13.12.2': {} + '@types/ws@7.4.7': dependencies: '@types/node': 22.9.0 @@ -14457,20 +15955,39 @@ snapshots: '@webassemblyjs/helper-numbers': 1.11.6 '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/ast@1.14.1': + dependencies: + '@webassemblyjs/helper-numbers': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/floating-point-hex-parser@1.11.6': {} + '@webassemblyjs/floating-point-hex-parser@1.13.2': {} + '@webassemblyjs/helper-api-error@1.11.6': {} + '@webassemblyjs/helper-api-error@1.13.2': {} + '@webassemblyjs/helper-buffer@1.12.1': {} + '@webassemblyjs/helper-buffer@1.14.1': {} + '@webassemblyjs/helper-numbers@1.11.6': dependencies: '@webassemblyjs/floating-point-hex-parser': 1.11.6 '@webassemblyjs/helper-api-error': 1.11.6 '@xtuc/long': 4.2.2 + '@webassemblyjs/helper-numbers@1.13.2': + dependencies: + '@webassemblyjs/floating-point-hex-parser': 1.13.2 + '@webassemblyjs/helper-api-error': 1.13.2 + '@xtuc/long': 4.2.2 + '@webassemblyjs/helper-wasm-bytecode@1.11.6': {} + '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} + '@webassemblyjs/helper-wasm-section@1.12.1': dependencies: '@webassemblyjs/ast': 1.12.1 @@ -14478,16 +15995,33 @@ snapshots: '@webassemblyjs/helper-wasm-bytecode': 1.11.6 '@webassemblyjs/wasm-gen': 1.12.1 + '@webassemblyjs/helper-wasm-section@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/ieee754@1.11.6': dependencies: '@xtuc/ieee754': 1.2.0 + '@webassemblyjs/ieee754@1.13.2': + dependencies: + '@xtuc/ieee754': 1.2.0 + '@webassemblyjs/leb128@1.11.6': dependencies: '@xtuc/long': 4.2.2 + '@webassemblyjs/leb128@1.13.2': + dependencies: + '@xtuc/long': 4.2.2 + '@webassemblyjs/utf8@1.11.6': {} + '@webassemblyjs/utf8@1.13.2': {} + '@webassemblyjs/wasm-edit@1.12.1': dependencies: '@webassemblyjs/ast': 1.12.1 @@ -14499,6 +16033,17 @@ snapshots: '@webassemblyjs/wasm-parser': 1.12.1 '@webassemblyjs/wast-printer': 1.12.1 + '@webassemblyjs/wasm-edit@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/helper-wasm-section': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-opt': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + '@webassemblyjs/wast-printer': 1.14.1 + '@webassemblyjs/wasm-gen@1.12.1': dependencies: '@webassemblyjs/ast': 1.12.1 @@ -14507,6 +16052,14 @@ snapshots: '@webassemblyjs/leb128': 1.11.6 '@webassemblyjs/utf8': 1.11.6 + '@webassemblyjs/wasm-gen@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + '@webassemblyjs/wasm-opt@1.12.1': dependencies: '@webassemblyjs/ast': 1.12.1 @@ -14514,6 +16067,13 @@ snapshots: '@webassemblyjs/wasm-gen': 1.12.1 '@webassemblyjs/wasm-parser': 1.12.1 + '@webassemblyjs/wasm-opt@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + '@webassemblyjs/wasm-parser@1.12.1': dependencies: '@webassemblyjs/ast': 1.12.1 @@ -14523,11 +16083,25 @@ snapshots: '@webassemblyjs/leb128': 1.11.6 '@webassemblyjs/utf8': 1.11.6 + '@webassemblyjs/wasm-parser@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-api-error': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + '@webassemblyjs/wast-printer@1.12.1': dependencies: '@webassemblyjs/ast': 1.12.1 '@xtuc/long': 4.2.2 + '@webassemblyjs/wast-printer@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@xtuc/long': 4.2.2 + '@whatwg-node/events@0.0.3': {} '@whatwg-node/fetch@0.8.8': @@ -14629,6 +16203,8 @@ snapshots: acorn@8.11.3: {} + acorn@8.14.0: {} + add-stream@1.0.0: {} address@1.2.2: {} @@ -14656,6 +16232,10 @@ snapshots: clean-stack: 2.2.0 indent-string: 4.0.0 + ajv-formats@2.1.1(ajv@8.12.0): + optionalDependencies: + ajv: 8.12.0 + ajv-formats@2.1.1(ajv@8.16.0): optionalDependencies: ajv: 8.16.0 @@ -14676,6 +16256,13 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ajv@8.12.0: + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + ajv@8.16.0: dependencies: fast-deep-equal: 3.1.3 @@ -14773,6 +16360,8 @@ snapshots: app-module-path@2.2.0: {} + append-field@1.0.0: {} + append-transform@2.0.0: dependencies: default-require-extensions: 3.0.1 @@ -14817,6 +16406,8 @@ snapshots: get-intrinsic: 1.2.4 is-string: 1.0.7 + array-timsort@1.0.3: {} + array-union@2.1.0: {} array-uniq@1.0.3: {} @@ -14953,6 +16544,19 @@ snapshots: b4a@1.6.6: {} + babel-jest@29.7.0(@babel/core@7.24.7): + dependencies: + '@babel/core': 7.24.7 + '@jest/transform': 29.7.0 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.6.3(@babel/core@7.24.7) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + babel-loader@9.1.3(@babel/core@7.24.7)(webpack@5.92.1): dependencies: '@babel/core': 7.24.7 @@ -14964,6 +16568,23 @@ snapshots: dependencies: object.assign: 4.1.5 + babel-plugin-istanbul@6.1.1: + dependencies: + '@babel/helper-plugin-utils': 7.24.7 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-jest-hoist@29.6.3: + dependencies: + '@babel/template': 7.24.7 + '@babel/types': 7.24.7 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.20.6 + babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.24.7): dependencies: '@babel/compat-data': 7.24.7 @@ -14988,6 +16609,31 @@ snapshots: transitivePeerDependencies: - supports-color + babel-preset-current-node-syntax@1.1.0(@babel/core@7.24.7): + dependencies: + '@babel/core': 7.24.7 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.7) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.7) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.7) + '@babel/plugin-syntax-import-attributes': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.7) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.7) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.7) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.7) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.7) + + babel-preset-jest@29.6.3(@babel/core@7.24.7): + dependencies: + '@babel/core': 7.24.7 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.24.7) + bail@2.0.2: {} balanced-match@1.0.2: {} @@ -14998,6 +16644,8 @@ snapshots: base64-js@1.5.1: {} + base64id@2.0.0: {} + batch@0.6.1: {} bech32@1.1.4: {} @@ -15110,6 +16758,23 @@ snapshots: transitivePeerDependencies: - supports-color + body-parser@1.20.3: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.13.0 + raw-body: 2.5.2 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + bonjour-service@1.2.1: dependencies: fast-deep-equal: 3.1.3 @@ -15185,6 +16850,17 @@ snapshots: node-releases: 2.0.14 update-browserslist-db: 1.0.16(browserslist@4.23.0) + browserslist@4.24.3: + dependencies: + caniuse-lite: 1.0.30001690 + electron-to-chromium: 1.5.76 + node-releases: 2.0.19 + update-browserslist-db: 1.1.1(browserslist@4.24.3) + + bs-logger@0.2.6: + dependencies: + fast-json-stable-stringify: 2.1.0 + bs58@4.0.1: dependencies: base-x: 3.0.9 @@ -15195,6 +16871,10 @@ snapshots: create-hash: 1.2.0 safe-buffer: 5.2.1 + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + buffer-alloc-unsafe@1.1.0: {} buffer-alloc@1.2.0: @@ -15300,6 +16980,8 @@ snapshots: caniuse-lite@1.0.30001628: {} + caniuse-lite@1.0.30001690: {} + cardinal@2.1.1: dependencies: ansicolors: 0.3.2 @@ -15498,6 +17180,16 @@ snapshots: - bufferutil - utf-8-validate + cjs-module-lexer@1.4.1: {} + + class-transformer@0.5.1: {} + + class-validator@0.14.1: + dependencies: + '@types/validator': 13.12.2 + libphonenumber-js: 1.11.17 + validator: 13.12.0 + clean-css@5.3.3: dependencies: source-map: 0.6.1 @@ -15555,6 +17247,8 @@ snapshots: cli-width@3.0.0: {} + cli-width@4.1.0: {} + cliui@6.0.0: dependencies: string-width: 4.2.3 @@ -15587,8 +17281,12 @@ snapshots: cmd-shim@6.0.3: {} + co@4.6.0: {} + collapse-white-space@2.1.0: {} + collect-v8-coverage@1.0.2: {} + color-convert@1.9.3: dependencies: color-name: 1.1.3 @@ -15646,6 +17344,8 @@ snapshots: commander@2.20.3: {} + commander@4.1.1: {} + commander@5.1.0: {} commander@6.2.1: {} @@ -15654,10 +17354,18 @@ snapshots: commander@8.3.0: {} - commitizen@4.3.0(@types/node@22.9.0)(typescript@5.6.3): + comment-json@4.2.5: + dependencies: + array-timsort: 1.0.3 + core-util-is: 1.0.3 + esprima: 4.0.1 + has-own-prop: 2.0.0 + repeat-string: 1.6.1 + + commitizen@4.3.0(@types/node@22.10.5)(typescript@5.6.3): dependencies: cachedir: 2.3.0 - cz-conventional-changelog: 3.3.0(@types/node@22.9.0)(typescript@5.6.3) + cz-conventional-changelog: 3.3.0(@types/node@22.10.5)(typescript@5.6.3) dedent: 0.7.0 detect-indent: 6.1.0 find-node-modules: 2.1.3 @@ -15687,6 +17395,8 @@ snapshots: array-ify: 1.0.0 dot-prop: 5.3.0 + component-emitter@1.3.1: {} + compressible@2.0.18: dependencies: mime-db: 1.52.0 @@ -15823,6 +17533,12 @@ snapshots: cookie@0.6.0: {} + cookie@0.7.1: {} + + cookie@0.7.2: {} + + cookiejar@2.1.4: {} + copy-text-to-clipboard@3.2.0: {} copy-webpack-plugin@11.0.0(webpack@5.92.1): @@ -15845,9 +17561,14 @@ snapshots: core-util-is@1.0.3: {} - cosmiconfig-typescript-loader@5.0.0(@types/node@22.9.0)(cosmiconfig@9.0.0(typescript@5.6.3))(typescript@5.6.3): + cors@2.8.5: dependencies: - '@types/node': 22.9.0 + object-assign: 4.1.1 + vary: 1.1.2 + + cosmiconfig-typescript-loader@5.0.0(@types/node@22.10.5)(cosmiconfig@9.0.0(typescript@5.6.3))(typescript@5.6.3): + dependencies: + '@types/node': 22.10.5 cosmiconfig: 9.0.0(typescript@5.6.3) jiti: 1.21.3 typescript: 5.6.3 @@ -15877,6 +17598,15 @@ snapshots: optionalDependencies: typescript: 5.6.3 + cosmiconfig@8.3.6(typescript@5.7.2): + dependencies: + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 + optionalDependencies: + typescript: 5.7.2 + cosmiconfig@9.0.0(typescript@5.6.3): dependencies: env-paths: 2.2.1 @@ -15886,6 +17616,15 @@ snapshots: optionalDependencies: typescript: 5.6.3 + cosmiconfig@9.0.0(typescript@5.7.2): + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + optionalDependencies: + typescript: 5.7.2 + create-hash@1.2.0: dependencies: cipher-base: 1.0.4 @@ -15903,6 +17642,21 @@ snapshots: safe-buffer: 5.2.1 sha.js: 2.4.11 + create-jest@29.7.0(@types/node@22.10.5)(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2)): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@22.10.5)(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2)) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + create-require@1.1.1: {} cross-spawn@7.0.3: @@ -16039,16 +17793,16 @@ snapshots: cycle@1.0.3: {} - cz-conventional-changelog@3.3.0(@types/node@22.9.0)(typescript@5.6.3): + cz-conventional-changelog@3.3.0(@types/node@22.10.5)(typescript@5.6.3): dependencies: chalk: 2.4.2 - commitizen: 4.3.0(@types/node@22.9.0)(typescript@5.6.3) + commitizen: 4.3.0(@types/node@22.10.5)(typescript@5.6.3) conventional-commit-types: 3.0.0 lodash.map: 4.6.0 longest: 2.0.1 word-wrap: 1.2.5 optionalDependencies: - '@commitlint/load': 19.2.0(@types/node@22.9.0)(typescript@5.6.3) + '@commitlint/load': 19.2.0(@types/node@22.10.5)(typescript@5.6.3) transitivePeerDependencies: - '@types/node' - typescript @@ -16077,6 +17831,8 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.1 + date-fns@4.1.0: {} + dateformat@3.0.3: {} death@1.1.0: {} @@ -16201,6 +17957,8 @@ snapshots: detect-indent@6.1.0: {} + detect-newline@3.1.0: {} + detect-node@2.1.0: {} detect-port-alt@1.1.6: @@ -16221,6 +17979,11 @@ snapshots: dependencies: dequal: 2.0.3 + dezalgo@1.0.4: + dependencies: + asap: 2.0.6 + wrappy: 1.0.2 + diff-sequences@29.6.3: {} diff@3.5.0: {} @@ -16366,6 +18129,8 @@ snapshots: electron-to-chromium@1.4.790: {} + electron-to-chromium@1.5.76: {} + elliptic@6.5.4: dependencies: bn.js: 4.12.0 @@ -16388,6 +18153,8 @@ snapshots: email-validator@2.0.4: {} + emittery@0.13.1: {} + emoji-regex@10.3.0: {} emoji-regex@8.0.0: {} @@ -16402,6 +18169,8 @@ snapshots: encodeurl@1.0.2: {} + encodeurl@2.0.0: {} + encoding-sniffer@0.2.0: dependencies: iconv-lite: 0.6.3 @@ -16415,11 +18184,35 @@ snapshots: dependencies: once: 1.4.0 + engine.io-parser@5.2.3: {} + + engine.io@6.6.2: + dependencies: + '@types/cookie': 0.4.1 + '@types/cors': 2.8.17 + '@types/node': 22.10.5 + accepts: 1.3.8 + base64id: 2.0.0 + cookie: 0.7.2 + cors: 2.8.5 + debug: 4.3.7(supports-color@8.1.1) + engine.io-parser: 5.2.3 + ws: 8.17.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + enhanced-resolve@5.17.0: dependencies: graceful-fs: 4.2.11 tapable: 2.2.1 + enhanced-resolve@5.18.0: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + enquirer@2.3.6: dependencies: ansi-colors: 4.1.3 @@ -16552,12 +18345,16 @@ snapshots: escalade@3.1.2: {} + escalade@3.2.0: {} + escape-goat@4.0.0: {} escape-html@1.0.3: {} escape-string-regexp@1.0.5: {} + escape-string-regexp@2.0.0: {} + escape-string-regexp@4.0.0: {} escape-string-regexp@5.0.0: {} @@ -16889,7 +18686,7 @@ snapshots: ethereum-bloom-filters@1.2.0: dependencies: - '@noble/hashes': 1.4.0 + '@noble/hashes': 1.6.1 ethereum-cryptography@0.1.3: dependencies: @@ -17059,10 +18856,20 @@ snapshots: signal-exit: 4.1.0 strip-final-newline: 3.0.0 + exit@0.1.2: {} + expand-tilde@2.0.2: dependencies: homedir-polyfill: 1.0.3 + expect@29.7.0: + dependencies: + '@jest/expect-utils': 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + exponential-backoff@3.1.1: {} express@4.19.2: @@ -17101,6 +18908,42 @@ snapshots: transitivePeerDependencies: - supports-color + express@4.21.2: + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.3 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.7.1 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.3.1 + fresh: 0.5.2 + http-errors: 2.0.0 + merge-descriptors: 1.0.3 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.12 + proxy-addr: 2.0.7 + qs: 6.13.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.19.0 + serve-static: 1.16.2 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + extend-shallow@2.0.1: dependencies: is-extendable: 0.1.1 @@ -17133,7 +18976,7 @@ snapshots: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.7 + micromatch: 4.0.8 fast-json-stable-stringify@2.1.0: {} @@ -17147,6 +18990,8 @@ snapshots: dependencies: fast-decode-uri-component: 1.0.1 + fast-safe-stringify@2.1.1: {} + fast-url-parser@1.1.3: dependencies: punycode: 1.4.1 @@ -17167,6 +19012,10 @@ snapshots: dependencies: websocket-driver: 0.7.4 + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + feed@4.2.2: dependencies: xml-js: 1.6.11 @@ -17231,6 +19080,18 @@ snapshots: transitivePeerDependencies: - supports-color + finalhandler@1.3.1: + dependencies: + debug: 2.6.9 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + find-cache-dir@3.3.2: dependencies: commondir: 1.0.1 @@ -17286,7 +19147,7 @@ snapshots: dependencies: detect-file: 1.0.0 is-glob: 4.0.3 - micromatch: 4.0.7 + micromatch: 4.0.8 resolve-dir: 1.0.1 flat-cache@3.2.0: @@ -17348,14 +19209,31 @@ snapshots: optionalDependencies: eslint: 8.57.0 - form-data-encoder@2.1.4: {} - - form-data@2.5.1: + fork-ts-checker-webpack-plugin@9.0.2(typescript@5.7.2)(webpack@5.97.1): dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - + '@babel/code-frame': 7.24.7 + chalk: 4.1.2 + chokidar: 3.6.0 + cosmiconfig: 8.3.6(typescript@5.7.2) + deepmerge: 4.3.1 + fs-extra: 10.1.0 + memfs: 3.5.3 + minimatch: 3.1.2 + node-abort-controller: 3.1.1 + schema-utils: 3.3.0 + semver: 7.6.3 + tapable: 2.2.1 + typescript: 5.7.2 + webpack: 5.97.1 + + form-data-encoder@2.1.4: {} + + form-data@2.5.1: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + form-data@4.0.0: dependencies: asynckit: 0.4.0 @@ -17364,6 +19242,12 @@ snapshots: format@0.2.2: {} + formidable@3.5.2: + dependencies: + dezalgo: 1.0.4 + hexoid: 2.0.0 + once: 1.4.0 + forwarded@0.2.0: {} fp-ts@1.19.3: {} @@ -17554,6 +19438,15 @@ snapshots: package-json-from-dist: 1.0.0 path-scurry: 1.11.1 + glob@10.4.5: + dependencies: + foreground-child: 3.3.0 + jackspeak: 3.4.0 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.0 + path-scurry: 1.11.1 + glob@11.0.0: dependencies: foreground-child: 3.1.1 @@ -17786,6 +19679,18 @@ snapshots: hardhat: 2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3) strip-ansi: 6.0.1 + hardhat-gas-reporter@1.0.10(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)): + dependencies: + array-uniq: 1.0.3 + eth-gas-reporter: 0.2.27 + hardhat: 2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2) + sha1: 1.1.1 + transitivePeerDependencies: + - '@codechecks/client' + - bufferutil + - debug + - utf-8-validate + hardhat-gas-reporter@1.0.10(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3)): dependencies: array-uniq: 1.0.3 @@ -17798,6 +19703,61 @@ snapshots: - debug - utf-8-validate + hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2): + dependencies: + '@ethersproject/abi': 5.7.0 + '@metamask/eth-sig-util': 4.0.1 + '@nomicfoundation/edr': 0.6.4 + '@nomicfoundation/ethereumjs-common': 4.0.4 + '@nomicfoundation/ethereumjs-tx': 5.0.4 + '@nomicfoundation/ethereumjs-util': 9.0.4 + '@nomicfoundation/solidity-analyzer': 0.1.1 + '@sentry/node': 5.30.0 + '@types/bn.js': 5.1.5 + '@types/lru-cache': 5.1.1 + adm-zip: 0.4.16 + aggregate-error: 3.1.0 + ansi-escapes: 4.3.2 + boxen: 5.1.2 + chalk: 2.4.2 + chokidar: 4.0.1 + ci-info: 2.0.0 + debug: 4.3.6(supports-color@8.1.1) + enquirer: 2.4.1 + env-paths: 2.2.1 + ethereum-cryptography: 1.2.0 + ethereumjs-abi: 0.6.8 + find-up: 2.1.0 + fp-ts: 1.19.3 + fs-extra: 7.0.1 + glob: 7.2.0 + immutable: 4.3.6 + io-ts: 1.10.4 + json-stream-stringify: 3.1.6 + keccak: 3.0.4 + lodash: 4.17.21 + mnemonist: 0.38.5 + mocha: 10.7.3 + p-map: 4.0.0 + raw-body: 2.5.2 + resolve: 1.17.0 + semver: 6.3.1 + solc: 0.8.26(debug@4.3.6) + source-map-support: 0.5.21 + stacktrace-parser: 0.1.10 + tsort: 0.0.1 + undici: 5.28.4 + uuid: 8.3.2 + ws: 7.5.9 + optionalDependencies: + ts-node: 10.9.2(@types/node@22.10.5)(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - bufferutil + - c-kzg + - supports-color + - utf-8-validate + hardhat@2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3): dependencies: '@ethersproject/abi': 5.7.0 @@ -17861,6 +19821,8 @@ snapshots: has-flag@4.0.0: {} + has-own-prop@2.0.0: {} + has-property-descriptors@1.0.2: dependencies: es-define-property: 1.0.0 @@ -18028,6 +19990,10 @@ snapshots: heap@0.2.7: {} + helmet@8.0.0: {} + + hexoid@2.0.0: {} + history@4.10.1: dependencies: '@babel/runtime': 7.24.7 @@ -18181,7 +20147,7 @@ snapshots: http-proxy: 1.18.1 is-glob: 4.0.3 is-plain-obj: 3.0.0 - micromatch: 4.0.7 + micromatch: 4.0.8 optionalDependencies: '@types/express': 4.17.21 transitivePeerDependencies: @@ -18193,7 +20159,7 @@ snapshots: http-proxy: 1.18.1(debug@4.3.6) is-glob: 4.0.3 is-plain-obj: 3.0.0 - micromatch: 4.0.7 + micromatch: 4.0.8 optionalDependencies: '@types/express': 4.17.21 transitivePeerDependencies: @@ -18367,6 +20333,24 @@ snapshots: through: 2.3.8 wrap-ansi: 6.2.0 + inquirer@9.2.15: + dependencies: + '@ljharb/through': 2.3.13 + ansi-escapes: 4.3.2 + chalk: 5.3.0 + cli-cursor: 3.1.0 + cli-width: 4.1.0 + external-editor: 3.1.0 + figures: 3.2.0 + lodash: 4.17.21 + mute-stream: 1.0.0 + ora: 5.4.1 + run-async: 3.0.0 + rxjs: 7.8.1 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + interface-datastore@6.1.1: dependencies: interface-store: 2.0.2 @@ -18572,6 +20556,8 @@ snapshots: dependencies: get-east-asian-width: 1.2.0 + is-generator-fn@2.1.0: {} + is-generator-function@1.0.10: dependencies: has-tostringtag: 1.0.2 @@ -18735,6 +20721,16 @@ snapshots: dependencies: append-transform: 2.0.0 + istanbul-lib-instrument@5.2.1: + dependencies: + '@babel/core': 7.24.7 + '@babel/parser': 7.24.7 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + istanbul-lib-instrument@6.0.2: dependencies: '@babel/core': 7.24.7 @@ -18797,6 +20793,8 @@ snapshots: p-fifo: 1.0.0 readable-stream: 3.6.2 + iterare@1.2.1: {} + iterator.prototype@1.1.3: dependencies: define-properties: 1.2.1 @@ -18842,6 +20840,88 @@ snapshots: - bufferutil - utf-8-validate + jest-changed-files@29.7.0: + dependencies: + execa: 5.1.1 + jest-util: 29.7.0 + p-limit: 3.1.0 + + jest-circus@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.10.5 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.5.3 + is-generator-fn: 2.1.0 + jest-each: 29.7.0 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + p-limit: 3.1.0 + pretty-format: 29.7.0 + pure-rand: 6.1.0 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-cli@29.7.0(@types/node@22.10.5)(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2)) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@22.10.5)(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2)) + exit: 0.1.2 + import-local: 3.1.0 + jest-config: 29.7.0(@types/node@22.10.5)(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2)) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + jest-config@29.7.0(@types/node@22.10.5)(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2)): + dependencies: + '@babel/core': 7.24.7 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.24.7) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 22.10.5 + ts-node: 10.9.2(@types/node@22.10.5)(typescript@5.7.2) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + jest-diff@29.7.0: dependencies: chalk: 4.1.2 @@ -18849,30 +20929,232 @@ snapshots: jest-get-type: 29.6.3 pretty-format: 29.7.0 + jest-docblock@29.7.0: + dependencies: + detect-newline: 3.1.0 + + jest-each@29.7.0: + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + jest-get-type: 29.6.3 + jest-util: 29.7.0 + pretty-format: 29.7.0 + + jest-environment-node@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.10.5 + jest-mock: 29.7.0 + jest-util: 29.7.0 + jest-get-type@29.6.3: {} - jest-util@29.7.0: + jest-haste-map@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/graceful-fs': 4.1.9 + '@types/node': 22.10.5 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + jest-worker: 29.7.0 + micromatch: 4.0.8 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + + jest-leak-detector@29.7.0: + dependencies: + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-matcher-utils@29.7.0: + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-message-util@29.7.0: + dependencies: + '@babel/code-frame': 7.24.7 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-mock@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 22.10.5 + jest-util: 29.7.0 + + jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): + optionalDependencies: + jest-resolve: 29.7.0 + + jest-regex-util@29.6.3: {} + + jest-resolve-dependencies@29.7.0: + dependencies: + jest-regex-util: 29.6.3 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + + jest-resolve@29.7.0: + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) + jest-util: 29.7.0 + jest-validate: 29.7.0 + resolve: 1.22.8 + resolve.exports: 2.0.3 + slash: 3.0.0 + + jest-runner@29.7.0: + dependencies: + '@jest/console': 29.7.0 + '@jest/environment': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.10.5 + chalk: 4.1.2 + emittery: 0.13.1 + graceful-fs: 4.2.11 + jest-docblock: 29.7.0 + jest-environment-node: 29.7.0 + jest-haste-map: 29.7.0 + jest-leak-detector: 29.7.0 + jest-message-util: 29.7.0 + jest-resolve: 29.7.0 + jest-runtime: 29.7.0 + jest-util: 29.7.0 + jest-watcher: 29.7.0 + jest-worker: 29.7.0 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + + jest-runtime@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/globals': 29.7.0 + '@jest/source-map': 29.6.3 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.10.5 + chalk: 4.1.2 + cjs-module-lexer: 1.4.1 + collect-v8-coverage: 1.0.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + + jest-snapshot@29.7.0: + dependencies: + '@babel/core': 7.24.7 + '@babel/generator': 7.24.7 + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-syntax-typescript': 7.24.7(@babel/core@7.24.7) + '@babel/types': 7.24.7 + '@jest/expect-utils': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.24.7) + chalk: 4.1.2 + expect: 29.7.0 + graceful-fs: 4.2.11 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + natural-compare: 1.4.0 + pretty-format: 29.7.0 + semver: 7.6.3 + transitivePeerDependencies: + - supports-color + + jest-util@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 22.10.5 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + + jest-validate@29.7.0: + dependencies: + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + + jest-watcher@29.7.0: dependencies: + '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.9.0 + '@types/node': 22.10.5 + ansi-escapes: 4.3.2 chalk: 4.1.2 - ci-info: 3.9.0 - graceful-fs: 4.2.11 - picomatch: 2.3.1 + emittery: 0.13.1 + jest-util: 29.7.0 + string-length: 4.0.2 jest-worker@27.5.1: dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.5 merge-stream: 2.0.0 supports-color: 8.1.1 jest-worker@29.7.0: dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.5 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 + jest@29.7.0(@types/node@22.10.5)(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2)) + '@jest/types': 29.6.3 + import-local: 3.1.0 + jest-cli: 29.7.0(@types/node@22.10.5)(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2)) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jiti@1.21.3: {} joi@17.13.1: @@ -18938,6 +21220,8 @@ snapshots: jsonc-parser@3.2.0: {} + jsonc-parser@3.2.1: {} + jsonc-parser@3.3.1: {} jsonfile@4.0.0: @@ -19012,7 +21296,7 @@ snapshots: lerna@8.1.9(encoding@0.1.13): dependencies: - '@lerna/create': 8.1.9(encoding@0.1.13)(typescript@5.6.3) + '@lerna/create': 8.1.9(encoding@0.1.13)(typescript@5.7.2) '@npmcli/arborist': 7.5.4 '@npmcli/package-json': 5.2.0 '@npmcli/run-script': 8.1.0 @@ -19030,7 +21314,7 @@ snapshots: conventional-changelog-angular: 7.0.0 conventional-changelog-core: 5.0.1 conventional-recommended-bump: 7.0.1 - cosmiconfig: 9.0.0(typescript@5.6.3) + cosmiconfig: 9.0.0(typescript@5.7.2) dedent: 1.5.3 envinfo: 7.13.0 execa: 5.0.0 @@ -19083,7 +21367,7 @@ snapshots: strong-log-transformer: 2.1.0 tar: 6.2.1 temp-dir: 1.0.0 - typescript: 5.6.3 + typescript: 5.7.2 upath: 2.0.1 uuid: 10.0.0 validate-npm-package-license: 3.0.4 @@ -19134,6 +21418,8 @@ snapshots: transitivePeerDependencies: - supports-color + libphonenumber-js@1.11.17: {} + lilconfig@3.1.2: {} lines-and-columns@1.2.4: {} @@ -19348,6 +21634,10 @@ snapshots: lunr@2.3.9: {} + magic-string@0.30.8: + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + make-dir@2.1.0: dependencies: pify: 4.0.1 @@ -19380,6 +21670,10 @@ snapshots: transitivePeerDependencies: - supports-color + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + map-obj@1.0.1: {} map-obj@4.3.0: {} @@ -19644,6 +21938,8 @@ snapshots: merge-descriptors@1.0.1: {} + merge-descriptors@1.0.3: {} + merge-options@3.0.4: dependencies: is-plain-obj: 2.1.0 @@ -19987,6 +22283,8 @@ snapshots: mime@1.6.0: {} + mime@2.6.0: {} + mimic-fn@2.1.0: {} mimic-fn@4.0.0: {} @@ -20136,6 +22434,16 @@ snapshots: ms@2.1.3: {} + multer@1.4.4-lts.1: + dependencies: + append-field: 1.0.0 + busboy: 1.6.0 + concat-stream: 1.6.2 + mkdirp: 0.5.6 + object-assign: 4.1.1 + type-is: 1.6.18 + xtend: 4.0.2 + multiaddr-to-uri@8.0.0(node-fetch@2.7.0(encoding@0.1.13)): dependencies: multiaddr: 10.0.1(node-fetch@2.7.0(encoding@0.1.13)) @@ -20209,6 +22517,8 @@ snapshots: lower-case: 2.0.2 tslib: 2.7.0 + node-abort-controller@3.1.1: {} + node-addon-api@2.0.2: {} node-addon-api@3.2.1: {} @@ -20255,6 +22565,8 @@ snapshots: transitivePeerDependencies: - supports-color + node-int64@0.4.0: {} + node-machine-id@1.1.12: {} node-preload@0.2.1: @@ -20263,6 +22575,8 @@ snapshots: node-releases@2.0.14: {} + node-releases@2.0.19: {} + nofilter@3.1.0: {} nopt@3.0.6: @@ -20444,6 +22758,8 @@ snapshots: object-assign@4.1.1: {} + object-hash@3.0.0: {} + object-inspect@1.13.1: {} object-keys@1.1.1: {} @@ -20804,6 +23120,8 @@ snapshots: lru-cache: 11.0.0 minipass: 7.1.2 + path-to-regexp@0.1.12: {} + path-to-regexp@0.1.7: {} path-to-regexp@1.8.0: @@ -20812,6 +23130,8 @@ snapshots: path-to-regexp@2.2.1: {} + path-to-regexp@3.3.0: {} + path-type@3.0.0: dependencies: pify: 3.0.0 @@ -20836,8 +23156,12 @@ snapshots: picocolors@1.0.1: {} + picocolors@1.1.1: {} + picomatch@2.3.1: {} + picomatch@4.0.1: {} + pidtree@0.6.0: {} pify@2.3.0: {} @@ -20848,6 +23172,8 @@ snapshots: pify@5.0.0: {} + pirates@4.0.6: {} + pkg-dir@4.2.0: dependencies: find-up: 4.1.0 @@ -21194,7 +23520,7 @@ snapshots: '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 '@types/long': 4.0.2 - '@types/node': 22.9.0 + '@types/node': 22.10.5 long: 4.0.0 protocols@2.0.1: {} @@ -21233,7 +23559,7 @@ snapshots: dependencies: side-channel: 1.0.6 - qs@6.12.1: + qs@6.13.0: dependencies: side-channel: 1.0.6 @@ -21489,6 +23815,8 @@ snapshots: reduce-flatten@2.0.0: {} + reflect-metadata@0.2.2: {} + reflect.getprototypeof@1.0.6: dependencies: call-bind: 1.0.7 @@ -21645,6 +23973,8 @@ snapshots: lodash: 4.17.21 strip-ansi: 6.0.1 + repeat-string@1.6.1: {} + req-cwd@2.0.0: dependencies: req-from: 2.0.0 @@ -21688,6 +24018,8 @@ snapshots: resolve-pkg-maps@1.0.0: {} + resolve.exports@2.0.3: {} + resolve@1.1.7: {} resolve@1.17.0: @@ -21768,6 +24100,8 @@ snapshots: run-async@2.4.1: {} + run-async@3.0.0: {} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -21899,6 +24233,24 @@ snapshots: transitivePeerDependencies: - supports-color + send@0.19.0: + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + serialize-javascript@6.0.2: dependencies: randombytes: 2.1.0 @@ -21935,6 +24287,15 @@ snapshots: transitivePeerDependencies: - supports-color + serve-static@1.16.2: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.0 + transitivePeerDependencies: + - supports-color + set-blocking@2.0.0: {} set-function-length@1.2.2: @@ -22089,6 +24450,36 @@ snapshots: logplease: 1.2.15 r1csfile: 0.0.48 + socket.io-adapter@2.5.5: + dependencies: + debug: 4.3.7(supports-color@8.1.1) + ws: 8.17.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + socket.io-parser@4.2.4: + dependencies: + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.7(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + + socket.io@4.8.1: + dependencies: + accepts: 1.3.8 + base64id: 2.0.0 + cors: 2.8.5 + debug: 4.3.7(supports-color@8.1.1) + engine.io: 6.6.2 + socket.io-adapter: 2.5.5 + socket.io-parser: 4.2.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + sockjs@0.3.24: dependencies: faye-websocket: 0.11.4 @@ -22149,6 +24540,29 @@ snapshots: dependencies: array.prototype.findlast: 1.2.5 + solidity-coverage@0.8.12(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2)): + dependencies: + '@ethersproject/abi': 5.7.0 + '@solidity-parser/parser': 0.18.0 + chalk: 2.4.2 + death: 1.1.0 + difflib: 0.2.4 + fs-extra: 8.1.0 + ghost-testrpc: 0.0.2 + global-modules: 2.0.0 + globby: 10.0.2 + hardhat: 2.22.15(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2))(typescript@5.7.2) + jsonschema: 1.4.1 + lodash: 4.17.21 + mocha: 10.7.3 + node-emoji: 1.11.0 + pify: 4.0.1 + recursive-readdir: 2.2.3 + sc-istanbul: 0.4.6 + semver: 7.6.3 + shelljs: 0.8.5 + web3-utils: 1.10.4 + solidity-coverage@0.8.12(hardhat@2.22.15(ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3))(typescript@5.6.3)): dependencies: '@ethersproject/abi': 5.7.0 @@ -22186,6 +24600,11 @@ snapshots: source-map-js@1.2.0: {} + source-map-support@0.5.13: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + source-map-support@0.5.21: dependencies: buffer-from: 1.1.2 @@ -22270,6 +24689,10 @@ snapshots: stack-trace@0.0.10: {} + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + stacktrace-parser@0.1.10: dependencies: type-fest: 0.7.1 @@ -22298,6 +24721,11 @@ snapshots: string-format@2.0.0: {} + string-length@4.0.2: + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + string-width@2.1.1: dependencies: is-fullwidth-code-point: 2.0.0 @@ -22445,6 +24873,27 @@ snapshots: postcss: 8.4.38 postcss-selector-parser: 6.1.0 + superagent@9.0.2: + dependencies: + component-emitter: 1.3.1 + cookiejar: 2.1.4 + debug: 4.3.7(supports-color@8.1.1) + fast-safe-stringify: 2.1.1 + form-data: 4.0.0 + formidable: 3.5.2 + methods: 1.1.2 + mime: 2.6.0 + qs: 6.13.0 + transitivePeerDependencies: + - supports-color + + supertest@7.0.0: + dependencies: + methods: 1.1.2 + superagent: 9.0.2 + transitivePeerDependencies: + - supports-color + supports-color@3.2.3: dependencies: has-flag: 1.0.0 @@ -22480,6 +24929,12 @@ snapshots: csso: 5.0.5 picocolors: 1.0.1 + swagger-ui-dist@5.18.2: + dependencies: + '@scarf/scarf': 1.4.0 + + symbol-observable@4.0.0: {} + sync-request@6.1.0: dependencies: http-response-object: 3.0.2 @@ -22568,6 +25023,15 @@ snapshots: terser: 5.31.0 webpack: 5.92.1 + terser-webpack-plugin@5.3.10(webpack@5.97.1): + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + jest-worker: 27.5.1 + schema-utils: 3.3.0 + serialize-javascript: 6.0.2 + terser: 5.31.0 + webpack: 5.97.1 + terser@5.31.0: dependencies: '@jridgewell/source-map': 0.3.6 @@ -22599,7 +25063,7 @@ snapshots: http-basic: 8.1.3 http-response-object: 3.0.2 promise: 8.3.0 - qs: 6.12.1 + qs: 6.13.0 through2@2.0.5: dependencies: @@ -22636,6 +25100,8 @@ snapshots: tmp@0.2.3: {} + tmpl@1.0.5: {} + to-buffer@1.1.1: {} to-fast-properties@2.0.0: {} @@ -22650,6 +25116,8 @@ snapshots: tr46@0.0.3: {} + tree-kill@1.2.2: {} + treeverse@3.0.0: {} trim-lines@3.0.1: {} @@ -22675,6 +25143,29 @@ snapshots: dependencies: typescript: 5.6.3 + ts-essentials@7.0.3(typescript@5.7.2): + dependencies: + typescript: 5.7.2 + + ts-jest@29.2.5(@babel/core@7.24.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@29.7.0(@types/node@22.10.5)(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2)))(typescript@5.7.2): + dependencies: + bs-logger: 0.2.6 + ejs: 3.1.10 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0(@types/node@22.10.5)(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2)) + jest-util: 29.7.0 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.6.3 + typescript: 5.7.2 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.24.7 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.24.7) + ts-mocha@10.0.0(mocha@10.7.3): dependencies: mocha: 10.7.3 @@ -22682,6 +25173,42 @@ snapshots: optionalDependencies: tsconfig-paths: 3.15.0 + ts-node@10.9.2(@types/node@22.10.5)(typescript@5.6.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.10.5 + acorn: 8.11.3 + acorn-walk: 8.3.2 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.6.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.10.5 + acorn: 8.11.3 + acorn-walk: 8.3.2 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.7.2 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -22711,6 +25238,13 @@ snapshots: source-map-support: 0.5.21 yn: 2.0.0 + tsconfig-paths-webpack-plugin@4.2.0: + dependencies: + chalk: 4.1.2 + enhanced-resolve: 5.17.0 + tapable: 2.2.1 + tsconfig-paths: 4.2.0 + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 @@ -22730,6 +25264,8 @@ snapshots: tslib@2.7.0: {} + tslib@2.8.1: {} + tsort@0.0.1: {} tuf-js@2.2.1: @@ -22797,6 +25333,22 @@ snapshots: transitivePeerDependencies: - supports-color + typechain@8.3.2(typescript@5.7.2): + dependencies: + '@types/prettier': 2.7.3 + debug: 4.3.7(supports-color@8.1.1) + fs-extra: 7.0.1 + glob: 7.1.7 + js-sha3: 0.8.0 + lodash: 4.17.21 + mkdirp: 1.0.4 + prettier: 2.8.8 + ts-command-line-args: 2.5.1 + ts-essentials: 7.0.3(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + typed-array-buffer@1.0.2: dependencies: call-bind: 1.0.7 @@ -22850,6 +25402,8 @@ snapshots: typescript@5.6.3: {} + typescript@5.7.2: {} + typical@4.0.0: {} typical@5.2.0: {} @@ -22859,6 +25413,10 @@ snapshots: uglify-js@3.17.4: optional: true + uid@2.0.2: + dependencies: + '@lukeed/csprng': 1.1.0 + uint8arrays@3.1.1: dependencies: multiformats: 9.9.0 @@ -22874,6 +25432,8 @@ snapshots: undici-types@6.19.8: {} + undici-types@6.20.0: {} + undici@5.28.4: dependencies: '@fastify/busboy': 2.1.1 @@ -22970,6 +25530,12 @@ snapshots: escalade: 3.1.2 picocolors: 1.0.1 + update-browserslist-db@1.1.1(browserslist@4.24.3): + dependencies: + browserslist: 4.24.3 + escalade: 3.2.0 + picocolors: 1.1.1 + update-notifier@6.0.2: dependencies: boxen: 7.1.1 @@ -23030,6 +25596,12 @@ snapshots: v8-compile-cache-lib@3.0.1: {} + v8-to-istanbul@9.3.0: + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 + validate-npm-package-license@3.0.4: dependencies: spdx-correct: 3.2.0 @@ -23042,6 +25614,8 @@ snapshots: resolve-package-path: 4.0.3 semver: 7.6.3 + validator@13.12.0: {} + value-equal@1.0.1: {} varint@6.0.0: {} @@ -23086,6 +25660,10 @@ snapshots: walk-up-path@3.0.1: {} + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + wasmbuilder@0.0.16: {} wasmcurves@0.2.0: @@ -23266,6 +25844,8 @@ snapshots: flat: 5.0.2 wildcard: 2.0.1 + webpack-node-externals@3.0.0: {} + webpack-sources@3.2.3: {} webpack@5.92.1: @@ -23299,6 +25879,36 @@ snapshots: - esbuild - uglify-js + webpack@5.97.1: + dependencies: + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.6 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + acorn: 8.14.0 + browserslist: 4.24.3 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.18.0 + es-module-lexer: 1.5.3 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.0 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 3.3.0 + tapable: 2.2.1 + terser-webpack-plugin: 5.3.10(webpack@5.97.1) + watchpack: 2.4.1 + webpack-sources: 3.2.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + webpackbar@5.0.2(webpack@5.92.1): dependencies: chalk: 4.1.2 @@ -23451,6 +26061,11 @@ snapshots: signal-exit: 3.0.7 typedarray-to-buffer: 3.1.5 + write-file-atomic@4.0.2: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + write-file-atomic@5.0.1: dependencies: imurmurhash: 0.1.4 From 3d4c33974fb35bef00d017a04a7c7bea1daed75a Mon Sep 17 00:00:00 2001 From: aguzmant103 Date: Tue, 7 Jan 2025 15:59:57 -0600 Subject: [PATCH 08/17] docs: add PGA to project list (#1983) --- apps/website/src/content/projects.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/website/src/content/projects.json b/apps/website/src/content/projects.json index 8e752ef9b5..e9a8ebd8eb 100644 --- a/apps/website/src/content/projects.json +++ b/apps/website/src/content/projects.json @@ -280,5 +280,15 @@ "website": "https://eth-global-sg.vercel.app/", "github": "https://github.com/MukulKolpe/ETHGlobalSG" } + }, + { + "name": "Pixel Game Assistant", + "description": "PGA is a tool that helps Pixel Game players to give community feedback on game features.", + "hackathon": null, + "status": "Production", + "links": { + "website": "https://voting.guildpal.work/", + "github": null + } } ] From 8b2eaf6ddfa9fdd3011ddaccb057c8f5b7a400db Mon Sep 17 00:00:00 2001 From: Crisgarner Date: Tue, 7 Jan 2025 16:52:38 -0600 Subject: [PATCH 09/17] chore: updated pr template (#1991) Co-authored-by: Crisgarner <@crisgarner> --- .github/pull_request_template.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 8e546c7f8c..385bb214f4 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -12,6 +12,8 @@ ## Confirmation +> [!IMPORTANT] +> We do not accept minor grammatical fixes (e.g., correcting typos, rewording sentences) unless they significantly improve clarity in technical documentation. These contributions, while appreciated, are not a priority for merging. If there is a grammatical error feel free to message the team. + - [ ] I have read and understand MACI's [contributor guidelines](https://maci.pse.dev/docs/contributing) and [code of conduct](https://maci.pse.dev/docs/contributing/code-of-conduct). -- [ ] I have read and understand MACI's [GitHub processes](https://github.com/privacy-scaling-explorations/maci/discussions/847). -- [ ] I have read and understand MACI's [testing guide](https://maci.pse.dev/docs/testing). +- [ ] I run and verified that all tests pass acording to MACI's [testing guide](https://maci.pse.dev/docs/guides/testing). From afb352945af61d34e98da5d3660babd9bbea4fca Mon Sep 17 00:00:00 2001 From: Shashank Trivedi <100513286+lordshashank@users.noreply.github.com> Date: Wed, 8 Jan 2025 16:22:09 +0530 Subject: [PATCH 10/17] feat: add pnpm genMaciKeyPair script (#1992) --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 39d007eb47..89df6e6975 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "test": "lerna run test --ignore maci-integrationtests --ignore maci-cli", "types": "lerna run types", "docs": "lerna run docs", - "prepare": "is-ci || husky" + "prepare": "is-ci || husky", + "genMaciKeyPair": "node packages/cli/build/ts/index.js genMaciKeyPair" }, "author": "PSE", "devDependencies": { From 67042d26bc6afe85478826050404489b69a746d2 Mon Sep 17 00:00:00 2001 From: linchizhen Date: Wed, 8 Jan 2025 19:12:58 +0800 Subject: [PATCH 11/17] chore: fix 404 status URL (#1977) Signed-off-by: linchizhen --- apps/website/versioned_docs/version-v1.2/workflow.md | 2 +- .../versioned_docs/version-v2.x/core-concepts/workflow.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/website/versioned_docs/version-v1.2/workflow.md b/apps/website/versioned_docs/version-v1.2/workflow.md index 50c583a46d..a3ea18cf4b 100644 --- a/apps/website/versioned_docs/version-v1.2/workflow.md +++ b/apps/website/versioned_docs/version-v1.2/workflow.md @@ -99,7 +99,7 @@ During this stage, users can sign up and vote. Before a user can cast a vote, they must sign up by generating a MACI keypair and then sending the public key they wish to use to cast their vote to the MACI smart contract. This MACI public key (distinct from their Ethereum account public key) acts as their identity when voting. Users can vote from any Ethereum address, but their message must contain a signature from that MACI public key. -This registration process is necessary to fortify MACI against Sybil attacks. The particular criteria used to allow user signups is customizable, and can be configured using any [SignUpGatekeeper contract](https://github.com/privacy-scaling-explorations/maci/blob/dev/contracts/contracts/gatekeepers/SignUpGatekeeper.sol). This contract dictates the criteria a user must pass in order to participate in a poll. For example, a user might need to prove ownership of a certain NFT, or that they've received some attestation on EAS, or prove that they have passed some sort of proof-of-personhood verification. Note that MACI presumes an identity system where each legitimate member +This registration process is necessary to fortify MACI against Sybil attacks. The particular criteria used to allow user signups is customizable, and can be configured using any [SignUpGatekeeper contract](https://github.com/privacy-scaling-explorations/maci/blob/dev/packages/contracts/contracts/gatekeepers/SignUpGatekeeper.sol). This contract dictates the criteria a user must pass in order to participate in a poll. For example, a user might need to prove ownership of a certain NFT, or that they've received some attestation on EAS, or prove that they have passed some sort of proof-of-personhood verification. Note that MACI presumes an identity system where each legitimate member controls a unique private key - MACI does not specifically solve for this, but allows for customization on how this is configured. #### Vote diff --git a/apps/website/versioned_docs/version-v2.x/core-concepts/workflow.md b/apps/website/versioned_docs/version-v2.x/core-concepts/workflow.md index c118452d23..7c87b919d2 100644 --- a/apps/website/versioned_docs/version-v2.x/core-concepts/workflow.md +++ b/apps/website/versioned_docs/version-v2.x/core-concepts/workflow.md @@ -99,7 +99,7 @@ During this stage, users can sign up and vote. Before a user can cast a vote, they must sign up by generating a MACI keypair and then sending the public key they wish to use to cast their vote to the MACI smart contract. This MACI public key (distinct from their Ethereum account public key) acts as their identity when voting. Users can vote from any Ethereum address, but their message must contain a signature from that MACI public key. -This registration process is necessary to fortify MACI against Sybil attacks. The particular criteria used to allow user signups is customizable, and can be configured using any [SignUpGatekeeper contract](https://github.com/privacy-scaling-explorations/maci/blob/dev/contracts/contracts/gatekeepers/SignUpGatekeeper.sol). This contract dictates the criteria a user must pass in order to participate in a poll. For example, a user might need to prove ownership of a certain NFT, or that they've received some attestation on EAS, or prove that they have passed some sort of proof-of-personhood verification. Note that MACI presumes an identity system where each legitimate member +This registration process is necessary to fortify MACI against Sybil attacks. The particular criteria used to allow user signups is customizable, and can be configured using any [SignUpGatekeeper contract](https://github.com/privacy-scaling-explorations/maci/blob/dev/packages/contracts/contracts/gatekeepers/SignUpGatekeeper.sol). This contract dictates the criteria a user must pass in order to participate in a poll. For example, a user might need to prove ownership of a certain NFT, or that they've received some attestation on EAS, or prove that they have passed some sort of proof-of-personhood verification. Note that MACI presumes an identity system where each legitimate member controls a unique private key - MACI does not specifically solve for this, but allows for customization on how this is configured. #### Vote From 8de3783d1f08dcd7633f58bb04012e89112afd6b Mon Sep 17 00:00:00 2001 From: Crisgarner Date: Thu, 9 Jan 2025 04:15:48 -0600 Subject: [PATCH 12/17] chore: fixed typo on pr template (#1994) Co-authored-by: Crisgarner <@crisgarner> --- .github/pull_request_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 385bb214f4..8aaef77a62 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -16,4 +16,4 @@ > We do not accept minor grammatical fixes (e.g., correcting typos, rewording sentences) unless they significantly improve clarity in technical documentation. These contributions, while appreciated, are not a priority for merging. If there is a grammatical error feel free to message the team. - [ ] I have read and understand MACI's [contributor guidelines](https://maci.pse.dev/docs/contributing) and [code of conduct](https://maci.pse.dev/docs/contributing/code-of-conduct). -- [ ] I run and verified that all tests pass acording to MACI's [testing guide](https://maci.pse.dev/docs/guides/testing). +- [ ] I ran and verified that all tests pass according to MACI's [testing guide](https://maci.pse.dev/docs/guides/testing). From e30bb8838d26cb46dada674f2efc9ede312c8b18 Mon Sep 17 00:00:00 2001 From: Anton <14254374+0xmad@users.noreply.github.com> Date: Wed, 8 Jan 2025 14:18:03 -0600 Subject: [PATCH 13/17] feat(relayer): add publish message api method - [x] Add controller api method for message publishing - [x] Add tests - [x] Add dto and validation --- apps/relayer/package.json | 1 + apps/relayer/tests/messages.test.ts | 89 +++++++++++++++++++ apps/relayer/ts/app.module.ts | 3 + .../__tests__/message.controller.test.ts | 55 ++++++++++++ .../message/__tests__/message.service.test.ts | 21 +++++ apps/relayer/ts/message/__tests__/utils.ts | 15 ++++ .../ts/message/__tests__/validation.test.ts | 30 +++++++ apps/relayer/ts/message/dto.ts | 88 ++++++++++++++++++ apps/relayer/ts/message/message.controller.ts | 41 +++++++++ apps/relayer/ts/message/message.module.ts | 10 +++ apps/relayer/ts/message/message.service.ts | 37 ++++++++ apps/relayer/ts/message/types.ts | 13 +++ apps/relayer/ts/message/validation.ts | 32 +++++++ pnpm-lock.yaml | 3 + 14 files changed, 438 insertions(+) create mode 100644 apps/relayer/tests/messages.test.ts create mode 100644 apps/relayer/ts/message/__tests__/message.controller.test.ts create mode 100644 apps/relayer/ts/message/__tests__/message.service.test.ts create mode 100644 apps/relayer/ts/message/__tests__/utils.ts create mode 100644 apps/relayer/ts/message/__tests__/validation.test.ts create mode 100644 apps/relayer/ts/message/dto.ts create mode 100644 apps/relayer/ts/message/message.controller.ts create mode 100644 apps/relayer/ts/message/message.module.ts create mode 100644 apps/relayer/ts/message/message.service.ts create mode 100644 apps/relayer/ts/message/types.ts create mode 100644 apps/relayer/ts/message/validation.ts diff --git a/apps/relayer/package.json b/apps/relayer/package.json index 649a03e07a..b5aa86a579 100644 --- a/apps/relayer/package.json +++ b/apps/relayer/package.json @@ -41,6 +41,7 @@ "hardhat": "^2.22.15", "helmet": "^8.0.0", "maci-contracts": "workspace:^2.5.0", + "maci-domainobjs": "workspace:^2.5.0", "mustache": "^4.2.0", "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1", diff --git a/apps/relayer/tests/messages.test.ts b/apps/relayer/tests/messages.test.ts new file mode 100644 index 0000000000..72d59ac633 --- /dev/null +++ b/apps/relayer/tests/messages.test.ts @@ -0,0 +1,89 @@ +import { HttpStatus, ValidationPipe, type INestApplication } from "@nestjs/common"; +import { Test } from "@nestjs/testing"; +import { ZeroAddress } from "ethers"; +import { Keypair } from "maci-domainobjs"; +import request from "supertest"; + +import type { App } from "supertest/types"; + +import { AppModule } from "../ts/app.module"; + +describe("e2e messages", () => { + let app: INestApplication; + + beforeAll(async () => { + const moduleFixture = await Test.createTestingModule({ + imports: [AppModule], + }).compile(); + + app = moduleFixture.createNestApplication(); + app.useGlobalPipes(new ValidationPipe({ transform: true })); + await app.listen(3001); + }); + + afterAll(async () => { + await app.close(); + }); + + describe("/v1/messages/publish", () => { + const keypair = new Keypair(); + + const defaultSaveMessagesArgs = { + maciContractAddress: ZeroAddress, + poll: 0, + messages: [ + { + data: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], + publicKey: keypair.pubKey.serialize(), + }, + ], + }; + + test("should throw an error if dto is invalid", async () => { + const result = await request(app.getHttpServer() as App) + .post("/v1/messages/publish") + .send({ + maciContractAddress: "invalid", + poll: "-1", + messages: [], + }) + .expect(HttpStatus.BAD_REQUEST); + + expect(result.body).toStrictEqual({ + error: "Bad Request", + statusCode: HttpStatus.BAD_REQUEST, + message: [ + "poll must not be less than 0", + "poll must be an integer number", + "maciContractAddress must be an Ethereum address", + "messages must contain at least 1 elements", + ], + }); + }); + + test("should throw an error if messages dto is invalid", async () => { + const result = await request(app.getHttpServer() as App) + .post("/v1/messages/publish") + .send({ + ...defaultSaveMessagesArgs, + messages: [{ data: [], publicKey: "invalid" }], + }) + .expect(HttpStatus.BAD_REQUEST); + + expect(result.body).toStrictEqual({ + error: "Bad Request", + statusCode: HttpStatus.BAD_REQUEST, + message: ["messages.0.data must contain at least 10 elements", "messages.0.Public key (invalid) is invalid"], + }); + }); + + test("should publish user messages properly", async () => { + const result = await request(app.getHttpServer() as App) + .post("/v1/messages/publish") + .send(defaultSaveMessagesArgs) + .expect(HttpStatus.CREATED); + + expect(result.status).toBe(HttpStatus.CREATED); + }); + }); +}); diff --git a/apps/relayer/ts/app.module.ts b/apps/relayer/ts/app.module.ts index b1a9046774..fdc8e1fa67 100644 --- a/apps/relayer/ts/app.module.ts +++ b/apps/relayer/ts/app.module.ts @@ -1,6 +1,8 @@ import { Module } from "@nestjs/common"; import { ThrottlerModule } from "@nestjs/throttler"; +import { MessageModule } from "./message/message.module"; + @Module({ imports: [ ThrottlerModule.forRoot([ @@ -9,6 +11,7 @@ import { ThrottlerModule } from "@nestjs/throttler"; limit: Number(process.env.LIMIT), }, ]), + MessageModule, ], }) export class AppModule {} diff --git a/apps/relayer/ts/message/__tests__/message.controller.test.ts b/apps/relayer/ts/message/__tests__/message.controller.test.ts new file mode 100644 index 0000000000..2451685a84 --- /dev/null +++ b/apps/relayer/ts/message/__tests__/message.controller.test.ts @@ -0,0 +1,55 @@ +import { HttpException, HttpStatus } from "@nestjs/common"; +import { Test } from "@nestjs/testing"; + +import { MessageController } from "../message.controller"; +import { MessageService } from "../message.service"; + +import { defaultSaveMessagesArgs } from "./utils"; + +describe("MessageController", () => { + let controller: MessageController; + + const mockMessageService = { + saveMessages: jest.fn(), + merge: jest.fn(), + }; + + beforeEach(async () => { + const app = await Test.createTestingModule({ + controllers: [MessageController], + }) + .useMocker((token) => { + if (token === MessageService) { + mockMessageService.saveMessages.mockResolvedValue(true); + + return mockMessageService; + } + + return jest.fn(); + }) + .compile(); + + controller = app.get(MessageController); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe("v1/messages/publish", () => { + test("should publish user messages properly", async () => { + const data = await controller.publish(defaultSaveMessagesArgs); + + expect(data).toBe(true); + }); + + test("should throw an error if messages saving is failed", async () => { + const error = new Error("error"); + mockMessageService.saveMessages.mockRejectedValue(error); + + await expect(controller.publish(defaultSaveMessagesArgs)).rejects.toThrow( + new HttpException(error.message, HttpStatus.BAD_REQUEST), + ); + }); + }); +}); diff --git a/apps/relayer/ts/message/__tests__/message.service.test.ts b/apps/relayer/ts/message/__tests__/message.service.test.ts new file mode 100644 index 0000000000..114b8d3267 --- /dev/null +++ b/apps/relayer/ts/message/__tests__/message.service.test.ts @@ -0,0 +1,21 @@ +import { MessageService } from "../message.service"; + +import { defaultSaveMessagesArgs } from "./utils"; + +describe("MessageService", () => { + test("should save messages properly", async () => { + const service = new MessageService(); + + const result = await service.saveMessages(defaultSaveMessagesArgs); + + expect(result).toBe(true); + }); + + test("should publish messages properly", async () => { + const service = new MessageService(); + + const result = await service.publishMessages(defaultSaveMessagesArgs); + + expect(result).toStrictEqual({ hash: "", ipfsHash: "" }); + }); +}); diff --git a/apps/relayer/ts/message/__tests__/utils.ts b/apps/relayer/ts/message/__tests__/utils.ts new file mode 100644 index 0000000000..3852210ea4 --- /dev/null +++ b/apps/relayer/ts/message/__tests__/utils.ts @@ -0,0 +1,15 @@ +import { ZeroAddress } from "ethers"; +import { Keypair } from "maci-domainobjs"; + +const keypair = new Keypair(); + +export const defaultSaveMessagesArgs = { + maciContractAddress: ZeroAddress, + poll: 0, + messages: [ + { + data: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], + publicKey: keypair.pubKey.serialize(), + }, + ], +}; diff --git a/apps/relayer/ts/message/__tests__/validation.test.ts b/apps/relayer/ts/message/__tests__/validation.test.ts new file mode 100644 index 0000000000..fe7e72671f --- /dev/null +++ b/apps/relayer/ts/message/__tests__/validation.test.ts @@ -0,0 +1,30 @@ +import { Keypair } from "maci-domainobjs"; + +import { PublicKeyValidator } from "../validation"; + +describe("PublicKeyValidator", () => { + test("should validate valid public key", () => { + const keypair = new Keypair(); + const validator = new PublicKeyValidator(); + + const result = validator.validate(keypair.pubKey.serialize()); + + expect(result).toBe(true); + }); + + test("should validate invalid public key", () => { + const validator = new PublicKeyValidator(); + + const result = validator.validate("invalid"); + + expect(result).toBe(false); + }); + + test("should return default message properly", () => { + const validator = new PublicKeyValidator(); + + const result = validator.defaultMessage(); + + expect(result).toBe("Public key ($value) is invalid"); + }); +}); diff --git a/apps/relayer/ts/message/dto.ts b/apps/relayer/ts/message/dto.ts new file mode 100644 index 0000000000..a5e25e7014 --- /dev/null +++ b/apps/relayer/ts/message/dto.ts @@ -0,0 +1,88 @@ +import { ApiProperty } from "@nestjs/swagger"; +import { Type } from "class-transformer"; +import { + IsEthereumAddress, + IsInt, + Min, + Validate, + IsArray, + ArrayMinSize, + ArrayMaxSize, + ValidateNested, +} from "class-validator"; +import { Message } from "maci-domainobjs"; + +import { PublicKeyValidator } from "./validation"; + +/** + * Max messages per batch + */ +const MAX_MESSAGES = 20; + +/** + * Data transfer object for user message + */ +export class MessageContractParamsDto { + /** + * Message data + */ + @ApiProperty({ + description: "Message data", + type: [String], + }) + @IsArray() + @ArrayMinSize(Message.DATA_LENGTH) + @ArrayMaxSize(Message.DATA_LENGTH) + data!: string[]; + + /** + * Public key + */ + @ApiProperty({ + description: "Public key", + type: String, + }) + @Validate(PublicKeyValidator) + publicKey!: string; +} + +/** + * Data transfer object for publish messages + */ +export class PublishMessagesDto { + /** + * Poll id + */ + @ApiProperty({ + description: "Poll id", + minimum: 0, + type: Number, + }) + @IsInt() + @Min(0) + poll!: number; + + /** + * Maci contract address + */ + @ApiProperty({ + description: "MACI contract address", + type: String, + }) + @IsEthereumAddress() + maciContractAddress!: string; + + /** + * Messages + */ + @ApiProperty({ + description: "User messages with public key", + type: [MessageContractParamsDto], + }) + @IsArray() + @ArrayMinSize(1) + @ArrayMaxSize(MAX_MESSAGES) + @ValidateNested({ each: true }) + @Type(() => MessageContractParamsDto) + messages!: MessageContractParamsDto[]; +} diff --git a/apps/relayer/ts/message/message.controller.ts b/apps/relayer/ts/message/message.controller.ts new file mode 100644 index 0000000000..1f2da30dc4 --- /dev/null +++ b/apps/relayer/ts/message/message.controller.ts @@ -0,0 +1,41 @@ +/* eslint-disable @typescript-eslint/no-shadow */ +import { Body, Controller, HttpException, HttpStatus, Logger, Post } from "@nestjs/common"; +import { ApiBearerAuth, ApiBody, ApiResponse, ApiTags } from "@nestjs/swagger"; + +import { PublishMessagesDto } from "./dto"; +import { MessageService } from "./message.service"; + +@ApiTags("v1/messages") +@ApiBearerAuth() +@Controller("v1/messages") +export class MessageController { + /** + * Logger + */ + private readonly logger = new Logger(MessageController.name); + + /** + * Initialize MessageController + * + */ + constructor(private readonly messageService: MessageService) {} + + /** + * Publish user messages api method. + * Saves messages batch and then send them onchain by calling `publishMessages` method via cron job. + * + * @param args - publish messages dto + * @returns success or not + */ + @ApiBody({ type: PublishMessagesDto }) + @ApiResponse({ status: HttpStatus.CREATED, description: "The messages have been successfully accepted" }) + @ApiResponse({ status: HttpStatus.FORBIDDEN, description: "Forbidden" }) + @ApiResponse({ status: HttpStatus.BAD_REQUEST, description: "BadRequest" }) + @Post("publish") + async publish(@Body() args: PublishMessagesDto): Promise { + return this.messageService.saveMessages(args).catch((error: Error) => { + this.logger.error(`Error:`, error); + throw new HttpException(error.message, HttpStatus.BAD_REQUEST); + }); + } +} diff --git a/apps/relayer/ts/message/message.module.ts b/apps/relayer/ts/message/message.module.ts new file mode 100644 index 0000000000..d24abda234 --- /dev/null +++ b/apps/relayer/ts/message/message.module.ts @@ -0,0 +1,10 @@ +import { Module } from "@nestjs/common"; + +import { MessageController } from "./message.controller"; +import { MessageService } from "./message.service"; + +@Module({ + controllers: [MessageController], + providers: [MessageService], +}) +export class MessageModule {} diff --git a/apps/relayer/ts/message/message.service.ts b/apps/relayer/ts/message/message.service.ts new file mode 100644 index 0000000000..c554f6a627 --- /dev/null +++ b/apps/relayer/ts/message/message.service.ts @@ -0,0 +1,37 @@ +import { Injectable, Logger } from "@nestjs/common"; + +import type { PublishMessagesDto } from "./dto"; +import type { IPublishMessagesReturn } from "./types"; + +/** + * MessageService is responsible for saving message batches and send them onchain + */ +@Injectable() +export class MessageService { + /** + * Logger + */ + private readonly logger: Logger = new Logger(MessageService.name); + + /** + * Save messages batch + * + * @param args - publish messages dto + * @returns success or not + */ + async saveMessages(args: PublishMessagesDto): Promise { + this.logger.log("Save messages", args); + return Promise.resolve(true); + } + + /** + * Publish messages onchain + * + * @param args - publish messages dto + * @returns transaction and ipfs hashes + */ + async publishMessages(args: PublishMessagesDto): Promise { + this.logger.log("Publish messages", args); + return Promise.resolve({ hash: "", ipfsHash: "" }); + } +} diff --git a/apps/relayer/ts/message/types.ts b/apps/relayer/ts/message/types.ts new file mode 100644 index 0000000000..cd15824c29 --- /dev/null +++ b/apps/relayer/ts/message/types.ts @@ -0,0 +1,13 @@ +/** + * Publish messages return type + */ +export interface IPublishMessagesReturn { + /** + * Transaction hash + */ + hash: string; + /** + * IPFS hash for messages batch + */ + ipfsHash: string; +} diff --git a/apps/relayer/ts/message/validation.ts b/apps/relayer/ts/message/validation.ts new file mode 100644 index 0000000000..598910ddf1 --- /dev/null +++ b/apps/relayer/ts/message/validation.ts @@ -0,0 +1,32 @@ +import { ValidatorConstraint, ValidatorConstraintInterface } from "class-validator"; +import { PubKey } from "maci-domainobjs"; + +/** + * Validate public key + */ +@ValidatorConstraint({ name: "publicKey", async: false }) +export class PublicKeyValidator implements ValidatorConstraintInterface { + /** + * Try to deserialize public key from text and return status of validation + * + * @param text - text to validate + * @returns status of validation + */ + validate(text: string): boolean { + try { + const [x, y] = PubKey.deserialize(text).asArray(); + return Boolean(new PubKey([x, y])); + } catch (error) { + return false; + } + } + + /** + * Return default validation message + * + * @returns default validation message + */ + defaultMessage(): string { + return "Public key ($value) is invalid"; + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ca2d6a5b67..fe81febef6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -149,6 +149,9 @@ importers: maci-contracts: specifier: workspace:^2.5.0 version: link:../../packages/contracts + maci-domainobjs: + specifier: workspace:^2.5.0 + version: link:../../packages/domainobjs mustache: specifier: ^4.2.0 version: 4.2.0 From a74a16600e236c9d5c855ad118bdbb45c443acc8 Mon Sep 17 00:00:00 2001 From: ctrlc03 <93448202+ctrlc03@users.noreply.github.com> Date: Mon, 23 Dec 2024 11:18:50 +0100 Subject: [PATCH 14/17] refactor: remove redundant init from poll contract --- packages/contracts/contracts/Poll.sol | 49 ++++++++------------ packages/contracts/contracts/PollFactory.sol | 3 -- packages/contracts/tests/Poll.test.ts | 4 -- 3 files changed, 19 insertions(+), 37 deletions(-) diff --git a/packages/contracts/contracts/Poll.sol b/packages/contracts/contracts/Poll.sol index e90d025b16..4e0695cbf5 100644 --- a/packages/contracts/contracts/Poll.sol +++ b/packages/contracts/contracts/Poll.sol @@ -16,9 +16,6 @@ import { CurveBabyJubJub } from "./crypto/BabyJubJub.sol"; /// @dev Do not deploy this directly. Use PollFactory.deploy() which performs some /// checks on the Poll constructor arguments. contract Poll is Params, Utilities, SnarkCommon, IPoll { - /// @notice Whether the Poll has been initialized - bool internal isInit; - /// @notice The coordinator's public key PubKey public coordinatorPubKey; @@ -163,6 +160,25 @@ contract Poll is Params, Utilities, SnarkCommon, IPoll { emptyBallotRoot = _emptyBallotRoot; // store the poll id pollId = _pollId; + + unchecked { + numMessages++; + } + + // init chainHash here by inserting placeholderLeaf + uint256[2] memory dat; + dat[0] = NOTHING_UP_MY_SLEEVE; + dat[1] = 0; + + (Message memory _message, PubKey memory _padKey, uint256 placeholderLeaf) = padAndHashMessage(dat); + chainHash = NOTHING_UP_MY_SLEEVE; + batchHashes.push(NOTHING_UP_MY_SLEEVE); + updateChainHash(placeholderLeaf); + + InternalLazyIMT._init(pollStateTree, extContracts.maci.stateTreeDepth()); + InternalLazyIMT._insert(pollStateTree, BLANK_STATE_LEAF_HASH); + + emit PublishMessage(_message, _padKey); } /// @notice A modifier that causes the function to revert if the voting period is @@ -186,33 +202,6 @@ contract Poll is Params, Utilities, SnarkCommon, IPoll { _; } - /// @notice The initialization function. - /// @dev Should be called immediately after Poll creation - function init() public virtual { - if (isInit) revert PollAlreadyInit(); - // set to true so it cannot be called again - isInit = true; - - unchecked { - numMessages++; - } - - // init chainHash here by inserting placeholderLeaf - uint256[2] memory dat; - dat[0] = NOTHING_UP_MY_SLEEVE; - dat[1] = 0; - - (Message memory _message, PubKey memory _padKey, uint256 placeholderLeaf) = padAndHashMessage(dat); - chainHash = NOTHING_UP_MY_SLEEVE; - batchHashes.push(NOTHING_UP_MY_SLEEVE); - updateChainHash(placeholderLeaf); - - InternalLazyIMT._init(pollStateTree, extContracts.maci.stateTreeDepth()); - InternalLazyIMT._insert(pollStateTree, BLANK_STATE_LEAF_HASH); - - emit PublishMessage(_message, _padKey); - } - // get all batch hash array elements function getBatchHashes() external view returns (uint256[] memory) { return batchHashes; diff --git a/packages/contracts/contracts/PollFactory.sol b/packages/contracts/contracts/PollFactory.sol index e2ce4d27a2..b68c0a8bb9 100644 --- a/packages/contracts/contracts/PollFactory.sol +++ b/packages/contracts/contracts/PollFactory.sol @@ -35,9 +35,6 @@ contract PollFactory is Params, DomainObjs, IPollFactory { _pollId ); - // init Poll - poll.init(); - pollAddr = address(poll); } } diff --git a/packages/contracts/tests/Poll.test.ts b/packages/contracts/tests/Poll.test.ts index 5b156e313c..df04312a07 100644 --- a/packages/contracts/tests/Poll.test.ts +++ b/packages/contracts/tests/Poll.test.ts @@ -131,10 +131,6 @@ describe("Poll", () => { ); }); - it("should not be possible to init the Poll contract twice", async () => { - await expect(pollContract.init()).to.be.revertedWithCustomError(pollContract, "PollAlreadyInit"); - }); - it("should have the correct coordinator public key set", async () => { const coordinatorPubKey = await pollContract.coordinatorPubKey(); expect(coordinatorPubKey[0].toString()).to.eq(coordinator.pubKey.rawPubKey[0].toString()); From 13acab2fc7578ef19d7fcc47bbda7476a12b7ff0 Mon Sep 17 00:00:00 2001 From: Shashank Trivedi <100513286+lordshashank@users.noreply.github.com> Date: Mon, 13 Jan 2025 17:02:27 +0530 Subject: [PATCH 15/17] docs: add MACI key generation instructions and typo correction (#1996) --- .../version-v2.x/contributing/contributing.md | 2 +- .../version-v2.x/core-concepts/maci-keys.md | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/website/versioned_docs/version-v2.x/contributing/contributing.md b/apps/website/versioned_docs/version-v2.x/contributing/contributing.md index 424a57d31d..db1f66ce8f 100644 --- a/apps/website/versioned_docs/version-v2.x/contributing/contributing.md +++ b/apps/website/versioned_docs/version-v2.x/contributing/contributing.md @@ -57,7 +57,7 @@ Pull requests are great if you want to add a feature or fix a bug. Here's a quic 7. Make the test pass. -8. Commit your changes. Please make sure your forked `dev` branch is synched as well feature/fix branch and there are no "temp" commits (like wip, fix typo/lint/types and etc). We recommend to squash the feature/fix branch commits before creating PR. You can use this command for it: +8. Commit your changes. Please make sure your forked `dev` branch is synced as well feature/fix branch and there are no "temp" commits (like wip, fix typo/lint/types and etc). We recommend to squash the feature/fix branch commits before creating PR. You can use this command for it: ```bash git reset $(git merge-base dev $(git rev-parse --abbrev-ref HEAD)) diff --git a/apps/website/versioned_docs/version-v2.x/core-concepts/maci-keys.md b/apps/website/versioned_docs/version-v2.x/core-concepts/maci-keys.md index 57384689bb..2cdfb0dc54 100644 --- a/apps/website/versioned_docs/version-v2.x/core-concepts/maci-keys.md +++ b/apps/website/versioned_docs/version-v2.x/core-concepts/maci-keys.md @@ -72,3 +72,13 @@ For instance, given a seed of `2751400778105288503616280864801989336281162831694 ``` Serialized, these will look like **macipk.0e5194a54562ea4d440ac6a0049a41d4b600e3eb0bf54486e7a5f7e27521f6ba** and **macisk.3cd46064ea59936f82efb384059dd4f5b6b8e5c7546614caf7c1c3be0daea00f**. + +## Generate MACI Keys + +After successfully [installing](../getting-started.md#installation) MACI, you can easily generate your MACI key pair by running: + +```bash +pnpm run genMaciKeyPair +``` + +This command will create the necessary public and private keys required for running various MACI operations. From 809e56fbc496f08bf542e90166b5dfad493e7fbb Mon Sep 17 00:00:00 2001 From: Anton <14254374+0xmad@users.noreply.github.com> Date: Fri, 10 Jan 2025 12:19:17 -0600 Subject: [PATCH 16/17] feat(relayer): add database integration - [x] Add mongodb integration - [x] Add message repository - [x] Add message batch repository - [x] Add message batch service - [x] Add message and message batch schemas - [x] Integrate message repository into message service - [x] Integrate message batch service into message service --- .github/workflows/relayer-build.yml | 8 +- apps/relayer/.env.example | 6 + apps/relayer/package.json | 3 + apps/relayer/tests/app.test.ts | 2 +- apps/relayer/tests/messages.test.ts | 2 +- apps/relayer/ts/app.module.ts | 21 + apps/relayer/ts/jest/mongo.ts | 20 + .../__tests__/message.repository.test.ts | 77 ++++ .../message/__tests__/message.service.test.ts | 53 ++- apps/relayer/ts/message/__tests__/utils.ts | 24 +- apps/relayer/ts/message/message.controller.ts | 6 +- apps/relayer/ts/message/message.module.ts | 8 +- apps/relayer/ts/message/message.repository.ts | 60 +++ apps/relayer/ts/message/message.schema.ts | 55 +++ apps/relayer/ts/message/message.service.ts | 42 +- apps/relayer/ts/message/validation.ts | 2 +- .../__tests__/messageBatch.repository.test.ts | 66 +++ .../__tests__/messageBatch.service.test.ts | 52 +++ .../ts/messageBatch/__tests__/utils.ts | 21 + .../messageBatch/__tests__/validation.test.ts | 29 ++ apps/relayer/ts/messageBatch/dto.ts | 39 ++ .../ts/messageBatch/messageBatch.module.ts | 13 + .../messageBatch/messageBatch.repository.ts | 54 +++ .../ts/messageBatch/messageBatch.schema.ts | 37 ++ .../ts/messageBatch/messageBatch.service.ts | 51 +++ apps/relayer/ts/messageBatch/validation.ts | 31 ++ pnpm-lock.yaml | 411 ++++++++++++++++-- 27 files changed, 1120 insertions(+), 73 deletions(-) create mode 100644 apps/relayer/ts/jest/mongo.ts create mode 100644 apps/relayer/ts/message/__tests__/message.repository.test.ts create mode 100644 apps/relayer/ts/message/message.repository.ts create mode 100644 apps/relayer/ts/message/message.schema.ts create mode 100644 apps/relayer/ts/messageBatch/__tests__/messageBatch.repository.test.ts create mode 100644 apps/relayer/ts/messageBatch/__tests__/messageBatch.service.test.ts create mode 100644 apps/relayer/ts/messageBatch/__tests__/utils.ts create mode 100644 apps/relayer/ts/messageBatch/__tests__/validation.test.ts create mode 100644 apps/relayer/ts/messageBatch/dto.ts create mode 100644 apps/relayer/ts/messageBatch/messageBatch.module.ts create mode 100644 apps/relayer/ts/messageBatch/messageBatch.repository.ts create mode 100644 apps/relayer/ts/messageBatch/messageBatch.schema.ts create mode 100644 apps/relayer/ts/messageBatch/messageBatch.service.ts create mode 100644 apps/relayer/ts/messageBatch/validation.ts diff --git a/.github/workflows/relayer-build.yml b/.github/workflows/relayer-build.yml index 143484ed04..6a5c764906 100644 --- a/.github/workflows/relayer-build.yml +++ b/.github/workflows/relayer-build.yml @@ -6,7 +6,13 @@ on: pull_request: env: - RPC_URL: "http://localhost:8545" + RELAYER_RPC_URL: "http://localhost:8545" + TTL: ${{ vars.RELAYER_TTL }} + LIMIT: ${{ vars.RELAYER_LIMIT }} + MONGO_DB_URI: ${{ secrets.RELAYER_MONGO_DB_URI }} + MONGODB_USER: ${{ secrets.MONGODB_USER }} + MONGODB_PASSWORD: ${{ secrets.MONGODB_PASSWORD }} + MONGODB_DATABASE: ${{ secrets.MONGODB_DATABASE }} concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} diff --git a/apps/relayer/.env.example b/apps/relayer/.env.example index a6389442ae..b0628a7ce0 100644 --- a/apps/relayer/.env.example +++ b/apps/relayer/.env.example @@ -5,6 +5,12 @@ LIMIT=10 # Coordinator RPC url RELAYER_RPC_URL=http://localhost:8545 +# MongoDB configuration +MONGO_DB_URI=mongodb://localhost +MONGODB_USER=maci +MONGODB_PASSWORD= +MONGODB_DATABASE=maci-relayer + # Allowed origin host, use comma to separate each of them ALLOWED_ORIGINS= diff --git a/apps/relayer/package.json b/apps/relayer/package.json index b5aa86a579..e22ff6d7de 100644 --- a/apps/relayer/package.json +++ b/apps/relayer/package.json @@ -26,6 +26,7 @@ "dependencies": { "@nestjs/common": "^10.4.7", "@nestjs/core": "^10.4.7", + "@nestjs/mongoose": "^10.1.0", "@nestjs/platform-express": "^10.4.7", "@nestjs/platform-socket.io": "^10.3.10", "@nestjs/swagger": "^8.0.3", @@ -42,6 +43,7 @@ "helmet": "^8.0.0", "maci-contracts": "workspace:^2.5.0", "maci-domainobjs": "workspace:^2.5.0", + "mongoose": "^8.9.3", "mustache": "^4.2.0", "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1", @@ -57,6 +59,7 @@ "@types/supertest": "^6.0.2", "fast-check": "^3.23.1", "jest": "^29.5.0", + "mongodb-memory-server": "^10.1.3", "supertest": "^7.0.0", "ts-jest": "^29.2.5", "typescript": "^5.7.2" diff --git a/apps/relayer/tests/app.test.ts b/apps/relayer/tests/app.test.ts index 26c6a977de..75194e5456 100644 --- a/apps/relayer/tests/app.test.ts +++ b/apps/relayer/tests/app.test.ts @@ -6,7 +6,7 @@ import type { App } from "supertest/types"; import { AppModule } from "../ts/app.module"; -describe("e2e", () => { +describe("Integration", () => { let app: INestApplication; beforeAll(async () => { diff --git a/apps/relayer/tests/messages.test.ts b/apps/relayer/tests/messages.test.ts index 72d59ac633..401d3971a6 100644 --- a/apps/relayer/tests/messages.test.ts +++ b/apps/relayer/tests/messages.test.ts @@ -8,7 +8,7 @@ import type { App } from "supertest/types"; import { AppModule } from "../ts/app.module"; -describe("e2e messages", () => { +describe("Integration messages", () => { let app: INestApplication; beforeAll(async () => { diff --git a/apps/relayer/ts/app.module.ts b/apps/relayer/ts/app.module.ts index fdc8e1fa67..752e77a5f7 100644 --- a/apps/relayer/ts/app.module.ts +++ b/apps/relayer/ts/app.module.ts @@ -1,7 +1,9 @@ import { Module } from "@nestjs/common"; +import { MongooseModule } from "@nestjs/mongoose"; import { ThrottlerModule } from "@nestjs/throttler"; import { MessageModule } from "./message/message.module"; +import { MessageBatchModule } from "./messageBatch/messageBatch.module"; @Module({ imports: [ @@ -11,7 +13,26 @@ import { MessageModule } from "./message/message.module"; limit: Number(process.env.LIMIT), }, ]), + MongooseModule.forRootAsync({ + useFactory: async () => { + if (process.env.NODE_ENV === "test") { + const { getTestMongooseModuleOptions } = await import("./jest/mongo"); + + return getTestMongooseModuleOptions(); + } + + return { + uri: process.env.MONGO_DB_URI, + auth: { + username: process.env.MONGODB_USER, + password: process.env.MONGODB_PASSWORD, + }, + dbName: process.env.MONGODB_DATABASE, + }; + }, + }), MessageModule, + MessageBatchModule, ], }) export class AppModule {} diff --git a/apps/relayer/ts/jest/mongo.ts b/apps/relayer/ts/jest/mongo.ts new file mode 100644 index 0000000000..0741623571 --- /dev/null +++ b/apps/relayer/ts/jest/mongo.ts @@ -0,0 +1,20 @@ +import type { MongooseModuleOptions } from "@nestjs/mongoose"; + +/** + * Get test mongoose module options + * + * @param options mongoose module options + * @returns mongoose module options for testing + */ +export const getTestMongooseModuleOptions = async ( + options: MongooseModuleOptions = {}, +): Promise => { + // eslint-disable-next-line import/no-extraneous-dependencies + const { MongoMemoryServer } = await import("mongodb-memory-server"); + const mongod = await MongoMemoryServer.create(); + + return { + uri: mongod.getUri(), + ...options, + }; +}; diff --git a/apps/relayer/ts/message/__tests__/message.repository.test.ts b/apps/relayer/ts/message/__tests__/message.repository.test.ts new file mode 100644 index 0000000000..d43c8a28b2 --- /dev/null +++ b/apps/relayer/ts/message/__tests__/message.repository.test.ts @@ -0,0 +1,77 @@ +import { ZeroAddress } from "ethers"; +import { Keypair } from "maci-domainobjs"; +import { Model } from "mongoose"; + +import { MessageRepository } from "../message.repository"; +import { Message } from "../message.schema"; + +import { defaultSaveMessagesArgs } from "./utils"; + +describe("MessageRepository", () => { + const defaultMessages: Message[] = [ + { + publicKey: new Keypair().pubKey.serialize(), + data: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], + maciContractAddress: ZeroAddress, + poll: 0, + }, + ]; + + const mockMessageModel = { + find: jest + .fn() + .mockReturnValue({ limit: jest.fn().mockReturnValue({ exec: jest.fn().mockResolvedValue(defaultMessages) }) }), + insertMany: jest.fn().mockResolvedValue(defaultMessages), + } as unknown as Model; + + beforeEach(() => { + mockMessageModel.find = jest + .fn() + .mockReturnValue({ limit: jest.fn().mockReturnValue({ exec: jest.fn().mockResolvedValue(defaultMessages) }) }); + mockMessageModel.insertMany = jest.fn().mockResolvedValue(defaultMessages); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test("should create messages properly", async () => { + const repository = new MessageRepository(mockMessageModel); + + const result = await repository.create(defaultSaveMessagesArgs); + + expect(result).toStrictEqual(defaultMessages); + }); + + test("should throw an error if creation is failed", async () => { + const error = new Error("error"); + + (mockMessageModel.insertMany as jest.Mock).mockRejectedValue(error); + + const repository = new MessageRepository(mockMessageModel); + + await expect(repository.create(defaultSaveMessagesArgs)).rejects.toThrow(error); + }); + + test("should find messages properly", async () => { + const repository = new MessageRepository(mockMessageModel); + + const result = await repository.find({}); + + expect(result).toStrictEqual(defaultMessages); + }); + + test("should throw an error if find is failed", async () => { + const error = new Error("error"); + + (mockMessageModel.find as jest.Mock).mockReturnValue({ + limit: jest.fn().mockReturnValue({ + exec: jest.fn().mockRejectedValue(error), + }), + }); + + const repository = new MessageRepository(mockMessageModel); + + await expect(repository.find({})).rejects.toThrow(error); + }); +}); diff --git a/apps/relayer/ts/message/__tests__/message.service.test.ts b/apps/relayer/ts/message/__tests__/message.service.test.ts index 114b8d3267..6a4ecd74e8 100644 --- a/apps/relayer/ts/message/__tests__/message.service.test.ts +++ b/apps/relayer/ts/message/__tests__/message.service.test.ts @@ -1,21 +1,64 @@ +import type { MessageBatchService } from "../../messageBatch/messageBatch.service"; +import type { MessageRepository } from "../message.repository"; + import { MessageService } from "../message.service"; -import { defaultSaveMessagesArgs } from "./utils"; +import { defaultMessages, defaultSaveMessagesArgs } from "./utils"; describe("MessageService", () => { + const mockMessageBatchService = { + saveMessageBatches: jest.fn().mockImplementation((args) => Promise.resolve(args)), + } as unknown as MessageBatchService; + + const mockRepository = { + create: jest.fn().mockResolvedValue(defaultMessages), + find: jest.fn().mockResolvedValue(defaultMessages), + } as unknown as MessageRepository; + + beforeEach(() => { + mockMessageBatchService.saveMessageBatches = jest.fn().mockImplementation((args) => Promise.resolve(args)); + + mockRepository.create = jest.fn().mockResolvedValue(defaultMessages); + mockRepository.find = jest.fn().mockResolvedValue(defaultMessages); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + test("should save messages properly", async () => { - const service = new MessageService(); + const service = new MessageService(mockMessageBatchService, mockRepository); const result = await service.saveMessages(defaultSaveMessagesArgs); - expect(result).toBe(true); + expect(result).toStrictEqual(defaultMessages); + }); + + test("should throw an error if can't save messages", async () => { + const error = new Error("error"); + + (mockRepository.create as jest.Mock).mockRejectedValue(error); + + const service = new MessageService(mockMessageBatchService, mockRepository); + + await expect(service.saveMessages(defaultSaveMessagesArgs)).rejects.toThrow(error); }); test("should publish messages properly", async () => { - const service = new MessageService(); + const service = new MessageService(mockMessageBatchService, mockRepository); - const result = await service.publishMessages(defaultSaveMessagesArgs); + const result = await service.publishMessages(); expect(result).toStrictEqual({ hash: "", ipfsHash: "" }); }); + + test("should throw an error if can't save message batch", async () => { + const error = new Error("error"); + + (mockMessageBatchService.saveMessageBatches as jest.Mock).mockRejectedValue(error); + + const service = new MessageService(mockMessageBatchService, mockRepository); + + await expect(service.publishMessages()).rejects.toThrow(error); + }); }); diff --git a/apps/relayer/ts/message/__tests__/utils.ts b/apps/relayer/ts/message/__tests__/utils.ts index 3852210ea4..2aeac02788 100644 --- a/apps/relayer/ts/message/__tests__/utils.ts +++ b/apps/relayer/ts/message/__tests__/utils.ts @@ -1,15 +1,19 @@ import { ZeroAddress } from "ethers"; import { Keypair } from "maci-domainobjs"; +import { defaultMessageBatches } from "../../messageBatch/__tests__/utils"; +import { PublishMessagesDto } from "../dto"; + const keypair = new Keypair(); -export const defaultSaveMessagesArgs = { - maciContractAddress: ZeroAddress, - poll: 0, - messages: [ - { - data: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], - publicKey: keypair.pubKey.serialize(), - }, - ], -}; +export const defaultMessages = defaultMessageBatches[0].messages; + +export const defaultSaveMessagesArgs = new PublishMessagesDto(); +defaultSaveMessagesArgs.maciContractAddress = ZeroAddress; +defaultSaveMessagesArgs.poll = 0; +defaultSaveMessagesArgs.messages = [ + { + data: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], + publicKey: keypair.pubKey.serialize(), + }, +]; diff --git a/apps/relayer/ts/message/message.controller.ts b/apps/relayer/ts/message/message.controller.ts index 1f2da30dc4..5bf1a8a516 100644 --- a/apps/relayer/ts/message/message.controller.ts +++ b/apps/relayer/ts/message/message.controller.ts @@ -3,6 +3,7 @@ import { Body, Controller, HttpException, HttpStatus, Logger, Post } from "@nest import { ApiBearerAuth, ApiBody, ApiResponse, ApiTags } from "@nestjs/swagger"; import { PublishMessagesDto } from "./dto"; +import { Message } from "./message.schema"; import { MessageService } from "./message.service"; @ApiTags("v1/messages") @@ -17,6 +18,7 @@ export class MessageController { /** * Initialize MessageController * + * @param messageService message service */ constructor(private readonly messageService: MessageService) {} @@ -24,7 +26,7 @@ export class MessageController { * Publish user messages api method. * Saves messages batch and then send them onchain by calling `publishMessages` method via cron job. * - * @param args - publish messages dto + * @param args publish messages dto * @returns success or not */ @ApiBody({ type: PublishMessagesDto }) @@ -32,7 +34,7 @@ export class MessageController { @ApiResponse({ status: HttpStatus.FORBIDDEN, description: "Forbidden" }) @ApiResponse({ status: HttpStatus.BAD_REQUEST, description: "BadRequest" }) @Post("publish") - async publish(@Body() args: PublishMessagesDto): Promise { + async publish(@Body() args: PublishMessagesDto): Promise { return this.messageService.saveMessages(args).catch((error: Error) => { this.logger.error(`Error:`, error); throw new HttpException(error.message, HttpStatus.BAD_REQUEST); diff --git a/apps/relayer/ts/message/message.module.ts b/apps/relayer/ts/message/message.module.ts index d24abda234..a8cbbf8f4e 100644 --- a/apps/relayer/ts/message/message.module.ts +++ b/apps/relayer/ts/message/message.module.ts @@ -1,10 +1,16 @@ import { Module } from "@nestjs/common"; +import { MongooseModule } from "@nestjs/mongoose"; + +import { MessageBatchModule } from "../messageBatch/messageBatch.module"; import { MessageController } from "./message.controller"; +import { MessageRepository } from "./message.repository"; +import { Message, MessageSchema } from "./message.schema"; import { MessageService } from "./message.service"; @Module({ + imports: [MongooseModule.forFeature([{ name: Message.name, schema: MessageSchema }]), MessageBatchModule], controllers: [MessageController], - providers: [MessageService], + providers: [MessageService, MessageRepository], }) export class MessageModule {} diff --git a/apps/relayer/ts/message/message.repository.ts b/apps/relayer/ts/message/message.repository.ts new file mode 100644 index 0000000000..5b65ac7e2a --- /dev/null +++ b/apps/relayer/ts/message/message.repository.ts @@ -0,0 +1,60 @@ +import { Injectable, Logger } from "@nestjs/common"; +import { InjectModel } from "@nestjs/mongoose"; +import { Model, RootFilterQuery } from "mongoose"; + +import { PublishMessagesDto } from "./dto"; +import { Message, MESSAGES_LIMIT } from "./message.schema"; + +/** + * Message repository is used to interact with the message collection + */ +@Injectable() +export class MessageRepository { + /** + * Logger + */ + private readonly logger: Logger = new Logger(MessageRepository.name); + + /** + * Initializes the message repository + * + * @param MessageModel message model + */ + constructor(@InjectModel(Message.name) private MessageModel: Model) {} + + /** + * Create messages from dto + * + * @param dto publish messages dto + * @returns inserted messages + */ + async create(dto: PublishMessagesDto): Promise { + const messages = dto.messages.map(({ data, publicKey }) => ({ + data, + publicKey, + maciContractAddress: dto.maciContractAddress, + poll: dto.poll, + })); + + return this.MessageModel.insertMany(messages).catch((error) => { + this.logger.error(`Create messages error:`, error); + throw error; + }); + } + + /** + * Find messages with filter query + * + * @param filter filter query + * @returns messages + */ + async find(filter: RootFilterQuery, limit = MESSAGES_LIMIT): Promise { + return this.MessageModel.find(filter) + .limit(limit) + .exec() + .catch((error) => { + this.logger.error(`Find messages error:`, error); + throw error; + }); + } +} diff --git a/apps/relayer/ts/message/message.schema.ts b/apps/relayer/ts/message/message.schema.ts new file mode 100644 index 0000000000..958163c5af --- /dev/null +++ b/apps/relayer/ts/message/message.schema.ts @@ -0,0 +1,55 @@ +import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; +import mongoose, { HydratedDocument } from "mongoose"; + +import type { MessageBatch } from "../messageBatch/messageBatch.schema"; + +/** + * Message document type + */ +export type MessageDocument = HydratedDocument; + +/** + * Messages limit + */ +export const MESSAGES_LIMIT = 100; + +/** + * Message model + */ +@Schema() +export class Message { + /** + * Public key + */ + @Prop({ required: true }) + publicKey!: string; + + /** + * Message data + */ + @Prop({ required: true }) + data!: string[]; + + /** + * MACI contract address + */ + @Prop({ required: true }) + maciContractAddress!: string; + + /** + * Poll ID + */ + @Prop({ required: true }) + poll!: number; + + /** + * Message batch + */ + @Prop({ type: mongoose.Schema.Types.ObjectId, required: false }) + messageBatch?: MessageBatch; +} + +/** + * Message schema + */ +export const MessageSchema = SchemaFactory.createForClass(Message); diff --git a/apps/relayer/ts/message/message.service.ts b/apps/relayer/ts/message/message.service.ts index c554f6a627..a786a5cd76 100644 --- a/apps/relayer/ts/message/message.service.ts +++ b/apps/relayer/ts/message/message.service.ts @@ -3,8 +3,13 @@ import { Injectable, Logger } from "@nestjs/common"; import type { PublishMessagesDto } from "./dto"; import type { IPublishMessagesReturn } from "./types"; +import { MessageBatchService } from "../messageBatch/messageBatch.service"; + +import { MessageRepository } from "./message.repository"; +import { Message } from "./message.schema"; + /** - * MessageService is responsible for saving message batches and send them onchain + * MessageService is responsible for saving messages and send them onchain */ @Injectable() export class MessageService { @@ -14,24 +19,43 @@ export class MessageService { private readonly logger: Logger = new Logger(MessageService.name); /** - * Save messages batch + * Initialize MessageService + * + * @param messageBatchService message batch service + * @param messageRepository message repository + */ + constructor( + private readonly messageBatchService: MessageBatchService, + private readonly messageRepository: MessageRepository, + ) {} + + /** + * Save messages * - * @param args - publish messages dto + * @param args publish messages dto * @returns success or not */ - async saveMessages(args: PublishMessagesDto): Promise { - this.logger.log("Save messages", args); - return Promise.resolve(true); + async saveMessages(args: PublishMessagesDto): Promise { + return this.messageRepository.create(args).catch((error) => { + this.logger.error(`Save messages error:`, error); + throw error; + }); } /** * Publish messages onchain * - * @param args - publish messages dto + * @param args publish messages dto * @returns transaction and ipfs hashes */ - async publishMessages(args: PublishMessagesDto): Promise { - this.logger.log("Publish messages", args); + async publishMessages(): Promise { + const messages = await this.messageRepository.find({ messageBatch: { $exists: false } }); + + await this.messageBatchService.saveMessageBatches([{ messages, ipfsHash: "" }]).catch((error) => { + this.logger.error(`Save message batch error:`, error); + throw error; + }); + return Promise.resolve({ hash: "", ipfsHash: "" }); } } diff --git a/apps/relayer/ts/message/validation.ts b/apps/relayer/ts/message/validation.ts index 598910ddf1..d14ee8b8fc 100644 --- a/apps/relayer/ts/message/validation.ts +++ b/apps/relayer/ts/message/validation.ts @@ -9,7 +9,7 @@ export class PublicKeyValidator implements ValidatorConstraintInterface { /** * Try to deserialize public key from text and return status of validation * - * @param text - text to validate + * @param text text to validate * @returns status of validation */ validate(text: string): boolean { diff --git a/apps/relayer/ts/messageBatch/__tests__/messageBatch.repository.test.ts b/apps/relayer/ts/messageBatch/__tests__/messageBatch.repository.test.ts new file mode 100644 index 0000000000..36be1f3efe --- /dev/null +++ b/apps/relayer/ts/messageBatch/__tests__/messageBatch.repository.test.ts @@ -0,0 +1,66 @@ +import { Model } from "mongoose"; + +import { MessageBatchRepository } from "../messageBatch.repository"; +import { MessageBatch } from "../messageBatch.schema"; + +import { defaultMessageBatches } from "./utils"; + +describe("MessageBatchRepository", () => { + const mockMessageBatchModel = { + find: jest.fn().mockReturnValue({ + limit: jest.fn().mockReturnValue({ exec: jest.fn().mockResolvedValue([defaultMessageBatches]) }), + }), + insertMany: jest.fn().mockResolvedValue(defaultMessageBatches), + } as unknown as Model; + + beforeEach(() => { + mockMessageBatchModel.find = jest.fn().mockReturnValue({ + limit: jest.fn().mockReturnValue({ exec: jest.fn().mockResolvedValue([defaultMessageBatches]) }), + }); + mockMessageBatchModel.insertMany = jest.fn().mockResolvedValue(defaultMessageBatches); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test("should create message batch properly", async () => { + const repository = new MessageBatchRepository(mockMessageBatchModel); + + const result = await repository.create(defaultMessageBatches); + + expect(result).toStrictEqual(defaultMessageBatches); + }); + + test("should throw an error if creation is failed", async () => { + const error = new Error("error"); + + (mockMessageBatchModel.insertMany as jest.Mock).mockRejectedValue(error); + + const repository = new MessageBatchRepository(mockMessageBatchModel); + + await expect(repository.create(defaultMessageBatches)).rejects.toThrow(error); + }); + + test("should find message batches properly", async () => { + const repository = new MessageBatchRepository(mockMessageBatchModel); + + const result = await repository.find({}); + + expect(result).toStrictEqual([defaultMessageBatches]); + }); + + test("should throw an error if find is failed", async () => { + const error = new Error("error"); + + (mockMessageBatchModel.find as jest.Mock).mockReturnValue({ + limit: jest.fn().mockReturnValue({ + exec: jest.fn().mockRejectedValue(error), + }), + }); + + const repository = new MessageBatchRepository(mockMessageBatchModel); + + await expect(repository.find({})).rejects.toThrow(error); + }); +}); diff --git a/apps/relayer/ts/messageBatch/__tests__/messageBatch.service.test.ts b/apps/relayer/ts/messageBatch/__tests__/messageBatch.service.test.ts new file mode 100644 index 0000000000..9743e592bc --- /dev/null +++ b/apps/relayer/ts/messageBatch/__tests__/messageBatch.service.test.ts @@ -0,0 +1,52 @@ +import { MessageBatchDto } from "../dto"; +import { MessageBatchRepository } from "../messageBatch.repository"; +import { MessageBatchService } from "../messageBatch.service"; + +import { defaultMessageBatches } from "./utils"; + +describe("MessageBatchService", () => { + const mockRepository = { + create: jest.fn().mockResolvedValue(defaultMessageBatches), + } as unknown as MessageBatchRepository; + + beforeEach(() => { + mockRepository.create = jest.fn().mockResolvedValue(defaultMessageBatches); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test("should save message batches properly", async () => { + const service = new MessageBatchService(mockRepository); + + const result = await service.saveMessageBatches(defaultMessageBatches); + + expect(result).toStrictEqual(defaultMessageBatches); + }); + + test("should throw an error if can't save message batches", async () => { + const error = new Error("error"); + + (mockRepository.create as jest.Mock).mockRejectedValue(error); + + const service = new MessageBatchService(mockRepository); + + await expect(service.saveMessageBatches(defaultMessageBatches)).rejects.toThrow(error); + }); + + test("should throw an error if validation is failed", async () => { + const service = new MessageBatchService(mockRepository); + + const invalidEmptyMessagesArgs = new MessageBatchDto(); + invalidEmptyMessagesArgs.messages = []; + invalidEmptyMessagesArgs.ipfsHash = "invalid"; + + const invalidMessageArgs = new MessageBatchDto(); + invalidMessageArgs.messages = []; + invalidMessageArgs.ipfsHash = "invalid"; + + await expect(service.saveMessageBatches([invalidEmptyMessagesArgs])).rejects.toThrow("Validation error"); + await expect(service.saveMessageBatches([invalidMessageArgs])).rejects.toThrow("Validation error"); + }); +}); diff --git a/apps/relayer/ts/messageBatch/__tests__/utils.ts b/apps/relayer/ts/messageBatch/__tests__/utils.ts new file mode 100644 index 0000000000..c717c8b125 --- /dev/null +++ b/apps/relayer/ts/messageBatch/__tests__/utils.ts @@ -0,0 +1,21 @@ +import { ZeroAddress } from "ethers"; +import { Keypair } from "maci-domainobjs"; + +import { MessageBatchDto } from "../dto"; + +const keypair = new Keypair(); + +export const defaultIpfsHash = "QmXj8v1qbwTqVp9RxkQR29Xjc6g5C1KL2m2gZ9b8t8THHj"; + +const defaultMessageBatch = new MessageBatchDto(); +defaultMessageBatch.messages = [ + { + publicKey: keypair.pubKey.serialize(), + data: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], + maciContractAddress: ZeroAddress, + poll: 0, + }, +]; +defaultMessageBatch.ipfsHash = defaultIpfsHash; + +export const defaultMessageBatches: MessageBatchDto[] = [defaultMessageBatch]; diff --git a/apps/relayer/ts/messageBatch/__tests__/validation.test.ts b/apps/relayer/ts/messageBatch/__tests__/validation.test.ts new file mode 100644 index 0000000000..15d3060124 --- /dev/null +++ b/apps/relayer/ts/messageBatch/__tests__/validation.test.ts @@ -0,0 +1,29 @@ +import { IpfsHashValidator } from "../validation"; + +import { defaultIpfsHash } from "./utils"; + +describe("IpfsHashValidator", () => { + test("should validate valid ipfs hash", () => { + const validator = new IpfsHashValidator(); + + const result = validator.validate(defaultIpfsHash); + + expect(result).toBe(true); + }); + + test("should validate invalid ipfs hash", () => { + const validator = new IpfsHashValidator(); + + const result = validator.validate("invalid"); + + expect(result).toBe(false); + }); + + test("should return default message properly", () => { + const validator = new IpfsHashValidator(); + + const result = validator.defaultMessage(); + + expect(result).toBe("IPFS hash ($value) is invalid"); + }); +}); diff --git a/apps/relayer/ts/messageBatch/dto.ts b/apps/relayer/ts/messageBatch/dto.ts new file mode 100644 index 0000000000..4ad3fdcd7b --- /dev/null +++ b/apps/relayer/ts/messageBatch/dto.ts @@ -0,0 +1,39 @@ +import { ApiProperty } from "@nestjs/swagger"; +import { IsArray, ArrayMinSize, ArrayMaxSize, ValidateNested, Validate } from "class-validator"; + +import { Message } from "../message/message.schema"; + +import { IpfsHashValidator } from "./validation"; + +/** + * Max messages per batch + */ +const MAX_MESSAGES = 100; + +/** + * Data transfer object for message batch + */ +export class MessageBatchDto { + /** + * Messages + */ + @ApiProperty({ + description: "Messages", + type: [String], + }) + @IsArray() + @ArrayMinSize(1) + @ArrayMaxSize(MAX_MESSAGES) + @ValidateNested({ each: true }) + messages!: Message[]; + + /** + * IPFS hash + */ + @ApiProperty({ + description: "IPFS hash", + type: String, + }) + @Validate(IpfsHashValidator) + ipfsHash!: string; +} diff --git a/apps/relayer/ts/messageBatch/messageBatch.module.ts b/apps/relayer/ts/messageBatch/messageBatch.module.ts new file mode 100644 index 0000000000..ec029fc1a4 --- /dev/null +++ b/apps/relayer/ts/messageBatch/messageBatch.module.ts @@ -0,0 +1,13 @@ +import { Module } from "@nestjs/common"; +import { MongooseModule } from "@nestjs/mongoose"; + +import { MessageBatchRepository } from "./messageBatch.repository"; +import { MessageBatch, MessageBatchSchema } from "./messageBatch.schema"; +import { MessageBatchService } from "./messageBatch.service"; + +@Module({ + imports: [MongooseModule.forFeature([{ name: MessageBatch.name, schema: MessageBatchSchema }])], + exports: [MessageBatchService], + providers: [MessageBatchService, MessageBatchRepository], +}) +export class MessageBatchModule {} diff --git a/apps/relayer/ts/messageBatch/messageBatch.repository.ts b/apps/relayer/ts/messageBatch/messageBatch.repository.ts new file mode 100644 index 0000000000..bac2e6efc0 --- /dev/null +++ b/apps/relayer/ts/messageBatch/messageBatch.repository.ts @@ -0,0 +1,54 @@ +import { Injectable, Logger } from "@nestjs/common"; +import { InjectModel } from "@nestjs/mongoose"; +import { Model, RootFilterQuery } from "mongoose"; + +import { MessageBatchDto } from "./dto"; +import { MESSAGE_BATCHES_LIMIT, MessageBatch } from "./messageBatch.schema"; + +/** + * Message batch repository is used to interact with the message batch collection + */ +@Injectable() +export class MessageBatchRepository { + /** + * Logger + */ + private readonly logger: Logger = new Logger(MessageBatchRepository.name); + + /** + * Initializes the message batch repository + * + * @param MessageBatchModel message batch model + */ + constructor(@InjectModel(MessageBatch.name) private MessageBatchModel: Model) {} + + /** + * Create message batch from messages and ipfs hash + * + * @param messages messages + * @param ipfsHash ipfs hash + * @returns inserted message batch + */ + async create(dto: MessageBatchDto[]): Promise { + return this.MessageBatchModel.insertMany(dto).catch((error) => { + this.logger.error(`Create message batch error:`, error); + throw error; + }); + } + + /** + * Find message batches with filter query + * + * @param filter filter query + * @returns message batches + */ + async find(filter: RootFilterQuery, limit = MESSAGE_BATCHES_LIMIT): Promise { + return this.MessageBatchModel.find(filter) + .limit(limit) + .exec() + .catch((error) => { + this.logger.error(`Find message batches error:`, error); + throw error; + }); + } +} diff --git a/apps/relayer/ts/messageBatch/messageBatch.schema.ts b/apps/relayer/ts/messageBatch/messageBatch.schema.ts new file mode 100644 index 0000000000..986a696d3c --- /dev/null +++ b/apps/relayer/ts/messageBatch/messageBatch.schema.ts @@ -0,0 +1,37 @@ +import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; +import mongoose, { HydratedDocument } from "mongoose"; + +import type { Message } from "../message/message.schema"; + +/** + * Message batch document type + */ +export type MessageBatchDocument = HydratedDocument; + +/** + * Message batches limit + */ +export const MESSAGE_BATCHES_LIMIT = 1; + +/** + * Message batch model + */ +@Schema() +export class MessageBatch { + /** + * Messages + */ + @Prop({ type: [{ type: mongoose.Schema.Types.ObjectId, ref: "Message" }], required: true }) + messages!: Message[]; + + /** + * IPFS hash + */ + @Prop({ required: true }) + ipfsHash!: string; +} + +/** + * Message batch schema + */ +export const MessageBatchSchema = SchemaFactory.createForClass(MessageBatch); diff --git a/apps/relayer/ts/messageBatch/messageBatch.service.ts b/apps/relayer/ts/messageBatch/messageBatch.service.ts new file mode 100644 index 0000000000..11c5e92044 --- /dev/null +++ b/apps/relayer/ts/messageBatch/messageBatch.service.ts @@ -0,0 +1,51 @@ +import { Injectable, Logger } from "@nestjs/common"; +import { validate } from "class-validator"; + +import type { MessageBatchDto } from "./dto"; + +import { MessageBatchRepository } from "./messageBatch.repository"; +import { MessageBatch } from "./messageBatch.schema"; + +/** + * MessageBatchService is responsible for saving message batches and send them to ipfs + */ +@Injectable() +export class MessageBatchService { + /** + * Logger + */ + private readonly logger: Logger = new Logger(MessageBatchService.name); + + /** + * Initialize MessageBatchService + * + * @param messageBatchRepository message batch repository + */ + constructor(private readonly messageBatchRepository: MessageBatchRepository) {} + + /** + * Save messages batch + * + * @param args publish messages dto + * @returns success or not + */ + async saveMessageBatches(args: MessageBatchDto[]): Promise { + const validationErrors = await Promise.all(args.map((values) => validate(values))).then((result) => + result.reduce((acc, errors) => { + acc.push(...errors); + return acc; + }, []), + ); + + if (validationErrors.length > 0) { + this.logger.error(`Validation error:`, validationErrors); + + throw new Error("Validation error"); + } + + return this.messageBatchRepository.create(args).catch((error) => { + this.logger.error(`Save message batch error:`, error); + throw error; + }); + } +} diff --git a/apps/relayer/ts/messageBatch/validation.ts b/apps/relayer/ts/messageBatch/validation.ts new file mode 100644 index 0000000000..08391abbbe --- /dev/null +++ b/apps/relayer/ts/messageBatch/validation.ts @@ -0,0 +1,31 @@ +import { ValidatorConstraint, ValidatorConstraintInterface } from "class-validator"; + +/** + * Check if the string is a valid base58 encoded CIDv1 hash + */ +const IPFS_REGEX = /^Qm[a-zA-Z0-9]{44}$/; + +/** + * Validate public key + */ +@ValidatorConstraint({ name: "ipfsHash", async: false }) +export class IpfsHashValidator implements ValidatorConstraintInterface { + /** + * Validate ipfs hash + * + * @param text text to validate + * @returns status of validation + */ + validate(text: string): boolean { + return IPFS_REGEX.test(text); + } + + /** + * Return default validation message + * + * @returns default validation message + */ + defaultMessage(): string { + return "IPFS hash ($value) is invalid"; + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fe81febef6..d4b9d64055 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -104,6 +104,9 @@ importers: '@nestjs/core': specifier: ^10.4.7 version: 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/mongoose': + specifier: ^10.1.0 + version: 10.1.0(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(mongoose@8.9.3(socks@2.8.3))(rxjs@7.8.1) '@nestjs/platform-express': specifier: ^10.4.7 version: 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15) @@ -152,6 +155,9 @@ importers: maci-domainobjs: specifier: workspace:^2.5.0 version: link:../../packages/domainobjs + mongoose: + specifier: ^8.9.3 + version: 8.9.3(socks@2.8.3) mustache: specifier: ^4.2.0 version: 4.2.0 @@ -192,6 +198,9 @@ importers: jest: specifier: ^29.5.0 version: 29.7.0(@types/node@22.10.5)(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.7.2)) + mongodb-memory-server: + specifier: ^10.1.3 + version: 10.1.3(socks@2.8.3) supertest: specifier: ^7.0.0 version: 7.0.0 @@ -2106,6 +2115,9 @@ packages: '@microsoft/tsdoc@0.15.1': resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==} + '@mongodb-js/saslprep@1.1.9': + resolution: {integrity: sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==} + '@napi-rs/wasm-runtime@0.2.4': resolution: {integrity: sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==} @@ -2165,6 +2177,14 @@ packages: class-validator: optional: true + '@nestjs/mongoose@10.1.0': + resolution: {integrity: sha512-1ExAnZUfh2QffEaGjqYGgVPy/sYBQCVLCLqVgkcClKx/BCd0QNgND8MB70lwyobp3nm/+nbGQqBpu9F3/hgOCw==} + peerDependencies: + '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 + '@nestjs/core': ^8.0.0 || ^9.0.0 || ^10.0.0 + mongoose: ^6.0.2 || ^7.0.0 || ^8.0.0 + rxjs: ^7.0.0 + '@nestjs/platform-express@10.4.15': resolution: {integrity: sha512-63ZZPkXHjoDyO7ahGOVcybZCRa7/Scp6mObQKjcX/fTEq1YJeU75ELvMsuQgc8U2opMGOBD7GVuc4DV0oeDHoA==} peerDependencies: @@ -3375,6 +3395,12 @@ packages: '@types/validator@13.12.2': resolution: {integrity: sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA==} + '@types/webidl-conversions@7.0.3': + resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} + + '@types/whatwg-url@11.0.5': + resolution: {integrity: sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==} + '@types/ws@7.4.7': resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} @@ -3657,6 +3683,10 @@ packages: resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} engines: {node: '>= 14'} + agent-base@7.1.3: + resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} + engines: {node: '>= 14'} + aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} @@ -3912,6 +3942,9 @@ packages: resolution: {integrity: sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==} hasBin: true + async-mutex@0.5.0: + resolution: {integrity: sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==} + async@1.5.2: resolution: {integrity: sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==} @@ -4015,6 +4048,9 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + bare-events@2.5.3: + resolution: {integrity: sha512-pCO3aoRJ0MBiRMu8B7vUga0qL3L7gO1+SW7ku6qlSsMLwuhaawnuvZDyzJY/kyC63Un0XAB0OPUcfF1eTO/V+Q==} + base-x@3.0.9: resolution: {integrity: sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==} @@ -4173,12 +4209,19 @@ packages: bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + bson@6.10.1: + resolution: {integrity: sha512-P92xmHDQjSKPLHqFxefqMxASNq/aWJMEZugpCjf+AF/pgcUpMMQCg7t7+ewko0/u8AapvF3luf/FoehddEK+sA==} + engines: {node: '>=16.20.1'} + buffer-alloc-unsafe@1.1.0: resolution: {integrity: sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==} buffer-alloc@1.2.0: resolution: {integrity: sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==} + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + buffer-fill@1.0.0: resolution: {integrity: sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==} @@ -6036,6 +6079,15 @@ packages: debug: optional: true + follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -6685,6 +6737,10 @@ packages: resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==} engines: {node: '>= 14'} + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -7522,6 +7578,10 @@ packages: just-diff@6.0.2: resolution: {integrity: sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA==} + kareem@2.6.3: + resolution: {integrity: sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==} + engines: {node: '>=12.0.0'} + katex@0.16.10: resolution: {integrity: sha512-ZiqaC04tp2O5utMsl2TEZTXxa6WSC4yo0fv5ML++D3QZv/vx2Mct0mTlRx3O+uUkjfuAgOkzsCmq5MiUEsDDdA==} hasBin: true @@ -7952,6 +8012,9 @@ packages: resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==} engines: {node: '>= 4.0.0'} + memory-pager@1.5.0: + resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==} + memorystream@0.3.1: resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} engines: {node: '>= 0.10.0'} @@ -8293,6 +8356,56 @@ packages: resolution: {integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==} engines: {node: '>=0.10.0'} + mongodb-connection-string-url@3.0.1: + resolution: {integrity: sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==} + + mongodb-memory-server-core@10.1.3: + resolution: {integrity: sha512-ayBQHeV74wRHhgcAKpxHYI4th9Ufidy/m3XhJnLFRufKsOyDsyHYU3Zxv5Fm4hxsWE6wVd0GAVcQ7t7XNkivOg==} + engines: {node: '>=16.20.1'} + + mongodb-memory-server@10.1.3: + resolution: {integrity: sha512-QCUjsIIXSYv/EgkpDAjfhlqRKo6N+qR6DD43q4lyrCVn24xQmvlArdWHW/Um5RS4LkC9YWC3XveSncJqht2Hbg==} + engines: {node: '>=16.20.1'} + + mongodb@6.12.0: + resolution: {integrity: sha512-RM7AHlvYfS7jv7+BXund/kR64DryVI+cHbVAy9P61fnb1RcWZqOW1/Wj2YhqMCx+MuYhqTRGv7AwHBzmsCKBfA==} + engines: {node: '>=16.20.1'} + peerDependencies: + '@aws-sdk/credential-providers': ^3.188.0 + '@mongodb-js/zstd': ^1.1.0 || ^2.0.0 + gcp-metadata: ^5.2.0 + kerberos: ^2.0.1 + mongodb-client-encryption: '>=6.0.0 <7' + snappy: ^7.2.2 + socks: ^2.7.1 + peerDependenciesMeta: + '@aws-sdk/credential-providers': + optional: true + '@mongodb-js/zstd': + optional: true + gcp-metadata: + optional: true + kerberos: + optional: true + mongodb-client-encryption: + optional: true + snappy: + optional: true + socks: + optional: true + + mongoose@8.9.3: + resolution: {integrity: sha512-G50GNPdMqhoiRAJ/24GYAzg13yxXDD3FOOFeYiFwtHmHpAJem3hxbYIxAhLJGWbYEiUZL0qFMu2LXYkgGAmo+Q==} + engines: {node: '>=16.20.1'} + + mpath@0.9.0: + resolution: {integrity: sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==} + engines: {node: '>=4.0.0'} + + mquery@5.0.0: + resolution: {integrity: sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==} + engines: {node: '>=14.0.0'} + mrmime@2.0.0: resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} engines: {node: '>=10'} @@ -8376,6 +8489,10 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + new-find-package-json@2.0.0: + resolution: {integrity: sha512-lDcBsjBSMlj3LXH2v/FW3txlh2pYTjmbOXPYJD93HI5EwuLzI11tdHSIpUMmfq/IOsldj4Ps8M8flhm+pCK4Ew==} + engines: {node: '>=12.22.0'} + no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} @@ -8891,6 +9008,9 @@ packages: resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} engines: {node: '>=0.12'} + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + periscopic@3.1.0: resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} @@ -9363,6 +9483,9 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + queue-tick@1.0.1: + resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} + queue@6.0.2: resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} @@ -9974,6 +10097,9 @@ packages: resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} engines: {node: '>= 0.4'} + sift@17.1.3: + resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==} + signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -10114,6 +10240,9 @@ packages: space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + sparse-bitfield@3.0.3: + resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==} + spawn-wrap@2.0.0: resolution: {integrity: sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==} engines: {node: '>=8'} @@ -10199,6 +10328,9 @@ packages: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} + streamx@2.21.1: + resolution: {integrity: sha512-PhP9wUnFLa+91CPy3N6tiQsK+gnYyUNuk15S3YG/zjYE7RuPeCjJngqnzpC31ow0lzBHQ+QGO4cNJnd0djYUsw==} + string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} @@ -10418,6 +10550,9 @@ packages: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} + tar-stream@3.1.7: + resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} @@ -10455,6 +10590,9 @@ packages: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} + text-decoder@1.2.3: + resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} + text-extensions@1.9.0: resolution: {integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==} engines: {node: '>=0.10'} @@ -10530,6 +10668,10 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + tr46@4.1.1: + resolution: {integrity: sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==} + engines: {node: '>=14'} + tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -11071,6 +11213,10 @@ packages: webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + webpack-bundle-analyzer@4.10.2: resolution: {integrity: sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==} engines: {node: '>= 10.13.0'} @@ -11149,6 +11295,10 @@ packages: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} + whatwg-url@13.0.0: + resolution: {integrity: sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==} + engines: {node: '>=16'} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -11359,6 +11509,10 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yauzl@3.2.0: + resolution: {integrity: sha512-Ow9nuGZE+qp1u4JIPvg+uCiUr7xGQWdff7JQSk5VGYTAZMDe2q8lxJ10ygv10qmSj031Ty/6FNJpLO4o1Sgc+w==} + engines: {node: '>=12'} + yn@2.0.0: resolution: {integrity: sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==} engines: {node: '>=4'} @@ -12776,12 +12930,12 @@ snapshots: cssnano-preset-advanced: 6.1.2(postcss@8.4.38) postcss: 8.4.38 postcss-sort-media-queries: 5.2.0(postcss@8.4.38) - tslib: 2.7.0 + tslib: 2.8.1 '@docusaurus/logger@3.5.2': dependencies: chalk: 4.1.2 - tslib: 2.7.0 + tslib: 2.8.1 '@docusaurus/mdx-loader@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: @@ -12805,7 +12959,7 @@ snapshots: remark-frontmatter: 5.0.0 remark-gfm: 4.0.0 stringify-object: 3.3.0 - tslib: 2.7.0 + tslib: 2.8.1 unified: 11.0.4 unist-util-visit: 5.0.0 url-loader: 4.1.1(file-loader@6.2.0(webpack@5.92.1))(webpack@5.92.1) @@ -12857,7 +13011,7 @@ snapshots: react-dom: 18.3.1(react@18.3.1) reading-time: 1.5.0 srcset: 4.0.0 - tslib: 2.7.0 + tslib: 2.8.1 unist-util-visit: 5.0.0 utility-types: 3.11.0 webpack: 5.92.1 @@ -12898,7 +13052,7 @@ snapshots: lodash: 4.17.21 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.7.0 + tslib: 2.8.1 utility-types: 3.11.0 webpack: 5.92.1 transitivePeerDependencies: @@ -12938,7 +13092,7 @@ snapshots: lodash: 4.17.21 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.7.0 + tslib: 2.8.1 utility-types: 3.11.0 webpack: 5.92.1 transitivePeerDependencies: @@ -12970,7 +13124,7 @@ snapshots: fs-extra: 11.2.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.7.0 + tslib: 2.8.1 webpack: 5.92.1 transitivePeerDependencies: - '@mdx-js/react' @@ -13000,7 +13154,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) react-json-view-lite: 1.4.0(react@18.3.1) - tslib: 2.7.0 + tslib: 2.8.1 transitivePeerDependencies: - '@mdx-js/react' - '@parcel/css' @@ -13027,7 +13181,7 @@ snapshots: '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.3) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.7.0 + tslib: 2.8.1 transitivePeerDependencies: - '@mdx-js/react' - '@parcel/css' @@ -13055,7 +13209,7 @@ snapshots: '@types/gtag.js': 0.0.12 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.7.0 + tslib: 2.8.1 transitivePeerDependencies: - '@mdx-js/react' - '@parcel/css' @@ -13082,7 +13236,7 @@ snapshots: '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.6.3) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.7.0 + tslib: 2.8.1 transitivePeerDependencies: - '@mdx-js/react' - '@parcel/css' @@ -13114,7 +13268,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) sitemap: 7.1.2 - tslib: 2.7.0 + tslib: 2.8.1 transitivePeerDependencies: - '@mdx-js/react' - '@parcel/css' @@ -13296,7 +13450,7 @@ snapshots: lodash: 4.17.21 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - tslib: 2.7.0 + tslib: 2.8.1 utility-types: 3.11.0 transitivePeerDependencies: - '@algolia/client-search' @@ -13324,7 +13478,7 @@ snapshots: '@docusaurus/theme-translations@3.5.2': dependencies: fs-extra: 11.2.0 - tslib: 2.7.0 + tslib: 2.8.1 '@docusaurus/tsconfig@3.5.2': {} @@ -13350,7 +13504,7 @@ snapshots: '@docusaurus/utils-common@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))': dependencies: - tslib: 2.7.0 + tslib: 2.8.1 optionalDependencies: '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -13363,7 +13517,7 @@ snapshots: joi: 17.13.1 js-yaml: 4.1.0 lodash: 4.17.21 - tslib: 2.7.0 + tslib: 2.8.1 transitivePeerDependencies: - '@docusaurus/types' - '@swc/core' @@ -13391,7 +13545,7 @@ snapshots: prompts: 2.4.2 resolve-pathname: 3.0.0 shelljs: 0.8.5 - tslib: 2.7.0 + tslib: 2.8.1 url-loader: 4.1.1(file-loader@6.2.0(webpack@5.92.1))(webpack@5.92.1) utility-types: 3.11.0 webpack: 5.92.1 @@ -13453,17 +13607,17 @@ snapshots: '@emnapi/core@1.2.0': dependencies: '@emnapi/wasi-threads': 1.0.1 - tslib: 2.7.0 + tslib: 2.8.1 optional: true '@emnapi/runtime@1.2.0': dependencies: - tslib: 2.7.0 + tslib: 2.8.1 optional: true '@emnapi/wasi-threads@1.0.1': dependencies: - tslib: 2.7.0 + tslib: 2.8.1 optional: true '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': @@ -14222,6 +14376,10 @@ snapshots: '@microsoft/tsdoc@0.15.1': {} + '@mongodb-js/saslprep@1.1.9': + dependencies: + sparse-bitfield: 3.0.3 + '@napi-rs/wasm-runtime@0.2.4': dependencies: '@emnapi/core': 1.2.0 @@ -14291,6 +14449,13 @@ snapshots: class-transformer: 0.5.1 class-validator: 0.14.1 + '@nestjs/mongoose@10.1.0(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(mongoose@8.9.3(socks@2.8.3))(rxjs@7.8.1)': + dependencies: + '@nestjs/common': 10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + mongoose: 8.9.3(socks@2.8.3) + rxjs: 7.8.1 + '@nestjs/platform-express@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15)': dependencies: '@nestjs/common': 10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) @@ -14871,7 +15036,7 @@ snapshots: '@nrwl/tao@19.2.0': dependencies: nx: 19.2.0 - tslib: 2.7.0 + tslib: 2.8.1 transitivePeerDependencies: - '@swc-node/register' - '@swc/core' @@ -14895,7 +15060,7 @@ snapshots: nx: 19.2.0 semver: 7.6.3 tmp: 0.2.3 - tslib: 2.7.0 + tslib: 2.8.1 yargs-parser: 21.1.1 '@nx/nx-darwin-arm64@19.2.0': @@ -14954,7 +15119,7 @@ snapshots: supports-color: 8.1.1 supports-hyperlinks: 2.3.0 ts-node: 10.9.2(@types/node@22.10.5)(typescript@5.7.2) - tslib: 2.7.0 + tslib: 2.8.1 widest-line: 3.1.0 wordwrap: 1.0.0 wrap-ansi: 7.0.0 @@ -14991,7 +15156,7 @@ snapshots: supports-color: 8.1.1 supports-hyperlinks: 2.3.0 ts-node: 10.9.2(@types/node@22.10.5)(typescript@5.7.2) - tslib: 2.6.3 + tslib: 2.8.1 widest-line: 3.1.0 wordwrap: 1.0.0 wrap-ansi: 7.0.0 @@ -15160,18 +15325,18 @@ snapshots: dependencies: asn1js: 3.0.5 pvtsutils: 1.3.5 - tslib: 2.7.0 + tslib: 2.8.1 '@peculiar/json-schema@1.1.12': dependencies: - tslib: 2.7.0 + tslib: 2.8.1 '@peculiar/webcrypto@1.5.0': dependencies: '@peculiar/asn1-schema': 2.3.8 '@peculiar/json-schema': 1.1.12 pvtsutils: 1.3.5 - tslib: 2.7.0 + tslib: 2.8.1 webcrypto-core: 1.8.0 '@pkgjs/parseargs@0.11.0': @@ -15486,7 +15651,7 @@ snapshots: '@tybys/wasm-util@0.9.0': dependencies: - tslib: 2.7.0 + tslib: 2.8.1 optional: true '@typechain/ethers-v6@0.5.1(ethers@6.13.4)(typechain@8.3.2(typescript@5.6.3))(typescript@5.6.3)': @@ -15856,6 +16021,12 @@ snapshots: '@types/validator@13.12.2': {} + '@types/webidl-conversions@7.0.3': {} + + '@types/whatwg-url@11.0.5': + dependencies: + '@types/webidl-conversions': 7.0.3 + '@types/ws@7.4.7': dependencies: '@types/node': 22.9.0 @@ -16121,7 +16292,7 @@ snapshots: busboy: 1.6.0 fast-querystring: 1.1.2 fast-url-parser: 1.1.3 - tslib: 2.7.0 + tslib: 2.8.1 '@xtuc/ieee754@1.2.0': {} @@ -16132,7 +16303,7 @@ snapshots: '@yarnpkg/parsers@3.0.0-rc.46': dependencies: js-yaml: 3.14.1 - tslib: 2.7.0 + tslib: 2.8.1 '@zk-kit/baby-jubjub@1.0.3': dependencies: @@ -16230,6 +16401,8 @@ snapshots: transitivePeerDependencies: - supports-color + agent-base@7.1.3: {} + aggregate-error@3.1.0: dependencies: clean-stack: 2.2.0 @@ -16476,7 +16649,7 @@ snapshots: dependencies: pvtsutils: 1.3.5 pvutils: 1.1.3 - tslib: 2.7.0 + tslib: 2.8.1 assemblyscript@0.19.10: dependencies: @@ -16499,6 +16672,10 @@ snapshots: astring@1.8.6: {} + async-mutex@0.5.0: + dependencies: + tslib: 2.8.1 + async@1.5.2: {} async@2.6.4: @@ -16641,6 +16818,9 @@ snapshots: balanced-match@1.0.2: {} + bare-events@2.5.3: + optional: true + base-x@3.0.9: dependencies: safe-buffer: 5.2.1 @@ -16878,6 +17058,8 @@ snapshots: dependencies: node-int64: 0.4.0 + bson@6.10.1: {} + buffer-alloc-unsafe@1.1.0: {} buffer-alloc@1.2.0: @@ -16885,6 +17067,8 @@ snapshots: buffer-alloc-unsafe: 1.1.0 buffer-fill: 1.0.0 + buffer-crc32@0.2.13: {} + buffer-fill@1.0.0: {} buffer-from@1.1.2: {} @@ -16960,7 +17144,7 @@ snapshots: camel-case@4.1.2: dependencies: pascal-case: 3.1.2 - tslib: 2.7.0 + tslib: 2.8.1 camelcase-keys@6.2.2: dependencies: @@ -18096,7 +18280,7 @@ snapshots: dot-case@3.0.4: dependencies: no-case: 3.0.4 - tslib: 2.7.0 + tslib: 2.8.1 dot-prop@5.3.0: dependencies: @@ -19173,6 +19357,10 @@ snapshots: optionalDependencies: debug: 4.3.6(supports-color@8.1.1) + follow-redirects@1.15.9(debug@4.3.7): + optionalDependencies: + debug: 4.3.7(supports-color@8.1.1) + for-each@0.3.3: dependencies: is-callable: 1.2.7 @@ -20207,6 +20395,13 @@ snapshots: transitivePeerDependencies: - supports-color + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.3 + debug: 4.3.7(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + human-signals@2.1.0: {} human-signals@5.0.0: {} @@ -21258,6 +21453,8 @@ snapshots: just-diff@6.0.2: {} + kareem@2.6.3: {} + katex@0.16.10: dependencies: commander: 8.3.0 @@ -21615,7 +21812,7 @@ snapshots: lower-case@2.0.2: dependencies: - tslib: 2.7.0 + tslib: 2.8.1 lowercase-keys@3.0.0: {} @@ -21921,6 +22118,8 @@ snapshots: dependencies: fs-monkey: 1.0.6 + memory-pager@1.5.0: {} + memorystream@0.3.1: {} meow@12.1.1: {} @@ -22429,6 +22628,84 @@ snapshots: modify-values@1.0.1: {} + mongodb-connection-string-url@3.0.1: + dependencies: + '@types/whatwg-url': 11.0.5 + whatwg-url: 13.0.0 + + mongodb-memory-server-core@10.1.3(socks@2.8.3): + dependencies: + async-mutex: 0.5.0 + camelcase: 6.3.0 + debug: 4.3.7(supports-color@8.1.1) + find-cache-dir: 3.3.2 + follow-redirects: 1.15.9(debug@4.3.7) + https-proxy-agent: 7.0.6 + mongodb: 6.12.0(socks@2.8.3) + new-find-package-json: 2.0.0 + semver: 7.6.3 + tar-stream: 3.1.7 + tslib: 2.8.1 + yauzl: 3.2.0 + transitivePeerDependencies: + - '@aws-sdk/credential-providers' + - '@mongodb-js/zstd' + - gcp-metadata + - kerberos + - mongodb-client-encryption + - snappy + - socks + - supports-color + + mongodb-memory-server@10.1.3(socks@2.8.3): + dependencies: + mongodb-memory-server-core: 10.1.3(socks@2.8.3) + tslib: 2.8.1 + transitivePeerDependencies: + - '@aws-sdk/credential-providers' + - '@mongodb-js/zstd' + - gcp-metadata + - kerberos + - mongodb-client-encryption + - snappy + - socks + - supports-color + + mongodb@6.12.0(socks@2.8.3): + dependencies: + '@mongodb-js/saslprep': 1.1.9 + bson: 6.10.1 + mongodb-connection-string-url: 3.0.1 + optionalDependencies: + socks: 2.8.3 + + mongoose@8.9.3(socks@2.8.3): + dependencies: + bson: 6.10.1 + kareem: 2.6.3 + mongodb: 6.12.0(socks@2.8.3) + mpath: 0.9.0 + mquery: 5.0.0 + ms: 2.1.3 + sift: 17.1.3 + transitivePeerDependencies: + - '@aws-sdk/credential-providers' + - '@mongodb-js/zstd' + - gcp-metadata + - kerberos + - mongodb-client-encryption + - snappy + - socks + - supports-color + + mpath@0.9.0: {} + + mquery@5.0.0: + dependencies: + debug: 4.3.7(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + mrmime@2.0.0: {} ms@2.0.0: {} @@ -22515,10 +22792,16 @@ snapshots: neo-async@2.6.2: {} + new-find-package-json@2.0.0: + dependencies: + debug: 4.3.7(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + no-case@3.0.4: dependencies: lower-case: 2.0.2 - tslib: 2.7.0 + tslib: 2.8.1 node-abort-controller@3.1.1: {} @@ -22710,7 +22993,7 @@ snapshots: tar-stream: 2.2.0 tmp: 0.2.3 tsconfig-paths: 4.2.0 - tslib: 2.7.0 + tslib: 2.8.1 yargs: 17.7.2 yargs-parser: 21.1.1 optionalDependencies: @@ -23015,7 +23298,7 @@ snapshots: param-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.7.0 + tslib: 2.8.1 parent-module@1.0.1: dependencies: @@ -23084,7 +23367,7 @@ snapshots: pascal-case@3.1.2: dependencies: no-case: 3.0.4 - tslib: 2.7.0 + tslib: 2.8.1 password-prompt@1.1.3: dependencies: @@ -23151,6 +23434,8 @@ snapshots: safe-buffer: 5.2.1 sha.js: 2.4.11 + pend@1.2.0: {} + periscopic@3.1.0: dependencies: '@types/estree': 1.0.5 @@ -23554,7 +23839,7 @@ snapshots: pvtsutils@1.3.5: dependencies: - tslib: 2.7.0 + tslib: 2.8.1 pvutils@1.1.3: {} @@ -23568,6 +23853,8 @@ snapshots: queue-microtask@1.2.3: {} + queue-tick@1.0.1: {} + queue@6.0.2: dependencies: inherits: 2.0.4 @@ -24366,6 +24653,8 @@ snapshots: get-intrinsic: 1.2.4 object-inspect: 1.13.1 + sift@17.1.3: {} + signal-exit@3.0.7: {} signal-exit@4.1.0: {} @@ -24425,7 +24714,7 @@ snapshots: snake-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.7.0 + tslib: 2.8.1 snarkjs@0.5.0: dependencies: @@ -24624,6 +24913,10 @@ snapshots: space-separated-tokens@2.0.2: {} + sparse-bitfield@3.0.3: + dependencies: + memory-pager: 1.5.0 + spawn-wrap@2.0.0: dependencies: foreground-child: 2.0.0 @@ -24720,6 +25013,14 @@ snapshots: streamsearch@1.1.0: {} + streamx@2.21.1: + dependencies: + fast-fifo: 1.3.2 + queue-tick: 1.0.1 + text-decoder: 1.2.3 + optionalDependencies: + bare-events: 2.5.3 + string-argv@0.3.2: {} string-format@2.0.0: {} @@ -24951,7 +25252,7 @@ snapshots: synckit@0.9.1: dependencies: '@pkgr/core': 0.1.1 - tslib: 2.7.0 + tslib: 2.8.1 table-layout@1.0.2: dependencies: @@ -24997,6 +25298,12 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 + tar-stream@3.1.7: + dependencies: + b4a: 1.6.6 + fast-fifo: 1.3.2 + streamx: 2.21.1 + tar@6.2.1: dependencies: chownr: 2.0.0 @@ -25048,6 +25355,10 @@ snapshots: glob: 7.2.3 minimatch: 3.1.2 + text-decoder@1.2.3: + dependencies: + b4a: 1.6.6 + text-extensions@1.9.0: {} text-extensions@2.4.0: {} @@ -25119,6 +25430,10 @@ snapshots: tr46@0.0.3: {} + tr46@4.1.1: + dependencies: + punycode: 2.3.1 + tree-kill@1.2.2: {} treeverse@3.0.0: {} @@ -25730,10 +26045,12 @@ snapshots: '@peculiar/json-schema': 1.1.12 asn1js: 3.0.5 pvtsutils: 1.3.5 - tslib: 2.7.0 + tslib: 2.8.1 webidl-conversions@3.0.1: {} + webidl-conversions@7.0.0: {} + webpack-bundle-analyzer@4.10.2: dependencies: '@discoveryjs/json-ext': 0.5.7 @@ -25934,6 +26251,11 @@ snapshots: whatwg-mimetype@4.0.0: {} + whatwg-url@13.0.0: + dependencies: + tr46: 4.1.1 + webidl-conversions: 7.0.0 + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -26167,6 +26489,11 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yauzl@3.2.0: + dependencies: + buffer-crc32: 0.2.13 + pend: 1.2.0 + yn@2.0.0: {} yn@3.1.1: {} From 15a01033a8b2ea0c32d710f68d38144d8cffddfa Mon Sep 17 00:00:00 2001 From: NicoSerranoP Date: Mon, 13 Jan 2025 16:40:44 -0500 Subject: [PATCH 17/17] feat: voice credit per tokens deployment --- .../ConstantInitialVoiceCreditProxy.sol | 0 .../InitialVoiceCreditProxy.sol | 0 .../PerTokenVoiceCreditProxy.sol} | 18 ++-- packages/contracts/deploy-config-example.json | 66 +++++++++++++ .../tasks/deploy/poll/01-voicecredits.ts | 98 +++++++++++++++++++ packages/contracts/tasks/helpers/constants.ts | 1 + packages/contracts/tasks/helpers/types.ts | 1 + packages/contracts/ts/deploy.ts | 23 +++++ packages/contracts/ts/index.ts | 1 + 9 files changed, 201 insertions(+), 7 deletions(-) rename packages/contracts/contracts/{initialVoiceCreditProxy => voicecredits}/ConstantInitialVoiceCreditProxy.sol (100%) rename packages/contracts/contracts/{initialVoiceCreditProxy => voicecredits}/InitialVoiceCreditProxy.sol (100%) rename packages/contracts/contracts/{initialVoiceCreditProxy/TokensSentInitialVoiceCreditProxy.sol => voicecredits/PerTokenVoiceCreditProxy.sol} (75%) create mode 100644 packages/contracts/tasks/deploy/poll/01-voicecredits.ts diff --git a/packages/contracts/contracts/initialVoiceCreditProxy/ConstantInitialVoiceCreditProxy.sol b/packages/contracts/contracts/voicecredits/ConstantInitialVoiceCreditProxy.sol similarity index 100% rename from packages/contracts/contracts/initialVoiceCreditProxy/ConstantInitialVoiceCreditProxy.sol rename to packages/contracts/contracts/voicecredits/ConstantInitialVoiceCreditProxy.sol diff --git a/packages/contracts/contracts/initialVoiceCreditProxy/InitialVoiceCreditProxy.sol b/packages/contracts/contracts/voicecredits/InitialVoiceCreditProxy.sol similarity index 100% rename from packages/contracts/contracts/initialVoiceCreditProxy/InitialVoiceCreditProxy.sol rename to packages/contracts/contracts/voicecredits/InitialVoiceCreditProxy.sol diff --git a/packages/contracts/contracts/initialVoiceCreditProxy/TokensSentInitialVoiceCreditProxy.sol b/packages/contracts/contracts/voicecredits/PerTokenVoiceCreditProxy.sol similarity index 75% rename from packages/contracts/contracts/initialVoiceCreditProxy/TokensSentInitialVoiceCreditProxy.sol rename to packages/contracts/contracts/voicecredits/PerTokenVoiceCreditProxy.sol index 99c54272a2..1142dafae6 100644 --- a/packages/contracts/contracts/initialVoiceCreditProxy/TokensSentInitialVoiceCreditProxy.sol +++ b/packages/contracts/contracts/voicecredits/PerTokenVoiceCreditProxy.sol @@ -4,10 +4,10 @@ pragma solidity ^0.8.20; import { InitialVoiceCreditProxy } from "./InitialVoiceCreditProxy.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -/// @title TokensSentInitialVoiceCreditProxy +/// @title PerTokenVoiceCreditProxy /// @notice This contract allows to set balances depending on the amount of ETH sent /// for MACI's voters. -contract TokensSentInitialVoiceCreditProxy is InitialVoiceCreditProxy { +contract PerTokenVoiceCreditProxy is InitialVoiceCreditProxy { /// @notice the address where the ETH will be sent address payable public immutable receiver; /// @notice the ERC20 token contract @@ -16,7 +16,7 @@ contract TokensSentInitialVoiceCreditProxy is InitialVoiceCreditProxy { uint256 internal immutable conversionRate; mapping(address => uint256) public balances; - /// @notice creates a new TokensSentInitialVoiceCreditProxy + /// @notice creates a new PerTokenVoiceCreditProxy /// @param _receiver the address where the ETH will be sent /// @param _conversionRate the conversion rate between ETH and voice credits constructor(address payable _receiver, IERC20 _token, uint256 _conversionRate) payable { @@ -25,12 +25,16 @@ contract TokensSentInitialVoiceCreditProxy is InitialVoiceCreditProxy { conversionRate = _conversionRate; } - /// @notice Returns the voice credits based on the amount of ETH sent for any new MACI's voter + /// @notice Returns the voice credits based on the amount of tokens sent for any new MACI's voter /// @return balance function getVoiceCredits(address _user, bytes memory) public view override returns (uint256) { - // Calculate the voice credits based on the amount of ETH sent - uint256 voiceCredits = (balances[_user] * conversionRate) / 1 ether; - return voiceCredits; + if (address(token) == address(0)) { + // Calculate the voice credits based on the amount of ETH sent + return (balances[_user] * conversionRate) / 1 ether; + } else { + // Calculate the voice credits based on the amount of ERC-20 tokens sent + return balances[_user] * conversionRate; + } } /// @notice Saves the amount of voice credits for any new MACI's voter diff --git a/packages/contracts/deploy-config-example.json b/packages/contracts/deploy-config-example.json index 136f2888da..c265d5120a 100644 --- a/packages/contracts/deploy-config-example.json +++ b/packages/contracts/deploy-config-example.json @@ -4,6 +4,12 @@ "deploy": true, "amount": 99 }, + "PerTokenVoiceCreditProxy": { + "deploy": false, + "receiver": "0xE4721A80C6e56f4ebeed6acEE91b3ee715e7dD64", + "token": "0x0000000000000000000000000000000000000000", + "conversionRate": 1 + }, "FreeForAllGatekeeper": { "deploy": false }, @@ -75,6 +81,12 @@ "deploy": true, "amount": 99 }, + "PerTokenVoiceCreditProxy": { + "deploy": false, + "receiver": "0xE4721A80C6e56f4ebeed6acEE91b3ee715e7dD64", + "token": "0x0000000000000000000000000000000000000000", + "conversionRate": 1 + }, "FreeForAllGatekeeper": { "deploy": false }, @@ -145,6 +157,12 @@ "deploy": true, "amount": 99 }, + "PerTokenVoiceCreditProxy": { + "deploy": false, + "receiver": "0xE4721A80C6e56f4ebeed6acEE91b3ee715e7dD64", + "token": "0x0000000000000000000000000000000000000000", + "conversionRate": 1 + }, "FreeForAllGatekeeper": { "deploy": false }, @@ -216,6 +234,12 @@ "deploy": true, "amount": 99 }, + "PerTokenVoiceCreditProxy": { + "deploy": false, + "receiver": "0xE4721A80C6e56f4ebeed6acEE91b3ee715e7dD64", + "token": "0x0000000000000000000000000000000000000000", + "conversionRate": 1 + }, "FreeForAllGatekeeper": { "deploy": true }, @@ -287,6 +311,12 @@ "deploy": true, "amount": 99 }, + "PerTokenVoiceCreditProxy": { + "deploy": false, + "receiver": "0xE4721A80C6e56f4ebeed6acEE91b3ee715e7dD64", + "token": "0x0000000000000000000000000000000000000000", + "conversionRate": 1 + }, "FreeForAllGatekeeper": { "deploy": true }, @@ -358,6 +388,12 @@ "deploy": true, "amount": 99 }, + "PerTokenVoiceCreditProxy": { + "deploy": false, + "receiver": "0xE4721A80C6e56f4ebeed6acEE91b3ee715e7dD64", + "token": "0x0000000000000000000000000000000000000000", + "conversionRate": 1 + }, "FreeForAllGatekeeper": { "deploy": true }, @@ -429,6 +465,12 @@ "deploy": true, "amount": 99 }, + "PerTokenVoiceCreditProxy": { + "deploy": false, + "receiver": "0xE4721A80C6e56f4ebeed6acEE91b3ee715e7dD64", + "token": "0x0000000000000000000000000000000000000000", + "conversionRate": 1 + }, "FreeForAllGatekeeper": { "deploy": true }, @@ -505,6 +547,12 @@ "deploy": true, "amount": 200 }, + "PerTokenVoiceCreditProxy": { + "deploy": false, + "receiver": "0xE4721A80C6e56f4ebeed6acEE91b3ee715e7dD64", + "token": "0x0000000000000000000000000000000000000000", + "conversionRate": 1 + }, "FreeForAllGatekeeper": { "deploy": true }, @@ -581,6 +629,12 @@ "deploy": true, "amount": 200 }, + "PerTokenVoiceCreditProxy": { + "deploy": false, + "receiver": "0xE4721A80C6e56f4ebeed6acEE91b3ee715e7dD64", + "token": "0x0000000000000000000000000000000000000000", + "conversionRate": 1 + }, "FreeForAllGatekeeper": { "deploy": true }, @@ -657,6 +711,12 @@ "deploy": true, "amount": 200 }, + "PerTokenVoiceCreditProxy": { + "deploy": false, + "receiver": "0xE4721A80C6e56f4ebeed6acEE91b3ee715e7dD64", + "token": "0x0000000000000000000000000000000000000000", + "conversionRate": 1 + }, "FreeForAllGatekeeper": { "deploy": true }, @@ -733,6 +793,12 @@ "deploy": true, "amount": 200 }, + "PerTokenVoiceCreditProxy": { + "deploy": false, + "receiver": "0xE4721A80C6e56f4ebeed6acEE91b3ee715e7dD64", + "token": "0x0000000000000000000000000000000000000000", + "conversionRate": 1 + }, "FreeForAllGatekeeper": { "deploy": true }, diff --git a/packages/contracts/tasks/deploy/poll/01-voicecredits.ts b/packages/contracts/tasks/deploy/poll/01-voicecredits.ts new file mode 100644 index 0000000000..2dbd1fd263 --- /dev/null +++ b/packages/contracts/tasks/deploy/poll/01-voicecredits.ts @@ -0,0 +1,98 @@ +import { MACI } from "../../../typechain-types"; +import { EDeploySteps } from "../../helpers/constants"; +import { ContractStorage } from "../../helpers/ContractStorage"; +import { Deployment } from "../../helpers/Deployment"; +import { EContracts, IDeployParams } from "../../helpers/types"; + +const DEFAULT_INITIAL_VOICE_CREDITS = 99; + +const deployment = Deployment.getInstance(); +const storage = ContractStorage.getInstance(); + +/** + * Deploy step registration and task itself + */ +deployment.deployTask(EDeploySteps.InitialVoiceCredit, "Deploy initial voice credit contracts").then((task) => + task.setAction(async ({ incremental }: IDeployParams, hre) => { + deployment.setHre(hre); + const deployer = await deployment.getDeployer(); + + const maciContract = await deployment.getContract({ name: EContracts.MACI }); + const pollId = await maciContract.nextPollId(); + + const voicecreditToUseInPoll = + deployment.getDeployConfigField(EContracts.Poll, "voicecredit") || + EContracts.ConstantInitialVoiceCreditProxy; + + const needDeployConstantVoiceCredit = deployment.getDeployConfigField( + EContracts.ConstantInitialVoiceCreditProxy, + "deploy", + ); + if (needDeployConstantVoiceCredit) { + const constantInitialVoiceCreditProxyContractAddress = storage.getAddress( + EContracts.ConstantInitialVoiceCreditProxy, + hre.network.name, + `poll-${pollId}`, + ); + if (incremental && constantInitialVoiceCreditProxyContractAddress) { + // eslint-disable-next-line no-console + console.log(`Skipping deployment of the ${EContracts.ConstantInitialVoiceCreditProxy} contract`); + } else { + const amount = + deployment.getDeployConfigField(EContracts.ConstantInitialVoiceCreditProxy, "amount") ?? + DEFAULT_INITIAL_VOICE_CREDITS; + const constantInitialVoiceCreditProxyContract = await deployment.deployContract( + { name: EContracts.ConstantInitialVoiceCreditProxy, signer: deployer }, + amount.toString(), + ); + await storage.register({ + id: EContracts.ConstantInitialVoiceCreditProxy, + key: voicecreditToUseInPoll === EContracts.ConstantInitialVoiceCreditProxy ? `poll-${pollId}` : undefined, + contract: constantInitialVoiceCreditProxyContract, + args: [amount.toString()], + network: hre.network.name, + }); + } + } + + const needDeployPerTokenVoiceCredit = deployment.getDeployConfigField( + EContracts.PerTokenVoiceCreditProxy, + "deploy", + ); + if (needDeployPerTokenVoiceCredit) { + const perTokenVoiceCreditProxyContractAddress = storage.getAddress( + EContracts.PerTokenVoiceCreditProxy, + hre.network.name, + `poll-${pollId}`, + ); + if (incremental && perTokenVoiceCreditProxyContractAddress) { + // eslint-disable-next-line no-console + console.log(`Skipping deployment of the ${EContracts.PerTokenVoiceCreditProxy} contract`); + } else { + const receiverAddress = deployment.getDeployConfigField( + EContracts.PerTokenVoiceCreditProxy, + "receiver", + ); + const tokenAddress = deployment.getDeployConfigField(EContracts.PerTokenVoiceCreditProxy, "token"); + const conversionRate = deployment.getDeployConfigField( + EContracts.PerTokenVoiceCreditProxy, + "conversionRate", + ); + + const perTokenVoiceCreditProxyContract = await deployment.deployContract( + { name: EContracts.PerTokenVoiceCreditProxy, signer: deployer }, + receiverAddress, + tokenAddress, + conversionRate, + ); + await storage.register({ + id: EContracts.PerTokenVoiceCreditProxy, + key: voicecreditToUseInPoll === EContracts.PerTokenVoiceCreditProxy ? `poll-${pollId}` : undefined, + contract: perTokenVoiceCreditProxyContract, + args: [receiverAddress, tokenAddress, conversionRate], + network: hre.network.name, + }); + } + } + }), +); diff --git a/packages/contracts/tasks/helpers/constants.ts b/packages/contracts/tasks/helpers/constants.ts index e0bbbbeac7..d565fa5edd 100644 --- a/packages/contracts/tasks/helpers/constants.ts +++ b/packages/contracts/tasks/helpers/constants.ts @@ -11,6 +11,7 @@ export enum EDeploySteps { Maci = "full:deploy-maci", VkRegistry = "full:deploy-vk-registry", ConstantInitialVoiceCreditProxy = "poll:deploy-constant-initial-voice-credit-proxy", + InitialVoiceCredit = "poll:deploy-initial-voice-credit", PollGatekeeper = "poll:deploy-gatekeeper", Poll = "poll:deploy-poll", } diff --git a/packages/contracts/tasks/helpers/types.ts b/packages/contracts/tasks/helpers/types.ts index 2ed1616770..69be94a7d9 100644 --- a/packages/contracts/tasks/helpers/types.ts +++ b/packages/contracts/tasks/helpers/types.ts @@ -573,6 +573,7 @@ export enum EInitialVoiceCreditProxies { */ export enum EContracts { ConstantInitialVoiceCreditProxy = "ConstantInitialVoiceCreditProxy", + PerTokenVoiceCreditProxy = "PerTokenVoiceCreditProxy", FreeForAllGatekeeper = "FreeForAllGatekeeper", EASGatekeeper = "EASGatekeeper", GitcoinPassportGatekeeper = "GitcoinPassportGatekeeper", diff --git a/packages/contracts/ts/deploy.ts b/packages/contracts/ts/deploy.ts index 1f40edf7c3..2cf989b107 100644 --- a/packages/contracts/ts/deploy.ts +++ b/packages/contracts/ts/deploy.ts @@ -32,6 +32,7 @@ import { GitcoinPassportGatekeeper, SemaphoreGatekeeper, AnonAadhaarGatekeeper, + PerTokenVoiceCreditProxy, } from "../typechain-types"; import { genEmptyBallotRoots } from "./genEmptyBallotRoots"; @@ -116,6 +117,28 @@ export const deployConstantInitialVoiceCreditProxy = async ( ): Promise => deployContract("ConstantInitialVoiceCreditProxy", signer, quiet, amount.toString()); +/** + * Deploy a per token initial voice credit proxy contract + * @param receiver - the address of the receiver of the tokens + * @param token - the address of the token contract + * @param conversionRate - the conversion rate of the token to voice credits + */ +export const deployPerTokenVoiceCreditProxy = async ( + receiver: string, + token: string, + conversionRate: number, + signer?: Signer, + quiet = false, +): Promise => + deployContract( + "PerTokenInitialVoiceCreditProxy", + signer, + quiet, + receiver, + token, + conversionRate, + ); + /** * Deploy a SignUpToken contract * @param signer - the signer to use to deploy the contract diff --git a/packages/contracts/ts/index.ts b/packages/contracts/ts/index.ts index 1de6bcd054..7fa71fa24a 100644 --- a/packages/contracts/ts/index.ts +++ b/packages/contracts/ts/index.ts @@ -7,6 +7,7 @@ export { deploySignupToken, deploySignupTokenGatekeeper, deployConstantInitialVoiceCreditProxy, + deployPerTokenVoiceCreditProxy, deployFreeForAllSignUpGatekeeper, deployGitcoinPassportGatekeeper, deploySemaphoreGatekeeper,