diff --git a/.github/workflows/create-version.yml b/.github/workflows/create-version.yml index 9cccd61a7..997f82322 100644 --- a/.github/workflows/create-version.yml +++ b/.github/workflows/create-version.yml @@ -31,18 +31,14 @@ jobs: node-version: ${{ env.NODE_VERSION }} - name: Checkout source code uses: actions/checkout@v3 - - name: Install dependencies + - name: Create new version run: | # use https to avoid error: unable to connect to github.com git config --global url."https://".insteadOf git:// - yarn && yarn build - - name: setup git config - run: | # setup the username and email. I tend to use 'GitHub Actions Bot' with no email by default git config user.name "GitHub Actions Bot" git config user.email "<>" - - name: Create new version - run: | + yarn && yarn build echo "Version: ${{ github.event.inputs.version }}" cd contracts npm version ${{ github.event.inputs.version }} diff --git a/.github/workflows/finalize-round.yml b/.github/workflows/finalize-round.yml index adfcdfdfc..0109651d5 100644 --- a/.github/workflows/finalize-round.yml +++ b/.github/workflows/finalize-round.yml @@ -29,6 +29,8 @@ env: CIRCUIT_TYPE: micro ZKEYS_DOWNLOAD_SCRIPT: "download-6-9-2-3.sh" JSONRPC_HTTP_URL: ${{ github.event.inputs.jsonrpc_url }} + PINATA_API_KEY: ${{ secrets.PINATA_API_KEY }} + PINATA_SECRET_API_KEY: ${{ secrets.PINATA_SECRET_API_KEY }} jobs: finalize: @@ -84,10 +86,9 @@ jobs: mkdir -p proof_output yarn hardhat tally --clrfund "${CLRFUND_ADDRESS}" --network "${NETWORK}" \ --rapidsnark ${RAPID_SNARK} \ - --circuit-directory ${CIRCUIT_DIRECTORY} \ + --params-dir ${CIRCUIT_DIRECTORY} \ --blocks-per-batch ${BLOCKS_PER_BATCH} \ - --maci-tx-hash "${MACI_TX_HASH}" --output-dir "./proof_output" - curl --location --request POST 'https://api.pinata.cloud/pinning/pinFileToIPFS' \ - --header "Authorization: Bearer ${{ secrets.PINATA_JWT }}" \ - --form 'file=@"./proof_output/tally.json"' - yarn hardhat --network "${NETWORK}" finalize --clrfund "${CLRFUND_ADDRESS}" + --maci-tx-hash "${MACI_TX_HASH}" \ + --proof-dir "./proof_output" + yarn hardhat --network "${NETWORK}" finalize --clrfund "${CLRFUND_ADDRESS}" \ + --proof-dir "./proof_output" diff --git a/.github/workflows/test-scripts.yml b/.github/workflows/test-scripts.yml index 5ebe7d346..05082aa5e 100644 --- a/.github/workflows/test-scripts.yml +++ b/.github/workflows/test-scripts.yml @@ -10,6 +10,8 @@ on: env: NODE_VERSION: 20.x ZKEYS_DOWNLOAD_SCRIPT: "download-6-9-2-3.sh" + PINATA_API_KEY: ${{ secrets.PINATA_API_KEY }} + PINATA_SECRET_API_KEY: ${{ secrets.PINATA_SECRET_API_KEY }} jobs: script-tests: diff --git a/common/package.json b/common/package.json index ee496d949..9e3d72dc2 100644 --- a/common/package.json +++ b/common/package.json @@ -22,9 +22,9 @@ }, "dependencies": { "@openzeppelin/merkle-tree": "^1.0.5", - "ethers": "^6.11.1", - "maci-crypto": "^1.2.0", - "maci-domainobjs": "^1.2.0" + "ethers": "^6.12.1", + "maci-crypto": "1.2.2", + "maci-domainobjs": "1.2.2" }, "repository": { "type": "git", diff --git a/common/src/__tests__/keypair.spec.ts b/common/src/__tests__/keypair.spec.ts new file mode 100644 index 000000000..7dbc6e195 --- /dev/null +++ b/common/src/__tests__/keypair.spec.ts @@ -0,0 +1,21 @@ +import { expect } from 'chai' +import { Keypair, PubKey } from '../keypair' +import { Wallet, sha256, randomBytes } from 'ethers' + +describe('keypair', function () { + for (let i = 0; i < 10; i++) { + it(`should generate key ${i} from seed successfully`, function () { + const wallet = Wallet.createRandom() + const signature = wallet.signMessageSync(randomBytes(32).toString()) + const seed = sha256(signature) + const keypair = Keypair.createFromSeed(seed) + expect(keypair.pubKey.serialize()).to.match(/^macipk./) + }) + } + + it('should throw if pubKey is invalid', () => { + expect(() => { + new PubKey([1n, 1n]) + }).to.throw('PubKey not on curve') + }) +}) diff --git a/common/src/keypair.ts b/common/src/keypair.ts index 8e02ab52f..c6c9ea165 100644 --- a/common/src/keypair.ts +++ b/common/src/keypair.ts @@ -1,37 +1,31 @@ import { keccak256, isBytesLike, concat, toBeArray } from 'ethers' import { Keypair as MaciKeypair, PrivKey, PubKey } from 'maci-domainobjs' -const SNARK_FIELD_SIZE = BigInt( - '21888242871839275222246405745257275088548364400416034343698204186575808495617' -) - /** - * Returns a BabyJub-compatible value. This function is modified from - * the MACI's genRandomBabyJubValue(). Instead of returning random value - * for the private key, it derives the private key from the users - * signature hash + * Derives the MACI private key from the users signature hash * @param hash - user's signature hash + * @return The MACI private key */ function genPrivKey(hash: string): PrivKey { - // Prevent modulo bias - //const lim = BigInt('0x10000000000000000000000000000000000000000000000000000000000000000') - //const min = (lim - SNARK_FIELD_SIZE) % SNARK_FIELD_SIZE - const min = BigInt( - '6350874878119819312338956282401532410528162663560392320966563075034087161851' - ) - if (!isBytesLike(hash)) { - throw new Error(`Hash must be a hex string: ${hash}`) + throw new Error(`genPrivKey() error. Hash must be a hex string: ${hash}`) } - let hashBN = BigInt(hash) - // don't think we'll enter the for loop below, but, just in case - for (let counter = 1; hashBN < min; counter++) { - const data = concat([toBeArray(hashBN), toBeArray(counter)]) - hashBN = BigInt(keccak256(data)) + let rawPrivKey = BigInt(hash) + let pubKey: PubKey | null = null + + for (let counter = 1; pubKey === null; counter++) { + try { + const privKey = new PrivKey(rawPrivKey) + // this will throw 'Invalid public key' if key is not on the Baby Jubjub elliptic curve + const keypair = new Keypair(privKey) + pubKey = keypair.pubKey + } catch { + const data = concat([toBeArray(rawPrivKey), toBeArray(counter)]) + rawPrivKey = BigInt(keccak256(data)) + } } - const rawPrivKey = hashBN % SNARK_FIELD_SIZE return new PrivKey(rawPrivKey) } diff --git a/common/src/utils.ts b/common/src/utils.ts index d0bd5cdcb..aee9aba9c 100644 --- a/common/src/utils.ts +++ b/common/src/utils.ts @@ -12,7 +12,9 @@ import { Keypair } from './keypair' import { Tally } from './tally' import { bnSqrt } from './math' -const LEAVES_PER_NODE = 5 +// This has to match the MACI TREE_ARITY at: +// github.com/privacy-scaling-explorations/maci/blob/0c18913d4c84bfa9fbfd66dc017e338df9fdda96/contracts/contracts/MACI.sol#L31 +export const MACI_TREE_ARITY = 5 export function createMessage( userStateIndex: number, @@ -65,7 +67,7 @@ export function getRecipientClaimData( const spentTree = new IncrementalQuinTree( recipientTreeDepth, BigInt(0), - LEAVES_PER_NODE, + MACI_TREE_ARITY, hash5 ) for (const leaf of tally.perVOSpentVoiceCredits.tally) { @@ -94,6 +96,15 @@ export function getRecipientClaimData( ] } +/** + * Returns the maximum MACI users allowed by the state tree + * @param stateTreeDepth MACI state tree depth + * @returns the maximum number of contributors allowed by MACI circuit + */ +export function getMaxContributors(stateTreeDepth: number): number { + return MACI_TREE_ARITY ** stateTreeDepth - 1 +} + export { genTallyResultCommitment, Message, @@ -103,5 +114,4 @@ export { hash2, hash3, hashLeftRight, - LEAVES_PER_NODE, } diff --git a/contracts/.env.example b/contracts/.env.example index 5ace336a7..2db7006e4 100644 --- a/contracts/.env.example +++ b/contracts/.env.example @@ -6,13 +6,17 @@ JSONRPC_HTTP_URL=https://eth-goerli.alchemyapi.io/v2/ADD_API_KEY WALLET_MNEMONIC= WALLET_PRIVATE_KEY= -# The coordinator MACI private key, required by the tally script +# The coordinator MACI private key, required by the gen-proofs script COORDINATOR_MACISK= # API key used to verify contracts on arbitrum chain (including testnet) # Update the etherscan section in hardhat.config to add API key for other chains ARBISCAN_API_KEY= +# PINATE credentials to upload tally.json file to IPFS; used by the tally script +PINATA_API_KEY= +PINATA_SECRET_API_KEY= + # these are used in the e2e testing CIRCUIT_TYPE= CIRCUIT_DIRECTORY= diff --git a/contracts/contracts/AnyOldERC20Token.sol b/contracts/contracts/AnyOldERC20Token.sol index 3d88c9508..be5ba8656 100644 --- a/contracts/contracts/AnyOldERC20Token.sol +++ b/contracts/contracts/AnyOldERC20Token.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; import '@openzeppelin/contracts/token/ERC20/ERC20.sol'; diff --git a/contracts/contracts/CloneFactory.sol b/contracts/contracts/CloneFactory.sol index 99247f723..fcdf5d9b6 100644 --- a/contracts/contracts/CloneFactory.sol +++ b/contracts/contracts/CloneFactory.sol @@ -21,7 +21,7 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -pragma solidity 0.8.10; +pragma solidity 0.8.20; contract CloneFactory { // implementation of eip-1167 - see https://eips.ethereum.org/EIPS/eip-1167 function createClone(address target) internal returns (address result) { diff --git a/contracts/contracts/ClrFund.sol b/contracts/contracts/ClrFund.sol index c9ad77389..499994383 100644 --- a/contracts/contracts/ClrFund.sol +++ b/contracts/contracts/ClrFund.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.10; +pragma solidity 0.8.20; import '@openzeppelin/contracts/token/ERC20/ERC20.sol'; import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; @@ -60,8 +60,14 @@ contract ClrFund is OwnableUpgradeable, DomainObjs, Params { error InvalidFundingRoundFactory(); error InvalidMaciFactory(); error RecipientRegistryNotSet(); + error MaxRecipientsNotSet(); error NotInitialized(); - error VoteOptionTreeDepthNotSet(); + + modifier maciFactoryInitialized() { + if (address(maciFactory) == address(0)) revert InvalidMaciFactory(); + if (maciFactory.maxRecipients() == 0) revert MaxRecipientsNotSet(); + _; + } /** @@ -128,20 +134,6 @@ contract ClrFund is OwnableUpgradeable, DomainObjs, Params { _setFundingRoundFactory(_roundFactory); } - /** - * @dev Get the maximum recipients allowed in the recipient registry - */ - function getMaxRecipients() public view returns (uint256 _maxRecipients) { - TreeDepths memory treeDepths = maciFactory.treeDepths(); - if (treeDepths.voteOptionTreeDepth == 0) revert VoteOptionTreeDepthNotSet(); - - uint256 maxVoteOption = maciFactory.TREE_ARITY() ** treeDepths.voteOptionTreeDepth; - - // -1 because the first slot of the recipients array is not used - // and maxRecipients is used to generate 0 based index to the array - _maxRecipients = maxVoteOption - 1; - } - /** * @dev Set registry of verified users. * @param _userRegistry Address of a user registry. @@ -162,10 +154,13 @@ contract ClrFund is OwnableUpgradeable, DomainObjs, Params { function setRecipientRegistry(IRecipientRegistry _recipientRegistry) external onlyOwner + maciFactoryInitialized { + recipientRegistry = _recipientRegistry; - uint256 maxRecipients = getMaxRecipients(); - recipientRegistry.setMaxRecipients(maxRecipients); + + // Make sure that the max number of recipients is set correctly + recipientRegistry.setMaxRecipients(maciFactory.maxRecipients()); emit RecipientRegistryChanged(address(_recipientRegistry)); } @@ -220,6 +215,7 @@ contract ClrFund is OwnableUpgradeable, DomainObjs, Params { ) external onlyOwner + maciFactoryInitialized { IFundingRound currentRound = getCurrentRound(); if (address(currentRound) != address(0) && !currentRound.isFinalized()) { @@ -229,8 +225,7 @@ contract ClrFund is OwnableUpgradeable, DomainObjs, Params { if (address(recipientRegistry) == address(0)) revert RecipientRegistryNotSet(); // Make sure that the max number of recipients is set correctly - uint256 maxRecipients = getMaxRecipients(); - recipientRegistry.setMaxRecipients(maxRecipients); + recipientRegistry.setMaxRecipients(maciFactory.maxRecipients()); // Deploy funding round and MACI contracts address newRound = roundFactory.deploy(duration, address(this)); diff --git a/contracts/contracts/ClrFundDeployer.sol b/contracts/contracts/ClrFundDeployer.sol index 2487723ff..4f2b279d5 100644 --- a/contracts/contracts/ClrFundDeployer.sol +++ b/contracts/contracts/ClrFundDeployer.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.10; +pragma solidity 0.8.20; import {MACIFactory} from './MACIFactory.sol'; import {ClrFund} from './ClrFund.sol'; @@ -9,7 +9,7 @@ import {SignUpGatekeeper} from "maci-contracts/contracts/gatekeepers/SignUpGatek import {InitialVoiceCreditProxy} from "maci-contracts/contracts/initialVoiceCreditProxy/InitialVoiceCreditProxy.sol"; import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; -contract ClrFundDeployer is CloneFactory, Ownable { +contract ClrFundDeployer is CloneFactory, Ownable(msg.sender) { address public clrfundTemplate; address public maciFactory; address public roundFactory; diff --git a/contracts/contracts/ExternalContacts.sol b/contracts/contracts/ExternalContacts.sol index 51706fb5f..d2f1d989e 100644 --- a/contracts/contracts/ExternalContacts.sol +++ b/contracts/contracts/ExternalContacts.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; /* * These imports are just for hardhat to find the contracts for deployment @@ -9,5 +9,4 @@ pragma solidity ^0.8.10; import {Poll} from 'maci-contracts/contracts/Poll.sol'; import {PollFactory} from 'maci-contracts/contracts/PollFactory.sol'; import {TallyFactory} from 'maci-contracts/contracts/TallyFactory.sol'; -import {SubsidyFactory} from 'maci-contracts/contracts/SubsidyFactory.sol'; import {MessageProcessorFactory} from 'maci-contracts/contracts/MessageProcessorFactory.sol'; diff --git a/contracts/contracts/FundingRound.sol b/contracts/contracts/FundingRound.sol index 38bb4f1ee..701872a8f 100644 --- a/contracts/contracts/FundingRound.sol +++ b/contracts/contracts/FundingRound.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.10; +pragma solidity 0.8.20; import '@openzeppelin/contracts/access/Ownable.sol'; import '@openzeppelin/contracts/token/ERC20/ERC20.sol'; @@ -15,7 +15,7 @@ import {SignUpGatekeeper} from 'maci-contracts/contracts/gatekeepers/SignUpGatek import {InitialVoiceCreditProxy} from 'maci-contracts/contracts/initialVoiceCreditProxy/InitialVoiceCreditProxy.sol'; import {CommonUtilities} from 'maci-contracts/contracts/utilities/CommonUtilities.sol'; import {SnarkCommon} from 'maci-contracts/contracts/crypto/SnarkCommon.sol'; -import {ITallySubsidyFactory} from 'maci-contracts/contracts/interfaces/ITallySubsidyFactory.sol'; +import {ITallyFactory} from 'maci-contracts/contracts/interfaces/ITallyFactory.sol'; import {IMessageProcessorFactory} from 'maci-contracts/contracts/interfaces/IMPFactory.sol'; import {IClrFund} from './interfaces/IClrFund.sol'; import {IMACIFactory} from './interfaces/IMACIFactory.sol'; @@ -25,7 +25,7 @@ import './userRegistry/IUserRegistry.sol'; import './recipientRegistry/IRecipientRegistry.sol'; contract FundingRound is - Ownable, + Ownable(msg.sender), SignUpGatekeeper, InitialVoiceCreditProxy, DomainObjs, @@ -66,6 +66,7 @@ contract FundingRound is error TallyHashNotPublished(); error IncompleteTallyResults(uint256 total, uint256 actual); error NoVotes(); + error NoSignUps(); error MaciNotSet(); error PollNotSet(); error InvalidMaci(); @@ -175,19 +176,6 @@ contract FundingRound is return (addressValue == address(0)); } - /** - * @dev Have the votes been tallied - */ - function isTallied() private view returns (bool) { - (uint256 numSignUps, ) = poll.numSignUpsAndMessages(); - (uint8 intStateTreeDepth, , , ) = poll.treeDepths(); - uint256 tallyBatchSize = TREE_ARITY ** uint256(intStateTreeDepth); - uint256 tallyBatchNum = tally.tallyBatchNum(); - uint256 totalTallied = tallyBatchNum * tallyBatchSize; - - return numSignUps > 0 && totalTallied >= numSignUps; - } - /** * @dev Set the tally contract * @param _tally The tally contract address @@ -221,10 +209,10 @@ contract FundingRound is address vkRegistry = address(tally.vkRegistry()); IMessageProcessorFactory messageProcessorFactory = maci.messageProcessorFactory(); - ITallySubsidyFactory tallyFactory = maci.tallyFactory(); + ITallyFactory tallyFactory = maci.tallyFactory(); - address mp = messageProcessorFactory.deploy(verifier, vkRegistry, address(poll), coordinator); - address newTally = tallyFactory.deploy(verifier, vkRegistry, address(poll), mp, coordinator); + address mp = messageProcessorFactory.deploy(verifier, vkRegistry, address(poll), coordinator, Mode.QV); + address newTally = tallyFactory.deploy(verifier, vkRegistry, address(poll), mp, coordinator, Mode.QV); _setTally(newTally); } @@ -470,18 +458,18 @@ contract FundingRound is _votingPeriodOver(poll); - if (!isTallied()) { + if (!tally.isTallied()) { revert VotesNotTallied(); } + if (bytes(tallyHash).length == 0) { revert TallyHashNotPublished(); } // make sure we have received all the tally results - (,,, uint8 voteOptionTreeDepth) = poll.treeDepths(); - uint256 totalResults = uint256(TREE_ARITY) ** uint256(voteOptionTreeDepth); - if ( totalTallyResults != totalResults ) { - revert IncompleteTallyResults(totalResults, totalTallyResults); + (, uint256 maxVoteOptions) = poll.maxValues(); + if (totalTallyResults != maxVoteOptions) { + revert IncompleteTallyResults(maxVoteOptions, totalTallyResults); } // If nobody voted, the round should be cancelled to avoid locking of matching funds @@ -494,7 +482,6 @@ contract FundingRound is revert IncorrectSpentVoiceCredits(); } - totalSpent = _totalSpent; // Total amount of spent voice credits is the size of the pool of direct rewards. // Everything else, including unspent voice credits and downscaling error, @@ -675,9 +662,15 @@ contract FundingRound is { if (isAddressZero(address(maci))) revert MaciNotSet(); - if (!isTallied()) { + if (maci.numSignUps() == 0) { + // no sign ups, so no tally results + revert NoSignUps(); + } + + if (!tally.isTallied()) { revert VotesNotTallied(); } + if (isFinalized) { revert RoundAlreadyFinalized(); } diff --git a/contracts/contracts/FundingRoundFactory.sol b/contracts/contracts/FundingRoundFactory.sol index 9a35c1077..06d0453e5 100644 --- a/contracts/contracts/FundingRoundFactory.sol +++ b/contracts/contracts/FundingRoundFactory.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; import {FundingRound} from './FundingRound.sol'; import {IClrFund} from './interfaces/IClrFund.sol'; diff --git a/contracts/contracts/MACICommon.sol b/contracts/contracts/MACICommon.sol index 3a73b4110..01224230b 100644 --- a/contracts/contracts/MACICommon.sol +++ b/contracts/contracts/MACICommon.sol @@ -1,14 +1,11 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; /** * @dev a contract that holds common MACI structures */ contract MACICommon { - // MACI tree arity - uint256 public constant TREE_ARITY = 5; - /** * @dev These are contract factories used to deploy MACI poll processing contracts * when creating a new ClrFund funding round. @@ -16,9 +13,6 @@ contract MACICommon { struct Factories { address pollFactory; address tallyFactory; - // subsidyFactory is not currently used, it's just a place holder here - address subsidyFactory; address messageProcessorFactory; } - } \ No newline at end of file diff --git a/contracts/contracts/MACIFactory.sol b/contracts/contracts/MACIFactory.sol index 1fb0b800b..f3952280d 100644 --- a/contracts/contracts/MACIFactory.sol +++ b/contracts/contracts/MACIFactory.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; import {MACI} from 'maci-contracts/contracts/MACI.sol'; import {IPollFactory} from 'maci-contracts/contracts/interfaces/IPollFactory.sol'; -import {ITallySubsidyFactory} from 'maci-contracts/contracts/interfaces/ITallySubsidyFactory.sol'; +import {ITallyFactory} from 'maci-contracts/contracts/interfaces/ITallyFactory.sol'; import {IMessageProcessorFactory} from 'maci-contracts/contracts/interfaces/IMPFactory.sol'; import {SignUpGatekeeper} from 'maci-contracts/contracts/gatekeepers/SignUpGatekeeper.sol'; import {InitialVoiceCreditProxy} from 'maci-contracts/contracts/initialVoiceCreditProxy/InitialVoiceCreditProxy.sol'; @@ -17,7 +17,7 @@ import {Params} from 'maci-contracts/contracts/utilities/Params.sol'; import {DomainObjs} from 'maci-contracts/contracts/utilities/DomainObjs.sol'; import {MACICommon} from './MACICommon.sol'; -contract MACIFactory is Ownable, Params, SnarkCommon, DomainObjs, MACICommon { +contract MACIFactory is Ownable(msg.sender), Params, SnarkCommon, DomainObjs, MACICommon { // Verifying Key Registry containing circuit parameters VkRegistry public vkRegistry; @@ -29,6 +29,8 @@ contract MACIFactory is Ownable, Params, SnarkCommon, DomainObjs, MACICommon { // circuit parameters uint8 public stateTreeDepth; TreeDepths public treeDepths; + uint256 public messageBatchSize; + uint256 public maxRecipients; // Events event MaciParametersChanged(); @@ -38,12 +40,15 @@ contract MACIFactory is Ownable, Params, SnarkCommon, DomainObjs, MACICommon { error NotInitialized(); error ProcessVkNotSet(); error TallyVkNotSet(); + error VoteOptionTreeDepthNotSet(); error InvalidVkRegistry(); error InvalidPollFactory(); error InvalidTallyFactory(); - error InvalidSubsidyFactory(); error InvalidMessageProcessorFactory(); error InvalidVerifier(); + error InvalidMaxRecipients(); + error InvalidMessageBatchSize(); + error InvalidVoteOptionTreeDepth(); constructor( address _vkRegistry, @@ -61,14 +66,6 @@ contract MACIFactory is Ownable, Params, SnarkCommon, DomainObjs, MACICommon { verifier = Verifier(_verifier); } - /** - * @dev calculate the message batch size - */ - function getMessageBatchSize(uint8 messageTreeSubDepth) public pure - returns(uint256 _messageBatchSize) { - _messageBatchSize = TREE_ARITY ** messageTreeSubDepth; - } - /** * @dev set vk registry */ @@ -123,19 +120,26 @@ contract MACIFactory is Ownable, Params, SnarkCommon, DomainObjs, MACICommon { */ function setMaciParameters( uint8 _stateTreeDepth, + uint256 _messageBatchSize, + uint256 _maxRecipients, TreeDepths calldata _treeDepths ) public onlyOwner { + if (_treeDepths.voteOptionTreeDepth == 0) revert InvalidVoteOptionTreeDepth(); + if (_maxRecipients == 0) revert InvalidMaxRecipients(); + if (_messageBatchSize == 0) revert InvalidMessageBatchSize(); - uint256 messageBatchSize = getMessageBatchSize(_treeDepths.messageTreeSubDepth); + messageBatchSize = _messageBatchSize; + maxRecipients = _maxRecipients; if (!vkRegistry.hasProcessVk( _stateTreeDepth, _treeDepths.messageTreeDepth, _treeDepths.voteOptionTreeDepth, - messageBatchSize) + messageBatchSize, + Mode.QV) ) { revert ProcessVkNotSet(); } @@ -143,7 +147,8 @@ contract MACIFactory is Ownable, Params, SnarkCommon, DomainObjs, MACICommon { if (!vkRegistry.hasTallyVk( _stateTreeDepth, _treeDepths.intStateTreeDepth, - _treeDepths.voteOptionTreeDepth) + _treeDepths.voteOptionTreeDepth, + Mode.QV) ) { revert TallyVkNotSet(); } @@ -154,6 +159,7 @@ contract MACIFactory is Ownable, Params, SnarkCommon, DomainObjs, MACICommon { emit MaciParametersChanged(); } + /** * @dev Deploy new MACI instance. */ @@ -169,13 +175,12 @@ contract MACIFactory is Ownable, Params, SnarkCommon, DomainObjs, MACICommon { external returns (MACI _maci, MACI.PollContracts memory _pollContracts) { - uint256 messageBatchSize = getMessageBatchSize(treeDepths.messageTreeSubDepth); - if (!vkRegistry.hasProcessVk( stateTreeDepth, treeDepths.messageTreeDepth, treeDepths.voteOptionTreeDepth, - messageBatchSize) + messageBatchSize, + Mode.QV) ) { revert ProcessVkNotSet(); } @@ -183,7 +188,8 @@ contract MACIFactory is Ownable, Params, SnarkCommon, DomainObjs, MACICommon { if (!vkRegistry.hasTallyVk( stateTreeDepth, treeDepths.intStateTreeDepth, - treeDepths.voteOptionTreeDepth) + treeDepths.voteOptionTreeDepth, + Mode.QV) ) { revert TallyVkNotSet(); } @@ -191,8 +197,7 @@ contract MACIFactory is Ownable, Params, SnarkCommon, DomainObjs, MACICommon { _maci = new MACI( IPollFactory(factories.pollFactory), IMessageProcessorFactory(factories.messageProcessorFactory), - ITallySubsidyFactory(factories.tallyFactory), - ITallySubsidyFactory(factories.subsidyFactory), + ITallyFactory(factories.tallyFactory), signUpGatekeeper, initialVoiceCreditProxy, TopupCredit(topupCredit), @@ -205,8 +210,7 @@ contract MACIFactory is Ownable, Params, SnarkCommon, DomainObjs, MACICommon { coordinatorPubKey, address(verifier), address(vkRegistry), - // pass false to not deploy the subsidy contract - false + Mode.QV ); // transfer ownership to coordinator to run the tally scripts diff --git a/contracts/contracts/OwnableUpgradeable.sol b/contracts/contracts/OwnableUpgradeable.sol index 3826e125a..152178fe4 100644 --- a/contracts/contracts/OwnableUpgradeable.sol +++ b/contracts/contracts/OwnableUpgradeable.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity 0.8.20; // NOTE: had to copy contracts over since OZ uses a higher pragma than we do in the one's they maintain. diff --git a/contracts/contracts/TopupToken.sol b/contracts/contracts/TopupToken.sol index c70068ae7..8cafce9e1 100644 --- a/contracts/contracts/TopupToken.sol +++ b/contracts/contracts/TopupToken.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; import {ERC20} from '@openzeppelin/contracts/token/ERC20/ERC20.sol'; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; @@ -9,7 +9,7 @@ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; * TopupToken is used by MACI Poll contract to validate the topup credits of a user * In clrfund, this is only used as gateway to pass the topup amount to the Poll contract */ -contract TopupToken is ERC20, Ownable { +contract TopupToken is ERC20, Ownable(msg.sender) { constructor() ERC20("TopupCredit", "TopupCredit") {} function airdrop(uint256 amount) public onlyOwner { diff --git a/contracts/contracts/interfaces/IClrFund.sol b/contracts/contracts/interfaces/IClrFund.sol index 5da1b8b45..2f77f992d 100644 --- a/contracts/contracts/interfaces/IClrFund.sol +++ b/contracts/contracts/interfaces/IClrFund.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.10; +pragma solidity 0.8.20; import {ERC20} from '@openzeppelin/contracts/token/ERC20/ERC20.sol'; import {IUserRegistry} from '../userRegistry/IUserRegistry.sol'; diff --git a/contracts/contracts/interfaces/IFundingRound.sol b/contracts/contracts/interfaces/IFundingRound.sol index 026f40c0a..65daf3ea6 100644 --- a/contracts/contracts/interfaces/IFundingRound.sol +++ b/contracts/contracts/interfaces/IFundingRound.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; import {ERC20} from '@openzeppelin/contracts/token/ERC20/ERC20.sol'; diff --git a/contracts/contracts/interfaces/IFundingRoundFactory.sol b/contracts/contracts/interfaces/IFundingRoundFactory.sol index 9ca5806f1..45ec956fa 100644 --- a/contracts/contracts/interfaces/IFundingRoundFactory.sol +++ b/contracts/contracts/interfaces/IFundingRoundFactory.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; import {ERC20} from '@openzeppelin/contracts/token/ERC20/ERC20.sol'; diff --git a/contracts/contracts/interfaces/IMACIFactory.sol b/contracts/contracts/interfaces/IMACIFactory.sol index d5d0bf3b2..7e207afe8 100644 --- a/contracts/contracts/interfaces/IMACIFactory.sol +++ b/contracts/contracts/interfaces/IMACIFactory.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; import {IVkRegistry} from 'maci-contracts/contracts/interfaces/IVkRegistry.sol'; import {IVerifier} from 'maci-contracts/contracts/interfaces/IVerifier.sol'; @@ -28,10 +28,7 @@ interface IMACIFactory { function stateTreeDepth() external view returns (uint8); function treeDepths() external view returns (Params.TreeDepths memory); - function getMessageBatchSize(uint8 _messageTreeSubDepth) external pure - returns(uint256 _messageBatchSize); - - function TREE_ARITY() external pure returns (uint256); + function maxRecipients() external view returns (uint256); function deployMaci( SignUpGatekeeper signUpGatekeeper, diff --git a/contracts/contracts/recipientRegistry/BaseRecipientRegistry.sol b/contracts/contracts/recipientRegistry/BaseRecipientRegistry.sol index 8215fce92..d8c656d21 100644 --- a/contracts/contracts/recipientRegistry/BaseRecipientRegistry.sol +++ b/contracts/contracts/recipientRegistry/BaseRecipientRegistry.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; import './IRecipientRegistry.sol'; diff --git a/contracts/contracts/recipientRegistry/IKlerosGTCR.sol b/contracts/contracts/recipientRegistry/IKlerosGTCR.sol index 6eda6f7cb..2326e70ba 100644 --- a/contracts/contracts/recipientRegistry/IKlerosGTCR.sol +++ b/contracts/contracts/recipientRegistry/IKlerosGTCR.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; /** * @dev Interface for Kleros Generalized TCR. diff --git a/contracts/contracts/recipientRegistry/IRecipientRegistry.sol b/contracts/contracts/recipientRegistry/IRecipientRegistry.sol index 3f139948e..edfbc5029 100644 --- a/contracts/contracts/recipientRegistry/IRecipientRegistry.sol +++ b/contracts/contracts/recipientRegistry/IRecipientRegistry.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; /** * @dev Interface of the recipient registry. @@ -17,6 +17,7 @@ pragma solidity ^0.8.10; */ interface IRecipientRegistry { + function maxRecipients() external returns (uint256); function setMaxRecipients(uint256 _maxRecipients) external returns (bool); function getRecipientAddress(uint256 _index, uint256 _startBlock, uint256 _endBlock) external view returns (address); diff --git a/contracts/contracts/recipientRegistry/KlerosGTCRAdapter.sol b/contracts/contracts/recipientRegistry/KlerosGTCRAdapter.sol index 2bf70bd6d..621e6dd45 100644 --- a/contracts/contracts/recipientRegistry/KlerosGTCRAdapter.sol +++ b/contracts/contracts/recipientRegistry/KlerosGTCRAdapter.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; import 'solidity-rlp/contracts/RLPReader.sol'; diff --git a/contracts/contracts/recipientRegistry/KlerosGTCRMock.sol b/contracts/contracts/recipientRegistry/KlerosGTCRMock.sol index abbc9bd16..e1988cd4e 100644 --- a/contracts/contracts/recipientRegistry/KlerosGTCRMock.sol +++ b/contracts/contracts/recipientRegistry/KlerosGTCRMock.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity 0.8.20; import '@openzeppelin/contracts/access/Ownable.sol'; @@ -9,7 +9,7 @@ import '@openzeppelin/contracts/access/Ownable.sol'; * This contract is a curated registry for any types of items. Just like a TCR contract it features the request-challenge protocol and appeal fees crowdfunding. * Adapted from https://github.com/kleros/tcr/blob/v2.0.0/contracts/GeneralizedTCR.sol */ -contract KlerosGTCRMock is Ownable { +contract KlerosGTCRMock is Ownable(msg.sender) { enum Status { Absent, // The item is not in the registry. diff --git a/contracts/contracts/recipientRegistry/OptimisticRecipientRegistry.sol b/contracts/contracts/recipientRegistry/OptimisticRecipientRegistry.sol index 8bc331dbb..57ac016f5 100644 --- a/contracts/contracts/recipientRegistry/OptimisticRecipientRegistry.sol +++ b/contracts/contracts/recipientRegistry/OptimisticRecipientRegistry.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; import '@openzeppelin/contracts/access/Ownable.sol'; @@ -9,7 +9,7 @@ import './BaseRecipientRegistry.sol'; /** * @dev Recipient registry with optimistic execution of registrations and removals. */ -contract OptimisticRecipientRegistry is Ownable, BaseRecipientRegistry { +contract OptimisticRecipientRegistry is Ownable(msg.sender), BaseRecipientRegistry { // Enums enum RequestType { diff --git a/contracts/contracts/recipientRegistry/PermissionedRecipientRegistry.sol b/contracts/contracts/recipientRegistry/PermissionedRecipientRegistry.sol index 3833f3f77..fe8e16829 100644 --- a/contracts/contracts/recipientRegistry/PermissionedRecipientRegistry.sol +++ b/contracts/contracts/recipientRegistry/PermissionedRecipientRegistry.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; import '@openzeppelin/contracts/access/Ownable.sol'; @@ -9,7 +9,7 @@ import './BaseRecipientRegistry.sol'; /** * @dev Recipient registry with permissioned execution of registrations and removals. */ -contract PermissionedRecipientRegistry is Ownable, BaseRecipientRegistry { +contract PermissionedRecipientRegistry is Ownable(msg.sender), BaseRecipientRegistry { // Enums enum RequestType { diff --git a/contracts/contracts/recipientRegistry/SimpleRecipientRegistry.sol b/contracts/contracts/recipientRegistry/SimpleRecipientRegistry.sol index bd273cea1..11c2b2014 100644 --- a/contracts/contracts/recipientRegistry/SimpleRecipientRegistry.sol +++ b/contracts/contracts/recipientRegistry/SimpleRecipientRegistry.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; import '@openzeppelin/contracts/access/Ownable.sol'; @@ -9,7 +9,7 @@ import './BaseRecipientRegistry.sol'; /** * @dev A simple recipient registry managed by a trusted entity. */ -contract SimpleRecipientRegistry is Ownable, BaseRecipientRegistry { +contract SimpleRecipientRegistry is Ownable(msg.sender), BaseRecipientRegistry { // Events event RecipientAdded( diff --git a/contracts/contracts/userRegistry/BrightIdSponsor.sol b/contracts/contracts/userRegistry/BrightIdSponsor.sol index 302a80b13..d27487d2a 100644 --- a/contracts/contracts/userRegistry/BrightIdSponsor.sol +++ b/contracts/contracts/userRegistry/BrightIdSponsor.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; contract BrightIdSponsor { event Sponsor(address indexed addr); diff --git a/contracts/contracts/userRegistry/BrightIdUserRegistry.sol b/contracts/contracts/userRegistry/BrightIdUserRegistry.sol index 09557af3a..49033f0bc 100644 --- a/contracts/contracts/userRegistry/BrightIdUserRegistry.sol +++ b/contracts/contracts/userRegistry/BrightIdUserRegistry.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; import './IUserRegistry.sol'; import './BrightIdSponsor.sol'; import '@openzeppelin/contracts/access/Ownable.sol'; -contract BrightIdUserRegistry is Ownable, IUserRegistry { +contract BrightIdUserRegistry is Ownable(msg.sender), IUserRegistry { string private constant ERROR_NEWER_VERIFICATION = 'NEWER VERIFICATION REGISTERED BEFORE'; string private constant ERROR_NOT_AUTHORIZED = 'NOT AUTHORIZED'; string private constant ERROR_INVALID_VERIFIER = 'INVALID VERIFIER'; diff --git a/contracts/contracts/userRegistry/IUserRegistry.sol b/contracts/contracts/userRegistry/IUserRegistry.sol index cce90ae42..2bd12bddf 100644 --- a/contracts/contracts/userRegistry/IUserRegistry.sol +++ b/contracts/contracts/userRegistry/IUserRegistry.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; /** * @dev Interface of the registry of verified users. diff --git a/contracts/contracts/userRegistry/MerkleUserRegistry.sol b/contracts/contracts/userRegistry/MerkleUserRegistry.sol index e6ff85c0f..0c6c39303 100644 --- a/contracts/contracts/userRegistry/MerkleUserRegistry.sol +++ b/contracts/contracts/userRegistry/MerkleUserRegistry.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; import '@openzeppelin/contracts/access/Ownable.sol'; @@ -13,7 +13,7 @@ import {MerkleProof} from '../utils/cryptography/MerkleProof.sol'; * a successful verification against the merkle root set by * the funding round coordinator. */ -contract MerkleUserRegistry is Ownable, IUserRegistry { +contract MerkleUserRegistry is Ownable(msg.sender), IUserRegistry { // verified users grouped by merkleRoot // merkleRoot -> user -> status diff --git a/contracts/contracts/userRegistry/SemaphoreUserRegistry.sol b/contracts/contracts/userRegistry/SemaphoreUserRegistry.sol index a141e422e..9be159b9b 100644 --- a/contracts/contracts/userRegistry/SemaphoreUserRegistry.sol +++ b/contracts/contracts/userRegistry/SemaphoreUserRegistry.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; import '@openzeppelin/contracts/access/Ownable.sol'; @@ -9,7 +9,7 @@ import './IUserRegistry.sol'; /** * @dev A simple semaphore user registry managed by a trusted entity. */ -contract SemaphoreUserRegistry is Ownable, IUserRegistry { +contract SemaphoreUserRegistry is Ownable(msg.sender), IUserRegistry { mapping(address => bool) private users; mapping(uint256 => bool) private semaphoreIds; diff --git a/contracts/contracts/userRegistry/SimpleUserRegistry.sol b/contracts/contracts/userRegistry/SimpleUserRegistry.sol index 4f4a7ff00..21fcaa38a 100644 --- a/contracts/contracts/userRegistry/SimpleUserRegistry.sol +++ b/contracts/contracts/userRegistry/SimpleUserRegistry.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; import '@openzeppelin/contracts/access/Ownable.sol'; @@ -9,7 +9,7 @@ import './IUserRegistry.sol'; /** * @dev A simple user registry managed by a trusted entity. */ -contract SimpleUserRegistry is Ownable, IUserRegistry { +contract SimpleUserRegistry is Ownable(msg.sender), IUserRegistry { mapping(address => bool) private users; diff --git a/contracts/contracts/userRegistry/SnapshotUserRegistry.sol b/contracts/contracts/userRegistry/SnapshotUserRegistry.sol index 754bf869c..3d7ecdd18 100644 --- a/contracts/contracts/userRegistry/SnapshotUserRegistry.sol +++ b/contracts/contracts/userRegistry/SnapshotUserRegistry.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; import '@openzeppelin/contracts/access/Ownable.sol'; @@ -14,7 +14,7 @@ import {StateProofVerifier} from '../utils/cryptography/StateProofVerifier.sol'; * @dev A user registry that verifies users based on ownership of a token * at a specific block snapshot */ -contract SnapshotUserRegistry is Ownable, IUserRegistry { +contract SnapshotUserRegistry is Ownable(msg.sender), IUserRegistry { using RLPReader for RLPReader.RLPItem; using RLPReader for bytes; diff --git a/contracts/contracts/utils/cryptography/MerklePatriciaProofVerifier.sol b/contracts/contracts/utils/cryptography/MerklePatriciaProofVerifier.sol index b0a6df1d3..a24404e9e 100644 --- a/contracts/contracts/utils/cryptography/MerklePatriciaProofVerifier.sol +++ b/contracts/contracts/utils/cryptography/MerklePatriciaProofVerifier.sol @@ -4,7 +4,7 @@ * Modified from https://github.com/lidofinance/curve-merkle-oracle/blob/main/contracts/MerklePatriciaProofVerifier.sol * git commit hash 1033b3e84142317ffd8f366b52e489d5eb49c73f */ -pragma solidity ^0.8.10; +pragma solidity 0.8.20; import {RLPReader} from 'solidity-rlp/contracts/RLPReader.sol'; diff --git a/contracts/contracts/utils/cryptography/MerkleProof.sol b/contracts/contracts/utils/cryptography/MerkleProof.sol index 08c4a87ed..dd2c0aa99 100644 --- a/contracts/contracts/utils/cryptography/MerkleProof.sol +++ b/contracts/contracts/utils/cryptography/MerkleProof.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // Modified from OpenZeppelin Contracts (last updated v4.9.2) (utils/cryptography/MerkleProof.sol) -pragma solidity ^0.8.10; +pragma solidity 0.8.20; /** * @dev These functions deal with verification of Merkle Tree proofs. diff --git a/contracts/contracts/utils/cryptography/StateProofVerifier.sol b/contracts/contracts/utils/cryptography/StateProofVerifier.sol index 407ccd0bc..9425345b1 100644 --- a/contracts/contracts/utils/cryptography/StateProofVerifier.sol +++ b/contracts/contracts/utils/cryptography/StateProofVerifier.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity 0.8.20; import {RLPReader} from 'solidity-rlp/contracts/RLPReader.sol'; import {MerklePatriciaProofVerifier} from './MerklePatriciaProofVerifier.sol'; diff --git a/contracts/deploy-config-example.json b/contracts/deploy-config-example.json index 77032cfed..4fbcc8441 100644 --- a/contracts/deploy-config-example.json +++ b/contracts/deploy-config-example.json @@ -16,11 +16,6 @@ "OptimisticRecipientRegistry": { "challengePeriodSeconds": 9007199254740990, "deposit": "0.001" - }, - "BrightIdUserRegistry": { - "deploy": false, - "context": "clrfund-arbitrum-goerli", - "verifier": "0xdbf0b2ee9887fe11934789644096028ed3febe9c" } }, "arbitrum-sepolia": { @@ -43,8 +38,7 @@ }, "BrightIdUserRegistry": { "context": "clrfund-arbitrum-goerli", - "verifier": "0xdbf0b2ee9887fe11934789644096028ed3febe9c", - "sponsor": "0xC7c81634Dac2de4E7f2Ba407B638ff003ce4534C" + "verifier": "0xdbf0b2ee9887fe11934789644096028ed3febe9c" } } } diff --git a/contracts/e2e/index.ts b/contracts/e2e/index.ts index 5a22205dd..52d949abe 100644 --- a/contracts/e2e/index.ts +++ b/contracts/e2e/index.ts @@ -16,7 +16,7 @@ import { DEFAULT_GET_LOG_BATCH_SIZE, DEFAULT_SR_QUEUE_OPS, } from '../utils/constants' -import { getEventArg } from '../utils/contracts' +import { getContractAt, getEventArg } from '../utils/contracts' import { deployPoseidonLibraries, deployMaciFactory } from '../utils/testutils' import { getIpfsHash } from '../utils/ipfs' import { @@ -36,6 +36,7 @@ import path from 'path' import { FundingRound } from '../typechain-types' import { JSONFile } from '../utils/JSONFile' import { EContracts } from '../utils/types' +import { getTalyFilePath } from '../utils/misc' type VoteData = { recipientIndex: number; voiceCredits: bigint } type ClaimData = { [index: number]: bigint } @@ -269,7 +270,11 @@ describe('End-to-end Tests', function () { pollId = await fundingRound.pollId() const pollAddress = await fundingRound.poll() - pollContract = await ethers.getContractAt(EContracts.Poll, pollAddress) + pollContract = await getContractAt( + EContracts.Poll, + pollAddress, + ethers + ) await mine() }) @@ -359,6 +364,8 @@ describe('End-to-end Tests', function () { mkdirSync(outputDir, { recursive: true }) } + const tallyFile = getTalyFilePath(outputDir) + // past an end block that's later than the MACI start block const genProofArgs = getGenProofArgs({ maciAddress, @@ -368,6 +375,7 @@ describe('End-to-end Tests', function () { circuitType: circuit, circuitDirectory, outputDir, + tallyFile, blocksPerBatch: DEFAULT_GET_LOG_BATCH_SIZE, maciTxHash: maciTransactionHash, signer: coordinator, @@ -386,7 +394,6 @@ describe('End-to-end Tests', function () { await proveOnChain({ pollId, proofDir: genProofArgs.outputDir, - subsidyEnabled: false, maciAddress, messageProcessorAddress, tallyAddress, @@ -406,7 +413,6 @@ describe('End-to-end Tests', function () { await proveOnChain({ pollId, proofDir: genProofArgs.outputDir, - subsidyEnabled: false, maciAddress, messageProcessorAddress, tallyAddress, diff --git a/contracts/hardhat.config.ts b/contracts/hardhat.config.ts index e9fcb6931..7837be09c 100644 --- a/contracts/hardhat.config.ts +++ b/contracts/hardhat.config.ts @@ -39,7 +39,7 @@ export default { url: 'http://127.0.0.1:8555', gasLimit: GAS_LIMIT, } as any, - goerli: { + sepolia: { url: process.env.JSONRPC_HTTP_URL || 'http://127.0.0.1:8545', accounts, }, @@ -67,10 +67,6 @@ export default { url: process.env.JSONRPC_HTTP_URL || 'https://sepolia.optimism.io', accounts, }, - sepolia: { - url: process.env.JSONRPC_HTTP_URL || 'http://127.0.0.1:8545', - accounts, - }, 'mantle-testnet': { url: process.env.JSONRPC_HTTP_URL || 'https://rpc.testnet.mantle.xyz', accounts, @@ -89,6 +85,7 @@ export default { process.env.OPTIMISMSCAN_API_KEY || 'YOUR_OPTIMISMSCAN_API_KEY', 'optimism-sepolia': process.env.OPTIMISMSCAN_API_KEY || 'YOUR_OPTIMISMSCAN_API_KEY', + sepolia: process.env.ETHERSCAN_API_KEY || 'YOUR_ETHERSCAN_API_KEY', }, customChains: [ { @@ -122,7 +119,7 @@ export default { disambiguatePaths: false, }, solidity: { - version: '0.8.10', + version: '0.8.20', settings: { optimizer: { enabled: true, @@ -131,7 +128,6 @@ export default { }, overrides: { 'contracts/FundingRoundFactory.sol': { - version: '0.8.10', settings: { optimizer: { enabled: true, @@ -140,7 +136,6 @@ export default { }, }, 'contracts/FundingRound.sol': { - version: '0.8.10', settings: { optimizer: { enabled: true, @@ -149,7 +144,6 @@ export default { }, }, 'contracts/recipientRegistry/OptimisticRecipientRegistry.sol': { - version: '0.8.10', settings: { optimizer: { enabled: true, @@ -158,7 +152,6 @@ export default { }, }, 'contracts/userRegistry/SimpleUserRegistry.sol': { - version: '0.8.10', settings: { optimizer: { enabled: true, @@ -167,7 +160,6 @@ export default { }, }, 'contracts/userRegistry/BrightIdUserRegistry.sol': { - version: '0.8.10', settings: { optimizer: { enabled: true, diff --git a/contracts/package.json b/contracts/package.json index 7bbbb8133..126d0a1ec 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -1,6 +1,6 @@ { "name": "@clrfund/contracts", - "version": "5.1.0", + "version": "6.0.0", "license": "GPL-3.0", "scripts": { "hardhat": "hardhat", @@ -15,17 +15,18 @@ "clean": "rm -rf cache && rm -rf build" }, "dependencies": { - "@openzeppelin/contracts": "4.9.0", + "@openzeppelin/contracts": "5.0.2", + "@pinata/sdk": "^2.1.0", "dotenv": "^8.2.0", - "maci-contracts": "^1.2.0", + "maci-contracts": "1.2.2", "solidity-rlp": "2.0.8" }, "devDependencies": { "@clrfund/common": "^0.0.1", - "@clrfund/waffle-mock-contract": "^0.0.4", + "@clrfund/waffle-mock-contract": "^0.0.11", "@kleros/gtcr-encoder": "^1.4.0", - "@nomicfoundation/hardhat-chai-matchers": "^2.0.3", - "@nomicfoundation/hardhat-ethers": "^3.0.5", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.6", + "@nomicfoundation/hardhat-ethers": "^3.0.6", "@nomicfoundation/hardhat-network-helpers": "^1.0.10", "@nomicfoundation/hardhat-toolbox": "^4.0.0", "@nomicfoundation/hardhat-verify": "^2.0.3", @@ -33,14 +34,15 @@ "@typechain/ethers-v6": "^0.5.1", "@typechain/hardhat": "^9.1.0", "@types/mocha": "^10.0.6", - "ethers": "^6.11.1", - "hardhat": "^2.19.4", + "chai": "4", + "ethers": "^6.12.1", + "hardhat": "^2.22.3", "hardhat-contract-sizer": "^2.10.0", "hardhat-gas-reporter": "^1.0.8", "ipfs-only-hash": "^2.0.1", - "maci-circuits": "^1.2.0", - "maci-cli": "^1.2.0", - "maci-domainobjs": "^1.2.0", + "maci-circuits": "1.2.2", + "maci-cli": "1.2.2", + "maci-domainobjs": "1.2.2", "mocha": "^10.2.0", "solidity-coverage": "^0.8.1", "ts-node": "^10.9.2", diff --git a/contracts/sh/deployLocal.sh b/contracts/sh/deployLocal.sh index d0c1aac73..0c48ffe01 100755 --- a/contracts/sh/deployLocal.sh +++ b/contracts/sh/deployLocal.sh @@ -26,4 +26,4 @@ export COORDINATOR_MACISK=$(echo "${MACI_KEYPAIR}" | grep -o "macisk.*$") yarn hardhat new-clrfund --network ${NETWORK} # deploy a new funding round -yarn hardhat new-round --network ${NETWORK} +yarn hardhat new-round --network ${NETWORK} --round-duration 3600 diff --git a/contracts/sh/runScriptTests.sh b/contracts/sh/runScriptTests.sh index f03a47bf9..11cde09a2 100755 --- a/contracts/sh/runScriptTests.sh +++ b/contracts/sh/runScriptTests.sh @@ -33,17 +33,17 @@ yarn hardhat contribute --network ${HARDHAT_NETWORK} yarn hardhat time-travel --seconds ${ROUND_DURATION} --network ${HARDHAT_NETWORK} -# run the tally script +# tally the votes NODE_OPTIONS="--max-old-space-size=4096" yarn hardhat tally \ --rapidsnark ${RAPID_SNARK} \ - --batch-size 8 \ - --output-dir ${OUTPUT_DIR} \ + --proof-dir ${OUTPUT_DIR} \ + --maci-start-block 0 \ --network "${HARDHAT_NETWORK}" # finalize the round -yarn hardhat finalize --tally-file ${TALLY_FILE} --network ${HARDHAT_NETWORK} +yarn hardhat finalize --proof-dir ${OUTPUT_DIR} --network ${HARDHAT_NETWORK} # claim funds -yarn hardhat claim --recipient 1 --tally-file ${TALLY_FILE} --network ${HARDHAT_NETWORK} -yarn hardhat claim --recipient 2 --tally-file ${TALLY_FILE} --network ${HARDHAT_NETWORK} +yarn hardhat claim --recipient 1 --proof-dir ${OUTPUT_DIR} --network ${HARDHAT_NETWORK} +yarn hardhat claim --recipient 2 --proof-dir ${OUTPUT_DIR} --network ${HARDHAT_NETWORK} diff --git a/contracts/tasks/helpers/ConstructorArguments.ts b/contracts/tasks/helpers/ConstructorArguments.ts new file mode 100644 index 000000000..9997e9683 --- /dev/null +++ b/contracts/tasks/helpers/ConstructorArguments.ts @@ -0,0 +1,343 @@ +import type { HardhatRuntimeEnvironment } from 'hardhat/types' +import { BaseContract, Interface } from 'ethers' +import { ContractStorage } from './ContractStorage' +import { EContracts } from './types' +import { HardhatEthersHelpers } from '@nomicfoundation/hardhat-ethers/types' +import { + BrightIdUserRegistry, + ClrFundDeployer, + MACIFactory, + MessageProcessor, + OptimisticRecipientRegistry, + Poll, + Tally, +} from '../../typechain-types' +import { getContractAt, getQualifiedContractName } from '../../utils/contracts' + +/** A list of functions to get contract constructor arguments from the contract */ +const ConstructorArgumentsGetters: Record< + string, + (address: string, ethers: HardhatEthersHelpers) => Promise> +> = { + [EContracts.FundingRound]: getFundingRoundConstructorArguments, + [EContracts.MACI]: getMaciConstructorArguments, + [EContracts.Poll]: getPollConstructorArguments, + [EContracts.Tally]: getTallyConstructorArguments, + [EContracts.MessageProcessor]: getMessageProcessorConstructorArguments, + [EContracts.BrightIdUserRegistry]: + getBrightIdUserRegistryConstructorArguments, + [EContracts.OptimisticRecipientRegistry]: + getOptimisticRecipientRegistryConstructorArguments, + [EContracts.ClrFundDeployer]: getClrFundDeployerConstructorArguments, + [EContracts.MACIFactory]: getMACIFactoryConstructorArguments, +} + +/** + * Get the constructor arguments for FundingRound + * @param address The funding round contract address + * @param ethers The Hardhat Ethers helper + * @returns The funding round constructor arguments + */ +async function getFundingRoundConstructorArguments( + address: string, + ethers: HardhatEthersHelpers +): Promise> { + const round = await ethers.getContractAt(EContracts.FundingRound, address) + + const args = await Promise.all([ + round.nativeToken(), + round.userRegistry(), + round.recipientRegistry(), + round.coordinator(), + ]) + + return args +} + +/** + * Get the constructor arguments for MACI + * @param address The MACI contract address + * @param ethers The Hardhat Ethers helper + * @returns The constructor arguments + */ +async function getMaciConstructorArguments( + address: string, + ethers: HardhatEthersHelpers +): Promise> { + const maci = await ethers.getContractAt(EContracts.MACI, address) + + const args = await Promise.all([ + maci.pollFactory(), + maci.messageProcessorFactory(), + maci.tallyFactory(), + maci.signUpGatekeeper(), + maci.initialVoiceCreditProxy(), + maci.topupCredit(), + maci.stateTreeDepth(), + ]) + + return args +} + +/** + * Get the constructor arguments for Poll + * @param address The Poll contract address + * @param ethers The Hardhat Ethers helper + * @returns The constructor arguments + */ +async function getPollConstructorArguments( + address: string, + ethers: HardhatEthersHelpers +): Promise> { + const pollContract = await getContractAt( + EContracts.Poll, + address, + ethers + ) + + const [, duration] = await pollContract.getDeployTimeAndDuration() + const [maxValues, treeDepths, coordinatorPubKey, extContracts] = + await Promise.all([ + pollContract.maxValues(), + pollContract.treeDepths(), + pollContract.coordinatorPubKey(), + pollContract.extContracts(), + ]) + + const args = [ + duration, + { + maxMessages: maxValues.maxMessages, + maxVoteOptions: maxValues.maxVoteOptions, + }, + { + intStateTreeDepth: treeDepths.intStateTreeDepth, + messageTreeSubDepth: treeDepths.messageTreeSubDepth, + messageTreeDepth: treeDepths.messageTreeDepth, + voteOptionTreeDepth: treeDepths.voteOptionTreeDepth, + }, + { + x: coordinatorPubKey.x, + y: coordinatorPubKey.y, + }, + { + maci: extContracts.maci, + messageAq: extContracts.messageAq, + topupCredit: extContracts.topupCredit, + }, + ] + + return args +} + +/** + * Get the constructor arguments for Tally + * @param address The Tally contract address + * @param ethers The Hardhat Ethers helper + * @returns The constructor arguments + */ +async function getTallyConstructorArguments( + address: string, + ethers: HardhatEthersHelpers +): Promise> { + const tallyContract = (await ethers.getContractAt( + EContracts.Tally, + address + )) as BaseContract as Tally + + const args = await Promise.all([ + tallyContract.verifier(), + tallyContract.vkRegistry(), + tallyContract.poll(), + tallyContract.messageProcessor(), + tallyContract.mode(), + ]) + + return args +} + +/** + * Get the constructor arguments for MessageProcessor + * @param address The MessageProcessor contract address + * @param ethers The Hardhat Ethers helper + * @returns The constructor arguments + */ +async function getMessageProcessorConstructorArguments( + address: string, + ethers: HardhatEthersHelpers +): Promise> { + const messageProcesor = (await ethers.getContractAt( + EContracts.MessageProcessor, + address + )) as BaseContract as MessageProcessor + + const args = await Promise.all([ + messageProcesor.verifier(), + messageProcesor.vkRegistry(), + messageProcesor.poll(), + messageProcesor.mode(), + ]) + + return args +} + +/** + * Get the constructor arguments for BrightIdUserRegistry + * @param address The BrightIdUserRegistry contract address + * @param ethers The Hardhat Ethers helper + * @returns The constructor arguments + */ +async function getBrightIdUserRegistryConstructorArguments( + address: string, + ethers: HardhatEthersHelpers +): Promise> { + const registry = (await ethers.getContractAt( + EContracts.BrightIdUserRegistry, + address + )) as BaseContract as BrightIdUserRegistry + + const args = await Promise.all([ + registry.context(), + registry.verifier(), + registry.brightIdSponsor(), + ]) + + return args +} + +/** + * Get the constructor arguments for OptimisticRecipientRegistry + * @param address The OptimisticRecipientRegistry contract address + * @param ethers The Hardhat Ethers helper + * @returns The constructor arguments + */ +async function getOptimisticRecipientRegistryConstructorArguments( + address: string, + ethers: HardhatEthersHelpers +): Promise> { + const registry = (await ethers.getContractAt( + EContracts.OptimisticRecipientRegistry, + address + )) as BaseContract as OptimisticRecipientRegistry + + const args = await Promise.all([ + registry.baseDeposit(), + registry.challengePeriodDuration(), + registry.controller(), + ]) + + return args +} + +/** + * Get the constructor arguments for ClrFundDeployer + * @param address The ClrFundDeployer contract address + * @param ethers The Hardhat Ethers helper + * @returns The constructor arguments + */ +async function getClrFundDeployerConstructorArguments( + address: string, + ethers: HardhatEthersHelpers +): Promise> { + const registry = (await ethers.getContractAt( + EContracts.ClrFundDeployer, + address + )) as BaseContract as ClrFundDeployer + + const args = await Promise.all([ + registry.clrfundTemplate(), + registry.maciFactory(), + registry.roundFactory(), + ]) + + return args +} + +/** + * Get the constructor arguments for MACIFactory + * @param address The MACIFactory contract address + * @param ethers The Hardhat Ethers helper + * @returns The constructor arguments + */ +async function getMACIFactoryConstructorArguments( + address: string, + ethers: HardhatEthersHelpers +): Promise> { + const registry = (await ethers.getContractAt( + EContracts.MACIFactory, + address + )) as BaseContract as MACIFactory + + const args = await Promise.all([ + registry.vkRegistry(), + registry.factories(), + registry.verifier(), + ]) + + return args +} + +/** + * @notice A helper to retrieve contract constructor arguments + */ +export class ConstructorArguments { + /** + * Hardhat runtime environment + */ + private hre: HardhatRuntimeEnvironment + + /** + * Local contract deployment information + */ + private storage: ContractStorage + + /** + * Initialize class properties + * + * @param hre - Hardhat runtime environment + */ + constructor(hre: HardhatRuntimeEnvironment) { + this.hre = hre + this.storage = ContractStorage.getInstance() + } + + /** + * Get the contract constructor arguments + * @param name - contract name + * @param address - contract address + * @param ethers = Hardhat Ethers helper + * @returns - stringified constructor arguments + */ + async get( + name: string, + address: string, + ethers: HardhatEthersHelpers + ): Promise> { + const qualifiedName = getQualifiedContractName(name) + const contractArtifact = this.hre.artifacts.readArtifactSync(qualifiedName) + const contractInterface = new Interface(contractArtifact.abi) + if (contractInterface.deploy.inputs.length === 0) { + // no argument + return [] + } + + // try to get arguments from deployed-contract.json file + const constructorArguments = this.storage.getConstructorArguments( + address, + this.hre.network.name + ) + if (constructorArguments) { + return constructorArguments + } + + // try to get custom constructor arguments from contract + let args: Array = [] + + const getConstructorArguments = ConstructorArgumentsGetters[name] + if (getConstructorArguments) { + args = await getConstructorArguments(address, ethers) + } + + return args + } +} diff --git a/contracts/tasks/helpers/ContractStorage.ts b/contracts/tasks/helpers/ContractStorage.ts index 9c092bd24..56db46e6e 100644 --- a/contracts/tasks/helpers/ContractStorage.ts +++ b/contracts/tasks/helpers/ContractStorage.ts @@ -204,6 +204,26 @@ export class ContractStorage { return instance?.txHash } + /** + * Get contract constructor argument by address from the json file + * + * @param address - contract address + * @param network - selected network + * @returns contract constructor arguments + */ + getConstructorArguments( + address: string, + network: string + ): Array | undefined { + if (!this.db[network]) { + return undefined + } + + const instance = this.db[network].instance?.[address] + const args = instance?.verify?.args + return args ? JSON.parse(args) : undefined + } + /** * Get contract address by name from the json file * diff --git a/contracts/tasks/helpers/ContractVerifier.ts b/contracts/tasks/helpers/ContractVerifier.ts index 6d71952bc..3a517373f 100644 --- a/contracts/tasks/helpers/ContractVerifier.ts +++ b/contracts/tasks/helpers/ContractVerifier.ts @@ -31,13 +31,13 @@ export class ContractVerifier { */ async verify( address: string, - constructorArguments: string, + constructorArguments: unknown[], libraries?: string, contract?: string ): Promise<[boolean, string]> { const params: IVerificationSubtaskArgs = { address, - constructorArguments: JSON.parse(constructorArguments) as unknown[], + constructorArguments, contract, } @@ -50,7 +50,7 @@ export class ContractVerifier { .run('verify:verify', params) .then(() => '') .catch((err: Error) => { - if (err.message === 'Contract source code already verified') { + if (err.message && err.message.match(/already verified/i)) { return '' } diff --git a/contracts/tasks/helpers/Subtask.ts b/contracts/tasks/helpers/Subtask.ts index 089cf06d6..06eed8015 100644 --- a/contracts/tasks/helpers/Subtask.ts +++ b/contracts/tasks/helpers/Subtask.ts @@ -18,7 +18,7 @@ import type { HardhatRuntimeEnvironment, } from 'hardhat/types' -import { deployContract } from '../../utils/contracts' +import { deployContract, getQualifiedContractName } from '../../utils/contracts' import { EContracts } from '../../utils/types' import { ContractStorage } from './ContractStorage' import { @@ -527,7 +527,8 @@ export class Subtask { const contractAddress = address || this.storage.mustGetAddress(name, this.hre.network.name) - const { abi } = await this.hre.artifacts.readArtifact(name.toString()) + const qualifiedName = getQualifiedContractName(name) + const { abi } = await this.hre.artifacts.readArtifact(qualifiedName) return new BaseContract(contractAddress, abi, deployer) as T } diff --git a/contracts/tasks/index.ts b/contracts/tasks/index.ts index 5bcc7e4fc..19050a901 100644 --- a/contracts/tasks/index.ts +++ b/contracts/tasks/index.ts @@ -23,3 +23,10 @@ import './runners/addRecipients' import './runners/findStorageSlot' import './runners/verifyTallyFile' import './runners/verifyAll' +import './runners/verifyDeployer' +import './runners/genProofs' +import './runners/proveOnChain' +import './runners/publishTallyResults' +import './runners/resetTally' +import './runners/maciPubkey' +import './runners/simulateContribute' diff --git a/contracts/tasks/runners/claim.ts b/contracts/tasks/runners/claim.ts index acce6d3a2..0f27a2e95 100644 --- a/contracts/tasks/runners/claim.ts +++ b/contracts/tasks/runners/claim.ts @@ -2,75 +2,92 @@ * Claim funds. This script is mainly used by e2e testing * * Sample usage: - * yarn hardhat claim \ - * --tally-file \ - * --recipient \ - * --network + * yarn hardhat claim --recipient --network */ -import { getEventArg } from '../../utils/contracts' +import { getContractAt, getEventArg } from '../../utils/contracts' import { getRecipientClaimData } from '@clrfund/common' import { JSONFile } from '../../utils/JSONFile' -import { isPathExist } from '../../utils/misc' +import { + getProofDirForRound, + getTalyFilePath, + isPathExist, +} from '../../utils/misc' import { getNumber } from 'ethers' import { task, types } from 'hardhat/config' import { EContracts } from '../../utils/types' import { ContractStorage } from '../helpers/ContractStorage' +import { Poll } from 'maci-contracts/build/typechain-types' task('claim', 'Claim funnds for test recipients') + .addOptionalParam('roundAddress', 'Funding round contract address') .addParam( 'recipient', 'The recipient index in the tally file', undefined, types.int ) - .addParam('tallyFile', 'The tally file') - .setAction(async ({ tallyFile, recipient }, { ethers, network }) => { - if (!isPathExist(tallyFile)) { - throw new Error(`Path ${tallyFile} does not exist`) - } + .addParam('proofDir', 'The proof output directory', './proof_output') + .setAction( + async ({ proofDir, recipient, roundAddress }, { ethers, network }) => { + if (recipient <= 0) { + throw new Error('Recipient must be greater than 0') + } - if (recipient <= 0) { - throw new Error('Recipient must be greater than 0') - } + const storage = ContractStorage.getInstance() + const fundingRound = + roundAddress ?? + storage.mustGetAddress(EContracts.FundingRound, network.name) - const storage = ContractStorage.getInstance() - const fundingRound = storage.mustGetAddress( - EContracts.FundingRound, - network.name - ) + const proofDirForRound = getProofDirForRound( + proofDir, + network.name, + fundingRound + ) - const tally = JSONFile.read(tallyFile) + const tallyFile = getTalyFilePath(proofDirForRound) + if (!isPathExist(tallyFile)) { + throw new Error(`Path ${tallyFile} does not exist`) + } - const fundingRoundContract = await ethers.getContractAt( - EContracts.FundingRound, - fundingRound - ) + const tally = JSONFile.read(tallyFile) - const recipientStatus = await fundingRoundContract.recipients(recipient) - if (recipientStatus.fundsClaimed) { - throw new Error(`Recipient already claimed funds`) - } + const fundingRoundContract = await ethers.getContractAt( + EContracts.FundingRound, + fundingRound + ) - const pollAddress = await fundingRoundContract.poll() - console.log('pollAddress', pollAddress) + const recipientStatus = await fundingRoundContract.recipients(recipient) + if (recipientStatus.fundsClaimed) { + throw new Error(`Recipient already claimed funds`) + } - const poll = await ethers.getContractAt(EContracts.Poll, pollAddress) - const treeDepths = await poll.treeDepths() - const recipientTreeDepth = getNumber(treeDepths.voteOptionTreeDepth) + const pollAddress = await fundingRoundContract.poll() + console.log('pollAddress', pollAddress) - // Claim funds - const recipientClaimData = getRecipientClaimData( - recipient, - recipientTreeDepth, - tally - ) - const claimTx = await fundingRoundContract.claimFunds(...recipientClaimData) - const claimedAmount = await getEventArg( - claimTx, - fundingRoundContract, - 'FundsClaimed', - '_amount' - ) - console.log(`Recipient ${recipient} claimed ${claimedAmount} tokens.`) - }) + const poll = await getContractAt( + EContracts.Poll, + pollAddress, + ethers + ) + const treeDepths = await poll.treeDepths() + const recipientTreeDepth = getNumber(treeDepths.voteOptionTreeDepth) + + // Claim funds + const recipientClaimData = getRecipientClaimData( + recipient, + recipientTreeDepth, + tally + ) + const claimTx = await fundingRoundContract.claimFunds( + ...recipientClaimData + ) + const claimedAmount = await getEventArg( + claimTx, + fundingRoundContract, + 'FundsClaimed', + '_amount' + ) + console.log(`Recipient ${recipient} claimed ${claimedAmount} tokens.`) + } + ) diff --git a/contracts/tasks/runners/contribute.ts b/contracts/tasks/runners/contribute.ts index 6060c17a1..41cb7d610 100644 --- a/contracts/tasks/runners/contribute.ts +++ b/contracts/tasks/runners/contribute.ts @@ -11,7 +11,7 @@ import { Keypair, createMessage, Message, PubKey } from '@clrfund/common' import { UNIT } from '../../utils/constants' -import { getEventArg } from '../../utils/contracts' +import { getContractAt, getEventArg } from '../../utils/contracts' import type { FundingRound, ERC20, Poll } from '../../typechain-types' import { task } from 'hardhat/config' import { EContracts } from '../../utils/types' @@ -98,9 +98,10 @@ task('contribute', 'Contribute to a funding round').setAction( const pollId = await fundingRound.pollId() const pollAddress = await fundingRound.poll() - const pollContract = await ethers.getContractAt( + const pollContract = await getContractAt( EContracts.Poll, - pollAddress + pollAddress, + ethers ) const rawCoordinatorPubKey = await pollContract.coordinatorPubKey() diff --git a/contracts/tasks/runners/exportRound.ts b/contracts/tasks/runners/exportRound.ts index 4eadf9818..42c3638f2 100644 --- a/contracts/tasks/runners/exportRound.ts +++ b/contracts/tasks/runners/exportRound.ts @@ -14,12 +14,14 @@ import { task, types } from 'hardhat/config' import { Contract, formatUnits, getNumber } from 'ethers' import { Ipfs } from '../../utils/ipfs' -import { Project, Round, RoundFileContent } from '../../utils/types' +import { EContracts, Project, Round, RoundFileContent } from '../../utils/types' import { RecipientRegistryLogProcessor } from '../../utils/RecipientRegistryLogProcessor' -import { getRecipientAddressAbi } from '../../utils/abi' +import { getRecipientAddressAbi, MaciV0Abi } from '../../utils/abi' import { JSONFile } from '../../utils/JSONFile' import path from 'path' import fs from 'fs' +import { getContractAt } from '../../utils/contracts' +import { Poll } from '../../typechain-types' type RoundListEntry = { network: string @@ -41,19 +43,6 @@ function roundListFileName(directory: string): string { return path.join(directory, 'rounds.json') } -function getEtherscanApiKey(config: any, network: string): string { - let etherscanApiKey = '' - if (config.etherscan?.apiKey) { - if (typeof config.etherscan.apiKey === 'string') { - etherscanApiKey = config.etherscan.apiKey - } else { - etherscanApiKey = config.etherscan.apiKey[network] - } - } - - return etherscanApiKey -} - function roundMapKey(round: RoundListEntry): string { return `${round.network}.${round.address}` } @@ -76,7 +65,10 @@ async function updateRoundList(filePath: string, round: RoundListEntry) { const rounds: RoundListEntry[] = Array.from(roundMap.values()) // sort in ascending start time order - rounds.sort((round1, round2) => round1.startTime - round2.startTime) + rounds.sort( + (round1, round2) => + getNumber(round1.startTime) - getNumber(round2.startTime) + ) JSONFile.write(filePath, rounds) console.log('Finished writing to', filePath) } @@ -137,7 +129,11 @@ async function mergeRecipientTally({ } const tallyResult = tally.results.tally[i] - const spentVoiceCredits = tally.perVOSpentVoiceCredits.tally[i] + + // In MACI V1, totalVoiceCreditsPerVoteOption is called perVOSpentVoiceCredits + const spentVoiceCredits = tally.perVOSpentVoiceCredits + ? tally.perVOSpentVoiceCredits.tally[i] + : tally.totalVoiceCreditsPerVoteOption.tally[i] const formattedDonationAmount = formatUnits( BigInt(spentVoiceCredits) * BigInt(voiceCreditFactor), nativeTokenDecimals @@ -222,12 +218,15 @@ async function getRoundInfo( try { if (pollAddress) { - const pollContract = await ethers.getContractAt('Poll', pollAddress) + const pollContract = await getContractAt( + EContracts.Poll, + pollAddress, + ethers + ) const [roundStartTime, roundDuration] = await pollContract.getDeployTimeAndDuration() startTime = getNumber(roundStartTime) signUpDuration = roundDuration - votingDuration = roundDuration endTime = startTime + getNumber(roundDuration) pollId = await roundContract.pollId() @@ -237,7 +236,7 @@ async function getRoundInfo( maxMessages = maxValues.maxMessages maxRecipients = maxValues.maxVoteOptions } else { - const maci = await ethers.getContractAt('MACI', maciAddress) + const maci = await ethers.getContractAt(MaciV0Abi, maciAddress) startTime = await maci.signUpTimestamp().catch(toZero) signUpDuration = await maci.signUpDurationSeconds().catch(toZero) votingDuration = await maci.votingDurationSeconds().catch(toZero) @@ -352,11 +351,6 @@ task('export-round', 'Export round data for the leaderboard') console.log('Processing on ', network.name) console.log('Funding round address', roundAddress) - const etherscanApiKey = getEtherscanApiKey(config, network.name) - if (!etherscanApiKey) { - throw new Error('Etherscan API key not set') - } - const outputSubDir = path.join(outputDir, network.name) try { fs.statSync(outputSubDir) @@ -383,7 +377,7 @@ task('export-round', 'Export round data for the leaderboard') endBlock, blocksPerBatch, network: network.name, - etherscanApiKey, + config, }) console.log('Parsing logs...') diff --git a/contracts/tasks/runners/finalize.ts b/contracts/tasks/runners/finalize.ts index 0240ba16b..74afe85e1 100644 --- a/contracts/tasks/runners/finalize.ts +++ b/contracts/tasks/runners/finalize.ts @@ -6,7 +6,7 @@ * - clrfund owner's wallet private key to interact with the contract * * Sample usage: - * yarn hardhat finalize --clrfund --tally-file --network + * yarn hardhat finalize --clrfund --network */ import { JSONFile } from '../../utils/JSONFile' @@ -16,20 +16,15 @@ import { task } from 'hardhat/config' import { EContracts } from '../../utils/types' import { ContractStorage } from '../helpers/ContractStorage' import { Subtask } from '../helpers/Subtask' +import { getProofDirForRound, getTalyFilePath } from '../../utils/misc' +import { getContractAt } from '../../utils/contracts' +import { Poll } from 'maci-contracts/build/typechain-types' task('finalize', 'Finalize a funding round') .addOptionalParam('clrfund', 'The ClrFund contract address') - .addOptionalParam( - 'tallyFile', - 'The tally file path', - './proof_output/tally.json' - ) - .setAction(async ({ clrfund, tallyFile }, hre) => { + .addParam('proofDir', 'The proof output directory', './proof_output') + .setAction(async ({ clrfund, proofDir }, hre) => { const { ethers, network } = hre - const tally = JSONFile.read(tallyFile) - if (!tally.maci) { - throw Error('Bad tally file ' + tallyFile) - } const storage = ContractStorage.getInstance() const subtask = Subtask.getInstance(hre) @@ -54,15 +49,27 @@ task('finalize', 'Finalize a funding round') console.log('Current round', fundingRound.target) const pollAddress = await fundingRound.poll() - const pollContract = await ethers.getContractAt( + const pollContract = await getContractAt( EContracts.Poll, - pollAddress + pollAddress, + ethers ) console.log('Poll', pollAddress) const treeDepths = await pollContract.treeDepths() console.log('voteOptionTreeDepth', treeDepths.voteOptionTreeDepth) + const currentRoundProofDir = getProofDirForRound( + proofDir, + network.name, + currentRoundAddress + ) + const tallyFile = getTalyFilePath(currentRoundProofDir) + const tally = JSONFile.read(tallyFile) + if (!tally.maci) { + throw Error('Bad tally file ' + tallyFile) + } + const totalSpent = tally.totalSpentVoiceCredits.spent const totalSpentSalt = tally.totalSpentVoiceCredits.salt diff --git a/contracts/tasks/runners/genProofs.ts b/contracts/tasks/runners/genProofs.ts new file mode 100644 index 000000000..708573980 --- /dev/null +++ b/contracts/tasks/runners/genProofs.ts @@ -0,0 +1,220 @@ +/** + * Script for generating MACI proofs + * + * Make sure to set the following environment variables in the .env file + * 1) WALLET_PRIVATE_KEY or WALLET_MNEMONIC + * - coordinator's wallet private key to interact with contracts + * 2) COORDINATOR_MACISK - coordinator's MACI private key to decrypt messages + * + * Sample usage: + * + * yarn hardhat gen-proofs --clrfund --proof-dir \ + * --maci-tx-hash --network + * + */ +import { getNumber, NonceManager } from 'ethers' +import { task, types } from 'hardhat/config' + +import { + DEFAULT_GET_LOG_BATCH_SIZE, + DEFAULT_SR_QUEUE_OPS, +} from '../../utils/constants' +import { + getGenProofArgs, + genProofs, + genLocalState, + mergeMaciSubtrees, +} from '../../utils/maci' +import { + getMaciStateFilePath, + getTalyFilePath, + isPathExist, + makeDirectory, +} from '../../utils/misc' +import { EContracts } from '../../utils/types' +import { Subtask } from '../helpers/Subtask' +import { getCurrentFundingRoundContract } from '../../utils/contracts' +import { ContractStorage } from '../helpers/ContractStorage' +import { DEFAULT_CIRCUIT } from '../../utils/circuits' +import { JSONFile } from '../../utils/JSONFile' + +/** + * Check if the tally file with the maci contract address exists + * @param tallyFile The tally file path + * @param maciAddress The MACI contract address + * @returns true if the file exists and it contains the MACI contract address + */ +function tallyFileExists(tallyFile: string, maciAddress: string): boolean { + if (!isPathExist(tallyFile)) { + return false + } + try { + const tallyData = JSONFile.read(tallyFile) + return ( + tallyData.maci && + tallyData.maci.toLowerCase() === maciAddress.toLowerCase() + ) + } catch { + // in case the file does not have the expected format/field + return false + } +} + +task('gen-proofs', 'Generate MACI proofs offchain') + .addOptionalParam('clrfund', 'FundingRound contract address') + .addParam('proofDir', 'The proof output directory') + .addOptionalParam('maciTxHash', 'MACI creation transaction hash') + .addOptionalParam( + 'maciStartBlock', + 'MACI creation block', + undefined, + types.int + ) + .addFlag('manageNonce', 'Whether to manually manage transaction nonce') + .addOptionalParam('rapidsnark', 'The rapidsnark prover path') + .addParam('paramsDir', 'The circuit zkeys directory', './params') + .addOptionalParam( + 'blocksPerBatch', + 'The number of blocks per batch of logs to fetch on-chain', + DEFAULT_GET_LOG_BATCH_SIZE, + types.int + ) + .addOptionalParam( + 'numQueueOps', + 'The number of operations for MACI tree merging', + getNumber(DEFAULT_SR_QUEUE_OPS), + types.int + ) + .addOptionalParam('sleep', 'Number of seconds to sleep between log fetch') + .addOptionalParam( + 'quiet', + 'Whether to disable verbose logging', + false, + types.boolean + ) + .setAction( + async ( + { + clrfund, + maciStartBlock, + maciTxHash, + quiet, + proofDir, + paramsDir, + blocksPerBatch, + rapidsnark, + numQueueOps, + sleep, + manageNonce, + }, + hre + ) => { + console.log('Verbose logging enabled:', !quiet) + + const { ethers, network } = hre + const storage = ContractStorage.getInstance() + const subtask = Subtask.getInstance(hre) + subtask.setHre(hre) + + const [coordinatorSigner] = await ethers.getSigners() + if (!coordinatorSigner) { + throw new Error('Env. variable WALLET_PRIVATE_KEY not set') + } + const coordinator = manageNonce + ? new NonceManager(coordinatorSigner) + : coordinatorSigner + console.log('Coordinator address: ', await coordinator.getAddress()) + + const coordinatorMacisk = process.env.COORDINATOR_MACISK + if (!coordinatorMacisk) { + throw new Error('Env. variable COORDINATOR_MACISK not set') + } + + const circuit = + subtask.tryGetConfigField(EContracts.VkRegistry, 'circuit') || + DEFAULT_CIRCUIT + + const circuitDirectory = + subtask.tryGetConfigField( + EContracts.VkRegistry, + 'paramsDirectory' + ) || paramsDir + + await subtask.logStart() + + const clrfundContractAddress = + clrfund ?? storage.mustGetAddress(EContracts.ClrFund, network.name) + const fundingRoundContract = await getCurrentFundingRoundContract( + clrfundContractAddress, + coordinator, + ethers + ) + console.log('Funding round contract', fundingRoundContract.target) + + const pollId = await fundingRoundContract.pollId() + console.log('PollId', pollId) + + const maciAddress = await fundingRoundContract.maci() + await mergeMaciSubtrees({ + maciAddress, + pollId, + numQueueOps, + signer: coordinator, + quiet, + }) + + if (!isPathExist(proofDir)) { + makeDirectory(proofDir) + } + + const tallyFile = getTalyFilePath(proofDir) + const maciStateFile = getMaciStateFilePath(proofDir) + const providerUrl = (network.config as any).url + + if (tallyFileExists(tallyFile, maciAddress)) { + console.log('The tally file has already been generated.') + return + } + + if (!isPathExist(maciStateFile)) { + if (!maciTxHash && maciStartBlock == null) { + throw new Error( + 'Please provide a value for --maci-tx-hash or --maci-start-block' + ) + } + + await genLocalState({ + quiet, + outputPath: maciStateFile, + pollId, + maciAddress, + coordinatorPrivateKey: coordinatorMacisk, + ethereumProvider: providerUrl, + transactionHash: maciTxHash, + startBlock: maciStartBlock, + blockPerBatch: blocksPerBatch, + signer: coordinator, + sleep, + }) + } + + const genProofArgs = getGenProofArgs({ + maciAddress, + pollId, + coordinatorMacisk, + rapidsnark, + circuitType: circuit, + circuitDirectory, + outputDir: proofDir, + blocksPerBatch: getNumber(blocksPerBatch), + maciStateFile, + tallyFile, + signer: coordinator, + quiet, + }) + await genProofs(genProofArgs) + + const success = true + await subtask.finish(success) + } + ) diff --git a/contracts/tasks/runners/maciPubkey.ts b/contracts/tasks/runners/maciPubkey.ts index c69ff002a..dad72f66e 100644 --- a/contracts/tasks/runners/maciPubkey.ts +++ b/contracts/tasks/runners/maciPubkey.ts @@ -4,7 +4,6 @@ * * Usage: hardhat maci-pubkey --macisk */ -import { id } from 'ethers' import { task } from 'hardhat/config' import { PubKey, PrivKey, Keypair } from '@clrfund/common' @@ -26,8 +25,5 @@ task('maci-pubkey', 'Get the serialized MACI public key') } const pubKey = new PubKey([BigInt(x), BigInt(y)]) console.log(`Public Key: ${pubKey.serialize()}`) - - const subgraphId = id(x + '.' + y) - console.log(`Subgraph id: ${subgraphId}`) } }) diff --git a/contracts/tasks/runners/newClrFund.ts b/contracts/tasks/runners/newClrFund.ts index 31ff081a0..9986ca223 100644 --- a/contracts/tasks/runners/newClrFund.ts +++ b/contracts/tasks/runners/newClrFund.ts @@ -13,9 +13,9 @@ * where `nonce too low` errors occur occasionally */ import { task, types } from 'hardhat/config' - +import { ContractStorage } from '../helpers/ContractStorage' import { Subtask } from '../helpers/Subtask' -import { type ISubtaskParams } from '../helpers/types' +import { EContracts, type ISubtaskParams } from '../helpers/types' task('new-clrfund', 'Deploy a new instance of ClrFund') .addFlag('incremental', 'Incremental deployment') @@ -26,6 +26,7 @@ task('new-clrfund', 'Deploy a new instance of ClrFund') .setAction(async (params: ISubtaskParams, hre) => { const { verify, manageNonce } = params const subtask = Subtask.getInstance(hre) + const storage = ContractStorage.getInstance() subtask.setHre(hre) const deployer = await subtask.getDeployer() @@ -62,7 +63,10 @@ task('new-clrfund', 'Deploy a new instance of ClrFund') await subtask.finish(success) if (verify) { - console.log('Verify all contracts') - await hre.run('verify-all') + const clrfund = storage.getAddress(EContracts.ClrFund, hre.network.name) + if (clrfund) { + console.log('Verify all contracts') + await hre.run('verify-all', { clrfund }) + } } }) diff --git a/contracts/tasks/runners/newDeployer.ts b/contracts/tasks/runners/newDeployer.ts index 14157d4f8..e0023e9b2 100644 --- a/contracts/tasks/runners/newDeployer.ts +++ b/contracts/tasks/runners/newDeployer.ts @@ -15,7 +15,8 @@ import { task, types } from 'hardhat/config' import { Subtask } from '../helpers/Subtask' -import { type ISubtaskParams } from '../helpers/types' +import { ContractStorage } from '../helpers/ContractStorage' +import { EContracts, type ISubtaskParams } from '../helpers/types' task('new-deployer', 'Deploy a new instance of ClrFund') .addFlag('incremental', 'Incremental deployment') @@ -26,6 +27,7 @@ task('new-deployer', 'Deploy a new instance of ClrFund') .setAction(async (params: ISubtaskParams, hre) => { const { verify, manageNonce } = params const subtask = Subtask.getInstance(hre) + const storage = ContractStorage.getInstance() subtask.setHre(hre) const deployer = await subtask.getDeployer() @@ -63,7 +65,10 @@ task('new-deployer', 'Deploy a new instance of ClrFund') await subtask.finish(success) if (verify) { - console.log('Verify all contracts') - await hre.run('verify-all') + const address = storage.mustGetAddress( + EContracts.ClrFundDeployer, + hre.network.name + ) + await hre.run('verify-deployer', { address }) } }) diff --git a/contracts/tasks/runners/proveOnChain.ts b/contracts/tasks/runners/proveOnChain.ts new file mode 100644 index 000000000..40946ba62 --- /dev/null +++ b/contracts/tasks/runners/proveOnChain.ts @@ -0,0 +1,102 @@ +/** + * Prove on chain the MACI proofs generated using genProofs + * + * Make sure to set the following environment variables in the .env file + * 1) WALLET_PRIVATE_KEY or WALLET_MNEMONIC + * - coordinator's wallet private key to interact with contracts + * + * Sample usage: + * + * yarn hardhat prove-on-chain --clrfund --proof-dir --network + * + */ +import { BaseContract, NonceManager } from 'ethers' +import { task, types } from 'hardhat/config' + +import { proveOnChain } from '../../utils/maci' +import { Tally } from '../../typechain-types' +import { HardhatEthersHelpers } from '@nomicfoundation/hardhat-ethers/types' +import { EContracts } from '../../utils/types' +import { Subtask } from '../helpers/Subtask' +import { getCurrentFundingRoundContract } from '../../utils/contracts' +import { ContractStorage } from '../helpers/ContractStorage' + +/** + * Get the message processor contract address from the tally contract + * @param tallyAddress Tally contract address + * @param ethers Hardhat ethers helper + * @returns Message processor contract address + */ +async function getMessageProcessorAddress( + tallyAddress: string, + ethers: HardhatEthersHelpers +): Promise { + const tallyContract = (await ethers.getContractAt( + EContracts.Tally, + tallyAddress + )) as BaseContract as Tally + + const messageProcessorAddress = await tallyContract.messageProcessor() + return messageProcessorAddress +} + +task('prove-on-chain', 'Prove on chain with the MACI proofs') + .addOptionalParam('clrfund', 'ClrFund contract address') + .addParam('proofDir', 'The proof output directory') + .addFlag('manageNonce', 'Whether to manually manage transaction nonce') + .addOptionalParam( + 'quiet', + 'Whether to disable verbose logging', + false, + types.boolean + ) + .setAction(async ({ clrfund, quiet, manageNonce, proofDir }, hre) => { + console.log('Verbose logging enabled:', !quiet) + + const { ethers, network } = hre + const storage = ContractStorage.getInstance() + const subtask = Subtask.getInstance(hre) + subtask.setHre(hre) + + const [coordinatorSigner] = await ethers.getSigners() + if (!coordinatorSigner) { + throw new Error('Env. variable WALLET_PRIVATE_KEY not set') + } + const coordinator = manageNonce + ? new NonceManager(coordinatorSigner) + : coordinatorSigner + console.log('Coordinator address: ', await coordinator.getAddress()) + + await subtask.logStart() + + const clrfundContractAddress = + clrfund ?? storage.mustGetAddress(EContracts.ClrFund, network.name) + const fundingRoundContract = await getCurrentFundingRoundContract( + clrfundContractAddress, + coordinator, + ethers + ) + console.log('Funding round contract', fundingRoundContract.target) + + const pollId = await fundingRoundContract.pollId() + const maciAddress = await fundingRoundContract.maci() + const tallyAddress = await fundingRoundContract.tally() + const messageProcessorAddress = await getMessageProcessorAddress( + tallyAddress, + ethers + ) + + // proveOnChain if not already processed + await proveOnChain({ + pollId, + proofDir, + maciAddress, + messageProcessorAddress, + tallyAddress, + signer: coordinator, + quiet, + }) + + const success = true + await subtask.finish(success) + }) diff --git a/contracts/tasks/runners/publishTallyResults.ts b/contracts/tasks/runners/publishTallyResults.ts new file mode 100644 index 000000000..b9db3404f --- /dev/null +++ b/contracts/tasks/runners/publishTallyResults.ts @@ -0,0 +1,189 @@ +/** + * Script for tallying votes which involves fetching MACI logs, generating proofs, + * and proving on chain + * + * Make sure to set the following environment variables in the .env file + * 1) WALLET_PRIVATE_KEY or WALLET_MNEMONIC + * - coordinator's wallet private key to interact with contracts + * 2) PINATA_API_KEY - The Pinata api key for pinning file to IPFS + * 3) PINATA_SECRET_API_KEY - The Pinata secret api key for pinning file to IPFS + * + * Sample usage: + * + * yarn hardhat publish-tally-results --clrfund + * --proof-dir --network + * + */ +import { BaseContract, getNumber, NonceManager } from 'ethers' +import { task, types } from 'hardhat/config' + +import { Ipfs } from '../../utils/ipfs' +import { JSONFile } from '../../utils/JSONFile' +import { addTallyResultsBatch, TallyData, verify } from '../../utils/maci' +import { FundingRound, Poll } from '../../typechain-types' +import { HardhatEthersHelpers } from '@nomicfoundation/hardhat-ethers/types' +import { EContracts } from '../../utils/types' +import { Subtask } from '../helpers/Subtask' +import { + getContractAt, + getCurrentFundingRoundContract, +} from '../../utils/contracts' +import { getTalyFilePath } from '../../utils/misc' +import { ContractStorage } from '../helpers/ContractStorage' + +/** + * Publish the tally IPFS hash on chain if it's not already published + * @param fundingRoundContract Funding round contract + * @param tallyHash Tally hash + */ +async function publishTallyHash( + fundingRoundContract: FundingRound, + tallyHash: string +) { + console.log(`Tally hash is ${tallyHash}`) + + const tallyHashOnChain = await fundingRoundContract.tallyHash() + if (tallyHashOnChain !== tallyHash) { + const tx = await fundingRoundContract.publishTallyHash(tallyHash) + const receipt = await tx.wait() + if (receipt?.status !== 1) { + throw new Error('Failed to publish tally hash on chain') + } + + console.log('Published tally hash on chain') + } +} +/** + * Submit tally data to funding round contract + * @param fundingRoundContract Funding round contract + * @param batchSize Number of tally results per batch + * @param tallyData Tally file content + */ +async function submitTallyResults( + fundingRoundContract: FundingRound, + recipientTreeDepth: number, + tallyData: TallyData, + batchSize: number +) { + const startIndex = await fundingRoundContract.totalTallyResults() + const total = tallyData.results.tally.length + if (startIndex < total) { + console.log('Uploading tally results in batches of', batchSize) + } + const addTallyGas = await addTallyResultsBatch( + fundingRoundContract, + recipientTreeDepth, + tallyData, + getNumber(batchSize), + getNumber(startIndex), + (processed: number) => { + console.log(`Processed ${processed} / ${total}`) + } + ) + console.log('Tally results uploaded. Gas used:', addTallyGas.toString()) +} + +/** + * Get the recipient tree depth (aka vote option tree depth) + * @param fundingRoundContract Funding round conract + * @param ethers Hardhat Ethers Helper + * @returns Recipient tree depth + */ +async function getRecipientTreeDepth( + fundingRoundContract: FundingRound, + ethers: HardhatEthersHelpers +): Promise { + const pollAddress = await fundingRoundContract.poll() + const pollContract = await getContractAt( + EContracts.Poll, + pollAddress, + ethers + ) + const treeDepths = await (pollContract as BaseContract as Poll).treeDepths() + const voteOptionTreeDepth = treeDepths.voteOptionTreeDepth + return getNumber(voteOptionTreeDepth) +} + +task('publish-tally-results', 'Publish tally results') + .addOptionalParam('clrfund', 'ClrFund contract address') + .addParam('proofDir', 'The proof output directory') + .addOptionalParam( + 'batchSize', + 'The batch size to upload tally result on-chain', + 8, + types.int + ) + .addFlag('manageNonce', 'Whether to manually manage transaction nonce') + .addFlag('quiet', 'Whether to log on the console') + .setAction( + async ({ clrfund, proofDir, batchSize, manageNonce, quiet }, hre) => { + const { ethers, network } = hre + const storage = ContractStorage.getInstance() + const subtask = Subtask.getInstance(hre) + subtask.setHre(hre) + + const [signer] = await ethers.getSigners() + if (!signer) { + throw new Error('Env. variable WALLET_PRIVATE_KEY not set') + } + const coordinator = manageNonce ? new NonceManager(signer) : signer + console.log('Coordinator address: ', await coordinator.getAddress()) + + const apiKey = process.env.PINATA_API_KEY + if (!apiKey) { + throw new Error('Env. variable PINATA_API_KEY not set') + } + + const secretApiKey = process.env.PINATA_SECRET_API_KEY + if (!secretApiKey) { + throw new Error('Env. variable PINATA_SECRET_API_KEY not set') + } + + await subtask.logStart() + + const clrfundContractAddress = + clrfund ?? storage.mustGetAddress(EContracts.ClrFund, network.name) + const fundingRoundContract = await getCurrentFundingRoundContract( + clrfundContractAddress, + coordinator, + ethers + ) + console.log('Funding round contract', fundingRoundContract.target) + + const recipientTreeDepth = await getRecipientTreeDepth( + fundingRoundContract, + ethers + ) + + const tallyFile = getTalyFilePath(proofDir) + const tallyData = JSONFile.read(tallyFile) + const tallyAddress = await fundingRoundContract.tally() + + await verify({ + pollId: BigInt(tallyData.pollId), + subsidyEnabled: false, + tallyData, + maciAddress: tallyData.maci, + tallyAddress, + signer: coordinator, + quiet, + }) + + const tallyHash = await Ipfs.pinFile(tallyFile, apiKey, secretApiKey) + + // Publish tally hash if it is not already published + await publishTallyHash(fundingRoundContract, tallyHash) + + // Submit tally results to the funding round contract + // This function can be re-run from where it left off + await submitTallyResults( + fundingRoundContract, + recipientTreeDepth, + tallyData, + batchSize + ) + + const success = true + await subtask.finish(success) + } + ) diff --git a/contracts/tasks/runners/resetTally.ts b/contracts/tasks/runners/resetTally.ts new file mode 100644 index 000000000..adc9ebb4e --- /dev/null +++ b/contracts/tasks/runners/resetTally.ts @@ -0,0 +1,53 @@ +/** + * WARNING: + * This script will create a new instance of the tally contract in the funding round contract + * + * Usage: + * hardhat resetTally --funding-round --network + * + * Note: + * 1) This script needs to be run by the coordinator + * 2) It can only be run if the funding round hasn't been finalized + */ +import { task } from 'hardhat/config' +import { getCurrentFundingRoundContract } from '../../utils/contracts' +import { Subtask } from '../helpers/Subtask' + +task('reset-tally', 'Reset the tally contract') + .addParam('clrfund', 'The clrfund contract address') + .setAction(async ({ clrfund }, hre) => { + const subtask = Subtask.getInstance(hre) + subtask.setHre(hre) + + let success = false + try { + await subtask.logStart() + + const [coordinator] = await hre.ethers.getSigners() + console.log('Coordinator address: ', await coordinator.getAddress()) + + const fundingRoundContract = await getCurrentFundingRoundContract( + clrfund, + coordinator, + hre.ethers + ) + + const tx = await fundingRoundContract.resetTally() + const receipt = await tx.wait() + if (receipt?.status !== 1) { + throw new Error('Failed to reset the tally contract') + } + + subtask.logTransaction(tx) + success = true + } catch (err) { + console.error( + '\n=========================================================\nERROR:', + err, + '\n' + ) + success = false + } + + await subtask.finish(success) + }) diff --git a/contracts/tasks/runners/setToken.ts b/contracts/tasks/runners/setToken.ts index f9fc9272a..348aac137 100644 --- a/contracts/tasks/runners/setToken.ts +++ b/contracts/tasks/runners/setToken.ts @@ -18,12 +18,11 @@ import { type ISubtaskParams } from '../helpers/types' task('set-token', 'Set the token in ClrFund') .addFlag('incremental', 'Incremental deployment') .addFlag('strict', 'Fail on warnings') - .addFlag('verify', 'Verify contracts at Etherscan') .addFlag('manageNonce', 'Manually increment nonce for each transaction') .addOptionalParam('clrfund', 'The ClrFund contract address') .addOptionalParam('skip', 'Skip steps with less or equal index', 0, types.int) .setAction(async (params: ISubtaskParams, hre) => { - const { verify, manageNonce } = params + const { manageNonce } = params const subtask = Subtask.getInstance(hre) subtask.setHre(hre) @@ -53,9 +52,4 @@ task('set-token', 'Set the token in ClrFund') } await subtask.finish(success) - - if (verify) { - console.log('Verify all contracts') - await hre.run('verify-all') - } }) diff --git a/contracts/tasks/runners/simulateContribute.ts b/contracts/tasks/runners/simulateContribute.ts new file mode 100644 index 000000000..dcfc2cb1b --- /dev/null +++ b/contracts/tasks/runners/simulateContribute.ts @@ -0,0 +1,214 @@ +/** + * Simulate contributions to a funding round. This script is mainly used for testing. + * + * Sample usage: + * yarn hardhat simulate-contribute --count \ + * --fund --network + * + * Make sure deployed-contracts.json exists with the funding round address + * Make sure to use a token with mint() function like 0x65bc8dd04808d99cf8aa6749f128d55c2051edde + */ + +import { Keypair, createMessage, Message, PubKey } from '@clrfund/common' + +import { UNIT } from '../../utils/constants' +import { getContractAt, getEventArg } from '../../utils/contracts' +import type { FundingRound, ERC20, Poll } from '../../typechain-types' +import { task, types } from 'hardhat/config' +import { EContracts } from '../../utils/types' +import { ContractStorage } from '../helpers/ContractStorage' +import { parseEther, Wallet } from 'ethers' + +const tokenAbi = [ + 'function mint(address,uint256)', + 'function transfer(address,uint256)', + 'function approve(address,uint256)', +] +/** + * Cast a vote by the contributor + * + * @param stateIndex The contributor stateIndex + * @param pollId The pollId + * @param contributorKeyPair The contributor MACI key pair + * @param coordinatorPubKey The coordinator MACI public key + * @param voiceCredits The total voice credits the contributor can use + * @param pollContract The poll contract with the vote function + */ +async function vote( + stateIndex: number, + pollId: bigint, + contributorKeyPair: Keypair, + coordinatorPubKey: PubKey, + voiceCredits: bigint, + pollContract: Poll +) { + const messages: Message[] = [] + const encPubKeys: PubKey[] = [] + let nonce = 1 + // Change key + const newContributorKeypair = new Keypair() + const [message, encPubKey] = createMessage( + stateIndex, + contributorKeyPair, + newContributorKeypair, + coordinatorPubKey, + null, + null, + nonce, + pollId + ) + messages.push(message) + encPubKeys.push(encPubKey) + nonce += 1 + // Vote + for (const recipientIndex of [1, 2]) { + const votes = BigInt(voiceCredits) / BigInt(2) + const [message, encPubKey] = createMessage( + stateIndex, + newContributorKeypair, + null, + coordinatorPubKey, + recipientIndex, + votes, + nonce, + pollId + ) + messages.push(message) + encPubKeys.push(encPubKey) + nonce += 1 + } + + const tx = await pollContract.publishMessageBatch( + messages.reverse().map((msg) => msg.asContractParam()), + encPubKeys.reverse().map((key) => key.asContractParam()) + ) + const receipt = await tx.wait() + if (receipt?.status !== 1) { + throw new Error(`Contributor ${stateIndex} failed to vote`) + } +} + +task('simulate-contribute', 'Contribute to a funding round') + .addParam('count', 'Number of contributors to simulate', 70, types.int) + .addParam('fund', 'Number of contributors to simulate', '0.01') + .setAction(async ({ count, fund }, { ethers, network }) => { + // gas for transactions + const value = parseEther(fund) + const contributionAmount = UNIT + + const [deployer] = await ethers.getSigners() + const storage = ContractStorage.getInstance() + const fundingRoundContractAddress = storage.mustGetAddress( + EContracts.FundingRound, + network.name + ) + const fundingRound = await ethers.getContractAt( + EContracts.FundingRound, + fundingRoundContractAddress + ) + + const pollId = await fundingRound.pollId() + const pollAddress = await fundingRound.poll() + const pollContract = await getContractAt( + EContracts.Poll, + pollAddress, + ethers + ) + + const rawCoordinatorPubKey = await pollContract.coordinatorPubKey() + const coordinatorPubKey = new PubKey([ + BigInt(rawCoordinatorPubKey.x), + BigInt(rawCoordinatorPubKey.y), + ]) + + const tokenAddress = await fundingRound.nativeToken() + const token = await ethers.getContractAt(tokenAbi, tokenAddress) + + const maciAddress = await fundingRound.maci() + const maci = await ethers.getContractAt(EContracts.MACI, maciAddress) + + const userRegistryAddress = await fundingRound.userRegistry() + const userRegistry = await ethers.getContractAt( + EContracts.SimpleUserRegistry, + userRegistryAddress + ) + + for (let i = 0; i < count; i++) { + const contributor = Wallet.createRandom(ethers.provider) + + let tx = await userRegistry.addUser(contributor.address) + let receipt = await tx.wait() + if (receipt.status !== 1) { + throw new Error(`Failed to add user to the user registry`) + } + + // transfer token to contributor first + tx = await token.mint(contributor.address, contributionAmount) + receipt = await tx.wait() + if (receipt.status !== 1) { + throw new Error(`Failed to mint token for ${contributor.address}`) + } + + tx = await deployer.sendTransaction({ value, to: contributor.address }) + receipt = await tx.wait() + if (receipt.status !== 1) { + throw new Error(`Failed to fund ${contributor.address}`) + } + + const contributorKeypair = new Keypair() + const tokenAsContributor = token.connect(contributor) as ERC20 + tx = await tokenAsContributor.approve( + fundingRound.target, + contributionAmount + ) + receipt = await tx.wait() + if (receipt.status !== 1) { + throw new Error('Failed to approve token') + } + + const fundingRoundAsContributor = fundingRound.connect( + contributor + ) as FundingRound + const contributionTx = await fundingRoundAsContributor.contribute( + contributorKeypair.pubKey.asContractParam(), + contributionAmount + ) + receipt = await contributionTx.wait() + if (receipt.status !== 1) { + throw new Error('Failed to contribute') + } + + const stateIndex = await getEventArg( + contributionTx, + maci, + 'SignUp', + '_stateIndex' + ) + const voiceCredits = await getEventArg( + contributionTx, + maci, + 'SignUp', + '_voiceCreditBalance' + ) + + console.log( + `Contributor ${ + contributor.address + } registered. State index: ${stateIndex}. Voice credits: ${voiceCredits.toString()}.` + ) + + const pollContractAsContributor = pollContract.connect( + contributor + ) as Poll + + await vote( + stateIndex, + pollId, + contributorKeypair, + coordinatorPubKey, + voiceCredits, + pollContractAsContributor + ) + console.log(`Contributor ${contributor.address} voted.`) + } + }) diff --git a/contracts/tasks/runners/tally.ts b/contracts/tasks/runners/tally.ts index eb135b3e8..94482b679 100644 --- a/contracts/tasks/runners/tally.ts +++ b/contracts/tasks/runners/tally.ts @@ -1,177 +1,43 @@ /** * Script for tallying votes which involves fetching MACI logs, generating proofs, - * and proving on chain - * - * This script can be rerun by passing in --maci-state-file and --tally-file - * If the --maci-state-file is passed, it will skip MACI log fetching - * If the --tally-file is passed, it will skip MACI log fetching and proof generation - * - * Make sure to set the following environment variables in the .env file - * 1) WALLET_PRIVATE_KEY or WALLET_MNEMONIC - * - coordinator's wallet private key to interact with contracts - * 2) COORDINATOR_MACISK - coordinator's MACI private key to decrypt messages + * proving on chain, and uploading tally results on chain * * Sample usage: - * * yarn hardhat tally --clrfund --maci-tx-hash --network * - * To rerun: - * - * yarn hardhat tally --clrfund --maci-state-file \ - * --tally-file --network + * This script can be re-run with the same input parameters */ -import { BaseContract, getNumber, Signer, NonceManager } from 'ethers' +import { getNumber } from 'ethers' import { task, types } from 'hardhat/config' +import { ClrFund } from '../../typechain-types' import { DEFAULT_SR_QUEUE_OPS, DEFAULT_GET_LOG_BATCH_SIZE, } from '../../utils/constants' -import { getIpfsHash } from '../../utils/ipfs' -import { JSONFile } from '../../utils/JSONFile' -import { - getGenProofArgs, - genProofs, - proveOnChain, - addTallyResultsBatch, - mergeMaciSubtrees, - genLocalState, - TallyData, -} from '../../utils/maci' -import { getMaciStateFilePath, getDirname } from '../../utils/misc' -import { FundingRound, Poll, Tally } from '../../typechain-types' -import { HardhatEthersHelpers } from '@nomicfoundation/hardhat-ethers/types' +import { getProofDirForRound } from '../../utils/misc' import { EContracts } from '../../utils/types' import { ContractStorage } from '../helpers/ContractStorage' import { Subtask } from '../helpers/Subtask' -/** - * Publish the tally IPFS hash on chain if it's not already published - * @param fundingRoundContract Funding round contract - * @param tallyData Tally data - */ -async function publishTallyHash( - fundingRoundContract: FundingRound, - tallyData: TallyData -) { - const tallyHash = await getIpfsHash(tallyData) - console.log(`Tally hash is ${tallyHash}`) - - const tallyHashOnChain = await fundingRoundContract.tallyHash() - if (tallyHashOnChain !== tallyHash) { - const tx = await fundingRoundContract.publishTallyHash(tallyHash) - const receipt = await tx.wait() - if (receipt?.status !== 1) { - throw new Error('Failed to publish tally hash on chain') - } - - console.log('Published tally hash on chain') - } -} -/** - * Submit tally data to funding round contract - * @param fundingRoundContract Funding round contract - * @param batchSize Number of tally results per batch - * @param tallyData Tally file content - */ -async function submitTallyResults( - fundingRoundContract: FundingRound, - recipientTreeDepth: number, - tallyData: TallyData, - batchSize: number -) { - const startIndex = await fundingRoundContract.totalTallyResults() - const total = tallyData.results.tally.length - console.log('Uploading tally results in batches of', batchSize) - const addTallyGas = await addTallyResultsBatch( - fundingRoundContract, - recipientTreeDepth, - tallyData, - getNumber(batchSize), - getNumber(startIndex), - (processed: number) => { - console.log(`Processed ${processed} / ${total}`) - } - ) - console.log('Tally results uploaded. Gas used:', addTallyGas.toString()) -} - -/** - * Return the current funding round contract handle - * @param clrfund ClrFund contract address - * @param coordinator Signer who will interact with the funding round contract - * @param hre Hardhat runtime environment - */ -async function getFundingRound( - clrfund: string, - coordinator: Signer, - ethers: HardhatEthersHelpers -): Promise { - const clrfundContract = await ethers.getContractAt( - EContracts.ClrFund, - clrfund, - coordinator - ) - - const fundingRound = await clrfundContract.getCurrentRound() - const fundingRoundContract = await ethers.getContractAt( - EContracts.FundingRound, - fundingRound, - coordinator - ) - - return fundingRoundContract as BaseContract as FundingRound -} - -/** - * Get the recipient tree depth (aka vote option tree depth) - * @param fundingRoundContract Funding round conract - * @param ethers Hardhat Ethers Helper - * @returns Recipient tree depth - */ -async function getRecipientTreeDepth( - fundingRoundContract: FundingRound, - ethers: HardhatEthersHelpers -): Promise { - const pollAddress = await fundingRoundContract.poll() - const pollContract = await ethers.getContractAt(EContracts.Poll, pollAddress) - const treeDepths = await (pollContract as BaseContract as Poll).treeDepths() - const voteOptionTreeDepth = treeDepths.voteOptionTreeDepth - return getNumber(voteOptionTreeDepth) -} - -/** - * Get the message processor contract address from the tally contract - * @param tallyAddress Tally contract address - * @param ethers Hardhat ethers helper - * @returns Message processor contract address - */ -async function getMessageProcessorAddress( - tallyAddress: string, - ethers: HardhatEthersHelpers -): Promise { - const tallyContract = (await ethers.getContractAt( - EContracts.Tally, - tallyAddress - )) as BaseContract as Tally - - const messageProcessorAddress = await tallyContract.messageProcessor() - return messageProcessorAddress -} - task('tally', 'Tally votes') .addOptionalParam('clrfund', 'ClrFund contract address') .addOptionalParam('maciTxHash', 'MACI creation transaction hash') - .addOptionalParam('maciStateFile', 'MACI state file') + .addOptionalParam( + 'maciStartBlock', + 'MACI creation block', + undefined, + types.int + ) .addFlag('manageNonce', 'Whether to manually manage transaction nonce') - .addOptionalParam('tallyFile', 'The tally file path') .addOptionalParam( 'batchSize', 'The batch size to upload tally result on-chain', - 10, + 8, types.int ) - .addParam('outputDir', 'The proof output directory', './proof_output') + .addParam('proofDir', 'The proof output directory', './proof_output') + .addParam('paramsDir', 'The circuit zkeys directory', './params') .addOptionalParam('rapidsnark', 'The rapidsnark prover path') .addOptionalParam( 'numQueueOps', @@ -197,11 +63,11 @@ task('tally', 'Tally votes') { clrfund, maciTxHash, + maciStartBlock, quiet, - maciStateFile, - outputDir, + proofDir, + paramsDir, numQueueOps, - tallyFile, blocksPerBatch, rapidsnark, sleep, @@ -212,140 +78,70 @@ task('tally', 'Tally votes') ) => { console.log('Verbose logging enabled:', !quiet) - const { ethers, network } = hre - const storage = ContractStorage.getInstance() - const subtask = Subtask.getInstance(hre) - subtask.setHre(hre) - - const [coordinatorSigner] = await ethers.getSigners() - if (!coordinatorSigner) { - throw new Error('Env. variable WALLET_PRIVATE_KEY not set') + const apiKey = process.env.PINATA_API_KEY + if (!apiKey) { + throw new Error('Env. variable PINATA_API_KEY not set') } - const coordinator = manageNonce - ? new NonceManager(coordinatorSigner) - : coordinatorSigner - console.log('Coordinator address: ', await coordinator.getAddress()) - const coordinatorMacisk = process.env.COORDINATOR_MACISK - if (!coordinatorMacisk) { - throw new Error('Env. variable COORDINATOR_MACISK not set') + const secretApiKey = process.env.PINATA_SECRET_API_KEY + if (!secretApiKey) { + throw new Error('Env. variable PINATA_SECRET_API_KEY not set') } - const circuit = subtask.getConfigField( - EContracts.VkRegistry, - 'circuit' - ) - const circuitDirectory = subtask.getConfigField( - EContracts.VkRegistry, - 'paramsDirectory' - ) + const storage = ContractStorage.getInstance() + const subtask = Subtask.getInstance(hre) + subtask.setHre(hre) await subtask.logStart() const clrfundContractAddress = - clrfund ?? storage.mustGetAddress(EContracts.ClrFund, network.name) - const fundingRoundContract = await getFundingRound( - clrfundContractAddress, - coordinator, - ethers - ) - console.log('Funding round contract', fundingRoundContract.target) - - const recipientTreeDepth = await getRecipientTreeDepth( - fundingRoundContract, - ethers - ) + clrfund ?? storage.mustGetAddress(EContracts.ClrFund, hre.network.name) - const pollId = await fundingRoundContract.pollId() - console.log('PollId', pollId) + const clrfundContract = subtask.getContract({ + name: EContracts.ClrFund, + address: clrfundContractAddress, + }) - const maciAddress = await fundingRoundContract.maci() - const maciTransactionHash = - maciTxHash ?? storage.getTxHash(maciAddress, network.name) - console.log('MACI address', maciAddress) + const fundingRoundContractAddress = await ( + await clrfundContract + ).getCurrentRound() - const tallyAddress = await fundingRoundContract.tally() - const messageProcessorAddress = await getMessageProcessorAddress( - tallyAddress, - ethers + const outputDir = getProofDirForRound( + proofDir, + hre.network.name, + fundingRoundContractAddress ) - const providerUrl = (network.config as any).url - - const outputPath = maciStateFile - ? maciStateFile - : getMaciStateFilePath(outputDir) - - await mergeMaciSubtrees({ - maciAddress, - pollId, + await hre.run('gen-proofs', { + clrfund: clrfundContractAddress, + maciStartBlock, + maciTxHash, numQueueOps, - signer: coordinator, + blocksPerBatch, + rapidsnark, + sleep, + proofDir: outputDir, + paramsDir, + manageNonce, quiet, }) - let tallyFilePath: string = tallyFile || '' - if (!tallyFile) { - if (!maciStateFile) { - await genLocalState({ - quiet, - outputPath, - pollId, - maciContractAddress: maciAddress, - coordinatorPrivateKey: coordinatorMacisk, - ethereumProvider: providerUrl, - transactionHash: maciTransactionHash, - blockPerBatch: blocksPerBatch, - signer: coordinator, - sleep, - }) - } - - const genProofArgs = getGenProofArgs({ - maciAddress, - pollId, - coordinatorMacisk, - rapidsnark, - circuitType: circuit, - circuitDirectory, - outputDir, - blocksPerBatch: getNumber(blocksPerBatch), - maciTxHash: maciTransactionHash, - maciStateFile: outputPath, - signer: coordinator, - quiet, - }) - await genProofs(genProofArgs) - tallyFilePath = genProofArgs.tallyFile - } - - const tally = JSONFile.read(tallyFilePath) as TallyData - const proofDir = getDirname(tallyFilePath) - console.log('Proof directory', proofDir) - // proveOnChain if not already processed - await proveOnChain({ - pollId, - proofDir, - subsidyEnabled: false, - maciAddress, - messageProcessorAddress, - tallyAddress, - signer: coordinator, + await hre.run('prove-on-chain', { + clrfund: clrfundContractAddress, + proofDir: outputDir, + manageNonce, quiet, }) // Publish tally hash if it is not already published - await publishTallyHash(fundingRoundContract, tally) - - // Submit tally results to the funding round contract - // This function can be re-run from where it left off - await submitTallyResults( - fundingRoundContract, - recipientTreeDepth, - tally, - batchSize - ) + await hre.run('publish-tally-results', { + clrfund: clrfundContractAddress, + proofDir: outputDir, + batchSize, + manageNonce, + quiet, + }) const success = true await subtask.finish(success) diff --git a/contracts/tasks/runners/verifyAll.ts b/contracts/tasks/runners/verifyAll.ts index ab4647563..7aa910b72 100644 --- a/contracts/tasks/runners/verifyAll.ts +++ b/contracts/tasks/runners/verifyAll.ts @@ -1,108 +1,352 @@ /* eslint-disable no-console */ import { task } from 'hardhat/config' -import type { IStorageInstanceEntry, IVerifyAllArgs } from '../helpers/types' +import { EContracts } from '../helpers/types' import { ContractStorage } from '../helpers/ContractStorage' import { ContractVerifier } from '../helpers/ContractVerifier' +import { + BrightIdUserRegistry, + ClrFund, + MerkleUserRegistry, + SemaphoreUserRegistry, + SnapshotUserRegistry, +} from '../../typechain-types' +import { BaseContract } from 'ethers' +import { HardhatEthersHelpers } from '@nomicfoundation/hardhat-ethers/types' +import { ZERO_ADDRESS } from '../../utils/constants' +import { ConstructorArguments } from '../helpers/ConstructorArguments' +import { getContractAt } from '../../utils/contracts' + +type ContractInfo = { + name: string + address: string +} + +type VerificationSummary = { + contract: string + ok: boolean + err?: string +} /** - * Main verification task which runs hardhat-etherscan task for all the deployed contract. + * Get the recipient registry contract name + * @param registryAddress The recipient registry contract address + * @param ethers The Hardhat Ethers helper + * @returns The recipient registry contract name */ -task('verify-all', 'Verify contracts listed in storage') - .addFlag('force', 'Ignore verified status') - .setAction(async ({ force = false }: IVerifyAllArgs, hre) => { - const storage = ContractStorage.getInstance() - const verifier = new ContractVerifier(hre) - const addressList: string[] = [] - const entryList: IStorageInstanceEntry[] = [] - let index = 0 +async function getRecipientRegistryName( + registryAddress: string, + ethers: HardhatEthersHelpers +): Promise { + try { + const contract = await ethers.getContractAt( + EContracts.KlerosGTCRAdapter, + registryAddress + ) + const tcr = await contract.tcr() + if (tcr === ZERO_ADDRESS) { + throw new Error( + 'Unexpected zero tcr from a Kleros recipient registry: ' + + registryAddress + ) + } + return EContracts.KlerosGTCRAdapter + } catch { + // not a kleros registry + } - const addEntry = (address: string, entry: IStorageInstanceEntry) => { - if (!entry.verify) { - return - } + // try optimistic + const contract = await ethers.getContractAt( + EContracts.OptimisticRecipientRegistry, + registryAddress + ) - addressList.push(address) - entryList.push(entry) - index += 1 - } + try { + await contract.challengePeriodDuration() + return EContracts.OptimisticRecipientRegistry + } catch { + // not optimistic, use simple registry + return EContracts.SimpleRecipientRegistry + } +} - const instances = storage.getInstances(hre.network.name) +/** + * Get the user registry contract name + * @param registryAddress The user registry contract address + * @param ethers The Hardhat Ethers helper + * @returns The user registry contract name + */ +async function getUserRegistryName( + registryAddress: string, + ethers: HardhatEthersHelpers +): Promise { + try { + const contract = (await ethers.getContractAt( + EContracts.BrightIdUserRegistry, + registryAddress + )) as BaseContract as BrightIdUserRegistry + await contract.context() + return EContracts.BrightIdUserRegistry + } catch { + // not a BrightId user registry + } - instances.forEach(([key, entry]) => { - if (entry.id.includes('Poseidon')) { - return - } + // try semaphore user registry + try { + const contract = (await ethers.getContractAt( + EContracts.SemaphoreUserRegistry, + registryAddress + )) as BaseContract as SemaphoreUserRegistry + await contract.isVerifiedSemaphoreId(1) + return EContracts.SemaphoreUserRegistry + } catch { + // not a semaphore user registry + } - addEntry(key, entry) + // try snapshot user regitry + try { + const contract = (await ethers.getContractAt( + EContracts.SnapshotUserRegistry, + registryAddress + )) as BaseContract as SnapshotUserRegistry + await contract.storageRoot() + } catch { + // not snapshot user registry + } + + // try merkle user regitry + try { + const contract = (await ethers.getContractAt( + EContracts.MerkleUserRegistry, + registryAddress + )) as BaseContract as MerkleUserRegistry + await contract.merkleRoot() + } catch { + // not merkle user registry + } + + return EContracts.SimpleUserRegistry +} + +/** + * Get the list of contracts to verify + * @param clrfund The ClrFund contract address + * @param ethers The Hardhat Ethers helper + * @returns The list of contracts to verify + */ +async function getContractList( + clrfund: string, + ethers: HardhatEthersHelpers +): Promise { + const userRegistries = new Set() + const recipientRegistries = new Set() + const contractList: ContractInfo[] = [ + { + name: EContracts.ClrFund, + address: clrfund, + }, + ] + + const clrfundContract = await getContractAt( + EContracts.ClrFund, + clrfund, + ethers + ) + + const fundingRoundFactoryAddress = await clrfundContract.roundFactory() + if (fundingRoundFactoryAddress !== ZERO_ADDRESS) { + contractList.push({ + name: EContracts.FundingRoundFactory, + address: fundingRoundFactoryAddress, }) + } - console.log( - '======================================================================' - ) - console.log( - '======================================================================' - ) - console.log( - `Verification batch with ${addressList.length} entries of ${index} total.` + const maciFactoryAddress = await clrfundContract.maciFactory() + if (maciFactoryAddress !== ZERO_ADDRESS) { + contractList.push({ + name: EContracts.MACIFactory, + address: maciFactoryAddress, + }) + + const maciFactory = await ethers.getContractAt( + EContracts.MACIFactory, + maciFactoryAddress ) - console.log( - '======================================================================' + const vkRegistryAddress = await maciFactory.vkRegistry() + contractList.push({ + name: EContracts.VkRegistry, + address: vkRegistryAddress, + }) + + const factories = await maciFactory.factories() + contractList.push({ + name: EContracts.PollFactory, + address: factories.pollFactory, + }) + + contractList.push({ + name: EContracts.TallyFactory, + address: factories.tallyFactory, + }) + + contractList.push({ + name: EContracts.MessageProcessorFactory, + address: factories.messageProcessorFactory, + }) + } + + const userRegistryAddress = await clrfundContract.userRegistry() + if (userRegistryAddress !== ZERO_ADDRESS) { + userRegistries.add(userRegistryAddress) + } + + const recipientRegistryAddress = await clrfundContract.recipientRegistry() + if (recipientRegistryAddress !== ZERO_ADDRESS) { + recipientRegistries.add(recipientRegistryAddress) + } + + const fundingRoundAddress = await clrfundContract.getCurrentRound() + if (fundingRoundAddress !== ZERO_ADDRESS) { + contractList.push({ + name: EContracts.FundingRound, + address: fundingRoundAddress, + }) + + const fundingRound = await ethers.getContractAt( + EContracts.FundingRound, + fundingRoundAddress ) - const summary: string[] = [] - for (let i = 0; i < addressList.length; i += 1) { - const address = addressList[i] - const entry = entryList[i] + const maciAddress = await fundingRound.maci() + if (maciAddress !== ZERO_ADDRESS) { + contractList.push({ + name: EContracts.MACI, + address: maciAddress, + }) + } - const params = entry.verify + // Poll + const pollAddress = await fundingRound.poll() + if (pollAddress !== ZERO_ADDRESS) { + contractList.push({ + name: EContracts.Poll, + address: pollAddress, + }) + } - console.log( - '\n======================================================================' - ) - console.log( - `[${i}/${addressList.length}] Verify contract: ${entry.id} ${address}` + // Tally + const tallyAddress = await fundingRound.tally() + if (tallyAddress !== ZERO_ADDRESS) { + contractList.push({ + name: EContracts.Tally, + address: tallyAddress, + }) + + // Verifier + const tallyContract = await ethers.getContractAt( + EContracts.Tally, + tallyAddress ) - console.log('\tArgs:', params?.args) + const verifierAddress = await tallyContract.verifier() + if (verifierAddress !== ZERO_ADDRESS) { + contractList.push({ + name: EContracts.Verifier, + address: verifierAddress, + }) + } + + // MessageProcessor + const messageProcessorAddress = await tallyContract.messageProcessor() + if (messageProcessorAddress !== ZERO_ADDRESS) { + contractList.push({ + name: EContracts.MessageProcessor, + address: messageProcessorAddress, + }) + } + } + + // User Registry + const userRegistryAddress = await fundingRound.userRegistry() + if (userRegistryAddress !== ZERO_ADDRESS) { + userRegistries.add(userRegistryAddress) + } + + // Recipient Registry + const recipientRegistryAddress = await fundingRound.recipientRegistry() + if (recipientRegistryAddress !== ZERO_ADDRESS) { + recipientRegistries.add(recipientRegistryAddress) + } + } + + for (const address of userRegistries) { + const name = await getUserRegistryName(address, ethers) + contractList.push({ + name, + address, + }) + } + + for (const address of recipientRegistries) { + const name = await getRecipientRegistryName(address, ethers) + contractList.push({ + name, + address, + }) + } - const verifiedEntity = storage.getVerified(address, hre.network.name) + return contractList +} - if (!force && verifiedEntity) { - console.log('Already verified') - } else { +/** + * Main verification task which runs hardhat-etherscan task for all the deployed contract. + */ +task('verify-all', 'Verify contracts listed in storage') + .addOptionalParam('clrfund', 'The ClrFund contract address') + .addFlag('force', 'Ignore verified status') + .setAction(async ({ clrfund }, hre) => { + const { ethers, network } = hre + + const storage = ContractStorage.getInstance() + const clrfundContractAddress = + clrfund ?? storage.mustGetAddress(EContracts.ClrFund, network.name) + + const contractList = await getContractList(clrfundContractAddress, ethers) + const constructorArguments = new ConstructorArguments(hre) + const verifier = new ContractVerifier(hre) + const summary: VerificationSummary[] = [] + + for (let i = 0; i < contractList.length; i += 1) { + const { name, address } = contractList[i] + + try { + const args = await constructorArguments.get(name, address, ethers) let contract: string | undefined let libraries: string | undefined - if (entry.id === 'AnyOldERC20Token') { - contract = 'contracts/AnyOldERC20Token.sol:AnyOldERC20Token' - } - // eslint-disable-next-line no-await-in-loop const [ok, err] = await verifier.verify( address, - params?.args ?? '', + args, libraries, contract ) - if (ok) { - storage.setVerified(address, hre.network.name, true) - } else { - summary.push(`${address} ${entry.id}: ${err}`) - } + summary.push({ contract: `${address} ${name}`, ok, err }) + } catch (e) { + // error getting the constructors, skipping + summary.push({ + contract: `${address} ${name}`, + ok: false, + err: 'Failed to get constructor. ' + (e as Error).message, + }) } } - console.log( - '\n======================================================================' - ) - console.log( - `Verification batch has finished with ${summary.length} issue(s).` - ) - console.log( - '======================================================================' - ) - console.log(summary.join('\n')) - console.log( - '======================================================================' - ) + summary.forEach(({ contract, ok, err }, i) => { + const color = ok ? '32' : '31' + console.log( + `${i + 1} ${contract}: \x1b[%sm%s\x1b[0m`, + color, + ok ? 'ok' : err + ) + }) }) diff --git a/contracts/tasks/runners/verifyDeployer.ts b/contracts/tasks/runners/verifyDeployer.ts new file mode 100644 index 000000000..284689063 --- /dev/null +++ b/contracts/tasks/runners/verifyDeployer.ts @@ -0,0 +1,33 @@ +import { task } from 'hardhat/config' +import { EContracts } from '../../utils/types' +import { ContractVerifier } from '../helpers/ContractVerifier' +import { ConstructorArguments } from '../helpers/ConstructorArguments' + +/** + * Verifies the ClrFundDeployer contract + * - it constructs the constructor arguments by querying the ClrFundDeployer contract + * - it calls the etherscan hardhat plugin to verify the contract + */ +task('verify-deployer', 'Verify a ClrFundDeployer contract') + .addParam('address', 'ClrFundDeployer contract address') + .setAction(async ({ address }, hre) => { + const contractVerifier = new ContractVerifier(hre) + const getter = new ConstructorArguments(hre) + + const name = EContracts.ClrFundDeployer + const constructorArgument = await getter.get( + EContracts.ClrFundDeployer, + address, + hre.ethers + ) + const [ok, err] = await contractVerifier.verify( + address, + constructorArgument + ) + + console.log( + `${address} ${name}: \x1b[%sm%s\x1b[0m`, + ok ? 32 : 31, + ok ? 'ok' : err + ) + }) diff --git a/contracts/tasks/subtasks/clrfund/03-setVkRegsitry.ts b/contracts/tasks/subtasks/clrfund/03-setVkRegsitry.ts index a3fefb412..fcbe9b1bb 100644 --- a/contracts/tasks/subtasks/clrfund/03-setVkRegsitry.ts +++ b/contracts/tasks/subtasks/clrfund/03-setVkRegsitry.ts @@ -3,6 +3,7 @@ import { setVerifyingKeys } from '../../../utils/contracts' import { MaciParameters } from '../../../utils/maciParameters' import { Subtask } from '../../helpers/Subtask' import { EContracts, ISubtaskParams } from '../../helpers/types' +import { EMode } from 'maci-contracts' const subtask = Subtask.getInstance() @@ -39,13 +40,15 @@ subtask stateTreeDepth, messageTreeDepth, voteOptionTreeDepth, - messageBatchSize + messageBatchSize, + EMode.QV ) const hasTallyVk = await vkRegistryContract.hasTallyVk( stateTreeDepth, intStateTreeDepth, - voteOptionTreeDepth + voteOptionTreeDepth, + EMode.QV ) if (incremental) { diff --git a/contracts/tasks/subtasks/clrfund/08-maciFactory.ts b/contracts/tasks/subtasks/clrfund/08-maciFactory.ts index cfaf146a6..c21c41817 100644 --- a/contracts/tasks/subtasks/clrfund/08-maciFactory.ts +++ b/contracts/tasks/subtasks/clrfund/08-maciFactory.ts @@ -48,8 +48,6 @@ subtask const factories = { pollFactory: pollFactoryContractAddress, tallyFactory: tallyFactoryContractAddress, - // subsidy is not currently used - subsidyFactory: ZERO_ADDRESS, messageProcessorFactory: messageProcessorFactoryContractAddress, } diff --git a/contracts/tasks/subtasks/coordinator/01-coordinator.ts b/contracts/tasks/subtasks/coordinator/01-coordinator.ts index 3b2f0b767..10685b5a7 100644 --- a/contracts/tasks/subtasks/coordinator/01-coordinator.ts +++ b/contracts/tasks/subtasks/coordinator/01-coordinator.ts @@ -44,19 +44,30 @@ subtask clrfundContract.coordinatorPubKey(), ]) - const currentPubKey = new PubKey([coordinatorPubKey.x, coordinatorPubKey.y]) + // if the coordinator has not been set in the clrfund contract + // use allowInvalid option to prevent it from throwing in new PubKey() + const allowInvalid = true + const currentPubKey = new PubKey( + [coordinatorPubKey.x, coordinatorPubKey.y], + allowInvalid + ) const newPrivKey = PrivKey.deserialize(coordinatorMacisk) const newKeypair = new Keypair(newPrivKey) const normalizedCurrentCoordinator = getAddress(currentCoordinator) const normalizedNewCoordinator = getAddress(coordinatorAddress) - console.log('Current coordinator', normalizedCurrentCoordinator) - console.log(' New coordinator', normalizedNewCoordinator) + console.log('Current coordinator:', normalizedCurrentCoordinator) + console.log(' New coordinator:', normalizedNewCoordinator) - const serializedCurrentPubKey = currentPubKey.serialize() + let serializedCurrentPubKey = 'Not set' + try { + serializedCurrentPubKey = currentPubKey.serialize() + } catch { + // if the public key was not set, serialize will throw. + } const serializedNewPubKey = newKeypair.pubKey.serialize() - console.log('Current MACI key', serializedCurrentPubKey) - console.log(' New MACI key', serializedNewPubKey) + console.log('Current MACI key:', serializedCurrentPubKey) + console.log(' New MACI key:', serializedNewPubKey) console.log() if ( diff --git a/contracts/tasks/subtasks/round/02-deploy-round.ts b/contracts/tasks/subtasks/round/02-deploy-round.ts index 812bf75b7..707216d2c 100644 --- a/contracts/tasks/subtasks/round/02-deploy-round.ts +++ b/contracts/tasks/subtasks/round/02-deploy-round.ts @@ -15,6 +15,7 @@ import { } from '../../../typechain-types' import { ContractTransactionResponse } from 'ethers' import { ISubtaskParams } from '../../helpers/types' +import { EMode } from 'maci-contracts' const subtask = Subtask.getInstance() const storage = ContractStorage.getInstance() @@ -69,7 +70,6 @@ async function registerMaci( maciContract.pollFactory(), maciContract.messageProcessorFactory(), maciContract.tallyFactory(), - maciContract.subsidyFactory(), maciContract.signUpGatekeeper(), maciContract.initialVoiceCreditProxy(), maciContract.topupCredit(), @@ -180,7 +180,7 @@ async function registerTallyAndMessageProcessor( tallyContract.vkRegistry(), ]) - let args = [verifier, vkRegistry, poll, mp] + let args = [verifier, vkRegistry, poll, mp, EMode.QV] await storage.register({ id: EContracts.Tally, contract: tallyContract, @@ -189,7 +189,7 @@ async function registerTallyAndMessageProcessor( tx, }) - args = [verifier, vkRegistry, poll] + args = [verifier, vkRegistry, poll, EMode.QV] await storage.register({ id: EContracts.MessageProcessor, contract: messageProcessorContract, diff --git a/contracts/tasks/subtasks/user/03-brightidSponsor.ts b/contracts/tasks/subtasks/user/03-brightidSponsor.ts deleted file mode 100644 index 9482a449e..000000000 --- a/contracts/tasks/subtasks/user/03-brightidSponsor.ts +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Deploy an instance of the BrightID sponsor contract - * - */ -import { ContractStorage } from '../../helpers/ContractStorage' -import { Subtask } from '../../helpers/Subtask' -import { EContracts } from '../../../utils/types' - -const subtask = Subtask.getInstance() -const storage = ContractStorage.getInstance() - -/** - * Deploy step registration and task itself - */ -subtask - .addTask('user:deploy-brightid-sponsor', 'Deploy BrightID sponsor contract') - .setAction(async (_, hre) => { - subtask.setHre(hre) - const deployer = await subtask.getDeployer() - - const userRegistryName = subtask.getConfigField( - EContracts.ClrFund, - 'userRegistry' - ) - - if (userRegistryName !== EContracts.BrightIdUserRegistry) { - return - } - - let brightidSponsorContractAddress = subtask.tryGetConfigField( - EContracts.BrightIdUserRegistry, - 'sponsor' - ) - - if (brightidSponsorContractAddress) { - console.log( - `Skip BrightIdSponsor deployment, use ${brightidSponsorContractAddress}` - ) - return - } - - brightidSponsorContractAddress = storage.getAddress( - EContracts.BrightIdSponsor, - hre.network.name - ) - - if (brightidSponsorContractAddress) { - return - } - - const BrightIdSponsorContract = await subtask.deployContract( - EContracts.BrightIdSponsor, - { signer: deployer } - ) - - await storage.register({ - id: EContracts.BrightIdSponsor, - contract: BrightIdSponsorContract, - args: [], - network: hre.network.name, - }) - }) diff --git a/contracts/tasks/subtasks/user/04-brightidUserRegistry.ts b/contracts/tasks/subtasks/user/04-brightidUserRegistry.ts index 6db98dc2c..73f1ce259 100644 --- a/contracts/tasks/subtasks/user/04-brightidUserRegistry.ts +++ b/contracts/tasks/subtasks/user/04-brightidUserRegistry.ts @@ -10,6 +10,10 @@ import { EContracts } from '../../../utils/types' const subtask = Subtask.getInstance() const storage = ContractStorage.getInstance() +// @TODO remove this on the next major release when the sponsor contract is removed +// Hardcode with a dummy address for now +const BRIGHTID_SPONSOR = '0xC7c81634Dac2de4E7f2Ba407B638ff003ce4534C' + /** * Deploy step registration and task itself */ @@ -58,15 +62,7 @@ subtask 'verifier' ) - let sponsor = subtask.tryGetConfigField( - EContracts.BrightIdUserRegistry, - 'sponsor' - ) - if (!sponsor) { - sponsor = storage.mustGetAddress(EContracts.BrightIdSponsor, network) - } - - const args = [encodeBytes32String(context), verifier, sponsor] + const args = [encodeBytes32String(context), verifier, BRIGHTID_SPONSOR] const brightidUserRegistryContract = await subtask.deployContract( EContracts.BrightIdUserRegistry, { signer: deployer, args } diff --git a/contracts/tests/deployer.ts b/contracts/tests/deployer.ts index f21353557..3eace1611 100644 --- a/contracts/tests/deployer.ts +++ b/contracts/tests/deployer.ts @@ -1,20 +1,27 @@ -import { ethers, config, artifacts } from 'hardhat' +import { ethers, artifacts } from 'hardhat' import { time } from '@nomicfoundation/hardhat-network-helpers' import { expect } from 'chai' import { BaseContract, Contract } from 'ethers' import { genRandomSalt } from 'maci-crypto' -import { Keypair } from '@clrfund/common' +import { Keypair, MACI_TREE_ARITY } from '@clrfund/common' -import { TREE_ARITY, ZERO_ADDRESS, UNIT } from '../utils/constants' -import { getGasUsage, getEventArg, deployContract } from '../utils/contracts' +import { ZERO_ADDRESS, UNIT } from '../utils/constants' +import { + getGasUsage, + getEventArg, + deployContract, + getContractAt, +} from '../utils/contracts' import { deployPoseidonLibraries, deployMaciFactory } from '../utils/testutils' import { MaciParameters } from '../utils/maciParameters' import { HardhatEthersSigner } from '@nomicfoundation/hardhat-ethers/signers' import { ClrFund, ClrFundDeployer, + FundingRound, FundingRoundFactory, MACIFactory, + Poll, } from '../typechain-types' import { EContracts } from '../utils/types' @@ -193,7 +200,8 @@ describe('Clr fund deployer', async () => { expect(await recipientRegistry.controller()).to.equal(clrfund.target) const params = MaciParameters.mock() expect(await recipientRegistry.maxRecipients()).to.equal( - BigInt(TREE_ARITY) ** BigInt(params.treeDepths.voteOptionTreeDepth) - + BigInt(MACI_TREE_ARITY) ** + BigInt(params.treeDepths.voteOptionTreeDepth) - BigInt(1) ) }) @@ -318,7 +326,11 @@ describe('Clr fund deployer', async () => { 'pollAddr' ) - const poll = await ethers.getContractAt('Poll', pollAddress.poll) + const poll = await getContractAt( + EContracts.Poll, + pollAddress.poll, + ethers + ) const roundCoordinatorPubKey = await poll.coordinatorPubKey() expect(roundCoordinatorPubKey.x).to.equal(coordinatorPubKey.x) expect(roundCoordinatorPubKey.y).to.equal(coordinatorPubKey.y) @@ -443,6 +455,14 @@ describe('Clr fund deployer', async () => { contributionAmount ) await clrfund.deployNewRound(roundDuration) + const roundAddress = await clrfund.getCurrentRound() + const roundContract = (await getContractAt( + EContracts.FundingRound, + roundAddress, + ethers, + coordinator + )) as FundingRound + await roundContract.publishTallyHash('xxx') await time.increase(roundDuration) await expect( clrfund.transferMatchingFunds( @@ -451,11 +471,19 @@ describe('Clr fund deployer', async () => { resultsCommitment, perVOVoiceCreditCommitment ) - ).to.be.revertedWithCustomError(roundInterface, 'VotesNotTallied') + ).to.be.revertedWithCustomError(roundInterface, 'IncompleteTallyResults') }) it('allows owner to finalize round even without matching funds', async () => { await clrfund.deployNewRound(roundDuration) + const roundAddress = await clrfund.getCurrentRound() + const roundContract = (await getContractAt( + EContracts.FundingRound, + roundAddress, + ethers, + coordinator + )) as FundingRound + await roundContract.publishTallyHash('xxx') await time.increase(roundDuration) await expect( clrfund.transferMatchingFunds( @@ -464,7 +492,7 @@ describe('Clr fund deployer', async () => { resultsCommitment, perVOVoiceCreditCommitment ) - ).to.be.revertedWithCustomError(roundInterface, 'VotesNotTallied') + ).to.be.revertedWithCustomError(roundInterface, 'IncompleteTallyResults') }) it('pulls funds from funding source', async () => { @@ -475,7 +503,15 @@ describe('Clr fund deployer', async () => { ) await clrfund.addFundingSource(deployer.address) // Doesn't have tokens await clrfund.deployNewRound(roundDuration) + const roundAddress = await clrfund.getCurrentRound() + const roundContract = (await getContractAt( + EContracts.FundingRound, + roundAddress, + ethers, + coordinator + )) as FundingRound await time.increase(roundDuration) + await roundContract.publishTallyHash('xxx') await expect( clrfund.transferMatchingFunds( totalSpent, @@ -483,7 +519,7 @@ describe('Clr fund deployer', async () => { resultsCommitment, perVOVoiceCreditCommitment ) - ).to.be.revertedWithCustomError(roundInterface, 'VotesNotTallied') + ).to.be.revertedWithCustomError(roundInterface, 'IncompleteTallyResults') }) it('pulls funds from funding source if allowance is greater than balance', async () => { @@ -493,7 +529,15 @@ describe('Clr fund deployer', async () => { contributionAmount * 2n ) await clrfund.deployNewRound(roundDuration) + const roundAddress = await clrfund.getCurrentRound() + const roundContract = (await getContractAt( + EContracts.FundingRound, + roundAddress, + ethers, + coordinator + )) as FundingRound await time.increase(roundDuration) + await roundContract.publishTallyHash('xxx') await expect( clrfund.transferMatchingFunds( totalSpent, @@ -501,7 +545,7 @@ describe('Clr fund deployer', async () => { resultsCommitment, perVOVoiceCreditCommitment ) - ).to.be.revertedWithCustomError(roundInterface, 'VotesNotTallied') + ).to.be.revertedWithCustomError(roundInterface, 'IncompleteTallyResults') }) it('allows only owner to finalize round', async () => { diff --git a/contracts/tests/maciFactory.ts b/contracts/tests/maciFactory.ts index 44296bbf9..fcaf8d483 100644 --- a/contracts/tests/maciFactory.ts +++ b/contracts/tests/maciFactory.ts @@ -1,4 +1,4 @@ -import { artifacts, ethers, config } from 'hardhat' +import { artifacts, ethers } from 'hardhat' import { Contract, TransactionResponse } from 'ethers' import { expect } from 'chai' import { deployMockContract, MockContract } from '@clrfund/waffle-mock-contract' @@ -89,7 +89,10 @@ describe('MACI factory', () => { coordinatorMaciFactory.setMaciParameters( ...maciParameters.asContractParam() ) - ).to.be.revertedWith('Ownable: caller is not the owner') + ).to.be.revertedWithCustomError( + coordinatorMaciFactory, + 'OwnableUnauthorizedAccount' + ) }) it('deploys MACI', async () => { diff --git a/contracts/tests/recipientRegistry.ts b/contracts/tests/recipientRegistry.ts index ea5932993..1e0124376 100644 --- a/contracts/tests/recipientRegistry.ts +++ b/contracts/tests/recipientRegistry.ts @@ -154,7 +154,10 @@ describe('Simple Recipient Registry', async () => { const registryAsRecipient = registry.connect(recipient) as Contract await expect( registryAsRecipient.addRecipient(recipientAddress, metadata) - ).to.be.revertedWith('Ownable: caller is not the owner') + ).to.be.revertedWithCustomError( + registryAsRecipient, + 'OwnableUnauthorizedAccount' + ) }) it('should not accept zero-address as recipient address', async () => { @@ -218,7 +221,10 @@ describe('Simple Recipient Registry', async () => { const registryAsRecipient = registry.connect(recipient) as Contract await expect( registryAsRecipient.removeRecipient(recipientId) - ).to.be.revertedWith('Ownable: caller is not the owner') + ).to.be.revertedWithCustomError( + registryAsRecipient, + 'OwnableUnauthorizedAccount' + ) }) it('reverts if recipient is not in registry', async () => { @@ -762,7 +768,7 @@ describe('Optimistic recipient registry', () => { recipientId, requester.address ) - ).to.be.revertedWith('Ownable: caller is not the owner') + ).to.be.revertedWithCustomError(registry, 'OwnableUnauthorizedAccount') }) it('should not allow to challenge resolved request', async () => { diff --git a/contracts/tests/round.ts b/contracts/tests/round.ts index c0fa4f813..fd6e8095b 100644 --- a/contracts/tests/round.ts +++ b/contracts/tests/round.ts @@ -10,9 +10,11 @@ import { randomBytes, hexlify, toNumber, + Wallet, + TransactionResponse, } from 'ethers' import { genRandomSalt } from 'maci-crypto' -import { Keypair } from '@clrfund/common' +import { getMaxContributors, Keypair, MACI_TREE_ARITY } from '@clrfund/common' import { time } from '@nomicfoundation/hardhat-network-helpers' import { @@ -21,7 +23,7 @@ import { VOICE_CREDIT_FACTOR, ALPHA_PRECISION, } from '../utils/constants' -import { getEventArg, getGasUsage } from '../utils/contracts' +import { getContractAt, getEventArg, getGasUsage } from '../utils/contracts' import { bnSqrt, createMessage, @@ -29,11 +31,15 @@ import { getRecipientClaimData, mergeMaciSubtrees, } from '../utils/maci' -import { deployTestFundingRound } from '../utils/testutils' +import { + deployTestFundingRound, + DeployTestFundingRoundOutput, +} from '../utils/testutils' // ethStaker test vectors for Quadratic Funding with alpha import smallTallyTestData from './data/testTallySmall.json' -import { FundingRound } from '../typechain-types' +import { AnyOldERC20Token, FundingRound } from '../typechain-types' +import { EContracts } from '../utils/types' const newResultCommitment = hexlify(randomBytes(32)) const perVOSpentVoiceCreditsHash = hexlify(randomBytes(32)) @@ -65,6 +71,33 @@ function calcAllocationAmount(tally: string, voiceCredit: string): bigint { return allocation / ALPHA_PRECISION } +/** + * Simulate contribution by a random user + * @param contracts list of contracts returned from the deployTestFundingRound function + * @param deployer the account that owns the contracts + * @returns contribute transaction response + */ +async function contributeByRandomUser( + contracts: DeployTestFundingRoundOutput, + deployer: HardhatEthersSigner +): Promise { + const amount = ethers.parseEther('0.1') + const keypair = new Keypair() + const user = Wallet.createRandom(ethers.provider) + await contracts.token.transfer(user.address, amount) + await deployer.sendTransaction({ to: user.address, value: amount }) + const tokenAsUser = contracts.token.connect(user) as AnyOldERC20Token + await tokenAsUser.approve(contracts.fundingRound.target, amount) + const fundingRoundAsUser = contracts.fundingRound.connect( + user + ) as FundingRound + const tx = await fundingRoundAsUser.contribute( + keypair.pubKey.asContractParam(), + amount + ) + return tx +} + describe('Funding Round', () => { const coordinatorPubKey = new Keypair().pubKey const roundDuration = 86400 * 7 @@ -100,13 +133,13 @@ describe('Funding Round', () => { beforeEach(async () => { const tokenInitialSupply = UNIT * BigInt(1000000) - const deployed = await deployTestFundingRound( - tokenInitialSupply + budget, - coordinator.address, - coordinatorPubKey, + const deployed = await deployTestFundingRound({ + tokenSupply: tokenInitialSupply + budget, + coordinatorAddress: coordinator.address, + coordinatorPubKey: coordinatorPubKey, roundDuration, - deployer - ) + deployer, + }) token = deployed.token fundingRound = deployed.fundingRound userRegistry = deployed.mockUserRegistry @@ -114,12 +147,13 @@ describe('Funding Round', () => { tally = deployed.mockTally const mockVerifier = deployed.mockVerifier - // make the verifier to alwasy returns true + // make the verifier to always returns true await mockVerifier.mock.verify.returns(true) await userRegistry.mock.isVerifiedUser.returns(true) await tally.mock.tallyBatchNum.returns(1) await tally.mock.verifyTallyResult.returns(true) await tally.mock.verifySpentVoiceCredits.returns(true) + await tally.mock.isTallied.returns(true) tokenAsContributor = token.connect(contributor) as Contract fundingRoundAsCoordinator = fundingRound.connect( @@ -136,7 +170,12 @@ describe('Funding Round', () => { maciAddress = await fundingRound.maci() maci = await ethers.getContractAt('MACI', maciAddress) const pollAddress = await fundingRound.poll() - poll = await ethers.getContractAt('Poll', pollAddress, deployer) + poll = await getContractAt( + EContracts.Poll, + pollAddress, + ethers, + deployer + ) pollId = await fundingRound.pollId() const treeDepths = await poll.treeDepths() @@ -199,8 +238,34 @@ describe('Funding Round', () => { ).to.equal(expectedVoiceCredits) }) + it('calculates max contributors correctly', async () => { + const stateTreeDepth = toNumber(await maci.stateTreeDepth()) + const maxUsers = MACI_TREE_ARITY ** stateTreeDepth - 1 + expect(getMaxContributors(stateTreeDepth)).to.eq(maxUsers) + }) + it('limits the number of contributors', async () => { - // TODO: add test later + // use a smaller stateTreeDepth to run the test faster + const stateTreeDepth = 1 + const contracts = await deployTestFundingRound({ + stateTreeDepth, + tokenSupply: UNIT * BigInt(1000000), + coordinatorAddress: coordinator.address, + coordinatorPubKey, + roundDuration, + deployer, + }) + await contracts.mockUserRegistry.mock.isVerifiedUser.returns(true) + + const maxUsers = getMaxContributors(stateTreeDepth) + for (let i = 0; i < maxUsers; i++) { + await contributeByRandomUser(contracts, deployer) + } + + // this should throw TooManySignups + await expect( + contributeByRandomUser(contracts, deployer) + ).to.be.revertedWithCustomError(maci, 'TooManySignups') }) it('rejects contributions if funding round has been finalized', async () => { @@ -243,7 +308,7 @@ describe('Funding Round', () => { it('requires approval', async () => { await expect( fundingRoundAsContributor.contribute(userPubKey, contributionAmount) - ).to.be.revertedWith('ERC20: insufficient allowance') + ).to.be.revertedWithCustomError(token, 'ERC20InsufficientAllowance') }) it('rejects contributions from unverified users', async () => { @@ -631,6 +696,7 @@ describe('Funding Round', () => { userKeypair.pubKey.asContractParam(), totalContributions ) + await tally.mock.isTallied.returns(false) await time.increase(roundDuration) await mergeMaciSubtrees({ maciAddress, pollId, signer: deployer }) @@ -744,7 +810,10 @@ describe('Funding Round', () => { newResultCommitment, perVOSpentVoiceCreditsHash ) - ).to.be.revertedWith('Ownable: caller is not the owner') + ).to.be.revertedWithCustomError( + fundingRoundAsCoordinator, + 'OwnableUnauthorizedAccount' + ) }) }) @@ -805,8 +874,11 @@ describe('Funding Round', () => { const fundingRoundAsCoordinator = fundingRound.connect( coordinator ) as Contract - await expect(fundingRoundAsCoordinator.cancel()).to.be.revertedWith( - 'Ownable: caller is not the owner' + await expect( + fundingRoundAsCoordinator.cancel() + ).to.be.revertedWithCustomError( + fundingRoundAsCoordinator, + 'OwnableUnauthorizedAccount' ) }) }) @@ -1424,7 +1496,7 @@ describe('Funding Round', () => { }) it('prevents adding tally results if maci has not completed tallying', async function () { - await tally.mock.tallyBatchNum.returns(0) + await tally.mock.isTallied.returns(false) await expect( addTallyResultsBatch( fundingRoundAsCoordinator, @@ -1436,7 +1508,7 @@ describe('Funding Round', () => { }) it('prevents adding batches of tally results if maci has not completed tallying', async function () { - await tally.mock.tallyBatchNum.returns(0) + await tally.mock.isTallied.returns(false) await expect( addTallyResultsBatch( fundingRoundAsCoordinator, diff --git a/contracts/tests/userRegistry.ts b/contracts/tests/userRegistry.ts index 63d05e76f..7d0c9e7bc 100644 --- a/contracts/tests/userRegistry.ts +++ b/contracts/tests/userRegistry.ts @@ -44,8 +44,11 @@ describe('Simple User Registry', () => { it('allows only owner to add users', async () => { const registryAsUser = registry.connect(user) as Contract - await expect(registryAsUser.addUser(user.address)).to.be.revertedWith( - 'Ownable: caller is not the owner' + await expect( + registryAsUser.addUser(user.address) + ).to.be.revertedWithCustomError( + registryAsUser, + 'OwnableUnauthorizedAccount' ) }) @@ -66,8 +69,11 @@ describe('Simple User Registry', () => { it('allows only owner to remove users', async () => { await registry.addUser(user.address) const registryAsUser = registry.connect(user) as Contract - await expect(registryAsUser.removeUser(user.address)).to.be.revertedWith( - 'Ownable: caller is not the owner' + await expect( + registryAsUser.removeUser(user.address) + ).to.be.revertedWithCustomError( + registryAsUser, + 'OwnableUnauthorizedAccount' ) }) }) diff --git a/contracts/tests/userRegistryMerkle.ts b/contracts/tests/userRegistryMerkle.ts index 87c021a55..8761e33dc 100644 --- a/contracts/tests/userRegistryMerkle.ts +++ b/contracts/tests/userRegistryMerkle.ts @@ -39,7 +39,10 @@ describe('Merkle User Registry', () => { const registryAsUser = registry.connect(signers[user1.address]) as Contract await expect( registryAsUser.setMerkleRoot(randomBytes(32), 'non owner') - ).to.be.revertedWith('Ownable: caller is not the owner') + ).to.be.revertedWithCustomError( + registryAsUser, + 'OwnableUnauthorizedAccount' + ) }) describe('registration', () => { diff --git a/contracts/tests/userRegistrySemaphore.ts b/contracts/tests/userRegistrySemaphore.ts index 95a71c4ef..af500261f 100644 --- a/contracts/tests/userRegistrySemaphore.ts +++ b/contracts/tests/userRegistrySemaphore.ts @@ -66,7 +66,10 @@ describe('Semaphore User Registry', () => { const registryAsUser = registry.connect(user) as Contract await expect( registryAsUser.addUser(user.address, semaphoreId) - ).to.be.revertedWith('Ownable: caller is not the owner') + ).to.be.revertedWithCustomError( + registryAsUser, + 'OwnableUnauthorizedAccount' + ) }) it('allows owner to remove user', async () => { @@ -88,8 +91,11 @@ describe('Semaphore User Registry', () => { const semaphoreId = 1 await registry.addUser(user.address, semaphoreId) const registryAsUser = registry.connect(user) as Contract - await expect(registryAsUser.removeUser(user.address)).to.be.revertedWith( - 'Ownable: caller is not the owner' + await expect( + registryAsUser.removeUser(user.address) + ).to.be.revertedWithCustomError( + registryAsUser, + 'OwnableUnauthorizedAccount' ) }) diff --git a/contracts/tests/userRegistrySnapshot.ts b/contracts/tests/userRegistrySnapshot.ts index 3a52f0a26..7b5b37d14 100644 --- a/contracts/tests/userRegistrySnapshot.ts +++ b/contracts/tests/userRegistrySnapshot.ts @@ -65,7 +65,9 @@ async function addUser( return userRegistry.addUser(userAccount, proofRlpBytes) } -describe('SnapshotUserRegistry', function () { +// TODO: find a better way to test snapshot. Currently this test fails +// because snapshot too old, it becomes unable +describe.skip('SnapshotUserRegistry', function () { let userRegistry: Contract let block: Block diff --git a/contracts/utils/RecipientRegistryLogProcessor.ts b/contracts/utils/RecipientRegistryLogProcessor.ts index 615ab1cb0..6d74a4334 100644 --- a/contracts/utils/RecipientRegistryLogProcessor.ts +++ b/contracts/utils/RecipientRegistryLogProcessor.ts @@ -7,6 +7,7 @@ import { Log } from './providers/BaseProvider' import { toDate } from './date' import { EVENT_ABIS } from './abi' import { AbiInfo } from './types' +import { HardhatConfig } from 'hardhat/types' function getFilter(address: string, abiInfo: AbiInfo): EventFilter { const eventInterface = new Interface([abiInfo.abi]) @@ -41,14 +42,14 @@ export class RecipientRegistryLogProcessor { endBlock, startBlock, blocksPerBatch, - etherscanApiKey, + config, network, }: { recipientRegistry: Contract startBlock: number endBlock: number blocksPerBatch: number - etherscanApiKey: string + config: HardhatConfig network: string }): Promise { // fetch event logs containing project information @@ -64,7 +65,7 @@ export class RecipientRegistryLogProcessor { const logProvider = ProviderFactory.createProvider({ network, - etherscanApiKey, + config, }) let logs: Log[] = [] diff --git a/contracts/utils/abi.ts b/contracts/utils/abi.ts index 98101978a..dc3c0c004 100644 --- a/contracts/utils/abi.ts +++ b/contracts/utils/abi.ts @@ -6,6 +6,17 @@ type EventAbiEntry = { remove: AbiInfo } +/** + * MACI v0 ABI used in exportRound.ts + */ +export const MaciV0Abi = [ + 'function signUpTimestamp() view returns (uint256)', + 'function signUpDurationSeconds() view returns (uint256)', + 'function votingDurationSeconds() view returns (uint256)', + `function treeDepths() view returns ((uint8 stateTreeDepth, uint8 messageTreeDepth, uint8 voteOptionTreeDepth))`, + 'function numMessages() view returns (uint256)', +] + export const getRecipientAddressAbi = [ `function getRecipientAddress(uint256 _index, uint256 _startTime, uint256 _endTime)` + ` external view returns (address)`, diff --git a/contracts/utils/circuits.ts b/contracts/utils/circuits.ts index f7cba55e6..acc73fca7 100644 --- a/contracts/utils/circuits.ts +++ b/contracts/utils/circuits.ts @@ -4,9 +4,7 @@ // the EmptyBallotRoots.sol published in MACI npm package is hardcoded for stateTreeDepth = 6 import path from 'path' - -// This should match MACI.TREE_ARITY in the contract -const TREE_ARITY = 5 +import { MACI_TREE_ARITY } from '@clrfund/common' export const DEFAULT_CIRCUIT = 'micro' @@ -65,11 +63,11 @@ export const CIRCUITS: { [name: string]: CircuitInfo } = { // maxMessages and maxVoteOptions are calculated using treeArity = 5 as seen in the following code: // https://github.com/privacy-scaling-explorations/maci/blob/master/contracts/contracts/Poll.sol#L115 // treeArity ** messageTreeDepth - maxMessages: BigInt(TREE_ARITY ** 9), + maxMessages: BigInt(MACI_TREE_ARITY ** 9), // treeArity ** voteOptionTreeDepth - maxVoteOptions: BigInt(TREE_ARITY ** 3), + maxVoteOptions: BigInt(MACI_TREE_ARITY ** 3), }, - messageBatchSize: BigInt(TREE_ARITY ** 2), + messageBatchSize: BigInt(MACI_TREE_ARITY ** 2), }, } diff --git a/contracts/utils/constants.ts b/contracts/utils/constants.ts index dfdbcd011..70687b10a 100644 --- a/contracts/utils/constants.ts +++ b/contracts/utils/constants.ts @@ -5,7 +5,6 @@ export const VOICE_CREDIT_FACTOR = 10n ** BigInt(4 + 18 - 9) export const ALPHA_PRECISION = 10n ** 18n export const DEFAULT_SR_QUEUE_OPS = '4' export const DEFAULT_GET_LOG_BATCH_SIZE = 20000 -export const TREE_ARITY = 5 // brightid.clr.fund node uses this to sign messages // see the ethSigningAddress in https://brightid.clr.fund diff --git a/contracts/utils/contracts.ts b/contracts/utils/contracts.ts index e60d11a76..3c26cf5d8 100644 --- a/contracts/utils/contracts.ts +++ b/contracts/utils/contracts.ts @@ -2,6 +2,7 @@ import { BaseContract, ContractTransactionResponse, TransactionResponse, + Signer, } from 'ethers' import { getEventArg } from '@clrfund/common' import { EContracts } from './types' @@ -9,9 +10,9 @@ import { DeployContractOptions, HardhatEthersHelpers, } from '@nomicfoundation/hardhat-ethers/types' -import { VkRegistry } from '../typechain-types' +import { VkRegistry, FundingRound } from '../typechain-types' import { MaciParameters } from './maciParameters' -import { IVerifyingKeyStruct } from 'maci-contracts' +import { EMode, IVerifyingKeyStruct } from 'maci-contracts' /** * Deploy a contract @@ -26,7 +27,7 @@ export async function deployContract( options?: DeployContractOptions & { args?: unknown[]; quiet?: boolean } ): Promise { const args = options?.args || [] - const contractName = String(name).includes('Poseidon') ? ':' + name : name + const contractName = getQualifiedContractName(name) const contract = await ethers.deployContract(contractName, args, options) await contract.waitForDeployment() @@ -53,6 +54,7 @@ export async function setVerifyingKeys( params.treeDepths.messageTreeDepth, params.treeDepths.voteOptionTreeDepth, messageBatchSize, + EMode.QV, params.processVk.asContractParam() as IVerifyingKeyStruct, params.tallyVk.asContractParam() as IVerifyingKeyStruct ) @@ -89,4 +91,66 @@ export async function getTxFee( return receipt ? BigInt(receipt.gasUsed) * BigInt(receipt.gasPrice) : 0n } +/** + * Return the current funding round contract handle + * @param clrfund ClrFund contract address + * @param signer Signer who will interact with the funding round contract + * @param hre Hardhat runtime environment + */ +export async function getCurrentFundingRoundContract( + clrfund: string, + signer: Signer, + ethers: HardhatEthersHelpers +): Promise { + const clrfundContract = await ethers.getContractAt( + EContracts.ClrFund, + clrfund, + signer + ) + + const fundingRound = await clrfundContract.getCurrentRound() + const fundingRoundContract = await ethers.getContractAt( + EContracts.FundingRound, + fundingRound, + signer + ) + + return fundingRoundContract as BaseContract as FundingRound +} + +/** + * Return the fully qualified contract name for Poll and PollFactory + * since there is a local copy and another in the maci-contracts + * otherwise return the name of the contract + * @param name The contract name + * @returns The qualified contract name + */ +export function getQualifiedContractName(name: EContracts | string): string { + let contractName = String(name) + if (contractName.includes('Poseidon')) { + contractName = `:${name}` + } + return contractName +} + +/** + * Get a contract + * @param name Name of the contract + * @param address The contract address + * @param ethers Hardhat ethers handle + * @param signers The signer + * @returns contract + */ +export async function getContractAt( + name: EContracts, + address: string, + ethers: HardhatEthersHelpers, + signer?: Signer +): Promise { + const contractName = getQualifiedContractName(name) + const contract = await ethers.getContractAt(contractName, address, signer) + + return contract as BaseContract as T +} + export { getEventArg } diff --git a/contracts/utils/ipfs.ts b/contracts/utils/ipfs.ts index 8fc5de275..092d9a876 100644 --- a/contracts/utils/ipfs.ts +++ b/contracts/utils/ipfs.ts @@ -2,7 +2,9 @@ const Hash = require('ipfs-only-hash') import { FetchRequest } from 'ethers' import { DEFAULT_IPFS_GATEWAY } from './constants' - +import fs from 'fs' +import path from 'path' +import pinataSDK from '@pinata/sdk' /** * Get the ipfs hash for the input object * @param object a json object to get the ipfs hash for @@ -26,4 +28,28 @@ export class Ipfs { const resp = await req.send() return resp.bodyJson } + + /** + * Pin a file to IPFS + * @param file The file path to be uploaded to IPFS + * @param apiKey Pinata api key + * @param secretApiKey Pinata secret api key + * @returns IPFS hash + */ + static async pinFile( + file: string, + apiKey: string, + secretApiKey: string + ): Promise { + const pinata = new pinataSDK(apiKey, secretApiKey) + const data = fs.createReadStream(file) + const name = path.basename(file) + const options = { + pinataMetadata: { + name, + }, + } + const res = await pinata.pinFileToIPFS(data, options) + return res.IpfsHash + } } diff --git a/contracts/utils/maci.ts b/contracts/utils/maci.ts index 6065f383d..340134752 100644 --- a/contracts/utils/maci.ts +++ b/contracts/utils/maci.ts @@ -7,7 +7,7 @@ import { hash5, hash3, hashLeftRight, - LEAVES_PER_NODE, + MACI_TREE_ARITY, genTallyResultCommitment, Keypair, Tally as TallyData, @@ -23,7 +23,7 @@ import { verify, } from 'maci-cli' -import { getTalyFilePath, isPathExist } from './misc' +import { isPathExist } from './misc' import { getCircuitFiles } from './circuits' import { FundingRound } from '../typechain-types' @@ -50,7 +50,7 @@ export function getTallyResultProof( const resultTree = new IncrementalQuinTree( recipientTreeDepth, BigInt(0), - LEAVES_PER_NODE, + MACI_TREE_ARITY, hash5 ) for (const leaf of tally.results.tally) { @@ -183,6 +183,8 @@ type getGenProofArgsInput = { endBlock?: number // MACI state file maciStateFile?: string + // Tally output file + tallyFile: string // transaction signer signer: Signer // flag to turn on verbose logging in MACI cli @@ -206,12 +208,11 @@ export function getGenProofArgs(args: getGenProofArgsInput): GenProofsArgs { startBlock, endBlock, maciStateFile, + tallyFile, signer, quiet, } = args - const tallyFile = getTalyFilePath(outputDir) - const { processZkFile, tallyZkFile, @@ -302,7 +303,7 @@ export async function mergeMaciSubtrees({ await mergeMessages({ pollId, - maciContractAddress: maciAddress, + maciAddress, numQueueOps, signer, quiet, @@ -310,7 +311,7 @@ export async function mergeMaciSubtrees({ await mergeSignups({ pollId, - maciContractAddress: maciAddress, + maciAddress, numQueueOps, signer, quiet, diff --git a/contracts/utils/maciParameters.ts b/contracts/utils/maciParameters.ts index e498a15e9..0e04d25ce 100644 --- a/contracts/utils/maciParameters.ts +++ b/contracts/utils/maciParameters.ts @@ -3,7 +3,7 @@ import { Contract, BigNumberish } from 'ethers' import { VerifyingKey } from 'maci-domainobjs' import { extractVk } from 'maci-circuits' import { CIRCUITS, getCircuitFiles } from './circuits' -import { TREE_ARITY } from './constants' +import { MACI_TREE_ARITY } from '@clrfund/common' import { Params } from '../typechain-types/contracts/MACIFactory' type TreeDepths = { @@ -36,15 +36,28 @@ export class MaciParameters { * @returns message batch size */ getMessageBatchSize(): number { - return TREE_ARITY ** this.treeDepths.messageTreeSubDepth + return MACI_TREE_ARITY ** this.treeDepths.messageTreeSubDepth + } + + /** + * Calculate the maximum recipients allowed by the MACI circuit + * @returns maximum recipient count + */ + getMaxRecipients(): number { + // -1 because recipients is 0 index based and the 0th slot is reserved + return MACI_TREE_ARITY ** this.treeDepths.voteOptionTreeDepth - 1 } asContractParam(): [ _stateTreeDepth: BigNumberish, + _messageBatchSize: BigNumberish, + _maxRecipients: BigNumberish, _treeDepths: Params.TreeDepthsStruct, ] { return [ this.stateTreeDepth, + this.getMessageBatchSize(), + this.getMaxRecipients(), { intStateTreeDepth: this.treeDepths.intStateTreeDepth, messageTreeSubDepth: this.treeDepths.messageTreeSubDepth, diff --git a/contracts/utils/misc.ts b/contracts/utils/misc.ts index 34bb53482..9f7a34297 100644 --- a/contracts/utils/misc.ts +++ b/contracts/utils/misc.ts @@ -19,6 +19,29 @@ export function getMaciStateFilePath(directory: string) { return path.join(directory, 'maci-state.json') } +/** + * Return the proof output directory + * @param directory The root directory + * @param network The network + * @param roundAddress The funding round contract address + * @returns The proofs output directory + */ +export function getProofDirForRound( + directory: string, + network: string, + roundAddress: string +) { + try { + return path.join( + directory, + network.toLowerCase(), + roundAddress.toLowerCase() + ) + } catch { + return directory + } +} + /** * Check if the path exist * @param path The path to check for existence @@ -29,10 +52,9 @@ export function isPathExist(path: string): boolean { } /** - * Returns the directory of the path - * @param file The file path - * @returns The directory of the file + * Create a directory + * @param directory The directory to create */ -export function getDirname(file: string): string { - return path.dirname(file) +export function makeDirectory(directory: string): void { + fs.mkdirSync(directory, { recursive: true }) } diff --git a/contracts/utils/parsers/RequestResolvedParser.ts b/contracts/utils/parsers/RequestResolvedParser.ts index 271cb563e..7b55c97a4 100644 --- a/contracts/utils/parsers/RequestResolvedParser.ts +++ b/contracts/utils/parsers/RequestResolvedParser.ts @@ -15,7 +15,7 @@ export class RequestResolvedParser extends BaseParser { const timestamp = toDate(args._timestamp) let state = - args._type === 1 ? RecipientState.Removed : RecipientState.Accepted + args._type === 1n ? RecipientState.Removed : RecipientState.Accepted if (args._rejected) { state = RecipientState.Rejected diff --git a/contracts/utils/providers/EtherscanProvider.ts b/contracts/utils/providers/EtherscanProvider.ts index 5a35ac557..047ccdbea 100644 --- a/contracts/utils/providers/EtherscanProvider.ts +++ b/contracts/utils/providers/EtherscanProvider.ts @@ -1,7 +1,9 @@ import { BaseProvider, FetchLogArgs, Log } from './BaseProvider' import { FetchRequest } from 'ethers' +import { HardhatConfig } from 'hardhat/types' const EtherscanApiUrl: Record = { + sepolia: 'https://api-sepolia.etherscan.io', xdai: 'https://api.gnosisscan.io', arbitrum: 'https://api.arbiscan.io', 'arbitrum-goerli': 'https://api-goerli.arbiscan.io', @@ -10,14 +12,57 @@ const EtherscanApiUrl: Record = { 'optimism-sepolia': 'https://api-sepolia-optimistic.etherscan.io', } +/** + * Mapping of the hardhat network name to the Etherscan network name in the hardhat.config + */ +const EtherscanNetworks: Record = { + arbitrum: 'arbitrumOne', + optimism: 'optimisticEthereum', +} + +/** + * The the Etherscan API key from the hardhat.config file + * @param config The Hardhat config object + * @param network The Hardhat network name + * @returns The Etherscan API key + */ +function getEtherscanApiKey(config: HardhatConfig, network: string): string { + let etherscanApiKey = '' + if (config.etherscan?.apiKey) { + if (typeof config.etherscan.apiKey === 'string') { + etherscanApiKey = config.etherscan.apiKey + } else { + const etherscanNetwork = EtherscanNetworks[network] ?? network + etherscanApiKey = config.etherscan.apiKey[etherscanNetwork] + } + } + + return etherscanApiKey +} + export class EtherscanProvider extends BaseProvider { apiKey: string network: string + baseUrl: string - constructor(apiKey: string, network: string) { + constructor(config: HardhatConfig, network: string) { super() - this.apiKey = apiKey + + const etherscanApiKey = getEtherscanApiKey(config, network) + if (!etherscanApiKey) { + throw new Error(`Etherscan API key is not found for ${network}`) + } + + const etherscanBaseUrl = EtherscanApiUrl[network] + if (!etherscanBaseUrl) { + throw new Error( + `Network ${network} is not supported in etherscan fetch log api` + ) + } + this.network = network + this.apiKey = etherscanApiKey + this.baseUrl = etherscanBaseUrl } async fetchLogs({ @@ -25,17 +70,10 @@ export class EtherscanProvider extends BaseProvider { startBlock, lastBlock, }: FetchLogArgs): Promise { - const baseUrl = EtherscanApiUrl[this.network] - if (!baseUrl) { - throw new Error( - `Network ${this.network} is not supported in etherscan fetch log api` - ) - } - const topic0 = filter.topics?.[0] || '' const toBlockQuery = lastBlock ? `&toBlock=${lastBlock}` : '' const url = - `${baseUrl}/api?module=logs&action=getLogs&address=${filter.address}` + + `${this.baseUrl}/api?module=logs&action=getLogs&address=${filter.address}` + `&topic0=${topic0}&fromBlock=${startBlock}${toBlockQuery}&apikey=${this.apiKey}` const req = new FetchRequest(url) diff --git a/contracts/utils/providers/ProviderFactory.ts b/contracts/utils/providers/ProviderFactory.ts index 6a79ad0ec..b7c5474d2 100644 --- a/contracts/utils/providers/ProviderFactory.ts +++ b/contracts/utils/providers/ProviderFactory.ts @@ -1,17 +1,15 @@ +import { HardhatConfig } from 'hardhat/types' import { BaseProvider } from './BaseProvider' import { EtherscanProvider } from './EtherscanProvider' export type CreateProviderArgs = { network: string - etherscanApiKey: string + config: HardhatConfig } export class ProviderFactory { - static createProvider({ - network, - etherscanApiKey, - }: CreateProviderArgs): BaseProvider { + static createProvider({ network, config }: CreateProviderArgs): BaseProvider { // use etherscan provider only as JsonRpcProvider is not reliable - return new EtherscanProvider(etherscanApiKey, network) + return new EtherscanProvider(config, network) } } diff --git a/contracts/utils/testutils.ts b/contracts/utils/testutils.ts index db63401ec..6d80b7a71 100644 --- a/contracts/utils/testutils.ts +++ b/contracts/utils/testutils.ts @@ -1,6 +1,6 @@ import { Signer, Contract } from 'ethers' import { MockContract, deployMockContract } from '@clrfund/waffle-mock-contract' -import { artifacts, ethers, config } from 'hardhat' +import { artifacts, ethers } from 'hardhat' import { MaciParameters } from './maciParameters' import { PubKey } from '@clrfund/common' import { deployContract, getEventArg, setVerifyingKeys } from './contracts' @@ -9,6 +9,7 @@ import { EContracts } from './types' import { Libraries } from 'hardhat/types' import { MACIFactory, VkRegistry } from '../typechain-types' import { ZERO_ADDRESS } from './constants' +import { EMode } from 'maci-contracts' /** * Deploy a mock contract with the given contract name @@ -127,8 +128,6 @@ export async function deployMaciFactory({ const factories = { pollFactory: pollFactory.target, tallyFactory: tallyFactory.target, - // subsidy is not currently used - subsidyFactory: ZERO_ADDRESS, messageProcessorFactory: messageProcessorFactory.target, } @@ -170,13 +169,21 @@ export type DeployTestFundingRoundOutput = { * @param deployer singer for the contract deployment * @returns all the deployed objects in DeployTestFundingRoundOutput */ -export async function deployTestFundingRound( - tokenSupply: bigint, - coordinatorAddress: string, - coordinatorPubKey: PubKey, - roundDuration: number, +export async function deployTestFundingRound({ + stateTreeDepth, + tokenSupply, + coordinatorAddress, + coordinatorPubKey, + roundDuration, + deployer, +}: { + stateTreeDepth?: number + tokenSupply: bigint + coordinatorAddress: string + coordinatorPubKey: PubKey + roundDuration: number deployer: Signer -): Promise { +}): Promise { const token = await ethers.deployContract( EContracts.AnyOldERC20Token, [tokenSupply], @@ -209,6 +216,12 @@ export async function deployTestFundingRound( }) const maciParameters = MaciParameters.mock() + + // use the stateTreeDepth from input + if (stateTreeDepth != undefined) { + maciParameters.stateTreeDepth = stateTreeDepth + } + const maciFactory = await deployMaciFactory({ libraries, ethers, @@ -236,7 +249,6 @@ export async function deployTestFundingRound( factories.pollFactory, factories.messageProcessorFactory, factories.tallyFactory, - factories.subsidyFactory, fundingRound.target, fundingRound.target, topupToken.target, @@ -254,8 +266,7 @@ export async function deployTestFundingRound( coordinatorPubKey.asContractParam(), mockVerifier.target, vkRegistry.target, - // pass false to not deploy the subsidy contract - false + EMode.QV ) const pollAddr = await getEventArg( deployPollTx, diff --git a/contracts/utils/types.ts b/contracts/utils/types.ts index ba8f753f4..a389bec65 100644 --- a/contracts/utils/types.ts +++ b/contracts/utils/types.ts @@ -27,6 +27,8 @@ export enum EContracts { IUserRegistry = 'IUserRegistry', SimpleUserRegistry = 'SimpleUserRegistry', SemaphoreUserRegistry = 'SemaphoreUserRegistry', + SnapshotUserRegistry = 'SnapshotUserRegistry', + MerkleUserRegistry = 'MerkleUserRegistry', BrightIdUserRegistry = 'BrightIdUserRegistry', AnyOldERC20Token = 'AnyOldERC20Token', BrightIdSponsor = 'BrightIdSponsor', diff --git a/docs/brightid.md b/docs/brightid.md index efd01636d..5c84d799e 100644 --- a/docs/brightid.md +++ b/docs/brightid.md @@ -18,13 +18,13 @@ USER_REGISTRY_TYPE=brightid Available envs: -| Network/Env | Context | Sponsor Contract | -| ----------- | ------- | ---------------- | -| arbitrum | clrfund-arbitrum |0x669A55Dd17a2f9F4dacC37C7eeB5Ed3e13f474f9| -| arbitrum rinkeby | clrfund-arbitrum-rinkeby | 0xC7c81634Dac2de4E7f2Ba407B638ff003ce4534C | -| arbitrum sepolia | clrfund-arbitrum-goerli | 0xF1ef516dEa7e6Dd334996726D58029Ee9bAD081D | -| goerli | clrfund-goerli | 0xF045234A776C87060DEEc5689056455A24a59c08 | -| xdai | clrfund-gnosischain |0x669A55Dd17a2f9F4dacC37C7eeB5Ed3e13f474f9| +| Network/Env | Context | +| ----------- | ------- | +| arbitrum | clrfund-arbitrum | +| arbitrum rinkeby | clrfund-arbitrum-rinkeby | +| arbitrum sepolia | clrfund-arbitrum-goerli | +| goerli | clrfund-goerli | +| xdai | clrfund-gnosischain | ```.sh # /vue-app/.env @@ -35,7 +35,6 @@ BRIGHTID_CONTEXT={CONTEXT} ``` Note: the BrightID context is specific to the BrightID network - it's independent from the Ethereum network you choose to run the app on. It refers to the BrightID app context where you want to burn sponsorship tokens. -The `Sponsor Contract` is the contract set up in the BrightID node to track the sponsorship event. The BrightID context can be found here: https://apps.brightid.org/#nodes @@ -55,38 +54,20 @@ BRIGHTID_VERIFIER_ADDR=0xdbf0b2ee9887fe11934789644096028ed3febe9c By default, the clrfund app will connect to the BrightId node run by clrfund, https://brightid.clr.fund. -**#4 configure the BrightID sponsorship page** -By default, the clrfund app will sponsor the BrightId users using the smart contract event logging method. The `Sponsor` contract is listed in the step #2 above. - -Alternatively, you can configure the clrfund app to use the BrightId sponsorship api to submit the sponsorship request directly by setting the following environment variables. Only one of VITE_BRIGHTID_SPONSOR_KEY_FOR_NETLIFY or VITE_BRIGHTID_SPONSOR_KEY needs to be set. If VITE_BRIGHTID_SPONSOR_KEY_FOR_NETLIFY is set, the clrfund app must be deployed to the netlify platform as it will use the netlify serverless function. The netlify option is used if you want to protect the BrightId sponsor key. - -The BrightId sponsor key can be generated using the random Nacl keypair at [https://tweetnacl.js.org/#/sign](https://tweetnacl.js.org/#/sign). Give the public key part to the BrightId folks to setup the context and put the private key part in VITE_BRIGHTID_SPONSOR_KEY or VITE_BRIGHTID_SPONSOR_KEY_FOR_NETLIFY. - -```.sh -# /vue-app/.env -VITE_BRIGHTID_SPONSOR_API_URL=https://brightid.clr.fund/brightid/v6/operations -VITE_BRIGHTID_SPONSOR_KEY_FOR_NETLIFY= -VITE_BRIGHTID_SPONSOR_KEY= -``` - -**#5 netlify function setup** -See the [deployment guide](./deploymnet.md) for special setup to use the sponsor netlify function. - ## Troubleshooting linking failure -### Sponsorship timeout -1. check for sponsorship status https://app.brightid.org/node/v6/sponsorships/WALLET_ADDRESS -2. check for sponsorship status from clrfund's brightid node: +### General linking error +1. check for sponsorship status from clrfund's brightid node: - https://brightid.clr.fund/brightid/v6/sponsorships/WALLET_ADDRESS -3. check the clrfund's brightid node docker logs +2. check the clrfund's brightid node docker logs - look for sponsorship event listening error ```.sh docker logs --since 1440m brightid-node-docker-db-1 ``` -4. check for sponsorship token balance +3. check for sponsorship token balance - for clrfund-arbitrum context: https://brightid.clr.fund/brightid/v6/apps/clrfund-arbitrum ### Signature is not valid 1. Check that the verifier address is correct, it is the `ethSigningAddress` from https://brightid.clr.fund -2. You can update the verifier address using `sponsorContract.setSettings()` +2. You can update the verifier address using `BrightIdUserRegistryContract.setSettings()` ## Resources diff --git a/docs/deploy-clrFundDeployer.md b/docs/deploy-clrFundDeployer.md new file mode 100644 index 000000000..6d34df2dd --- /dev/null +++ b/docs/deploy-clrFundDeployer.md @@ -0,0 +1,18 @@ +# Deploy the ClrFundDeployer contract + +The ClrFundDeployer contract is used to deploy `ClrFund` instances from the [ClrFund Admin](https://github.com/clrfund/clrfund-admin). + +1. Follow the steps in the [deployment guide](./deployment.md) to install the dependencies, download the zkeys, setup BrightId (if applicable), and configure the `.env` and `deploy-config.json` files in the `contracts` folder + +2. Run the deployment script + +Run the following command in the contracts folder. Make sure you backup the `deployed-contracts.json` file (if exists) as the following command will overwrite the file. + +```sh +yarn hardhat new-deployer --verify --network {network} +``` + +Use the `--verify` flag to verify the newly deployed contracts. Make sure the `etherscan` API key is setup in the hardhat.config file +Use the `--incremental` flag to resume a deployment if it was interrupted due to error. +Use the `--manage-nonce` flag to let the script manually set the nonce (as opposed to getting the nonce from the node). This is useful if using testnet public node like `optimism-sepolia` where the node may occasionally give `nonce too low` error. + diff --git a/docs/deployment.md b/docs/deployment.md index d0c3f585d..4d292238e 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -24,13 +24,6 @@ Note: select the `hex address (ONLY)` option to identify users and the `meet` ve Once the app is registered, you will get an appId which will be set to `BRIGHTID_CONTEXT` when deploying the contracts in later steps. -### Setup BrightID sponsorship keys - -1. Generate sponsorship signing keys here: https://tweetnacl.js.org/#/sign -2. Provide the public key to BrightID support through their discord channel: https://discord.gg/QW7ThZ5K4V -3. Save the private key for setting up the clrfund user interface in environment variable: `VITE_BRIGHTID_SPONSOR_KEY` - - ## Deploy Contracts Goto the `contracts` folder. @@ -73,9 +66,8 @@ cp deploy-config-example.json deploy-config.json Update the `VkRegistry.paramsDirectory` with the circuit parameter folder. If you ran the `monorepo/.github/scripts/download-6-9-2-3.sh` in the `contracts` folder, it should be `./params`. -### Run the deploy script -Use the `-h` switch to print the command line help menu for all the scripts in the `cli` folder. For hardhat help, use `yarn hardhat help`. - +### Run the deployment scripts +Use `yarn hardhat help` to print the command line help menu for all available commands. Note that the following steps are for deploying a standalone ClrFund instance. To deploy an instance of the ClrFundDeployer contract, please refer to the [ClrFundDeployer Deployment Guide](./deploy-clrFundDeployer.md) 1. Deploy an instance of ClrFund @@ -128,14 +120,19 @@ Currently, we are using the [Hosted Service](https://thegraph.com/docs/en/hosted Inside `/subgraph`: -1. Prepare the `subgraph.yaml` with the correct network data - - Update or create a new JSON file which you want to use, under `/config` +1. Prepare the config file + - Under the `/config` folder, create a new JSON file or update an existing one + - If you deployed a standalone ClrFund contract, use the `xdai.json` as a template to create your config file + - If you deployed a ClrFundDeployer contract, use the `deployer-arbitrum-sepolia.json` as a template +2. Prepare the `schema.graphql` file + - Run `npx mustache schema.template.graphql > schema.graphql` +2. Prepare the `subgraph.yaml` file - Run `npx mustache subgraph.template.yaml > subgraph.yaml` -2. Build: +3. Build: - `yarn codegen` - `yarn build` -3. Authenticate with `yarn graph auth --product hosted-service ` -4. Deploy it by running `yarn graph deploy --product hosted-service USERNAME/SUBGRAPH` +4. Authenticate with `yarn graph auth --product hosted-service ` +5. Deploy it by running `yarn graph deploy --product hosted-service USERNAME/SUBGRAPH` ### Deploy the user interface @@ -157,8 +154,6 @@ VITE_SUBGRAPH_URL= VITE_CLRFUND_ADDRESS= VITE_USER_REGISTRY_TYPE= VITE_BRIGHTID_CONTEXT= -VITE_BRIGHTID_SPONSOR_KEY= -VITE_BRIGHTID_SPONSOR_API_URL=https://brightid.clr.fund/brightid/v6/operations VITE_RECIPIENT_REGISTRY_TYPE= # see google-sheets.md for instruction on how to set these @@ -167,16 +162,14 @@ VITE_GOOGLE_SPREADSHEET_ID= ``` +Note: if VITE_SUBGRAPH_URL is not set, the app will try to get the round information from the vue-app/src/rounds.json file which can be generated using the `hardhat export-round` command. + ##### Setup the netlify functions 1. Set the `functions directory` to `vue-app/dist/lambda`. See [How to set netlify function directory](https://docs.netlify.com/functions/optional-configuration/?fn-language=ts) -2. Set environment variable: `AWS_LAMBDA_JS_RUNTIME=nodejs18.x` - -This environment variable is needed for the `sponsor.js` function. If not set, it will throw error `fetch not found`. - #### Deploy on IPFS diff --git a/docs/tally-verify.md b/docs/tally-verify.md index b2edd2a50..080d219c1 100644 --- a/docs/tally-verify.md +++ b/docs/tally-verify.md @@ -18,34 +18,23 @@ COORDINATOR_MACISK= # private key for interacting with contracts WALLET_MNEMONIC= WALLET_PRIVATE_KEY -``` - -Decrypt messages and tally the votes: +# credential to upload tally result to IPFS +PINATA_API_KEY= +PINATA_SECRET_API_KEY= ``` -yarn hardhat tally --rapidsnark {RAPID_SNARK} --output-dir {OUTPUT_DIR} --network {network} -``` - -You only need to provide `--rapidsnark` if you are running the `tally` command on an intel chip. -If there's error and the tally task was stopped prematurely, it can be resumed by passing 2 additional parameters, '--tally-file' and/or '--maci-state-file', if the files were generated. +Decrypt messages, tally the votes: ``` -# for rerun -yarn hardhat tally --maci-state-file {maci-state.json} --tally-file {tally.json} --output-dir {OUTPUT_DIR} --network {network} +yarn hardhat tally --clrfund {CLRFUND_CONTRACT_ADDRESS} --maci-tx-hash {MACI_CREATION_TRANSACTION_HASH} --proof-dir {OUTPUT_DIR} --rapidsnark {RAPID_SNARK} --network {network} ``` -Result will be saved to `tally.json` file, which must then be published via IPFS. - -**Using [command line](https://docs.ipfs.tech/reference/kubo/cli/#ipfs)** - +You only need to provide `--rapidsnark` if you are running the `tally` command on an intel chip. +If the `tally` script failed, you can rerun the command with the same parameters. ``` -# start ipfs daemon in one terminal -ipfs daemon -# in a diff terminal, go to `/contracts` (or where you have the file) and publish the file -ipfs add tally.json -``` +Result will be saved to `{OUTPUT_DIR}/{network}-{fundingRoundAddress}/tally.json` file, which is also available on IPFS at `https://{ipfs-gateway-host}/ipfs/{tally-hash}`. ### Finalize round @@ -60,7 +49,7 @@ WALLET_PRIVATE_KEY= Once you have the `tally.json` from the tally script, run: ``` -yarn hardhat finalize --tally-file {tally.json} --network {network} +yarn hardhat finalize --clrfund {CLRFUND_CONTRACT_ADDRESS} --proof-dir {OUTPUT_DIR} --network {network} ``` # How to verify the tally results @@ -98,6 +87,4 @@ Also, lack of memory can also cause `core dump`, try to work around it by settin export NODE_OPTIONS=--max-old-space-size=4096 ``` -If you notice `Error at message index 0 - failed decryption due to either wrong encryption public key or corrupted ciphertext` while running the tally script, don't worry, it's just a warning. This issue is tracked [here](https://github.com/privacy-scaling-explorations/maci/issues/1134) - `Error at message index n - invalid nonce` is also a warning, not an error. This error occurs when users reallocated their contribution. diff --git a/package.json b/package.json index 072d15e02..0ae9648b6 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "test:contracts": "yarn workspace @clrfund/contracts run test", "test:e2e": "yarn workspace @clrfund/contracts run e2e", "test:web": "yarn workspace @clrfund/vue-app run test", + "test:common": "yarn workspace @clrfund/common run test", "test:format": "yarn prettier --check", "test:lint-i18n": "echo yarn workspace @clrfund/vue-app run test:lint-i18n --ci", "deploy:subgraph": "yarn workspace @clrfund/subgraph run deploy", diff --git a/subgraph/abis/ClrFund.json b/subgraph/abis/ClrFund.json index 30e4badb0..1146484de 100644 --- a/subgraph/abis/ClrFund.json +++ b/subgraph/abis/ClrFund.json @@ -1,9 +1,36 @@ [ + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "AddressEmptyCode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "AddressInsufficientBalance", + "type": "error" + }, { "inputs": [], "name": "AlreadyFinalized", "type": "error" }, + { + "inputs": [], + "name": "FailedInnerCall", + "type": "error" + }, { "inputs": [], "name": "FundingSourceAlreadyAdded", @@ -24,6 +51,11 @@ "name": "InvalidMaciFactory", "type": "error" }, + { + "inputs": [], + "name": "MaxRecipientsNotSet", + "type": "error" + }, { "inputs": [], "name": "NoCurrentRound", @@ -55,8 +87,14 @@ "type": "error" }, { - "inputs": [], - "name": "VoteOptionTreeDepthNotSet", + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "SafeERC20FailedOperation", "type": "error" }, { @@ -343,19 +381,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "getMaxRecipients", - "outputs": [ - { - "internalType": "uint256", - "name": "_maxRecipients", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { diff --git a/subgraph/abis/ClrFundDeployer.json b/subgraph/abis/ClrFundDeployer.json new file mode 100644 index 000000000..3dd329580 --- /dev/null +++ b/subgraph/abis/ClrFundDeployer.json @@ -0,0 +1,259 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_clrfundTemplate", + "type": "address" + }, + { + "internalType": "address", + "name": "_maciFactory", + "type": "address" + }, + { + "internalType": "address", + "name": "_roundFactory", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "ClrFundAlreadyRegistered", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidClrFundTemplate", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidFundingRoundFactory", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidMaciFactory", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnableInvalidOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "OwnableUnauthorizedAccount", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newTemplate", + "type": "address" + } + ], + "name": "NewClrfundTemplate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newTemplate", + "type": "address" + } + ], + "name": "NewFundingRoundTemplate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "clrfund", + "type": "address" + } + ], + "name": "NewInstance", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "clrfund", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "metadata", + "type": "string" + } + ], + "name": "Register", + "type": "event" + }, + { + "inputs": [], + "name": "clrfundTemplate", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "clrfunds", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "deployClrFund", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "maciFactory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "roundFactory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_clrfundTemplate", + "type": "address" + } + ], + "name": "setClrFundTemplate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/subgraph/abis/FundingRound.json b/subgraph/abis/FundingRound.json index 7bfd15417..9d7aa994b 100644 --- a/subgraph/abis/FundingRound.json +++ b/subgraph/abis/FundingRound.json @@ -25,6 +25,28 @@ "stateMutability": "nonpayable", "type": "constructor" }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "AddressEmptyCode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "AddressInsufficientBalance", + "type": "error" + }, { "inputs": [], "name": "AlreadyContributed", @@ -45,6 +67,11 @@ "name": "EmptyTallyHash", "type": "error" }, + { + "inputs": [], + "name": "FailedInnerCall", + "type": "error" + }, { "inputs": [], "name": "FundsAlreadyClaimed", @@ -141,6 +168,11 @@ "name": "NoProjectHasMoreThanOneVote", "type": "error" }, + { + "inputs": [], + "name": "NoSignUps", + "type": "error" + }, { "inputs": [], "name": "NoVoiceCredits", @@ -166,6 +198,28 @@ "name": "OnlyMaciCanRegisterVoters", "type": "error" }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnableInvalidOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "OwnableUnauthorizedAccount", + "type": "error" + }, { "inputs": [], "name": "PollNotSet", @@ -191,6 +245,17 @@ "name": "RoundNotFinalized", "type": "error" }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "SafeERC20FailedOperation", + "type": "error" + }, { "inputs": [], "name": "TallyHashNotPublished", @@ -402,19 +467,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "TREE_ARITY", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "alpha", @@ -891,11 +943,6 @@ "internalType": "address", "name": "tally", "type": "address" - }, - { - "internalType": "address", - "name": "subsidy", - "type": "address" } ], "internalType": "struct MACI.PollContracts", diff --git a/subgraph/abis/MACI.json b/subgraph/abis/MACI.json index 4a09120f9..ba7b1c96a 100644 --- a/subgraph/abis/MACI.json +++ b/subgraph/abis/MACI.json @@ -12,15 +12,10 @@ "type": "address" }, { - "internalType": "contract ITallySubsidyFactory", + "internalType": "contract ITallyFactory", "name": "_tallyFactory", "type": "address" }, - { - "internalType": "contract ITallySubsidyFactory", - "name": "_subsidyFactory", - "type": "address" - }, { "internalType": "contract SignUpGatekeeper", "name": "_signUpGatekeeper", @@ -63,7 +58,29 @@ }, { "inputs": [], - "name": "MaciPubKeyLargerThanSnarkFieldSize", + "name": "InvalidPubKey", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnableInvalidOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "OwnableUnauthorizedAccount", "type": "error" }, { @@ -140,11 +157,6 @@ "internalType": "address", "name": "tally", "type": "address" - }, - { - "internalType": "address", - "name": "subsidy", - "type": "address" } ], "indexed": false, @@ -287,9 +299,9 @@ "type": "address" }, { - "internalType": "bool", - "name": "useSubsidy", - "type": "bool" + "internalType": "enum DomainObjs.Mode", + "name": "_mode", + "type": "uint8" } ], "name": "deployPoll", @@ -310,11 +322,6 @@ "internalType": "address", "name": "tally", "type": "address" - }, - { - "internalType": "address", - "name": "subsidy", - "type": "address" } ], "internalType": "struct MACI.PollContracts", @@ -845,19 +852,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "subsidyFactory", - "outputs": [ - { - "internalType": "contract ITallySubsidyFactory", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "subtreesMerged", @@ -876,7 +870,7 @@ "name": "tallyFactory", "outputs": [ { - "internalType": "contract ITallySubsidyFactory", + "internalType": "contract ITallyFactory", "name": "", "type": "address" } diff --git a/subgraph/abis/MACIFactory.json b/subgraph/abis/MACIFactory.json index c8ab362b8..3488fff8d 100644 --- a/subgraph/abis/MACIFactory.json +++ b/subgraph/abis/MACIFactory.json @@ -18,11 +18,6 @@ "name": "tallyFactory", "type": "address" }, - { - "internalType": "address", - "name": "subsidyFactory", - "type": "address" - }, { "internalType": "address", "name": "messageProcessorFactory", @@ -44,17 +39,22 @@ }, { "inputs": [], - "name": "InvalidMessageProcessorFactory", + "name": "InvalidMaxRecipients", "type": "error" }, { "inputs": [], - "name": "InvalidPollFactory", + "name": "InvalidMessageBatchSize", "type": "error" }, { "inputs": [], - "name": "InvalidSubsidyFactory", + "name": "InvalidMessageProcessorFactory", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidPollFactory", "type": "error" }, { @@ -72,11 +72,38 @@ "name": "InvalidVkRegistry", "type": "error" }, + { + "inputs": [], + "name": "InvalidVoteOptionTreeDepth", + "type": "error" + }, { "inputs": [], "name": "NotInitialized", "type": "error" }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnableInvalidOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "OwnableUnauthorizedAccount", + "type": "error" + }, { "inputs": [], "name": "ProcessVkNotSet", @@ -87,6 +114,11 @@ "name": "TallyVkNotSet", "type": "error" }, + { + "inputs": [], + "name": "VoteOptionTreeDepthNotSet", + "type": "error" + }, { "anonymous": false, "inputs": [ @@ -138,19 +170,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "TREE_ARITY", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -224,11 +243,6 @@ "internalType": "address", "name": "tally", "type": "address" - }, - { - "internalType": "address", - "name": "subsidy", - "type": "address" } ], "internalType": "struct MACI.PollContracts", @@ -253,11 +267,6 @@ "name": "tallyFactory", "type": "address" }, - { - "internalType": "address", - "name": "subsidyFactory", - "type": "address" - }, { "internalType": "address", "name": "messageProcessorFactory", @@ -268,22 +277,29 @@ "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "maxRecipients", + "outputs": [ { - "internalType": "uint8", - "name": "messageTreeSubDepth", - "type": "uint8" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "getMessageBatchSize", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "messageBatchSize", "outputs": [ { "internalType": "uint256", - "name": "_messageBatchSize", + "name": "", "type": "uint256" } ], - "stateMutability": "pure", + "stateMutability": "view", "type": "function" }, { @@ -313,6 +329,16 @@ "name": "_stateTreeDepth", "type": "uint8" }, + { + "internalType": "uint256", + "name": "_messageBatchSize", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxRecipients", + "type": "uint256" + }, { "components": [ { diff --git a/subgraph/abis/Poll.json b/subgraph/abis/Poll.json index 671177ba2..e31d07163 100644 --- a/subgraph/abis/Poll.json +++ b/subgraph/abis/Poll.json @@ -105,7 +105,29 @@ }, { "inputs": [], - "name": "MaciPubKeyLargerThanSnarkFieldSize", + "name": "InvalidPubKey", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnableInvalidOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "OwnableUnauthorizedAccount", "type": "error" }, { @@ -142,13 +164,13 @@ "anonymous": false, "inputs": [ { - "indexed": false, + "indexed": true, "internalType": "uint256", "name": "_stateRoot", "type": "uint256" }, { - "indexed": false, + "indexed": true, "internalType": "uint256", "name": "_numSignups", "type": "uint256" @@ -161,7 +183,7 @@ "anonymous": false, "inputs": [ { - "indexed": false, + "indexed": true, "internalType": "uint256", "name": "_numSrQueueOps", "type": "uint256" @@ -174,7 +196,7 @@ "anonymous": false, "inputs": [ { - "indexed": false, + "indexed": true, "internalType": "uint256", "name": "_messageRoot", "type": "uint256" @@ -187,7 +209,7 @@ "anonymous": false, "inputs": [ { - "indexed": false, + "indexed": true, "internalType": "uint256", "name": "_numSrQueueOps", "type": "uint256" diff --git a/subgraph/config/arbitrum-goerli.json b/subgraph/config/arbitrum-goerli.json deleted file mode 100644 index b3053c192..000000000 --- a/subgraph/config/arbitrum-goerli.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "network": "arbitrum-goerli", - "address": "0x0a12CE1B7a95f2067AB930f0b2316FF21Cd5A430", - "clrFundStartBlock": 325577, - "recipientRegistryStartBlock": 325577 -} diff --git a/subgraph/config/arbitrum-rinkeby.json b/subgraph/config/arbitrum-rinkeby.json deleted file mode 100644 index c8850d0b0..000000000 --- a/subgraph/config/arbitrum-rinkeby.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "network": "arbitrum-rinkeby", - "address": "0xC032e80a413Be959d9a9B6e5CadE53c870074d37", - "factoryStartBlock": 4806990, - "recipientRegistryStartBlock": 4806990 -} diff --git a/subgraph/config/arbitrum-sepolia.json b/subgraph/config/arbitrum-sepolia.json index 82727f44c..37bdfe64a 100644 --- a/subgraph/config/arbitrum-sepolia.json +++ b/subgraph/config/arbitrum-sepolia.json @@ -1,6 +1,6 @@ { "network": "arbitrum-sepolia", - "address": "0xEd7dD059294dE1B053B2B50Fb6A73a559219F678", + "clrFundAddress": "0xEd7dD059294dE1B053B2B50Fb6A73a559219F678", "clrFundStartBlock": 22697290, "recipientRegistryStartBlock": 22697290 } diff --git a/subgraph/config/arbitrum.json b/subgraph/config/arbitrum.json index 66548bb55..9b0bf753b 100644 --- a/subgraph/config/arbitrum.json +++ b/subgraph/config/arbitrum.json @@ -1,6 +1,6 @@ { "network": "arbitrum-one", - "address": "0x2e89494a8fE02891511a43f7877b726787E0C160", + "clrFundAddress": "0x2e89494a8fE02891511a43f7877b726787E0C160", "clrFundStartBlock": 3461582, "recipientRegistryStartBlock": 3461582 } diff --git a/subgraph/config/deployer-arbitrum-sepolia.json b/subgraph/config/deployer-arbitrum-sepolia.json new file mode 100644 index 000000000..858db0f32 --- /dev/null +++ b/subgraph/config/deployer-arbitrum-sepolia.json @@ -0,0 +1,6 @@ +{ + "network": "arbitrum-sepolia", + "clrFundDeployerAddress": "0xC0F9054083D42b61C9bbA8EB3533fF3f0208C1fb", + "clrFundDeployerStartBlock": 24627080, + "recipientRegistryStartBlock": 24627080 +} diff --git a/subgraph/config/goerli.json b/subgraph/config/goerli.json deleted file mode 100644 index c413e317f..000000000 --- a/subgraph/config/goerli.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "network": "goerli", - "address": "0xb1709e5dbB787E82A7feA30da5322e77F3c7D00F", - "factoryStartBlock": 7109979, - "recipientRegistryStartBlock": 7109979 -} diff --git a/subgraph/config/hardhat.json b/subgraph/config/hardhat.json index 0520de5d5..47a121d11 100644 --- a/subgraph/config/hardhat.json +++ b/subgraph/config/hardhat.json @@ -1,6 +1,6 @@ { "network": "hardhat", - "address": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82", + "clrFundAddress": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82", "clrFundStartBlock": 0, "recipientRegistryStartBlock": 0 } diff --git a/subgraph/config/optimism-sepolia.json b/subgraph/config/optimism-sepolia.json index 7ea9d8b34..d052bf9af 100644 --- a/subgraph/config/optimism-sepolia.json +++ b/subgraph/config/optimism-sepolia.json @@ -1,6 +1,6 @@ { "network": "optimism-sepolia", - "address": "0x9deB2f0A56FeCEe7ECE9B742Ab4f5Bc21A634F83", + "clrFundAddress": "0x9deB2f0A56FeCEe7ECE9B742Ab4f5Bc21A634F83", "clrFundStartBlock": 8973710, "recipientRegistryStartBlock": 8973710 } diff --git a/subgraph/config/xdai.json b/subgraph/config/xdai.json index ab3c34558..b92df0999 100644 --- a/subgraph/config/xdai.json +++ b/subgraph/config/xdai.json @@ -1,6 +1,6 @@ { "network": "xdai", - "address": "0x4ede8f30d9c2dc96a9d6787e9c4a478424fb960a", + "clrFundAddress": "0x4ede8f30d9c2dc96a9d6787e9c4a478424fb960a", "clrFundStartBlock": 15217676, "recipientRegistryStartBlock": 15217676 } diff --git a/subgraph/generated/ClrFund/ClrFund.ts b/subgraph/generated/ClrFund/ClrFund.ts index 3446a9e7b..5810bf338 100644 --- a/subgraph/generated/ClrFund/ClrFund.ts +++ b/subgraph/generated/ClrFund/ClrFund.ts @@ -389,29 +389,6 @@ export class ClrFund extends ethereum.SmartContract { return ethereum.CallResult.fromValue(value[0].toBigInt()); } - getMaxRecipients(): BigInt { - let result = super.call( - "getMaxRecipients", - "getMaxRecipients():(uint256)", - [], - ); - - return result[0].toBigInt(); - } - - try_getMaxRecipients(): ethereum.CallResult { - let result = super.tryCall( - "getMaxRecipients", - "getMaxRecipients():(uint256)", - [], - ); - if (result.reverted) { - return new ethereum.CallResult(); - } - let value = result.value; - return ethereum.CallResult.fromValue(value[0].toBigInt()); - } - maciFactory(): Address { let result = super.call("maciFactory", "maciFactory():(address)", []); diff --git a/subgraph/generated/ClrFund/FundingRound.ts b/subgraph/generated/ClrFund/FundingRound.ts index 32be22df9..a2660d7ad 100644 --- a/subgraph/generated/ClrFund/FundingRound.ts +++ b/subgraph/generated/ClrFund/FundingRound.ts @@ -277,21 +277,6 @@ export class FundingRound extends ethereum.SmartContract { return ethereum.CallResult.fromValue(value[0].toI32()); } - TREE_ARITY(): BigInt { - let result = super.call("TREE_ARITY", "TREE_ARITY():(uint256)", []); - - return result[0].toBigInt(); - } - - try_TREE_ARITY(): ethereum.CallResult { - let result = super.tryCall("TREE_ARITY", "TREE_ARITY():(uint256)", []); - if (result.reverted) { - return new ethereum.CallResult(); - } - let value = result.value; - return ethereum.CallResult.fromValue(value[0].toBigInt()); - } - alpha(): BigInt { let result = super.call("alpha", "alpha():(uint256)", []); @@ -1237,10 +1222,6 @@ export class SetMaciCall_pollContractsStruct extends ethereum.Tuple { get tally(): Address { return this[2].toAddress(); } - - get subsidy(): Address { - return this[3].toAddress(); - } } export class SetMaciInstanceCall extends ethereum.Call { diff --git a/subgraph/generated/ClrFund/MACI.ts b/subgraph/generated/ClrFund/MACI.ts index b1b8238e1..a770b955e 100644 --- a/subgraph/generated/ClrFund/MACI.ts +++ b/subgraph/generated/ClrFund/MACI.ts @@ -54,10 +54,6 @@ export class DeployPollPollAddrStruct extends ethereum.Tuple { get tally(): Address { return this[2].toAddress(); } - - get subsidy(): Address { - return this[3].toAddress(); - } } export class OwnershipTransferred extends ethereum.Event { @@ -128,10 +124,6 @@ export class MACI__deployPollResultPollAddrStruct extends ethereum.Tuple { get tally(): Address { return this[2].toAddress(); } - - get subsidy(): Address { - return this[3].toAddress(); - } } export class MACI__deployPollInput_treeDepthsStruct extends ethereum.Tuple { @@ -298,18 +290,18 @@ export class MACI extends ethereum.SmartContract { _coordinatorPubKey: MACI__deployPollInput_coordinatorPubKeyStruct, _verifier: Address, _vkRegistry: Address, - useSubsidy: boolean, + _mode: i32, ): MACI__deployPollResultPollAddrStruct { let result = super.call( "deployPoll", - "deployPoll(uint256,(uint8,uint8,uint8,uint8),(uint256,uint256),address,address,bool):((address,address,address,address))", + "deployPoll(uint256,(uint8,uint8,uint8,uint8),(uint256,uint256),address,address,uint8):((address,address,address))", [ ethereum.Value.fromUnsignedBigInt(_duration), ethereum.Value.fromTuple(_treeDepths), ethereum.Value.fromTuple(_coordinatorPubKey), ethereum.Value.fromAddress(_verifier), ethereum.Value.fromAddress(_vkRegistry), - ethereum.Value.fromBoolean(useSubsidy), + ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(_mode)), ], ); @@ -324,18 +316,18 @@ export class MACI extends ethereum.SmartContract { _coordinatorPubKey: MACI__deployPollInput_coordinatorPubKeyStruct, _verifier: Address, _vkRegistry: Address, - useSubsidy: boolean, + _mode: i32, ): ethereum.CallResult { let result = super.tryCall( "deployPoll", - "deployPoll(uint256,(uint8,uint8,uint8,uint8),(uint256,uint256),address,address,bool):((address,address,address,address))", + "deployPoll(uint256,(uint8,uint8,uint8,uint8),(uint256,uint256),address,address,uint8):((address,address,address))", [ ethereum.Value.fromUnsignedBigInt(_duration), ethereum.Value.fromTuple(_treeDepths), ethereum.Value.fromTuple(_coordinatorPubKey), ethereum.Value.fromAddress(_verifier), ethereum.Value.fromAddress(_vkRegistry), - ethereum.Value.fromBoolean(useSubsidy), + ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(_mode)), ], ); if (result.reverted) { @@ -831,25 +823,6 @@ export class MACI extends ethereum.SmartContract { return ethereum.CallResult.fromValue(value[0].toI32()); } - subsidyFactory(): Address { - let result = super.call("subsidyFactory", "subsidyFactory():(address)", []); - - return result[0].toAddress(); - } - - try_subsidyFactory(): ethereum.CallResult
{ - let result = super.tryCall( - "subsidyFactory", - "subsidyFactory():(address)", - [], - ); - if (result.reverted) { - return new ethereum.CallResult(); - } - let value = result.value; - return ethereum.CallResult.fromValue(value[0].toAddress()); - } - subtreesMerged(): boolean { let result = super.call("subtreesMerged", "subtreesMerged():(bool)", []); @@ -925,24 +898,20 @@ export class ConstructorCall__Inputs { return this._call.inputValues[2].value.toAddress(); } - get _subsidyFactory(): Address { - return this._call.inputValues[3].value.toAddress(); - } - get _signUpGatekeeper(): Address { - return this._call.inputValues[4].value.toAddress(); + return this._call.inputValues[3].value.toAddress(); } get _initialVoiceCreditProxy(): Address { - return this._call.inputValues[5].value.toAddress(); + return this._call.inputValues[4].value.toAddress(); } get _topupCredit(): Address { - return this._call.inputValues[6].value.toAddress(); + return this._call.inputValues[5].value.toAddress(); } get _stateTreeDepth(): i32 { - return this._call.inputValues[7].value.toI32(); + return this._call.inputValues[6].value.toI32(); } } @@ -995,8 +964,8 @@ export class DeployPollCall__Inputs { return this._call.inputValues[4].value.toAddress(); } - get useSubsidy(): boolean { - return this._call.inputValues[5].value.toBoolean(); + get _mode(): i32 { + return this._call.inputValues[5].value.toI32(); } } @@ -1054,10 +1023,6 @@ export class DeployPollCallPollAddrStruct extends ethereum.Tuple { get tally(): Address { return this[2].toAddress(); } - - get subsidy(): Address { - return this[3].toAddress(); - } } export class MergeStateAqCall extends ethereum.Call { diff --git a/subgraph/generated/ClrFund/MACIFactory.ts b/subgraph/generated/ClrFund/MACIFactory.ts index c9f330074..0f6f79fc3 100644 --- a/subgraph/generated/ClrFund/MACIFactory.ts +++ b/subgraph/generated/ClrFund/MACIFactory.ts @@ -76,10 +76,6 @@ export class MACIFactory__deployMaciResult_pollContractsStruct extends ethereum. get tally(): Address { return this[2].toAddress(); } - - get subsidy(): Address { - return this[3].toAddress(); - } } export class MACIFactory__deployMaciResult { @@ -124,18 +120,11 @@ export class MACIFactory__factoriesResult { value0: Address; value1: Address; value2: Address; - value3: Address; - constructor( - value0: Address, - value1: Address, - value2: Address, - value3: Address, - ) { + constructor(value0: Address, value1: Address, value2: Address) { this.value0 = value0; this.value1 = value1; this.value2 = value2; - this.value3 = value3; } toMap(): TypedMap { @@ -143,7 +132,6 @@ export class MACIFactory__factoriesResult { map.set("value0", ethereum.Value.fromAddress(this.value0)); map.set("value1", ethereum.Value.fromAddress(this.value1)); map.set("value2", ethereum.Value.fromAddress(this.value2)); - map.set("value3", ethereum.Value.fromAddress(this.value3)); return map; } @@ -155,12 +143,8 @@ export class MACIFactory__factoriesResult { return this.value1; } - getSubsidyFactory(): Address { - return this.value2; - } - getMessageProcessorFactory(): Address { - return this.value3; + return this.value2; } } @@ -243,21 +227,6 @@ export class MACIFactory extends ethereum.SmartContract { return ethereum.CallResult.fromValue(value[0].toI32()); } - TREE_ARITY(): BigInt { - let result = super.call("TREE_ARITY", "TREE_ARITY():(uint256)", []); - - return result[0].toBigInt(); - } - - try_TREE_ARITY(): ethereum.CallResult { - let result = super.tryCall("TREE_ARITY", "TREE_ARITY():(uint256)", []); - if (result.reverted) { - return new ethereum.CallResult(); - } - let value = result.value; - return ethereum.CallResult.fromValue(value[0].toBigInt()); - } - deployMaci( signUpGatekeeper: Address, initialVoiceCreditProxy: Address, @@ -269,7 +238,7 @@ export class MACIFactory extends ethereum.SmartContract { ): MACIFactory__deployMaciResult { let result = super.call( "deployMaci", - "deployMaci(address,address,address,uint256,address,(uint256,uint256),address):(address,(address,address,address,address))", + "deployMaci(address,address,address,uint256,address,(uint256,uint256),address):(address,(address,address,address))", [ ethereum.Value.fromAddress(signUpGatekeeper), ethereum.Value.fromAddress(initialVoiceCreditProxy), @@ -300,7 +269,7 @@ export class MACIFactory extends ethereum.SmartContract { ): ethereum.CallResult { let result = super.tryCall( "deployMaci", - "deployMaci(address,address,address,uint256,address,(uint256,uint256),address):(address,(address,address,address,address))", + "deployMaci(address,address,address,uint256,address,(uint256,uint256),address):(address,(address,address,address))", [ ethereum.Value.fromAddress(signUpGatekeeper), ethereum.Value.fromAddress(initialVoiceCreditProxy), @@ -328,7 +297,7 @@ export class MACIFactory extends ethereum.SmartContract { factories(): MACIFactory__factoriesResult { let result = super.call( "factories", - "factories():(address,address,address,address)", + "factories():(address,address,address)", [], ); @@ -336,14 +305,13 @@ export class MACIFactory extends ethereum.SmartContract { result[0].toAddress(), result[1].toAddress(), result[2].toAddress(), - result[3].toAddress(), ); } try_factories(): ethereum.CallResult { let result = super.tryCall( "factories", - "factories():(address,address,address,address)", + "factories():(address,address,address)", [], ); if (result.reverted) { @@ -355,28 +323,44 @@ export class MACIFactory extends ethereum.SmartContract { value[0].toAddress(), value[1].toAddress(), value[2].toAddress(), - value[3].toAddress(), ), ); } - getMessageBatchSize(messageTreeSubDepth: i32): BigInt { + maxRecipients(): BigInt { + let result = super.call("maxRecipients", "maxRecipients():(uint256)", []); + + return result[0].toBigInt(); + } + + try_maxRecipients(): ethereum.CallResult { + let result = super.tryCall( + "maxRecipients", + "maxRecipients():(uint256)", + [], + ); + if (result.reverted) { + return new ethereum.CallResult(); + } + let value = result.value; + return ethereum.CallResult.fromValue(value[0].toBigInt()); + } + + messageBatchSize(): BigInt { let result = super.call( - "getMessageBatchSize", - "getMessageBatchSize(uint8):(uint256)", - [ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(messageTreeSubDepth))], + "messageBatchSize", + "messageBatchSize():(uint256)", + [], ); return result[0].toBigInt(); } - try_getMessageBatchSize( - messageTreeSubDepth: i32, - ): ethereum.CallResult { + try_messageBatchSize(): ethereum.CallResult { let result = super.tryCall( - "getMessageBatchSize", - "getMessageBatchSize(uint8):(uint256)", - [ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(messageTreeSubDepth))], + "messageBatchSize", + "messageBatchSize():(uint256)", + [], ); if (result.reverted) { return new ethereum.CallResult(); @@ -534,12 +518,8 @@ export class ConstructorCall_factoriesStruct extends ethereum.Tuple { return this[1].toAddress(); } - get subsidyFactory(): Address { - return this[2].toAddress(); - } - get messageProcessorFactory(): Address { - return this[3].toAddress(); + return this[2].toAddress(); } } @@ -631,10 +611,6 @@ export class DeployMaciCall_pollContractsStruct extends ethereum.Tuple { get tally(): Address { return this[2].toAddress(); } - - get subsidy(): Address { - return this[3].toAddress(); - } } export class RenounceOwnershipCall extends ethereum.Call { @@ -684,9 +660,17 @@ export class SetMaciParametersCall__Inputs { return this._call.inputValues[0].value.toI32(); } + get _messageBatchSize(): BigInt { + return this._call.inputValues[1].value.toBigInt(); + } + + get _maxRecipients(): BigInt { + return this._call.inputValues[2].value.toBigInt(); + } + get _treeDepths(): SetMaciParametersCall_treeDepthsStruct { return changetype( - this._call.inputValues[1].value.toTuple(), + this._call.inputValues[3].value.toTuple(), ); } } diff --git a/subgraph/generated/schema.ts b/subgraph/generated/schema.ts index 97e62f0d3..50ce4aecf 100644 --- a/subgraph/generated/schema.ts +++ b/subgraph/generated/schema.ts @@ -551,21 +551,17 @@ export class PublicKey extends Entity { this.set("id", Value.fromString(value)); } - get fundingRound(): string | null { - let value = this.get("fundingRound"); + get maci(): string { + let value = this.get("maci"); if (!value || value.kind == ValueKind.NULL) { - return null; + throw new Error("Cannot return null for a required field."); } else { return value.toString(); } } - set fundingRound(value: string | null) { - if (!value) { - this.unset("fundingRound"); - } else { - this.set("fundingRound", Value.fromString(value)); - } + set maci(value: string) { + this.set("maci", Value.fromString(value)); } get messages(): MessageLoader { @@ -1020,6 +1016,40 @@ export class FundingRound extends Entity { this.set("voteOptionTreeDepth", Value.fromI32(value)); } + get maxMessages(): BigInt | null { + let value = this.get("maxMessages"); + if (!value || value.kind == ValueKind.NULL) { + return null; + } else { + return value.toBigInt(); + } + } + + set maxMessages(value: BigInt | null) { + if (!value) { + this.unset("maxMessages"); + } else { + this.set("maxMessages", Value.fromBigInt(value)); + } + } + + get maxVoteOptions(): BigInt | null { + let value = this.get("maxVoteOptions"); + if (!value || value.kind == ValueKind.NULL) { + return null; + } else { + return value.toBigInt(); + } + } + + set maxVoteOptions(value: BigInt | null) { + if (!value) { + this.unset("maxVoteOptions"); + } else { + this.set("maxVoteOptions", Value.fromBigInt(value)); + } + } + get coordinatorPubKeyX(): BigInt | null { let value = this.get("coordinatorPubKeyX"); if (!value || value.kind == ValueKind.NULL) { diff --git a/subgraph/generated/templates/FundingRound/FundingRound.ts b/subgraph/generated/templates/FundingRound/FundingRound.ts index 32be22df9..a2660d7ad 100644 --- a/subgraph/generated/templates/FundingRound/FundingRound.ts +++ b/subgraph/generated/templates/FundingRound/FundingRound.ts @@ -277,21 +277,6 @@ export class FundingRound extends ethereum.SmartContract { return ethereum.CallResult.fromValue(value[0].toI32()); } - TREE_ARITY(): BigInt { - let result = super.call("TREE_ARITY", "TREE_ARITY():(uint256)", []); - - return result[0].toBigInt(); - } - - try_TREE_ARITY(): ethereum.CallResult { - let result = super.tryCall("TREE_ARITY", "TREE_ARITY():(uint256)", []); - if (result.reverted) { - return new ethereum.CallResult(); - } - let value = result.value; - return ethereum.CallResult.fromValue(value[0].toBigInt()); - } - alpha(): BigInt { let result = super.call("alpha", "alpha():(uint256)", []); @@ -1237,10 +1222,6 @@ export class SetMaciCall_pollContractsStruct extends ethereum.Tuple { get tally(): Address { return this[2].toAddress(); } - - get subsidy(): Address { - return this[3].toAddress(); - } } export class SetMaciInstanceCall extends ethereum.Call { diff --git a/subgraph/generated/templates/MACI/FundingRound.ts b/subgraph/generated/templates/MACI/FundingRound.ts index 32be22df9..a2660d7ad 100644 --- a/subgraph/generated/templates/MACI/FundingRound.ts +++ b/subgraph/generated/templates/MACI/FundingRound.ts @@ -277,21 +277,6 @@ export class FundingRound extends ethereum.SmartContract { return ethereum.CallResult.fromValue(value[0].toI32()); } - TREE_ARITY(): BigInt { - let result = super.call("TREE_ARITY", "TREE_ARITY():(uint256)", []); - - return result[0].toBigInt(); - } - - try_TREE_ARITY(): ethereum.CallResult { - let result = super.tryCall("TREE_ARITY", "TREE_ARITY():(uint256)", []); - if (result.reverted) { - return new ethereum.CallResult(); - } - let value = result.value; - return ethereum.CallResult.fromValue(value[0].toBigInt()); - } - alpha(): BigInt { let result = super.call("alpha", "alpha():(uint256)", []); @@ -1237,10 +1222,6 @@ export class SetMaciCall_pollContractsStruct extends ethereum.Tuple { get tally(): Address { return this[2].toAddress(); } - - get subsidy(): Address { - return this[3].toAddress(); - } } export class SetMaciInstanceCall extends ethereum.Call { diff --git a/subgraph/generated/templates/MACI/MACI.ts b/subgraph/generated/templates/MACI/MACI.ts index b1b8238e1..a770b955e 100644 --- a/subgraph/generated/templates/MACI/MACI.ts +++ b/subgraph/generated/templates/MACI/MACI.ts @@ -54,10 +54,6 @@ export class DeployPollPollAddrStruct extends ethereum.Tuple { get tally(): Address { return this[2].toAddress(); } - - get subsidy(): Address { - return this[3].toAddress(); - } } export class OwnershipTransferred extends ethereum.Event { @@ -128,10 +124,6 @@ export class MACI__deployPollResultPollAddrStruct extends ethereum.Tuple { get tally(): Address { return this[2].toAddress(); } - - get subsidy(): Address { - return this[3].toAddress(); - } } export class MACI__deployPollInput_treeDepthsStruct extends ethereum.Tuple { @@ -298,18 +290,18 @@ export class MACI extends ethereum.SmartContract { _coordinatorPubKey: MACI__deployPollInput_coordinatorPubKeyStruct, _verifier: Address, _vkRegistry: Address, - useSubsidy: boolean, + _mode: i32, ): MACI__deployPollResultPollAddrStruct { let result = super.call( "deployPoll", - "deployPoll(uint256,(uint8,uint8,uint8,uint8),(uint256,uint256),address,address,bool):((address,address,address,address))", + "deployPoll(uint256,(uint8,uint8,uint8,uint8),(uint256,uint256),address,address,uint8):((address,address,address))", [ ethereum.Value.fromUnsignedBigInt(_duration), ethereum.Value.fromTuple(_treeDepths), ethereum.Value.fromTuple(_coordinatorPubKey), ethereum.Value.fromAddress(_verifier), ethereum.Value.fromAddress(_vkRegistry), - ethereum.Value.fromBoolean(useSubsidy), + ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(_mode)), ], ); @@ -324,18 +316,18 @@ export class MACI extends ethereum.SmartContract { _coordinatorPubKey: MACI__deployPollInput_coordinatorPubKeyStruct, _verifier: Address, _vkRegistry: Address, - useSubsidy: boolean, + _mode: i32, ): ethereum.CallResult { let result = super.tryCall( "deployPoll", - "deployPoll(uint256,(uint8,uint8,uint8,uint8),(uint256,uint256),address,address,bool):((address,address,address,address))", + "deployPoll(uint256,(uint8,uint8,uint8,uint8),(uint256,uint256),address,address,uint8):((address,address,address))", [ ethereum.Value.fromUnsignedBigInt(_duration), ethereum.Value.fromTuple(_treeDepths), ethereum.Value.fromTuple(_coordinatorPubKey), ethereum.Value.fromAddress(_verifier), ethereum.Value.fromAddress(_vkRegistry), - ethereum.Value.fromBoolean(useSubsidy), + ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(_mode)), ], ); if (result.reverted) { @@ -831,25 +823,6 @@ export class MACI extends ethereum.SmartContract { return ethereum.CallResult.fromValue(value[0].toI32()); } - subsidyFactory(): Address { - let result = super.call("subsidyFactory", "subsidyFactory():(address)", []); - - return result[0].toAddress(); - } - - try_subsidyFactory(): ethereum.CallResult
{ - let result = super.tryCall( - "subsidyFactory", - "subsidyFactory():(address)", - [], - ); - if (result.reverted) { - return new ethereum.CallResult(); - } - let value = result.value; - return ethereum.CallResult.fromValue(value[0].toAddress()); - } - subtreesMerged(): boolean { let result = super.call("subtreesMerged", "subtreesMerged():(bool)", []); @@ -925,24 +898,20 @@ export class ConstructorCall__Inputs { return this._call.inputValues[2].value.toAddress(); } - get _subsidyFactory(): Address { - return this._call.inputValues[3].value.toAddress(); - } - get _signUpGatekeeper(): Address { - return this._call.inputValues[4].value.toAddress(); + return this._call.inputValues[3].value.toAddress(); } get _initialVoiceCreditProxy(): Address { - return this._call.inputValues[5].value.toAddress(); + return this._call.inputValues[4].value.toAddress(); } get _topupCredit(): Address { - return this._call.inputValues[6].value.toAddress(); + return this._call.inputValues[5].value.toAddress(); } get _stateTreeDepth(): i32 { - return this._call.inputValues[7].value.toI32(); + return this._call.inputValues[6].value.toI32(); } } @@ -995,8 +964,8 @@ export class DeployPollCall__Inputs { return this._call.inputValues[4].value.toAddress(); } - get useSubsidy(): boolean { - return this._call.inputValues[5].value.toBoolean(); + get _mode(): i32 { + return this._call.inputValues[5].value.toI32(); } } @@ -1054,10 +1023,6 @@ export class DeployPollCallPollAddrStruct extends ethereum.Tuple { get tally(): Address { return this[2].toAddress(); } - - get subsidy(): Address { - return this[3].toAddress(); - } } export class MergeStateAqCall extends ethereum.Call { diff --git a/subgraph/generated/templates/Poll/FundingRound.ts b/subgraph/generated/templates/Poll/FundingRound.ts index 32be22df9..a2660d7ad 100644 --- a/subgraph/generated/templates/Poll/FundingRound.ts +++ b/subgraph/generated/templates/Poll/FundingRound.ts @@ -277,21 +277,6 @@ export class FundingRound extends ethereum.SmartContract { return ethereum.CallResult.fromValue(value[0].toI32()); } - TREE_ARITY(): BigInt { - let result = super.call("TREE_ARITY", "TREE_ARITY():(uint256)", []); - - return result[0].toBigInt(); - } - - try_TREE_ARITY(): ethereum.CallResult { - let result = super.tryCall("TREE_ARITY", "TREE_ARITY():(uint256)", []); - if (result.reverted) { - return new ethereum.CallResult(); - } - let value = result.value; - return ethereum.CallResult.fromValue(value[0].toBigInt()); - } - alpha(): BigInt { let result = super.call("alpha", "alpha():(uint256)", []); @@ -1237,10 +1222,6 @@ export class SetMaciCall_pollContractsStruct extends ethereum.Tuple { get tally(): Address { return this[2].toAddress(); } - - get subsidy(): Address { - return this[3].toAddress(); - } } export class SetMaciInstanceCall extends ethereum.Call { diff --git a/subgraph/package.json b/subgraph/package.json index 3b9809da7..3da61b629 100644 --- a/subgraph/package.json +++ b/subgraph/package.json @@ -1,6 +1,6 @@ { "name": "@clrfund/subgraph", - "version": "5.1.0", + "version": "6.0.0", "repository": "https://github.com/clrfund/monorepo/subgraph", "keywords": [ "clr.fund", diff --git a/subgraph/schema.graphql b/subgraph/schema.graphql index 147b3225f..2d779393a 100644 --- a/subgraph/schema.graphql +++ b/subgraph/schema.graphql @@ -37,7 +37,7 @@ type Message @entity { type PublicKey @entity { id: ID! - fundingRound: FundingRound + maci: String! messages: [Message!] @derivedFrom(field: "publicKey") x: BigInt! y: BigInt! @@ -73,6 +73,9 @@ type FundingRound @entity { messageTreeDepth: Int voteOptionTreeDepth: Int + maxMessages: BigInt + maxVoteOptions: BigInt + coordinatorPubKeyX: BigInt coordinatorPubKeyY: BigInt coordinator: Bytes diff --git a/subgraph/schema.template.graphql b/subgraph/schema.template.graphql new file mode 100644 index 000000000..e8f1db50d --- /dev/null +++ b/subgraph/schema.template.graphql @@ -0,0 +1,210 @@ +{{#clrFundDeployerAddress}} +type ClrFundDeployer @entity { + id: ID! + clrFunds: [ClrFund!] @derivedFrom(field: "clrFundDeployer") + createdAt: String + lastUpdatedAt: String +} + +{{/clrFundDeployerAddress}} +type ClrFund @entity { + id: ID! + owner: Bytes + {{#clrFundDeployerAddress}} + clrFundDeployer: ClrFundDeployer! + {{/clrFundDeployerAddress}} + coordinator: Bytes + nativeToken: Bytes + nativeTokenInfo: Token + contributorRegistry: ContributorRegistry + contributorRegistryAddress: Bytes + recipientRegistry: RecipientRegistry + recipientRegistryAddress: Bytes + currentRound: FundingRound + + maciFactory: Bytes + coordinatorPubKey: String + stateTreeDepth: BigInt + messageTreeDepth: BigInt + voteOptionTreeDepth: BigInt + + fundingRounds: [FundingRound!] @derivedFrom(field: "clrFund") + + createdAt: String + lastUpdatedAt: String +} + +type Message @entity { + id: ID! + data: [BigInt!] + msgType: BigInt! + publicKey: PublicKey + fundingRound: FundingRound + poll: Poll + submittedBy: Bytes + timestamp: String + blockNumber: BigInt! + transactionIndex: BigInt! +} + +type PublicKey @entity { + id: ID! + maci: String! + messages: [Message!] @derivedFrom(field: "publicKey") + x: BigInt! + y: BigInt! + stateIndex: BigInt + voiceCreditBalance: BigInt +} + +type Poll @entity { + id: ID! + fundingRound: FundingRound! + messages: [Message!] @derivedFrom(field: "poll") +} + +type FundingRound @entity { + id: ID! + clrFund: ClrFund + maci: Bytes + maciTxHash: Bytes + pollId: BigInt + pollAddress: Bytes + messages: [Message!] @derivedFrom(field: "fundingRound") + recipientRegistry: RecipientRegistry + recipientRegistryAddress: Bytes + contributorRegistry: ContributorRegistry + contributorRegistryAddress: Bytes + nativeToken: Bytes + nativeTokenInfo: Token + startTime: BigInt + signUpDeadline: BigInt + votingDeadline: BigInt + + stateTreeDepth: Int + messageTreeDepth: Int + voteOptionTreeDepth: Int + + maxMessages: BigInt + maxVoteOptions: BigInt + + coordinatorPubKeyX: BigInt + coordinatorPubKeyY: BigInt + coordinator: Bytes + + voiceCreditFactor: BigInt + contributorCount: BigInt! + recipientCount: BigInt! + matchingPoolSize: BigInt + totalSpent: BigInt + totalVotes: BigInt + isFinalized: Boolean + isCancelled: Boolean + tallyHash: String + + recipients: [Recipient!] @derivedFrom(field: "fundingRounds") + contributors: [Contributor!] @derivedFrom(field: "fundingRounds") + contributions: [Contribution!] @derivedFrom(field: "fundingRound") + createdAt: String + lastUpdatedAt: String +} + +type RecipientRegistry @entity { + id: ID! + clrFund: ClrFund + baseDeposit: BigInt + challengePeriodDuration: BigInt + controller: Bytes + maxRecipients: BigInt + owner: Bytes + recipients: [Recipient!] @derivedFrom(field: "recipientRegistry") + createdAt: String + lastUpdatedAt: String +} + +type Recipient @entity { + id: ID! + recipientRegistry: RecipientRegistry + + recipientIndex: BigInt + requestType: String + requester: String + submissionTime: String + deposit: BigInt + recipientAddress: Bytes + recipientMetadata: String + rejected: Boolean + verified: Boolean + voteOptionIndex: BigInt + requestResolvedHash: Bytes + requestSubmittedHash: Bytes + + fundingRounds: [FundingRound!] + + createdAt: String + lastUpdatedAt: String +} + +type ContributorRegistry @entity { + id: ID! + clrFund: ClrFund! + context: String + owner: Bytes + contributors: [Contributor!] @derivedFrom(field: "contributorRegistry") + + createdAt: String + lastUpdatedAt: String +} + +type Contributor @entity { + id: ID! + contributorRegistry: ContributorRegistry! + + verifiedTimeStamp: String + # sponsors: [Bytes] + contributorAddress: Bytes + + fundingRounds: [FundingRound!] + contributions: [Contribution!] @derivedFrom(field: "contributor") + + createdAt: String + lastUpdatedAt: String +} + +type Coordinator @entity { + id: ID! + contact: String + + createdAt: String + lastUpdatedAt: String +} + +type Contribution @entity { + id: ID! + contributor: Contributor + fundingRound: FundingRound + amount: BigInt + voiceCredits: BigInt + + createdAt: String +} + +type Donation @entity { + id: ID! + recipient: Bytes + fundingRound: FundingRound + amount: BigInt + voteOptionIndex: BigInt + + createdAt: String +} + +type Token @entity { + id: ID! + tokenAddress: Bytes + symbol: String + decimals: BigInt + createdAt: String + lastUpdatedAt: String +} + diff --git a/subgraph/src/ClrFundDeployerMapping.ts b/subgraph/src/ClrFundDeployerMapping.ts new file mode 100644 index 000000000..840ccf8c8 --- /dev/null +++ b/subgraph/src/ClrFundDeployerMapping.ts @@ -0,0 +1,27 @@ +import { log } from '@graphprotocol/graph-ts' +import { NewInstance } from '../generated/ClrFundDeployer/ClrFundDeployer' + +import { ClrFundDeployer, ClrFund } from '../generated/schema' +import { ClrFund as ClrFundTemplate } from '../generated/templates' + +export function handleNewInstance(event: NewInstance): void { + let clrfundDeployerAddress = event.address + let clrfundDeployerId = clrfundDeployerAddress.toHex() + + let clrFundDeployer = ClrFundDeployer.load(clrfundDeployerId) + if (!clrFundDeployer) { + clrFundDeployer = new ClrFundDeployer(clrfundDeployerId) + clrFundDeployer.createdAt = event.block.timestamp.toString() + } + + ClrFundTemplate.create(event.params.clrfund) + let clrFundAddress = event.params.clrfund + let clrFundId = clrFundAddress.toHexString() + let clrFund = new ClrFund(clrFundId) + clrFund.clrFundDeployer = clrfundDeployerId + clrFund.save() + + clrFundDeployer.lastUpdatedAt = event.block.timestamp.toString() + clrFundDeployer.save() + log.info('NewInstance {}', [clrFundId]) +} diff --git a/subgraph/src/ClrFundMapping.ts b/subgraph/src/ClrFundMapping.ts index f26e32586..3e97056c8 100644 --- a/subgraph/src/ClrFundMapping.ts +++ b/subgraph/src/ClrFundMapping.ts @@ -132,8 +132,10 @@ function createOrUpdateClrFund( let recipientRegistryId = recipientRegistryAddress.toHexString() let recipientRegistry = RecipientRegistry.load(recipientRegistryId) if (!recipientRegistry) { - createRecipientRegistry(clrFundId, recipientRegistryAddress) + recipientRegistry = createRecipientRegistry(recipientRegistryAddress) } + recipientRegistry.clrFund = clrFundId + recipientRegistry.save() let contributorRegistryAddress = clrFundContract.userRegistry() let contributorRegistryId = contributorRegistryAddress.toHexString() @@ -289,6 +291,12 @@ export function handleRoundStarted(event: RoundStarted): void { fundingRound.voteOptionTreeDepth = treeDepths.value.value3 } + let maxValues = pollContract.try_maxValues() + if (!maxValues.reverted) { + fundingRound.maxMessages = maxValues.value.value0 + fundingRound.maxVoteOptions = maxValues.value.value1 + } + let coordinatorPubKey = pollContract.try_coordinatorPubKey() if (!coordinatorPubKey.reverted) { fundingRound.coordinatorPubKeyX = coordinatorPubKey.value.value0 diff --git a/subgraph/src/MACIMapping.ts b/subgraph/src/MACIMapping.ts index 75da4929b..667822f48 100644 --- a/subgraph/src/MACIMapping.ts +++ b/subgraph/src/MACIMapping.ts @@ -21,11 +21,11 @@ import { makePublicKeyId } from './PublicKey' // - contract.verifier(...) export function handleSignUp(event: SignUp): void { - let fundingRoundAddress = event.transaction.to! - let fundingRoundId = fundingRoundAddress.toHex() + let maciAddress = event.address + let maciId = maciAddress.toHex() let publicKeyId = makePublicKeyId( - fundingRoundId, + maciId, event.params._userPubKeyX, event.params._userPubKeyY ) @@ -39,14 +39,7 @@ export function handleSignUp(event: SignUp): void { publicKey.y = event.params._userPubKeyY publicKey.stateIndex = event.params._stateIndex publicKey.voiceCreditBalance = event.params._voiceCreditBalance - - let fundingRound = FundingRound.load(fundingRoundId) - if (fundingRound == null) { - log.error('Error: handleSignUp failed, fundingRound not registered', []) - return - } - - publicKey.fundingRound = fundingRoundId + publicKey.maci = maciId publicKey.save() log.info('SignUp', []) diff --git a/subgraph/src/PollMapping.ts b/subgraph/src/PollMapping.ts index 99aa537fb..e566813e6 100644 --- a/subgraph/src/PollMapping.ts +++ b/subgraph/src/PollMapping.ts @@ -5,15 +5,7 @@ import { FundingRound, Poll, Message, PublicKey } from '../generated/schema' import { makePublicKeyId } from './PublicKey' export function handlePublishMessage(event: PublishMessage): void { - if (!event.transaction.to) { - log.error( - 'Error: handlePublishMessage failed fundingRound not registered', - [] - ) - return - } - - let pollEntityId = event.transaction.to!.toHex() + let pollEntityId = event.address.toHex() let poll = Poll.load(pollEntityId) if (poll == null) { log.error('Error: handlePublishMessage failed poll not found {}', [ @@ -25,12 +17,24 @@ export function handlePublishMessage(event: PublishMessage): void { let fundingRoundId = poll.fundingRound if (!fundingRoundId) { log.error( - 'Error: handlePublishMessage failed poll {} missing funding round', + 'Error: handlePublishMessage failed poll {} missing funding round id', [pollEntityId] ) return } + let fundingRound = FundingRound.load(fundingRoundId) + if (!fundingRound) { + log.error( + 'Error: handlePublishMessage failed poll {} missing funding round entity', + [pollEntityId] + ) + return + } + + let maci = fundingRound.maci + let maciId = maci ? maci.toHex() : '' + let messageID = event.transaction.hash.toHexString() + '-' + @@ -45,7 +49,7 @@ export function handlePublishMessage(event: PublishMessage): void { message.submittedBy = event.transaction.from let publicKeyId = makePublicKeyId( - fundingRoundId, + maciId, event.params._encPubKey.x, event.params._encPubKey.y ) @@ -56,8 +60,7 @@ export function handlePublishMessage(event: PublishMessage): void { let publicKey = new PublicKey(publicKeyId) publicKey.x = event.params._encPubKey.x publicKey.y = event.params._encPubKey.y - publicKey.fundingRound = fundingRoundId - + publicKey.maci = maciId publicKey.save() } diff --git a/subgraph/src/PublicKey.ts b/subgraph/src/PublicKey.ts index d34f33706..d3edacbc0 100644 --- a/subgraph/src/PublicKey.ts +++ b/subgraph/src/PublicKey.ts @@ -2,15 +2,11 @@ import { ByteArray, crypto, BigInt } from '@graphprotocol/graph-ts' // Create the PublicKey entity id used in subgraph // using MACI public key x and y values -export function makePublicKeyId( - fundingRoundId: string, - x: BigInt, - y: BigInt -): string { +export function makePublicKeyId(maciId: string, x: BigInt, y: BigInt): string { let publicKeyX = x.toString() let publicKeyY = y.toString() let publicKeyXY = ByteArray.fromUTF8( - fundingRoundId + '.' + publicKeyX + '.' + publicKeyY + maciId + '.' + publicKeyX + '.' + publicKeyY ) let publicKeyId = crypto.keccak256(publicKeyXY).toHexString() return publicKeyId diff --git a/subgraph/src/RecipientRegistry.ts b/subgraph/src/RecipientRegistry.ts index a9af36950..751a30e45 100644 --- a/subgraph/src/RecipientRegistry.ts +++ b/subgraph/src/RecipientRegistry.ts @@ -8,7 +8,6 @@ import { OptimisticRecipientRegistry as RecipientRegistryTemplate } from '../gen * Create the recipient registry entity */ export function createRecipientRegistry( - clrFundId: string, recipientRegistryAddress: Address ): RecipientRegistry { let recipientRegistryId = recipientRegistryAddress.toHexString() @@ -41,7 +40,6 @@ export function createRecipientRegistry( if (!owner.reverted) { recipientRegistry.owner = owner.value } - recipientRegistry.clrFund = clrFundId recipientRegistry.save() return recipientRegistry @@ -56,22 +54,7 @@ export function loadRecipientRegistry( let recipientRegistryId = address.toHexString() let recipientRegistry = RecipientRegistry.load(recipientRegistryId) if (!recipientRegistry) { - let recipientRegistryContract = RecipientRegistryContract.bind(address) - let controller = recipientRegistryContract.try_controller() - if (!controller.reverted) { - // Recipient registry's controller must be the ClrFund contract - let clrFundId = controller.value.toHexString() - let clrFund = ClrFund.load(clrFundId) - if (clrFund) { - /* This is our registry, create it */ - recipientRegistry = createRecipientRegistry(clrFund.id, address) - - // update factory - clrFund.recipientRegistry = recipientRegistryId - clrFund.recipientRegistryAddress = address - clrFund.save() - } - } + recipientRegistry = createRecipientRegistry(address) } return recipientRegistry diff --git a/subgraph/subgraph-deployer.template.yaml b/subgraph/subgraph-deployer.template.yaml new file mode 100644 index 000000000..12eab9f70 --- /dev/null +++ b/subgraph/subgraph-deployer.template.yaml @@ -0,0 +1,226 @@ +specVersion: 0.0.4 +description: clr.fund +repository: https://github.com/clrfund/monorepo +schema: + file: ./schema-deployer.graphql +dataSources: + - kind: ethereum/contract + name: ClrFundDeployer + network: {{network}} + source: + address: '{{address}}' + abi: ClrFundDeployer + startBlock: {{startBlock}} + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + entities: + - ClrFundDeployer + - ClrFund + abis: + - name: ClrFund + file: ./abis/ClrFund.json + - name: ClrFundDeployer + file: ./abis/ClrFundDeployer.json + eventHandlers: + - event: NewInstance(indexed address) + handler: handleNewInstance + file: ./src/ClrFundDeployerMapping.ts + - kind: ethereum/contract + name: OptimisticRecipientRegistry + network: {{network}} + source: + abi: OptimisticRecipientRegistry + startBlock: {{startBlock}} + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + entities: + - RecipientRegistry + - Recipient + abis: + - name: OptimisticRecipientRegistry + file: ./abis/OptimisticRecipientRegistry.json + eventHandlers: + - event: OwnershipTransferred(indexed address,indexed address) + handler: handleOwnershipTransferred + - event: RequestResolved(indexed bytes32,indexed uint8,indexed bool,uint256,uint256) + handler: handleRequestResolved + - event: RequestSubmitted(indexed bytes32,indexed uint8,address,string,uint256) + handler: handleRequestSubmitted + file: ./src/OptimisticRecipientRegistryMapping.ts +templates: + - name: ClrFund + kind: ethereum/contract + network: {{network}} + source: + abi: ClrFund + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + entities: + - ClrFund + - RecipientRegistry + - ContributorRegistry + - FundingRound + - Token + abis: + - name: ClrFund + file: ./abis/ClrFund.json + - name: FundingRound + file: ./abis/FundingRound.json + - name: MACIFactory + file: ./abis/MACIFactory.json + - name: OptimisticRecipientRegistry + file: ./abis/OptimisticRecipientRegistry.json + - name: BrightIdUserRegistry + file: ./abis/BrightIdUserRegistry.json + - name: Token + file: ./abis/Token.json + - name: Poll + file: ./abis/Poll.json + - name: MACI + file: ./abis/MACI.json + eventHandlers: + - event: CoordinatorChanged(address) + handler: handleCoordinatorChanged + - event: FundingSourceAdded(address) + handler: handleFundingSourceAdded + - event: FundingSourceRemoved(address) + handler: handleFundingSourceRemoved + - event: OwnershipTransferred(indexed address,indexed address) + handler: handleOwnershipTransferred + - event: RoundFinalized(address) + handler: handleRoundFinalized + - event: RoundStarted(address) + handler: handleRoundStarted + - event: TokenChanged(address) + handler: handleTokenChanged + - event: UserRegistryChanged(address) + handler: handleUserRegistryChanged + - event: RecipientRegistryChanged(address) + handler: handleRecipientRegistryChanged + file: ./src/ClrFundMapping.ts + - name: FundingRound + kind: ethereum/contract + network: {{network}} + source: + abi: FundingRound + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + entities: + - FundingRound + - Contribution + - Donation + - Recipient + - Contributor + abis: + - name: FundingRound + file: ./abis/FundingRound.json + - name: OptimisticRecipientRegistry + file: ./abis/OptimisticRecipientRegistry.json + - name: BrightIdUserRegistry + file: ./abis/BrightIdUserRegistry.json + eventHandlers: + - event: Contribution(indexed address,uint256) + handler: handleContribution + - event: ContributionWithdrawn(indexed address) + handler: handleContributionWithdrawn + - event: FundsClaimed(indexed uint256,indexed address,uint256) + handler: handleFundsClaimed + - event: OwnershipTransferred(indexed address,indexed address) + handler: handleOwnershipTransferred + - event: TallyPublished(string) + handler: handleTallyPublished + file: ./src/FundingRoundMapping.ts + - name: OptimisticRecipientRegistry + kind: ethereum/contract + network: {{network}} + source: + abi: OptimisticRecipientRegistry + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + entities: + - RecipientRegistry + - Recipient + abis: + - name: OptimisticRecipientRegistry + file: ./abis/OptimisticRecipientRegistry.json + eventHandlers: + - event: OwnershipTransferred(indexed address,indexed address) + handler: handleOwnershipTransferred + - event: RequestResolved(indexed bytes32,indexed uint8,indexed bool,uint256,uint256) + handler: handleRequestResolved + - event: RequestSubmitted(indexed bytes32,indexed uint8,address,string,uint256) + handler: handleRequestSubmitted + file: ./src/OptimisticRecipientRegistryMapping.ts + - name: BrightIdUserRegistry + kind: ethereum/contract + network: {{network}} + source: + abi: BrightIdUserRegistry + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + entities: + - ContributorRegistry + - Contributor + abis: + - name: BrightIdUserRegistry + file: ./abis/BrightIdUserRegistry.json + eventHandlers: + - event: OwnershipTransferred(indexed address,indexed address) + handler: handleOwnershipTransferred + - event: SetBrightIdSettings(bytes32,address) + handler: handleSetBrightIdSettings + file: ./src/BrightIdUserRegistryMapping.ts + - name: MACI + kind: ethereum/contract + network: {{network}} + source: + abi: MACI + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + entities: + - MACI + - FundingRound + abis: + - name: MACI + file: ./abis/MACI.json + - name: FundingRound + file: ./abis/FundingRound.json + eventHandlers: + - event: SignUp(uint256,indexed uint256,indexed uint256,uint256,uint256) + handler: handleSignUp + file: ./src/MACIMapping.ts + - name: Poll + kind: ethereum/contract + network: {{network}} + source: + abi: Poll + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + entities: + - Poll + - FundingRound + abis: + - name: Poll + file: ./abis/Poll.json + - name: FundingRound + file: ./abis/FundingRound.json + eventHandlers: + - event: PublishMessage((uint256,uint256[10]),(uint256,uint256)) + handler: handlePublishMessage + file: ./src/PollMapping.ts diff --git a/subgraph/subgraph.template.yaml b/subgraph/subgraph.template.yaml index 2e084d44f..09916998e 100644 --- a/subgraph/subgraph.template.yaml +++ b/subgraph/subgraph.template.yaml @@ -4,11 +4,37 @@ repository: https://github.com/clrfund/monorepo schema: file: ./schema.graphql dataSources: +{{#clrFundDeployerAddress}} + - kind: ethereum/contract + name: ClrFundDeployer + network: {{network}} + source: + address: '{{clrFundDeployerAddress}}' + abi: ClrFundDeployer + startBlock: {{clrFundDeployerStartBlock}} + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + entities: + - ClrFundDeployer + - ClrFund + abis: + - name: ClrFund + file: ./abis/ClrFund.json + - name: ClrFundDeployer + file: ./abis/ClrFundDeployer.json + eventHandlers: + - event: NewInstance(indexed address) + handler: handleNewInstance + file: ./src/ClrFundDeployerMapping.ts +{{/clrFundDeployerAddress}} +{{#clrFundAddress}} - kind: ethereum/contract name: ClrFund network: {{network}} source: - address: '{{address}}' + address: '{{clrFundAddress}}' abi: ClrFund startBlock: {{clrFundStartBlock}} mapping: @@ -58,6 +84,7 @@ dataSources: - event: RecipientRegistryChanged(address) handler: handleRecipientRegistryChanged file: ./src/ClrFundMapping.ts + {{/clrFundAddress}} - kind: ethereum/contract name: OptimisticRecipientRegistry network: {{network}} @@ -83,6 +110,60 @@ dataSources: handler: handleRequestSubmitted file: ./src/OptimisticRecipientRegistryMapping.ts templates: +{{#clrFundDeployerAddress}} + - name: ClrFund + kind: ethereum/contract + network: {{network}} + source: + abi: ClrFund + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + entities: + - ClrFund + - RecipientRegistry + - ContributorRegistry + - FundingRound + - Token + abis: + - name: ClrFund + file: ./abis/ClrFund.json + - name: FundingRound + file: ./abis/FundingRound.json + - name: MACIFactory + file: ./abis/MACIFactory.json + - name: OptimisticRecipientRegistry + file: ./abis/OptimisticRecipientRegistry.json + - name: BrightIdUserRegistry + file: ./abis/BrightIdUserRegistry.json + - name: Token + file: ./abis/Token.json + - name: Poll + file: ./abis/Poll.json + - name: MACI + file: ./abis/MACI.json + eventHandlers: + - event: CoordinatorChanged(address) + handler: handleCoordinatorChanged + - event: FundingSourceAdded(address) + handler: handleFundingSourceAdded + - event: FundingSourceRemoved(address) + handler: handleFundingSourceRemoved + - event: OwnershipTransferred(indexed address,indexed address) + handler: handleOwnershipTransferred + - event: RoundFinalized(address) + handler: handleRoundFinalized + - event: RoundStarted(address) + handler: handleRoundStarted + - event: TokenChanged(address) + handler: handleTokenChanged + - event: UserRegistryChanged(address) + handler: handleUserRegistryChanged + - event: RecipientRegistryChanged(address) + handler: handleRecipientRegistryChanged + file: ./src/ClrFundMapping.ts +{{/clrFundDeployerAddress}} - name: FundingRound kind: ethereum/contract network: {{network}} diff --git a/vue-app/.env.example b/vue-app/.env.example index b7a9357e4..a1da8a51b 100644 --- a/vue-app/.env.example +++ b/vue-app/.env.example @@ -21,27 +21,18 @@ VITE_SUBGRAPH_URL=http://localhost:8000/subgraphs/name/clrfund/clrfund VITE_CLRFUND_ADDRESS=0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82 -# Supported values: simple, brightid, snapshot, merkle +# Supported values: simple, brightid, snapshot, merkle, semaphore VITE_USER_REGISTRY_TYPE=simple # clr.fund (prod) or CLRFundTest (testing) # Learn more about BrightID and context in /docs/brightid.md VITE_BRIGHTID_CONTEXT=clrfund-goerli -# These are for interacting with the BrightID api. When the SPONSOR_API_URL and one of the -# SPONSOR_KEY is set, a sponsor request will be sent to the BrightID node when the QR code -# to link users wallet address to BrightID is displayed. SPONSOR_KEY is used to sign the -# sponsor request. The SPONSOR_KEY_FOR_NETLIFY will trigger the netlify serverless function -# to send the sponsor request. The SPONSOR_KEY alone will send the request directly from -# the web app without using the netlify function. # VITE_BRIGHTID_NODE_URL is the BrightID node used to query BrightID status. It needs to # match the BRIGHTID_VERIFIER_ADDR defined in the contract .env file. This address is used # to verify the signature returned from the BrightID verification status for user registration. # The BRIGHTID_VERIFIER_ADDR value is the ethSigningAddress from the node url, # e.g. https://brightid.clr.fund -#VITE_BRIGHTID_SPONSOR_KEY_FOR_NETLIFY= -#VITE_BRIGHTID_SPONSOR_KEY= -#VITE_BRIGHTID_SPONSOR_API_URL=https://brightid.clr.fund/brightid/v6/operations # BrightId node one url, default to clrfund node at https://brightid.clr.fund/brightid/v6 #VITE_BRIGHTID_NODE_URL=https://app.brightid.org/node/v6 @@ -75,9 +66,6 @@ GOOGLE_SHEET_NAME= # the number of record to export in a pending submissions JSON file. Default 60. VITE_EXPORT_BATCH_SIZE= -# This is only used for netlify function, sponsor.js, to avoid getting the 'fetch not found' error -AWS_LAMBDA_JS_RUNTIME=nodejs18.x - # walletconnect project id VITE_WALLET_CONNECT_PROJECT_ID=walletconnect_project_id diff --git a/vue-app/package.json b/vue-app/package.json index e5317799f..ccd226c26 100644 --- a/vue-app/package.json +++ b/vue-app/package.json @@ -1,6 +1,6 @@ { "name": "@clrfund/vue-app", - "version": "5.1.0", + "version": "6.0.0", "private": true, "license": "GPL-3.0", "type": "module", @@ -34,7 +34,7 @@ "@walletconnect/modal": "^2.6.0", "crypto-js": "^4.1.1", "ethereum-blockies-base64": "^1.0.2", - "ethers": "^6.11.1", + "ethers": "^6.12.1", "floating-vue": "^2.0.0-beta.20", "google-spreadsheet": "^3.3.0", "graphql": "^16.6.0", diff --git a/vue-app/src/App.vue b/vue-app/src/App.vue index 019d15523..3c7ad9b98 100644 --- a/vue-app/src/App.vue +++ b/vue-app/src/App.vue @@ -4,25 +4,12 @@
- -
+
-
- - -
-
- -
+ +
@@ -32,33 +19,23 @@ diff --git a/vue-app/src/components/TransactionModal.vue b/vue-app/src/components/TransactionModal.vue index ab008bc05..c26b1e75a 100644 --- a/vue-app/src/components/TransactionModal.vue +++ b/vue-app/src/components/TransactionModal.vue @@ -1,5 +1,5 @@ diff --git a/yarn.lock b/yarn.lock index 11e8b7f78..0f640e5d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,11 +7,6 @@ resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== -"@adraffy/ens-normalize@1.10.0": - version "1.10.0" - resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz#d2a39395c587e092d77cbbc80acf956a54f38bf7" - integrity sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q== - "@adraffy/ens-normalize@1.10.1": version "1.10.1" resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" @@ -578,48 +573,12 @@ resolved "https://registry.yarnpkg.com/@bugsnag/safe-json-stringify/-/safe-json-stringify-6.0.0.tgz#22abdcd83e008c369902976730c34c150148a758" integrity sha512-htzFO1Zc57S8kgdRK9mLcPVTW1BY2ijfH7Dk2CeZmspTWKdKqSo1iwmqrq2WtRjFlo8aRZYgLX0wFrDXF/9DLA== -"@chainsafe/as-sha256@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@chainsafe/as-sha256/-/as-sha256-0.3.1.tgz#3639df0e1435cab03f4d9870cc3ac079e57a6fc9" - integrity sha512-hldFFYuf49ed7DAakWVXSJODuq3pzJEguD8tQ7h+sGkM18vja+OFoJI9krnGmgzyuZC2ETX0NOIcCTy31v2Mtg== - -"@chainsafe/persistent-merkle-tree@^0.4.2": - version "0.4.2" - resolved "https://registry.yarnpkg.com/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.4.2.tgz#4c9ee80cc57cd3be7208d98c40014ad38f36f7ff" - integrity sha512-lLO3ihKPngXLTus/L7WHKaw9PnNJWizlOF1H9NNzHP6Xvh82vzg9F2bzkXhYIFshMZ2gTCEz8tq6STe7r5NDfQ== - dependencies: - "@chainsafe/as-sha256" "^0.3.1" - -"@chainsafe/persistent-merkle-tree@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz#2b4a62c9489a5739dedd197250d8d2f5427e9f63" - integrity sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw== - dependencies: - "@chainsafe/as-sha256" "^0.3.1" - -"@chainsafe/ssz@^0.10.0": - version "0.10.2" - resolved "https://registry.yarnpkg.com/@chainsafe/ssz/-/ssz-0.10.2.tgz#c782929e1bb25fec66ba72e75934b31fd087579e" - integrity sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg== - dependencies: - "@chainsafe/as-sha256" "^0.3.1" - "@chainsafe/persistent-merkle-tree" "^0.5.0" - -"@chainsafe/ssz@^0.9.2": - version "0.9.4" - resolved "https://registry.yarnpkg.com/@chainsafe/ssz/-/ssz-0.9.4.tgz#696a8db46d6975b600f8309ad3a12f7c0e310497" - integrity sha512-77Qtg2N1ayqs4Bg/wvnWfg5Bta7iy7IRh8XqXh7oNMeP2HBbBwx8m6yTpA8p0EHItWPEBkgZd5S5/LSlp3GXuQ== - dependencies: - "@chainsafe/as-sha256" "^0.3.1" - "@chainsafe/persistent-merkle-tree" "^0.4.2" - case "^1.6.3" - -"@clrfund/waffle-mock-contract@^0.0.4": - version "0.0.4" - resolved "https://registry.yarnpkg.com/@clrfund/waffle-mock-contract/-/waffle-mock-contract-0.0.4.tgz#97bb6b20df60a77b8a501e45fb4f049bdaebbea0" - integrity sha512-YRAMIFIHVpvu99b7mvVY0+XsN1JWJ57St7xv5M2VzBTXB/ARPLZENAdfpyjr1xPdpyFVed6TCurdsR6K8SWWpQ== +"@clrfund/waffle-mock-contract@^0.0.11": + version "0.0.11" + resolved "https://registry.yarnpkg.com/@clrfund/waffle-mock-contract/-/waffle-mock-contract-0.0.11.tgz#4e5917ca19ce90ae9e3160b6a1d5858e7121e408" + integrity sha512-PkaTsujg4Ybbwuq7QjWlakO3io1B88GGVesfc3VlY5EWptA3LuNqfv51KpK7L1qoWpbyZP8vsBheL8GxHwfw6A== dependencies: - ethers "^6.9.2" + ethers "^6.12.1" "@colors/colors@1.5.0": version "1.5.0" @@ -631,10 +590,10 @@ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0" integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== -"@commander-js/extra-typings@^12.0.0": - version "12.0.0" - resolved "https://registry.yarnpkg.com/@commander-js/extra-typings/-/extra-typings-12.0.0.tgz#a3ef893e75dcf08bb1e51fc7e9fe8ed2d9246bf4" - integrity sha512-7zGCwtRKOJ978LCuEZbQ9ZmLdrRkNNASphEO5i9MZb6HfOk7KfsA3f4oXqYDhko4tNrU3GmZTlHqQ/nRlYtYSw== +"@commander-js/extra-typings@^12.0.1": + version "12.0.1" + resolved "https://registry.yarnpkg.com/@commander-js/extra-typings/-/extra-typings-12.0.1.tgz#4a74a9ccf1d19ef24e71df59359c6d90a605a469" + integrity sha512-OvkMobb1eMqOCuJdbuSin/KJkkZr7n24/UNV+Lcz/0Dhepf3r2p9PaGwpRpAWej7A+gQnny4h8mGhpFl4giKkg== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" @@ -1157,7 +1116,7 @@ dependencies: "@ethersproject/logger" "^5.7.0" -"@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.7.1", "@ethersproject/providers@^5.7.2": +"@ethersproject/providers@5.7.2": version "5.7.2" resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== @@ -1912,6 +1871,14 @@ fastfile "0.0.20" ffjavascript "^0.2.48" +"@iden3/binfileutils@0.0.12": + version "0.0.12" + resolved "https://registry.yarnpkg.com/@iden3/binfileutils/-/binfileutils-0.0.12.tgz#3772552f57551814ff606fa68ea1e0ef52795ce3" + integrity sha512-naAmzuDufRIcoNfQ1d99d7hGHufLA3wZSibtr4dMe6ZeiOPV1KwOZWTJ1YVz4HbaWlpDuzVU72dS4ATQS4PXBQ== + dependencies: + fastfile "0.0.20" + ffjavascript "^0.3.0" + "@import-maps/resolve@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@import-maps/resolve/-/resolve-1.0.1.tgz#1e9fcadcf23aa0822256a329aabca241879d37c9" @@ -2674,73 +2641,53 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@nomicfoundation/ethereumjs-block@5.0.2": - version "5.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.2.tgz#13a7968f5964f1697da941281b7f7943b0465d04" - integrity sha512-hSe6CuHI4SsSiWWjHDIzWhSiAVpzMUcDRpWYzN0T9l8/Rz7xNn3elwVOJ/tAyS0LqL6vitUD78Uk7lQDXZun7Q== - dependencies: - "@nomicfoundation/ethereumjs-common" "4.0.2" - "@nomicfoundation/ethereumjs-rlp" "5.0.2" - "@nomicfoundation/ethereumjs-trie" "6.0.2" - "@nomicfoundation/ethereumjs-tx" "5.0.2" - "@nomicfoundation/ethereumjs-util" "9.0.2" - ethereum-cryptography "0.1.3" - ethers "^5.7.1" - -"@nomicfoundation/ethereumjs-block@5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.4.tgz#ff2acb98a86b9290e35e315a6abfb9aebb9cf39e" - integrity sha512-AcyacJ9eX/uPEvqsPiB+WO1ymE+kyH48qGGiGV+YTojdtas8itUTW5dehDSOXEEItWGbbzEJ4PRqnQZlWaPvDw== - dependencies: - "@nomicfoundation/ethereumjs-common" "4.0.4" - "@nomicfoundation/ethereumjs-rlp" "5.0.4" - "@nomicfoundation/ethereumjs-trie" "6.0.4" - "@nomicfoundation/ethereumjs-tx" "5.0.4" - "@nomicfoundation/ethereumjs-util" "9.0.4" - ethereum-cryptography "0.1.3" - -"@nomicfoundation/ethereumjs-blockchain@7.0.2": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.2.tgz#45323b673b3d2fab6b5008535340d1b8fea7d446" - integrity sha512-8UUsSXJs+MFfIIAKdh3cG16iNmWzWC/91P40sazNvrqhhdR/RtGDlFk2iFTGbBAZPs2+klZVzhRX8m2wvuvz3w== - dependencies: - "@nomicfoundation/ethereumjs-block" "5.0.2" - "@nomicfoundation/ethereumjs-common" "4.0.2" - "@nomicfoundation/ethereumjs-ethash" "3.0.2" - "@nomicfoundation/ethereumjs-rlp" "5.0.2" - "@nomicfoundation/ethereumjs-trie" "6.0.2" - "@nomicfoundation/ethereumjs-tx" "5.0.2" - "@nomicfoundation/ethereumjs-util" "9.0.2" - abstract-level "^1.0.3" - debug "^4.3.3" - ethereum-cryptography "0.1.3" - level "^8.0.0" - lru-cache "^5.1.1" - memory-level "^1.0.0" - -"@nomicfoundation/ethereumjs-blockchain@7.0.4": - version "7.0.4" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.4.tgz#b77511b389290b186c8d999e70f4b15c27ef44ea" - integrity sha512-jYsd/kwzbmpnxx86tXsYV8wZ5xGvFL+7/P0c6OlzpClHsbFzeF41KrYA9scON8Rg6bZu3ZTv6JOAgj3t7USUfg== - dependencies: - "@nomicfoundation/ethereumjs-block" "5.0.4" - "@nomicfoundation/ethereumjs-common" "4.0.4" - "@nomicfoundation/ethereumjs-ethash" "3.0.4" - "@nomicfoundation/ethereumjs-rlp" "5.0.4" - "@nomicfoundation/ethereumjs-trie" "6.0.4" - "@nomicfoundation/ethereumjs-tx" "5.0.4" - "@nomicfoundation/ethereumjs-util" "9.0.4" - debug "^4.3.3" - ethereum-cryptography "0.1.3" - lru-cache "^10.0.0" - -"@nomicfoundation/ethereumjs-common@4.0.2": - version "4.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.2.tgz#a15d1651ca36757588fdaf2a7d381a150662a3c3" - integrity sha512-I2WGP3HMGsOoycSdOTSqIaES0ughQTueOsddJ36aYVpI3SN8YSusgRFLwzDJwRFVIYDKx/iJz0sQ5kBHVgdDwg== - dependencies: - "@nomicfoundation/ethereumjs-util" "9.0.2" - crc-32 "^1.2.0" +"@nomicfoundation/edr-darwin-arm64@0.3.7": + version "0.3.7" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.3.7.tgz#c204edc79643624dbd431b489b254778817d8244" + integrity sha512-6tK9Lv/lSfyBvpEQ4nsTfgxyDT1y1Uv/x8Wa+aB+E8qGo3ToexQ1BMVjxJk6PChXCDOWxB3B4KhqaZFjdhl3Ow== + +"@nomicfoundation/edr-darwin-x64@0.3.7": + version "0.3.7" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.3.7.tgz#c3b394445084270cc5250d6c1869b0574e7ef810" + integrity sha512-1RrQ/1JPwxrYO69e0tglFv5H+ggour5Ii3bb727+yBpBShrxtOTQ7fZyfxA5h62LCN+0Z9wYOPeQ7XFcVurMaQ== + +"@nomicfoundation/edr-linux-arm64-gnu@0.3.7": + version "0.3.7" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.3.7.tgz#6d65545a44d1323bb7ab08c3306947165d2071de" + integrity sha512-ds/CKlBoVXIihjhflhgPn13EdKWed6r5bgvMs/YwRqT5wldQAQJZWAfA2+nYm0Yi2gMGh1RUpBcfkyl4pq7G+g== + +"@nomicfoundation/edr-linux-arm64-musl@0.3.7": + version "0.3.7" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.3.7.tgz#5368534bceac1a8c18b1be6b908caca5d39b0c03" + integrity sha512-e29udiRaPujhLkM3+R6ju7QISrcyOqpcaxb2FsDWBkuD7H8uU9JPZEyyUIpEp5uIY0Jh1eEJPKZKIXQmQAEAuw== + +"@nomicfoundation/edr-linux-x64-gnu@0.3.7": + version "0.3.7" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.3.7.tgz#42349bf5941dbb54a5719942924c6e4e8cde348e" + integrity sha512-/xkjmTyv+bbJ4akBCW0qzFKxPOV4AqLOmqurov+s9umHb16oOv72osSa3SdzJED2gHDaKmpMITT4crxbar4Axg== + +"@nomicfoundation/edr-linux-x64-musl@0.3.7": + version "0.3.7" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.3.7.tgz#e6babe11c9a8012f1284e6e48c3551861f2a7cd4" + integrity sha512-QwBP9xlmsbf/ldZDGLcE4QiAb8Zt46E/+WLpxHBATFhGa7MrpJh6Zse+h2VlrT/SYLPbh2cpHgSmoSlqVxWG9g== + +"@nomicfoundation/edr-win32-x64-msvc@0.3.7": + version "0.3.7" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.3.7.tgz#1504b98f305f03be153b0220a546985660de9dc6" + integrity sha512-j/80DEnkxrF2ewdbk/gQ2EOPvgF0XSsg8D0o4+6cKhUVAW6XwtWKzIphNL6dyD2YaWEPgIrNvqiJK/aln0ww4Q== + +"@nomicfoundation/edr@^0.3.7": + version "0.3.7" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.3.7.tgz#9c75edf1fcf601617905b2c89acf103f4786d017" + integrity sha512-v2JFWnFKRsnOa6PDUrD+sr8amcdhxnG/YbL7LzmgRGU1odWEyOF4/EwNeUajQr4ZNKVWrYnJ6XjydXtUge5OBQ== + optionalDependencies: + "@nomicfoundation/edr-darwin-arm64" "0.3.7" + "@nomicfoundation/edr-darwin-x64" "0.3.7" + "@nomicfoundation/edr-linux-arm64-gnu" "0.3.7" + "@nomicfoundation/edr-linux-arm64-musl" "0.3.7" + "@nomicfoundation/edr-linux-x64-gnu" "0.3.7" + "@nomicfoundation/edr-linux-x64-musl" "0.3.7" + "@nomicfoundation/edr-win32-x64-msvc" "0.3.7" "@nomicfoundation/ethereumjs-common@4.0.4": version "4.0.4" @@ -2749,128 +2696,11 @@ dependencies: "@nomicfoundation/ethereumjs-util" "9.0.4" -"@nomicfoundation/ethereumjs-ethash@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.2.tgz#da77147f806401ee996bfddfa6487500118addca" - integrity sha512-8PfoOQCcIcO9Pylq0Buijuq/O73tmMVURK0OqdjhwqcGHYC2PwhbajDh7GZ55ekB0Px197ajK3PQhpKoiI/UPg== - dependencies: - "@nomicfoundation/ethereumjs-block" "5.0.2" - "@nomicfoundation/ethereumjs-rlp" "5.0.2" - "@nomicfoundation/ethereumjs-util" "9.0.2" - abstract-level "^1.0.3" - bigint-crypto-utils "^3.0.23" - ethereum-cryptography "0.1.3" - -"@nomicfoundation/ethereumjs-ethash@3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.4.tgz#06cb2502b3012fb6c11cffd44af08aecf71310da" - integrity sha512-xvIrwIMl9sSaiYKRem68+O7vYdj7Q2XWv5P7JXiIkn83918QzWHvqbswTRsH7+r6X1UEvdsURRnZbvZszEjAaQ== - dependencies: - "@nomicfoundation/ethereumjs-block" "5.0.4" - "@nomicfoundation/ethereumjs-rlp" "5.0.4" - "@nomicfoundation/ethereumjs-util" "9.0.4" - bigint-crypto-utils "^3.2.2" - ethereum-cryptography "0.1.3" - -"@nomicfoundation/ethereumjs-evm@2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.2.tgz#4c2f4b84c056047102a4fa41c127454e3f0cfcf6" - integrity sha512-rBLcUaUfANJxyOx9HIdMX6uXGin6lANCulIm/pjMgRqfiCRMZie3WKYxTSd8ZE/d+qT+zTedBF4+VHTdTSePmQ== - dependencies: - "@ethersproject/providers" "^5.7.1" - "@nomicfoundation/ethereumjs-common" "4.0.2" - "@nomicfoundation/ethereumjs-tx" "5.0.2" - "@nomicfoundation/ethereumjs-util" "9.0.2" - debug "^4.3.3" - ethereum-cryptography "0.1.3" - mcl-wasm "^0.7.1" - rustbn.js "~0.2.0" - -"@nomicfoundation/ethereumjs-evm@2.0.4": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.4.tgz#c9c761767283ac53946185474362230b169f8f63" - integrity sha512-lTyZZi1KpeMHzaO6cSVisR2tjiTTedjo7PcmhI/+GNFo9BmyY6QYzGeSti0sFttmjbEMioHgXxl5yrLNRg6+1w== - dependencies: - "@nomicfoundation/ethereumjs-common" "4.0.4" - "@nomicfoundation/ethereumjs-statemanager" "2.0.4" - "@nomicfoundation/ethereumjs-tx" "5.0.4" - "@nomicfoundation/ethereumjs-util" "9.0.4" - "@types/debug" "^4.1.9" - debug "^4.3.3" - ethereum-cryptography "0.1.3" - rustbn-wasm "^0.2.0" - -"@nomicfoundation/ethereumjs-rlp@5.0.2": - version "5.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.2.tgz#4fee8dc58a53ac6ae87fb1fca7c15dc06c6b5dea" - integrity sha512-QwmemBc+MMsHJ1P1QvPl8R8p2aPvvVcKBbvHnQOKBpBztEo0omN0eaob6FeZS/e3y9NSe+mfu3nNFBHszqkjTA== - "@nomicfoundation/ethereumjs-rlp@5.0.4": version "5.0.4" resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.4.tgz#66c95256fc3c909f6fb18f6a586475fc9762fa30" integrity sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw== -"@nomicfoundation/ethereumjs-statemanager@2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.2.tgz#3ba4253b29b1211cafe4f9265fee5a0d780976e0" - integrity sha512-dlKy5dIXLuDubx8Z74sipciZnJTRSV/uHG48RSijhgm1V7eXYFC567xgKtsKiVZB1ViTP9iFL4B6Je0xD6X2OA== - dependencies: - "@nomicfoundation/ethereumjs-common" "4.0.2" - "@nomicfoundation/ethereumjs-rlp" "5.0.2" - debug "^4.3.3" - ethereum-cryptography "0.1.3" - ethers "^5.7.1" - js-sdsl "^4.1.4" - -"@nomicfoundation/ethereumjs-statemanager@2.0.4": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.4.tgz#bf14415e1f31b5ea8b98a0c027c547d0555059b6" - integrity sha512-HPDjeFrxw6llEi+BzqXkZ+KkvFnTOPczuHBtk21hRlDiuKuZz32dPzlhpRsDBGV1b5JTmRDUVqCS1lp3Gghw4Q== - dependencies: - "@nomicfoundation/ethereumjs-common" "4.0.4" - "@nomicfoundation/ethereumjs-rlp" "5.0.4" - "@nomicfoundation/ethereumjs-trie" "6.0.4" - "@nomicfoundation/ethereumjs-util" "9.0.4" - debug "^4.3.3" - ethereum-cryptography "0.1.3" - js-sdsl "^4.1.4" - lru-cache "^10.0.0" - -"@nomicfoundation/ethereumjs-trie@6.0.2": - version "6.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.2.tgz#9a6dbd28482dca1bc162d12b3733acab8cd12835" - integrity sha512-yw8vg9hBeLYk4YNg5MrSJ5H55TLOv2FSWUTROtDtTMMmDGROsAu+0tBjiNGTnKRi400M6cEzoFfa89Fc5k8NTQ== - dependencies: - "@nomicfoundation/ethereumjs-rlp" "5.0.2" - "@nomicfoundation/ethereumjs-util" "9.0.2" - "@types/readable-stream" "^2.3.13" - ethereum-cryptography "0.1.3" - readable-stream "^3.6.0" - -"@nomicfoundation/ethereumjs-trie@6.0.4": - version "6.0.4" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.4.tgz#688a3f76646c209365ee6d959c3d7330ede5e609" - integrity sha512-3nSwQiFMvr2VFe/aZUyinuohYvtytUqZCUCvIWcPJ/BwJH6oQdZRB42aNFBJ/8nAh2s3OcroWpBLskzW01mFKA== - dependencies: - "@nomicfoundation/ethereumjs-rlp" "5.0.4" - "@nomicfoundation/ethereumjs-util" "9.0.4" - "@types/readable-stream" "^2.3.13" - ethereum-cryptography "0.1.3" - lru-cache "^10.0.0" - readable-stream "^3.6.0" - -"@nomicfoundation/ethereumjs-tx@5.0.2": - version "5.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.2.tgz#117813b69c0fdc14dd0446698a64be6df71d7e56" - integrity sha512-T+l4/MmTp7VhJeNloMkM+lPU3YMUaXdcXgTGCf8+ZFvV9NYZTRLFekRwlG6/JMmVfIfbrW+dRRJ9A6H5Q/Z64g== - dependencies: - "@chainsafe/ssz" "^0.9.2" - "@ethersproject/providers" "^5.7.2" - "@nomicfoundation/ethereumjs-common" "4.0.2" - "@nomicfoundation/ethereumjs-rlp" "5.0.2" - "@nomicfoundation/ethereumjs-util" "9.0.2" - ethereum-cryptography "0.1.3" - "@nomicfoundation/ethereumjs-tx@5.0.4": version "5.0.4" resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.4.tgz#b0ceb58c98cc34367d40a30d255d6315b2f456da" @@ -2881,15 +2711,6 @@ "@nomicfoundation/ethereumjs-util" "9.0.4" ethereum-cryptography "0.1.3" -"@nomicfoundation/ethereumjs-util@9.0.2": - version "9.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.2.tgz#16bdc1bb36f333b8a3559bbb4b17dac805ce904d" - integrity sha512-4Wu9D3LykbSBWZo8nJCnzVIYGvGCuyiYLIJa9XXNVt1q1jUzHdB+sJvx95VGCpPkCT+IbLecW6yfzy3E1bQrwQ== - dependencies: - "@chainsafe/ssz" "^0.10.0" - "@nomicfoundation/ethereumjs-rlp" "5.0.2" - ethereum-cryptography "0.1.3" - "@nomicfoundation/ethereumjs-util@9.0.4": version "9.0.4" resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.4.tgz#84c5274e82018b154244c877b76bc049a4ed7b38" @@ -2898,56 +2719,10 @@ "@nomicfoundation/ethereumjs-rlp" "5.0.4" ethereum-cryptography "0.1.3" -"@nomicfoundation/ethereumjs-verkle@0.0.2": - version "0.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-verkle/-/ethereumjs-verkle-0.0.2.tgz#7686689edec775b2efea5a71548f417c18f7dea4" - integrity sha512-bjnfZElpYGK/XuuVRmLS3yDvr+cDs85D9oonZ0YUa5A3lgFgokWMp76zXrxX2jVQ0BfHaw12y860n1+iOi6yFQ== - dependencies: - "@nomicfoundation/ethereumjs-rlp" "5.0.4" - "@nomicfoundation/ethereumjs-util" "9.0.4" - lru-cache "^10.0.0" - rust-verkle-wasm "^0.0.1" - -"@nomicfoundation/ethereumjs-vm@7.0.2": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.2.tgz#3b0852cb3584df0e18c182d0672a3596c9ca95e6" - integrity sha512-Bj3KZT64j54Tcwr7Qm/0jkeZXJMfdcAtRBedou+Hx0dPOSIgqaIr0vvLwP65TpHbak2DmAq+KJbW2KNtIoFwvA== - dependencies: - "@nomicfoundation/ethereumjs-block" "5.0.2" - "@nomicfoundation/ethereumjs-blockchain" "7.0.2" - "@nomicfoundation/ethereumjs-common" "4.0.2" - "@nomicfoundation/ethereumjs-evm" "2.0.2" - "@nomicfoundation/ethereumjs-rlp" "5.0.2" - "@nomicfoundation/ethereumjs-statemanager" "2.0.2" - "@nomicfoundation/ethereumjs-trie" "6.0.2" - "@nomicfoundation/ethereumjs-tx" "5.0.2" - "@nomicfoundation/ethereumjs-util" "9.0.2" - debug "^4.3.3" - ethereum-cryptography "0.1.3" - mcl-wasm "^0.7.1" - rustbn.js "~0.2.0" - -"@nomicfoundation/ethereumjs-vm@7.0.4": - version "7.0.4" - resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.4.tgz#e5a6eec4877dc62dda93003c6d7afd1fe4b9625b" - integrity sha512-gsA4IhmtWHI4BofKy3kio9W+dqZQs5Ji5mLjLYxHCkat+JQBUt5szjRKra2F9nGDJ2XcI/wWb0YWUFNgln4zRQ== - dependencies: - "@nomicfoundation/ethereumjs-block" "5.0.4" - "@nomicfoundation/ethereumjs-blockchain" "7.0.4" - "@nomicfoundation/ethereumjs-common" "4.0.4" - "@nomicfoundation/ethereumjs-evm" "2.0.4" - "@nomicfoundation/ethereumjs-rlp" "5.0.4" - "@nomicfoundation/ethereumjs-statemanager" "2.0.4" - "@nomicfoundation/ethereumjs-trie" "6.0.4" - "@nomicfoundation/ethereumjs-tx" "5.0.4" - "@nomicfoundation/ethereumjs-util" "9.0.4" - debug "^4.3.3" - ethereum-cryptography "0.1.3" - -"@nomicfoundation/hardhat-chai-matchers@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-2.0.3.tgz#f4c074d39b74bd283c99e2c2bf143e3cef51ae18" - integrity sha512-A40s7EAK4Acr8UP1Yudgi9GGD9Cca/K3LHt3DzmRIje14lBfHtg9atGQ7qK56vdPcTwKmeaGn30FzxMUfPGEMw== +"@nomicfoundation/hardhat-chai-matchers@^2.0.6": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-2.0.6.tgz#ef88be3bd666adf29c06ac7882e96c8dbaaa32ba" + integrity sha512-Te1Uyo9oJcTCF0Jy9dztaLpshmlpjLf2yPtWXlXuLjMt3RRSmJLm/+rKVTW6gfadAEs12U/it6D0ZRnnRGiICQ== dependencies: "@types/chai-as-promised" "^7.1.3" chai-as-promised "^7.1.1" @@ -2962,6 +2737,14 @@ debug "^4.1.1" lodash.isequal "^4.5.0" +"@nomicfoundation/hardhat-ethers@^3.0.6": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.6.tgz#e8ba7f9719de360c03501b85dae4999bb3a7e1c5" + integrity sha512-/xzkFQAaHQhmIAYOQmvHBPwL+NkwLzT9gRZBsgWUYeV+E6pzXsBQsHfRYbAZ3XEYare+T7S+5Tg/1KDJgepSkA== + dependencies: + debug "^4.1.1" + lodash.isequal "^4.5.0" + "@nomicfoundation/hardhat-network-helpers@^1.0.10": version "1.0.10" resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.10.tgz#c61042ceb104fdd6c10017859fdef6529c1d6585" @@ -2974,6 +2757,11 @@ resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-toolbox/-/hardhat-toolbox-4.0.0.tgz#eb1f619218dd1414fa161dfec92d3e5e53a2f407" integrity sha512-jhcWHp0aHaL0aDYj8IJl80v4SZXWMS1A2XxXa1CA6pBiFfJKuZinCkO6wb+POAt0LIfXB3gA3AgdcOccrcwBwA== +"@nomicfoundation/hardhat-toolbox@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-toolbox/-/hardhat-toolbox-5.0.0.tgz#165b47f8a3d2bf668cc5d453ce7f496a1156948d" + integrity sha512-FnUtUC5PsakCbwiVNsqlXVIWG5JIb5CEZoSXbJUsEBun22Bivx2jhF1/q9iQbzuaGpJKFQyOhemPB2+XlEE6pQ== + "@nomicfoundation/hardhat-verify@^2.0.3": version "2.0.3" resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.3.tgz#173557f8cfa53c8c9da23a326f54d24fe459ae68" @@ -3272,15 +3060,10 @@ resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.6.0.tgz#de2c6823203d6f319511898bb5de7e70f5267e19" integrity sha512-OWlrQAnWn9577PhVgqjUvMr1pg57Bc4jv0iL4w0PRuOSRvq67rvHW9Ie/dZVMvCzhSCB+UxhcY/PmCmFj33Q+g== -"@openzeppelin/contracts@4.9.0": - version "4.9.0" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.0.tgz#683f33b6598970051bc5f0806fd8660da9e018dd" - integrity sha512-DUP74AFGKlic2sQb/CmgrN2aUPMFGxRrmCTUxLHsiU2RzwWqVuMPZBxiAyvlff6Pea77uylAX6B5x9W6evEbhA== - -"@openzeppelin/contracts@^4.8.0": - version "4.9.5" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.5.tgz#1eed23d4844c861a1835b5d33507c1017fa98de8" - integrity sha512-ZK+W5mVhRppff9BE6YdR8CC52C8zAvsVAiWhEtQ5+oNxFE6h1WdeWo+FJSF8KKvtxxVYZ7MTP/5KoVpAU3aSWg== +"@openzeppelin/contracts@5.0.2", "@openzeppelin/contracts@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-5.0.2.tgz#b1d03075e49290d06570b2fd42154d76c2a5d210" + integrity sha512-ytPc6eLGcHHnapAZ9S+5qsdomhjo6QBHTDRRBFfTxXIpsicMhVPouPgmUPebZZZGX7vt9USA+Z+0M0dSVtSUEA== "@openzeppelin/merkle-tree@^1.0.5": version "1.0.5" @@ -3409,6 +3192,16 @@ tslib "^2.5.0" webcrypto-core "^1.7.7" +"@pinata/sdk@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@pinata/sdk/-/sdk-2.1.0.tgz#d61aa8f21ec1206e867f4b65996db52b70316945" + integrity sha512-hkS0tcKtsjf9xhsEBs2Nbey5s+Db7x5rlOH9TaWHBXkJ7IwwOs2xnEDigNaxAHKjYAwcw+m2hzpO5QgOfeF7Zw== + dependencies: + axios "^0.21.1" + form-data "^2.3.3" + is-ipfs "^0.6.0" + path "^0.12.7" + "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" @@ -3534,7 +3327,7 @@ resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.6.1.tgz#9ab8f811930d7af3e3d549183a50884f9eb83f36" integrity sha512-UY+FGM/2jjMkzQLn8pxcHGMaVLh9aEitG3zY2CiY7XHdLiz3bZOwa6oDxNqEMv7zZkV+cj5DOdz0cQ1BP5Hjgw== -"@scure/base@^1.1.1", "@scure/base@~1.1.0": +"@scure/base@~1.1.0": version "1.1.5" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.5.tgz#1d85d17269fe97694b9c592552dd9e5e33552157" integrity sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ== @@ -3954,13 +3747,6 @@ dependencies: "@types/node" "*" -"@types/debug@^4.1.9": - version "4.1.12" - resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917" - integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ== - dependencies: - "@types/ms" "*" - "@types/estree@^1.0.0": version "1.0.5" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" @@ -4081,11 +3867,6 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.6.tgz#818551d39113081048bdddbef96701b4e8bb9d1b" integrity sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg== -"@types/ms@*": - version "0.7.34" - resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433" - integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== - "@types/node@*", "@types/node@>=13.7.0": version "20.11.2" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.2.tgz#39cea3fe02fbbc2f80ed283e94e1d24f2d3856fb" @@ -4147,14 +3928,6 @@ resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.11.tgz#208d8a30bc507bd82e03ada29e4732ea46a6bbda" integrity sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ== -"@types/readable-stream@^2.3.13": - version "2.3.15" - resolved "https://registry.yarnpkg.com/@types/readable-stream/-/readable-stream-2.3.15.tgz#3d79c9ceb1b6a57d5f6e6976f489b9b5384321ae" - integrity sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ== - dependencies: - "@types/node" "*" - safe-buffer "~5.1.1" - "@types/resolve@^0.0.8": version "0.0.8" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194" @@ -4946,40 +4719,62 @@ resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== -"@zk-kit/baby-jubjub@0.1.1", "@zk-kit/baby-jubjub@^0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@zk-kit/baby-jubjub/-/baby-jubjub-0.1.1.tgz#8da922d1c0138ca8668c6ba1134ec04f51b24804" - integrity sha512-eWpUSpKKpllGZXE6mdS1IVuegRjY2Yu+3Qccyfg0+gMI8+p0ruioMM/MCK3tg2lRIUJTVd+16UghVcK0145yWg== +"@zk-kit/baby-jubjub@0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@zk-kit/baby-jubjub/-/baby-jubjub-0.2.0.tgz#71c5396ddacb97e4e3db677933f74bde3332b236" + integrity sha512-pqiPq621oKpwiIkf1KcVh5MdbFX0V67s9gCmiEkhLMeafZaIXEwVt5qmIu1d2HB4mjXgr4Ys8Jpn2Rw4KXxnFQ== dependencies: - "@zk-kit/utils" "0.1.0" + "@zk-kit/utils" "0.3.0" -"@zk-kit/circuits@^0.3.0": +"@zk-kit/baby-jubjub@0.3.0", "@zk-kit/baby-jubjub@^0.3.0": version "0.3.0" - resolved "https://registry.yarnpkg.com/@zk-kit/circuits/-/circuits-0.3.0.tgz#716d932e9b09f33c71c7ff940a507e519ce0a6f4" - integrity sha512-v46KHC3sBRXUJbYi8d5PTAm3zCdBeArvWw3de+A2LcW/C9beYqBo8QJ/h6NWKZWOgpwqvCHzJa5HvyG6x3lIZQ== + resolved "https://registry.yarnpkg.com/@zk-kit/baby-jubjub/-/baby-jubjub-0.3.0.tgz#78b8d3226670dd02dc8ced713aec64d6bb2a6e62" + integrity sha512-mA3/M/+4C2vDtc0SpXf/q/nsvwBh+s42ou176sgDzqIBQD/u/N+LaLGorDh+X5AD3dVMHb8rheFpnnrJmjsqdA== + dependencies: + "@zk-kit/utils" "0.6.0" + +"@zk-kit/circuits@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@zk-kit/circuits/-/circuits-0.4.0.tgz#17a8333e8afe5a4e79260600a2dcefb2bc751a8f" + integrity sha512-Di7mokhwBS3qxVeCfHxGeNIpDg1kTnr1JXmsWiQMZLkRTn3Hugh6Tl07J394rWD0pIWRwPQsinaMVL2sB4F8yQ== dependencies: circomlib "^2.0.5" -"@zk-kit/eddsa-poseidon@^0.5.1": - version "0.5.1" - resolved "https://registry.yarnpkg.com/@zk-kit/eddsa-poseidon/-/eddsa-poseidon-0.5.1.tgz#7fef431f441f5385f82e6005cdf83d72d298e8c2" - integrity sha512-sPyoyjwg9EZ+tHLGxOG+FDj9XJK1knVjm27nTMV4ZSiQIf0427QWnLhOk7b6zMvFmEpBWTG9gneJ5pr3jzJ4zg== +"@zk-kit/eddsa-poseidon@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@zk-kit/eddsa-poseidon/-/eddsa-poseidon-0.11.0.tgz#f648b50a79ce660df75896d8fafa30c0f6eb9a43" + integrity sha512-8XgIVSD+nTnTEjvdrFVvju6lVQ5rxCfkBnf/nCFN/IteiIpYX7LnxrTOV7pIp3RrWL29WuTvNrT8TlBrHRrUFA== dependencies: - "@zk-kit/baby-jubjub" "0.1.1" - "@zk-kit/utils" "0.1.0" + "@zk-kit/baby-jubjub" "0.3.0" + "@zk-kit/utils" "0.8.1" + buffer "6.0.3" -"@zk-kit/poseidon-cipher@^0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@zk-kit/poseidon-cipher/-/poseidon-cipher-0.2.1.tgz#74cd80144b6755eff8e92643c4ef3f828f5822c5" - integrity sha512-/k7lUzYPuzFmdjBCvl8yTE4aDCnqxoVC46Txa9Z0i7rb+ilXHp2EEwfig/G7moTukSiOB3hywF3im/QGs3cYHg== +"@zk-kit/poseidon-cipher@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@zk-kit/poseidon-cipher/-/poseidon-cipher-0.3.0.tgz#e05a5d8a39a2d3a9aadb1b9997c2580713eacfff" + integrity sha512-Byszt7dxssgsR7hog2nf9AMaBKYr8LrgtlU/PPHPEe2OkJwIeQSshoxqquLlZsyfOn2c1ZmTJb4Mo4aHY11pCA== dependencies: - "@zk-kit/baby-jubjub" "0.1.1" - "@zk-kit/utils" "0.1.0" + "@zk-kit/baby-jubjub" "0.2.0" + "@zk-kit/utils" "0.3.0" -"@zk-kit/utils@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@zk-kit/utils/-/utils-0.1.0.tgz#6c134c22541efc6e634d4a89884c8bfe209b2da1" - integrity sha512-MZmuw2w2StB7XOSNg1TW4VwnBJ746UDmdXTvxwDO/U85UZfGfM3zb53gG35qz5sWpQo/DjfoKqaScmh6HUtQpA== +"@zk-kit/utils@0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@zk-kit/utils/-/utils-0.3.0.tgz#ca85ab40540ee76b3a09b91df66a55d7f319a71d" + integrity sha512-yVBczOwOSV+evSgdsJ0tpPn3oQpbL7a7fRqANDogleaLLte1IFxKTFLz3WNcgd28Asq2guMGiU6SmiEc61uHAg== + +"@zk-kit/utils@0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@zk-kit/utils/-/utils-0.6.0.tgz#30124e98df8e29f7af31e19ce4dc6302f178c0a4" + integrity sha512-sUF1yVjlGmm7/NIN/+d+N8WOcI77bTzgV5+vZmp/S7lXcy4fmO+5TdHERRsDbs8Ep8K33EOC6V+U+JXzmjSe5A== + dependencies: + buffer "^6.0.3" + +"@zk-kit/utils@0.8.1": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@zk-kit/utils/-/utils-0.8.1.tgz#9d358542e6b223dde35f32f3e161d1d3a41b0644" + integrity sha512-m5cvnYo5IBZQCO8H5X0Mw3rGRGEoSqlYXVVF1+4M9IT3olDWcJHLPRqtYGF9zNf+vXV/21srpZ0hX3X2Lzp1TQ== + dependencies: + buffer "^6.0.3" JSONStream@1.3.2: version "1.3.2" @@ -5019,19 +4814,6 @@ abort-controller@^3.0.0: dependencies: event-target-shim "^5.0.0" -abstract-level@^1.0.0, abstract-level@^1.0.2, abstract-level@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/abstract-level/-/abstract-level-1.0.3.tgz#78a67d3d84da55ee15201486ab44c09560070741" - integrity sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA== - dependencies: - buffer "^6.0.3" - catering "^2.1.0" - is-buffer "^2.0.5" - level-supports "^4.0.0" - level-transcoder "^1.0.1" - module-error "^1.0.1" - queue-microtask "^1.2.3" - abstract-leveldown@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-3.0.0.tgz#5cb89f958a44f526779d740d1440e743e0c30a57" @@ -6454,11 +6236,6 @@ bfj@^7.0.2: jsonpath "^1.1.1" tryer "^1.0.1" -bigint-crypto-utils@^3.0.23, bigint-crypto-utils@^3.2.2: - version "3.3.0" - resolved "https://registry.yarnpkg.com/bigint-crypto-utils/-/bigint-crypto-utils-3.3.0.tgz#72ad00ae91062cf07f2b1def9594006c279c1d77" - integrity sha512-jOTSb+drvEDxEq6OuUybOAv/xxoh3cuYRUIPyu8sSHQNKM303UQ2R1DAo45o1AkcIXw6fzbaFI1+xGGdaXs2lg== - bignumber.js@^9.0.0: version "9.1.2" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" @@ -6724,16 +6501,6 @@ brorand@^1.0.1, brorand@^1.1.0: resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== -browser-level@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browser-level/-/browser-level-1.0.1.tgz#36e8c3183d0fe1c405239792faaab5f315871011" - integrity sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ== - dependencies: - abstract-level "^1.0.2" - catering "^2.1.1" - module-error "^1.0.2" - run-parallel-limit "^1.1.0" - browser-readablestream-to-it@^1.0.0, browser-readablestream-to-it@^1.0.1, browser-readablestream-to-it@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/browser-readablestream-to-it/-/browser-readablestream-to-it-1.0.3.tgz#ac3e406c7ee6cdf0a502dd55db33bab97f7fba76" @@ -6830,7 +6597,7 @@ browserslist@^4.21.10, browserslist@^4.22.2: node-releases "^2.0.14" update-browserslist-db "^1.0.13" -bs58@^4.0.0: +bs58@^4.0.0, bs58@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== @@ -6886,7 +6653,7 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== -"buffer-polyfill@npm:buffer@^6.0.3", buffer@^6.0.1, buffer@^6.0.3: +"buffer-polyfill@npm:buffer@^6.0.3", buffer@6.0.3, buffer@^6.0.1, buffer@^6.0.3: name buffer-polyfill version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" @@ -7136,21 +6903,11 @@ cardinal@^2.1.1: ansicolors "~0.3.2" redeyed "~2.1.0" -case@^1.6.3: - version "1.6.3" - resolved "https://registry.yarnpkg.com/case/-/case-1.6.3.tgz#0a4386e3e9825351ca2e6216c60467ff5f1ea1c9" - integrity sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ== - caseless@^0.12.0, caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== -catering@^2.1.0, catering@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" - integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== - cbor@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/cbor/-/cbor-8.1.0.tgz#cfc56437e770b73417a2ecbfc9caf6b771af60d5" @@ -7170,7 +6927,7 @@ chai-as-promised@^7.1.1: dependencies: check-error "^1.0.2" -chai@^4.2.0, chai@^4.3.6, chai@^4.3.7: +chai@4, chai@^4.2.0, chai@^4.3.6, chai@^4.3.7: version "4.4.1" resolved "https://registry.yarnpkg.com/chai/-/chai-4.4.1.tgz#3603fa6eba35425b0f2ac91a009fe924106e50d1" integrity sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g== @@ -7397,6 +7154,13 @@ circom_runtime@0.1.24: dependencies: ffjavascript "0.2.60" +circom_runtime@0.1.25: + version "0.1.25" + resolved "https://registry.yarnpkg.com/circom_runtime/-/circom_runtime-0.1.25.tgz#62a33b371f4633f30238db7a326c43d988e3a170" + integrity sha512-xBGsBFF5Uv6AKvbpgExYqpHfmfawH2HKe+LyjfKSRevqEV8u63i9KGHVIILsbJNW+0c5bm/66f0PUYQ7qZSkJA== + dependencies: + ffjavascript "0.3.0" + circom_tester@^0.0.19: version "0.0.19" resolved "https://registry.yarnpkg.com/circom_tester/-/circom_tester-0.0.19.tgz#e8bed494d080f8186bd0ac6571755d00ccec83bd" @@ -7411,10 +7175,10 @@ circom_tester@^0.0.19: tmp-promise "^3.0.3" util "^0.12.4" -circomkit@^0.0.24: - version "0.0.24" - resolved "https://registry.yarnpkg.com/circomkit/-/circomkit-0.0.24.tgz#11db0ba17da9f5bd3e58bc87d5b39bb8375e3bf8" - integrity sha512-lw5Kj6zAWS8NYZjlDCGEDeA1e0/Vpa6t6W3GT0AxfhswUoqK0Nu3sz5hu8ZQ+Efh0Ss3eLoD0y+9sOkySEwgEA== +circomkit@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/circomkit/-/circomkit-0.1.0.tgz#f44cf86d46b3a3dff5a4958b6450f494d6fa9970" + integrity sha512-Mnc9IuOoaN7FitfURvbg2Q5j62S7/zQl6l18u5dcIhZg3Ot9MZYLiGIotCaF1Gfp/vAUKnvO2lnS3Xc1TdTISA== dependencies: chai "^4.3.7" circom_tester "^0.0.19" @@ -7458,17 +7222,6 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -classic-level@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/classic-level/-/classic-level-1.3.0.tgz#5e36680e01dc6b271775c093f2150844c5edd5c8" - integrity sha512-iwFAJQYtqRTRM0F6L8h4JCt00ZSGdOyqh7yVrhhjrOpFhmBjNlRUey64MCiyo6UmQHMJ+No3c81nujPv+n9yrg== - dependencies: - abstract-level "^1.0.2" - catering "^2.1.0" - module-error "^1.0.1" - napi-macros "^2.2.2" - node-gyp-build "^4.3.0" - clean-deep@3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/clean-deep/-/clean-deep-3.4.0.tgz#c465c4de1003ae13a1a859e6c69366ab96069f75" @@ -8457,7 +8210,7 @@ debug@3.2.6: dependencies: ms "^2.1.1" -debug@4, debug@4.3.4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: +debug@4, debug@4.3.4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -10123,7 +9876,7 @@ ethereumjs-wallet@0.6.5: utf8 "^3.0.0" uuid "^3.3.2" -ethers@^5.0.3, ethers@^5.5.1, ethers@^5.7.1, ethers@^5.7.2: +ethers@^5.0.3, ethers@^5.5.1, ethers@^5.7.2: version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== @@ -10159,10 +9912,10 @@ ethers@^5.0.3, ethers@^5.5.1, ethers@^5.7.1, ethers@^5.7.2: "@ethersproject/web" "5.7.1" "@ethersproject/wordlists" "5.7.0" -ethers@^6.11.1: - version "6.11.1" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.11.1.tgz#96aae00b627c2e35f9b0a4d65c7ab658259ee6af" - integrity sha512-mxTAE6wqJQAbp5QAe/+o+rXOID7Nw91OZXvgpjDa1r4fAbq2Nu314oEZSbjoRLacuCzs7kUC3clEvkCQowffGg== +ethers@^6.12.0, ethers@^6.12.1: + version "6.12.1" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.12.1.tgz#517ff6d66d4fd5433e38e903051da3e57c87ff37" + integrity sha512-j6wcVoZf06nqEcBbDWkKg8Fp895SS96dSnTCjiXT+8vt2o02raTn4Lo9ERUuIVU5bAjoPYeA+7ytQFexFmLuVw== dependencies: "@adraffy/ens-normalize" "1.10.1" "@noble/curves" "1.2.0" @@ -10172,19 +9925,6 @@ ethers@^6.11.1: tslib "2.4.0" ws "8.5.0" -ethers@^6.9.2: - version "6.10.0" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.10.0.tgz#20f3c63c60d59a993f8090ad423d8a3854b3b1cd" - integrity sha512-nMNwYHzs6V1FR3Y4cdfxSQmNgZsRj1RiTU25JwvnJLmyzw9z3SKxNc2XKDuiXXo/v9ds5Mp9m6HBabgYQQ26tA== - dependencies: - "@adraffy/ens-normalize" "1.10.0" - "@noble/curves" "1.2.0" - "@noble/hashes" "1.3.2" - "@types/node" "18.15.13" - aes-js "4.0.0-beta.5" - tslib "2.4.0" - ws "8.5.0" - ethjs-unit@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" @@ -10698,6 +10438,15 @@ ffjavascript@0.2.63, ffjavascript@^0.2.45, ffjavascript@^0.2.48, ffjavascript@^0 wasmcurves "0.2.2" web-worker "1.2.0" +ffjavascript@0.3.0, ffjavascript@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.3.0.tgz#442cd8fbb1ee4cbb1be9d26fd7b2951a1ea45d6a" + integrity sha512-l7sR5kmU3gRwDy8g0Z2tYBXy5ttmafRPFOqY7S6af5cq51JqJWt5eQ/lSR/rs2wQNbDYaYlQr5O+OSUf/oMLoQ== + dependencies: + wasmbuilder "0.0.16" + wasmcurves "0.2.2" + web-worker "1.2.0" + figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -10984,7 +10733,7 @@ form-data-encoder@^2.1.2: resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-2.1.4.tgz#261ea35d2a70d48d30ec7a9603130fa5515e9cd5" integrity sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw== -form-data@^2.2.0: +form-data@^2.2.0, form-data@^2.3.3: version "2.5.1" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== @@ -11896,78 +11645,17 @@ hardhat-gas-reporter@^1.0.8: eth-gas-reporter "^0.2.25" sha1 "^1.1.1" -hardhat@^2.19.4: - version "2.19.4" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.19.4.tgz#5112c30295d8be2e18e55d847373c50483ed1902" - integrity sha512-fTQJpqSt3Xo9Mn/WrdblNGAfcANM6XC3tAEi6YogB4s02DmTf93A8QsGb8uR0KR8TFcpcS8lgiW4ugAIYpnbrQ== +hardhat@^2.22.3: + version "2.22.4" + resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.22.4.tgz#766227b6cefca5dbf4fd15ab5b5a68138fa13baf" + integrity sha512-09qcXJFBHQUaraJkYNr7XlmwjOj27xBB0SL2rYS024hTj9tPMbp26AFjlf5quBMO9SR4AJFg+4qWahcYcvXBuQ== dependencies: "@ethersproject/abi" "^5.1.2" "@metamask/eth-sig-util" "^4.0.0" - "@nomicfoundation/ethereumjs-block" "5.0.2" - "@nomicfoundation/ethereumjs-blockchain" "7.0.2" - "@nomicfoundation/ethereumjs-common" "4.0.2" - "@nomicfoundation/ethereumjs-evm" "2.0.2" - "@nomicfoundation/ethereumjs-rlp" "5.0.2" - "@nomicfoundation/ethereumjs-statemanager" "2.0.2" - "@nomicfoundation/ethereumjs-trie" "6.0.2" - "@nomicfoundation/ethereumjs-tx" "5.0.2" - "@nomicfoundation/ethereumjs-util" "9.0.2" - "@nomicfoundation/ethereumjs-vm" "7.0.2" - "@nomicfoundation/solidity-analyzer" "^0.1.0" - "@sentry/node" "^5.18.1" - "@types/bn.js" "^5.1.0" - "@types/lru-cache" "^5.1.0" - adm-zip "^0.4.16" - aggregate-error "^3.0.0" - ansi-escapes "^4.3.0" - chalk "^2.4.2" - chokidar "^3.4.0" - ci-info "^2.0.0" - debug "^4.1.1" - enquirer "^2.3.0" - env-paths "^2.2.0" - ethereum-cryptography "^1.0.3" - 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.0.0-rc.12" - io-ts "1.10.4" - keccak "^3.0.2" - lodash "^4.17.11" - mnemonist "^0.38.0" - mocha "^10.0.0" - p-map "^4.0.0" - raw-body "^2.4.1" - resolve "1.17.0" - semver "^6.3.0" - solc "0.7.3" - source-map-support "^0.5.13" - stacktrace-parser "^0.1.10" - tsort "0.0.1" - undici "^5.14.0" - uuid "^8.3.2" - ws "^7.4.6" - -hardhat@^2.20.1: - version "2.20.1" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.20.1.tgz#3ad8f2b003a96c9ce80a55fec3575580ff2ddcd4" - integrity sha512-q75xDQiQtCZcTMBwjTovrXEU5ECr49baxr4/OBkIu/ULTPzlB20yk1dRWNmD2IFbAeAeXggaWvQAdpiScaHtPw== - dependencies: - "@ethersproject/abi" "^5.1.2" - "@metamask/eth-sig-util" "^4.0.0" - "@nomicfoundation/ethereumjs-block" "5.0.4" - "@nomicfoundation/ethereumjs-blockchain" "7.0.4" + "@nomicfoundation/edr" "^0.3.7" "@nomicfoundation/ethereumjs-common" "4.0.4" - "@nomicfoundation/ethereumjs-evm" "2.0.4" - "@nomicfoundation/ethereumjs-rlp" "5.0.4" - "@nomicfoundation/ethereumjs-statemanager" "2.0.4" - "@nomicfoundation/ethereumjs-trie" "6.0.4" "@nomicfoundation/ethereumjs-tx" "5.0.4" "@nomicfoundation/ethereumjs-util" "9.0.4" - "@nomicfoundation/ethereumjs-verkle" "0.0.2" - "@nomicfoundation/ethereumjs-vm" "7.0.4" "@nomicfoundation/solidity-analyzer" "^0.1.0" "@sentry/node" "^5.18.1" "@types/bn.js" "^5.1.0" @@ -12507,6 +12195,11 @@ inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, i resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== + ini@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" @@ -13014,11 +12707,6 @@ is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-buffer@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" - integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== - is-builtin-module@^3.1.0: version "3.2.1" resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" @@ -13200,6 +12888,18 @@ is-ip@^3.1.0: dependencies: ip-regex "^4.0.0" +is-ipfs@^0.6.0: + version "0.6.3" + resolved "https://registry.yarnpkg.com/is-ipfs/-/is-ipfs-0.6.3.tgz#82a5350e0a42d01441c40b369f8791e91404c497" + integrity sha512-HyRot1dvLcxImtDqPxAaY1miO6WsiP/z7Yxpg2qpaLWv5UdhAPtLvHJ4kMLM0w8GSl8AFsVF23PHe1LzuWrUlQ== + dependencies: + bs58 "^4.0.1" + cids "~0.7.0" + mafmt "^7.0.0" + multiaddr "^7.2.1" + multibase "~0.6.0" + multihashes "~0.4.13" + is-lower-case@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-lower-case/-/is-lower-case-2.0.2.tgz#1c0884d3012c841556243483aa5d522f47396d2a" @@ -13301,6 +13001,11 @@ is-potential-custom-element-name@^1.0.1: resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== +is-promise@^2.1.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" + integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== + is-promise@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-4.0.0.tgz#42ff9f84206c1991d26debf520dd5c01042dd2f3" @@ -13668,11 +13373,6 @@ jose@^4.11.4: resolved "https://registry.yarnpkg.com/jose/-/jose-4.15.4.tgz#02a9a763803e3872cf55f29ecef0dfdcc218cc03" integrity sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ== -js-sdsl@^4.1.4: - version "4.4.2" - resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.4.2.tgz#2e3c031b1f47d3aca8b775532e3ebb0818e7f847" - integrity sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w== - js-sha3@0.8.0, js-sha3@^0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" @@ -14257,11 +13957,6 @@ level-sublevel@6.6.4: typewiselite "~1.0.0" xtend "~4.0.0" -level-supports@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-4.0.1.tgz#431546f9d81f10ff0fea0e74533a0e875c08c66a" - integrity sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA== - level-supports@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-1.0.1.tgz#2f530a596834c7301622521988e2c36bb77d122d" @@ -14269,14 +13964,6 @@ level-supports@~1.0.0: dependencies: xtend "^4.0.2" -level-transcoder@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/level-transcoder/-/level-transcoder-1.0.1.tgz#f8cef5990c4f1283d4c86d949e73631b0bc8ba9c" - integrity sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w== - dependencies: - buffer "^6.0.3" - module-error "^1.0.1" - level-ws@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-0.0.0.tgz#372e512177924a00424b0b43aef2bb42496d228b" @@ -14304,14 +13991,6 @@ level@^5.0.1: leveldown "^5.0.0" opencollective-postinstall "^2.0.0" -level@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/level/-/level-8.0.0.tgz#41b4c515dabe28212a3e881b61c161ffead14394" - integrity sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ== - dependencies: - browser-level "^1.0.1" - classic-level "^1.2.0" - leveldown@^5.0.0: version "5.6.0" resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-5.6.0.tgz#16ba937bb2991c6094e13ac5a6898ee66d3eee98" @@ -14687,16 +14366,16 @@ lodash.upperfirst@^4.3.1: resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce" integrity sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg== +lodash@4, lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@~4.17.0: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + lodash@4.17.20: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== -lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@~4.17.0: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - log-process-errors@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/log-process-errors/-/log-process-errors-8.0.0.tgz#f88a9556e4914037ad97ceee24b148dc1b566dfd" @@ -14810,6 +14489,17 @@ loupe@^2.3.6: dependencies: get-func-name "^2.0.1" +lowdb@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lowdb/-/lowdb-1.0.0.tgz#5243be6b22786ccce30e50c9a33eac36b20c8064" + integrity sha512-2+x8esE/Wb9SQ1F9IHaYWfsC9FIecLOPrK4g17FGEayjUWH172H6nwicRovGvSE2CPZouc2MCIqCI7h9d+GftQ== + dependencies: + graceful-fs "^4.1.3" + is-promise "^2.1.0" + lodash "4" + pify "^3.0.0" + steno "^0.4.1" + lower-case-first@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/lower-case-first/-/lower-case-first-2.0.2.tgz#64c2324a2250bf7c37c5901e76a5b5309301160b" @@ -14846,11 +14536,6 @@ lru-cache@5.1.1, lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -lru-cache@^10.0.0: - version "10.2.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3" - integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== - lru-cache@^10.0.2, "lru-cache@^9.1.1 || ^10.0.0": version "10.1.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.1.0.tgz#2098d41c2dc56500e6c88584aa656c84de7d0484" @@ -14890,84 +14575,92 @@ luxon@^3.1.1, luxon@^3.2.1: resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.4.4.tgz#cf20dc27dc532ba41a169c43fdcc0063601577af" integrity sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA== -maci-circuits@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/maci-circuits/-/maci-circuits-1.2.0.tgz#9b1f9c64d48e4dc3c3c7c8ffc4d0f254d60cce3e" - integrity sha512-51VMv7prUfRuko+PWDJOhwl9dLP82lAW2WHA39x+SFn1tkGAF3K3gw5TcIu7P6DQcwDblmbufn4OlrMc6jQXZg== +maci-circuits@1.2.2, maci-circuits@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/maci-circuits/-/maci-circuits-1.2.2.tgz#2c3823dce9a8d29675eaeb8f1d9e9b1eb8d7437a" + integrity sha512-CBKeLfT5uywgUC+l4W+ZpDf7Av3ZGNpVX//tjgiy0Bgaps5bOhAScmKpAZIfB3aTitpOtiao9E9veb9syTNhnw== dependencies: - "@zk-kit/circuits" "^0.3.0" - circomkit "^0.0.24" + "@zk-kit/circuits" "^0.4.0" + circomkit "^0.1.0" circomlib "^2.0.5" - maci-core "^1.2.0" - maci-crypto "^1.2.0" - maci-domainobjs "^1.2.0" - snarkjs "^0.7.3" + maci-core "^1.2.2" + maci-crypto "^1.2.2" + maci-domainobjs "^1.2.2" + snarkjs "^0.7.4" -maci-cli@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/maci-cli/-/maci-cli-1.2.0.tgz#caf8756d7e8dbfef61af6c7ac14068dfbc7d5db4" - integrity sha512-l3HYHvcafD6Z9ctPOBsYfZ5H/hdiS4rh0X3vEeLlncnsfKRPIpAej+2RHzsTooBH3ZvAp2f6wh+m2C9fRiU/7A== +maci-cli@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/maci-cli/-/maci-cli-1.2.2.tgz#187f4c204f1ab46919b13c042508a8216a10d3c9" + integrity sha512-l5L7FpUH5eH5NkNFPsqXrWvJkdgkdSSZmjy28FR3SBNIGzfbgfT32x0hBoNSDs2QIb+72KZ3rgGyorc/icTXlg== dependencies: - "@commander-js/extra-typings" "^12.0.0" - "@nomicfoundation/hardhat-toolbox" "^4.0.0" + "@commander-js/extra-typings" "^12.0.1" + "@nomicfoundation/hardhat-toolbox" "^5.0.0" commander "^12.0.0" dotenv "^16.4.5" - ethers "^6.11.1" - hardhat "^2.20.1" - maci-circuits "^1.2.0" - maci-contracts "^1.2.0" - maci-core "^1.2.0" - maci-crypto "^1.2.0" - maci-domainobjs "^1.2.0" + ethers "^6.12.0" + hardhat "^2.22.3" + maci-circuits "^1.2.2" + maci-contracts "^1.2.2" + maci-core "^1.2.2" + maci-crypto "^1.2.2" + maci-domainobjs "^1.2.2" prompt "^1.3.0" -maci-contracts@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/maci-contracts/-/maci-contracts-1.2.0.tgz#a724b3e757d2402442d822c34a5221660ef43b94" - integrity sha512-zLYmGzBIBTygw7FiukK9nLNFnDdEWDmizuHruXFjpawCIwH+kzBsGImRy77Rn58SOe9XORdlGZOQckEGvaT4QQ== +maci-contracts@1.2.2, maci-contracts@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/maci-contracts/-/maci-contracts-1.2.2.tgz#65892940f04cff2f7abeed0e32ca3a3275b96887" + integrity sha512-Iws+V2EOe6z8hobEwGnVTV90i6eyCHixFAYdAcVU34bCwksFgL03EssXLi5baS+a3Uig3VgjUE4QbidpBFi0Jw== dependencies: "@nomicfoundation/hardhat-ethers" "^3.0.5" - "@nomicfoundation/hardhat-toolbox" "^4.0.0" - "@openzeppelin/contracts" "^4.8.0" + "@nomicfoundation/hardhat-toolbox" "^5.0.0" + "@openzeppelin/contracts" "^5.0.2" circomlibjs "^0.1.7" - ethers "^6.11.1" - hardhat "^2.20.1" - maci-circuits "^1.2.0" - maci-core "^1.2.0" - maci-crypto "^1.2.0" - maci-domainobjs "^1.2.0" + ethers "^6.12.0" + hardhat "^2.22.3" + lowdb "^1.0.0" + maci-circuits "^1.2.2" + maci-core "^1.2.2" + maci-crypto "^1.2.2" + maci-domainobjs "^1.2.2" solidity-docgen "^0.6.0-beta.36" -maci-core@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/maci-core/-/maci-core-1.2.0.tgz#57ff4b92c457f42a3043fe5b34cfef98a9ac1cf5" - integrity sha512-odqIpafdQmSN0VlvaPESyPQybVcQzxxg9Zvh/DEUSiPMNHBJfHd0ke+CIUVdBN0z2pLaN9VlAFyMDf/CYEuivw== +maci-core@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/maci-core/-/maci-core-1.2.2.tgz#a0a570838ff820a347c18738cac4fa9c75c15f55" + integrity sha512-a4OdSnlP7Rk9g4rn5D8oCjQIIYSMxd5DH1Entgj1JnJ7G4GuIEoC1RP2zw/Bh7wolDi1J9IYFmwFIzdS332ggA== dependencies: - maci-crypto "^1.2.0" - maci-domainobjs "^1.2.0" + maci-crypto "^1.2.2" + maci-domainobjs "^1.2.2" -maci-crypto@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/maci-crypto/-/maci-crypto-1.2.0.tgz#b894810fa2ab379d93f77a2518f55abfe2f22dbe" - integrity sha512-OOQvI+uDR0Q8wji9cbBqfDcwQgjoIIiv5r1pnne4ST15taxgMygep13rsA6UCU/A007rYBa93YAR3vnnBTnmrw== +maci-crypto@1.2.2, maci-crypto@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/maci-crypto/-/maci-crypto-1.2.2.tgz#cd90a741ec9e8713e54c142c01c0648a1d414e7c" + integrity sha512-N752cmfC+guhCrV+2szXsf+1ChFBsVRVGiFLJAGw+rKIERlct4jJryzM4kTVIfL0qFSKBsw8NsQQfrRacLMlFQ== dependencies: - "@zk-kit/baby-jubjub" "^0.1.1" - "@zk-kit/eddsa-poseidon" "^0.5.1" - "@zk-kit/poseidon-cipher" "^0.2.1" - ethers "^6.11.1" + "@zk-kit/baby-jubjub" "^0.3.0" + "@zk-kit/eddsa-poseidon" "^0.11.0" + "@zk-kit/poseidon-cipher" "^0.3.0" + ethers "^6.12.0" -maci-domainobjs@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/maci-domainobjs/-/maci-domainobjs-1.2.0.tgz#27a6a9e05b3712e54c48dd080dcfc0c1d6035f93" - integrity sha512-9ItdA/EVSVqDMOD+Foe+OkDdj/LEfpwSAtXLCxG900TeAZpI486qiAbiJoI5sR8gnoRfSvwnZGJqiB+w0BPgSQ== +maci-domainobjs@1.2.2, maci-domainobjs@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/maci-domainobjs/-/maci-domainobjs-1.2.2.tgz#7b72d93ad88d7306342b3d9691247396f3bc870a" + integrity sha512-Wdtb/baKeITXGTAfA+6X573bcarCxD0KGXaSxoEuxZDbdamwhBqYdTRBcLNBFLK4eWC0RethzwW7lAQuGJfPdg== dependencies: - maci-crypto "^1.2.0" + maci-crypto "^1.2.2" macos-release@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-3.2.0.tgz#dcee82b6a4932971b1538dbf6f3aabc4a903b613" integrity sha512-fSErXALFNsnowREYZ49XCdOHF8wOPWuFOGQrAhP7x5J/BqQv+B02cNsTykGpDgRVx43EKg++6ANmTaGTtW+hUA== +mafmt@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/mafmt/-/mafmt-7.1.0.tgz#4126f6d0eded070ace7dbbb6fb04977412d380b5" + integrity sha512-vpeo9S+hepT3k2h5iFxzEHvvR0GPBx9uKaErmnRzYNcaKb03DgOArjEMlgG4a9LcuZZ89a3I8xbeto487n26eA== + dependencies: + multiaddr "^7.3.0" + magic-string@^0.26.7: version "0.26.7" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.26.7.tgz#caf7daf61b34e9982f8228c4527474dac8981d6f" @@ -15071,11 +14764,6 @@ maxstache@^1.0.0: resolved "https://registry.yarnpkg.com/maxstache/-/maxstache-1.0.7.tgz#2231d5180ba783d5ecfc31c45fedac7ae4276984" integrity sha512-53ZBxHrZM+W//5AcRVewiLpDunHnucfdzZUGz54Fnvo4tE+J3p8EL66kBrs2UhBXvYKTWckWYYWBqJqoTcenqg== -mcl-wasm@^0.7.1: - version "0.7.9" - resolved "https://registry.yarnpkg.com/mcl-wasm/-/mcl-wasm-0.7.9.tgz#c1588ce90042a8700c3b60e40efb339fc07ab87f" - integrity sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ== - md5-hex@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-3.0.1.tgz#be3741b510591434b2784d79e556eefc2c9a8e5c" @@ -15141,15 +14829,6 @@ memoize-one@^6.0.0: resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw== -memory-level@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/memory-level/-/memory-level-1.0.0.tgz#7323c3fd368f9af2f71c3cd76ba403a17ac41692" - integrity sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og== - dependencies: - abstract-level "^1.0.0" - functional-red-black-tree "^1.0.1" - module-error "^1.0.1" - memorystream@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" @@ -15570,11 +15249,6 @@ module-definition@^5.0.1: ast-module-types "^5.0.0" node-source-walk "^6.0.1" -module-error@^1.0.1, module-error@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" - integrity sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA== - moize@^6.1.0, moize@^6.1.3: version "6.1.6" resolved "https://registry.yarnpkg.com/moize/-/moize-6.1.6.tgz#ac2e723e74b951875fe2c0c3433405c2b098c3e6" @@ -15646,6 +15320,18 @@ multiaddr@^10.0.0: uint8arrays "^3.0.0" varint "^6.0.0" +multiaddr@^7.2.1, multiaddr@^7.3.0: + version "7.5.0" + resolved "https://registry.yarnpkg.com/multiaddr/-/multiaddr-7.5.0.tgz#976c88e256e512263445ab03b3b68c003d5f485e" + integrity sha512-GvhHsIGDULh06jyb6ev+VfREH9evJCFIRnh3jUt9iEZ6XDbyoisZRFEI9bMvK/AiR6y66y6P+eoBw9mBYMhMvw== + dependencies: + buffer "^5.5.0" + cids "~0.8.0" + class-is "^1.1.0" + is-ip "^3.1.0" + multibase "^0.7.0" + varint "^5.0.0" + multibase@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.7.0.tgz#1adfc1c50abe05eefeb5091ac0c2728d6b84581b" @@ -15690,7 +15376,7 @@ multiformats@^9.4.13, multiformats@^9.4.2, multiformats@^9.4.5, multiformats@^9. resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-9.9.0.tgz#c68354e7d21037a8f1f8833c8ccd68618e8f1d37" integrity sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg== -multihashes@^0.4.15, multihashes@~0.4.15: +multihashes@^0.4.15, multihashes@~0.4.13, multihashes@~0.4.15: version "0.4.21" resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-0.4.21.tgz#dc02d525579f334a7909ade8a122dabb58ccfcb5" integrity sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw== @@ -15810,11 +15496,6 @@ napi-build-utils@^1.0.1: resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== -napi-macros@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.2.2.tgz#817fef20c3e0e40a963fbf7b37d1600bd0201044" - integrity sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g== - napi-macros@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" @@ -17063,6 +16744,14 @@ path-type@^5.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-5.0.0.tgz#14b01ed7aea7ddf9c7c3f46181d4d04f9c785bb8" integrity sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg== +path@^0.12.7: + version "0.12.7" + resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f" + integrity sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q== + dependencies: + process "^0.11.1" + util "^0.10.3" + pathe@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/pathe/-/pathe-0.2.0.tgz#30fd7bbe0a0d91f0e60bae621f5d19e9e225c339" @@ -17119,6 +16808,11 @@ pify@^2.3.0: resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg== + pify@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" @@ -17431,7 +17125,7 @@ process-warning@^3.0.0: resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-3.0.0.tgz#96e5b88884187a1dce6f5c3166d611132058710b" integrity sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ== -process@^0.11.10: +process@^0.11.1, process@^0.11.10: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== @@ -17723,7 +17417,7 @@ querystringify@^2.1.1: resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== -queue-microtask@^1.2.2, queue-microtask@^1.2.3: +queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== @@ -17773,6 +17467,16 @@ r1csfile@0.0.47: fastfile "0.0.20" ffjavascript "0.2.60" +r1csfile@0.0.48: + version "0.0.48" + resolved "https://registry.yarnpkg.com/r1csfile/-/r1csfile-0.0.48.tgz#a317fc75407a9da92631666c75bdfc13f0a7835a" + integrity sha512-kHRkKUJNaor31l05f2+RFzvcH5XSa7OfEfd/l4hzjte6NL6fjRkSMfZ4BjySW9wmfdwPOtq3mXurzPvPGEf5Tw== + dependencies: + "@iden3/bigarray" "0.0.2" + "@iden3/binfileutils" "0.0.12" + fastfile "0.0.20" + ffjavascript "0.3.0" + rabin-wasm@~0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/rabin-wasm/-/rabin-wasm-0.0.8.tgz#5b61b1d519d0377453435fbca5f82510b3f956cb" @@ -18423,13 +18127,6 @@ run-async@^2.2.0, run-async@^2.4.0: resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== -run-parallel-limit@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz#be80e936f5768623a38a963262d6bef8ff11e7ba" - integrity sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw== - dependencies: - queue-microtask "^1.2.2" - run-parallel@^1.1.4, run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -18437,18 +18134,6 @@ run-parallel@^1.1.4, run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rust-verkle-wasm@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/rust-verkle-wasm/-/rust-verkle-wasm-0.0.1.tgz#fd8396a7060d8ee8ea10da50ab6e862948095a74" - integrity sha512-BN6fiTsxcd2dCECz/cHtGTt9cdLJR925nh7iAuRcj8ymKw7OOaPmCneQZ7JePOJ/ia27TjEL91VdOi88Yf+mcA== - -rustbn-wasm@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/rustbn-wasm/-/rustbn-wasm-0.2.0.tgz#0407521fb55ae69eeb4968d01885d63efd1c4ff9" - integrity sha512-FThvYFNTqrEKGqXuseeg0zR7yROh/6U1617mCHF68OVqrN1tNKRN7Tdwy4WayPVsCmmK+eMxtIZX1qL6JxTkMg== - dependencies: - "@scure/base" "^1.1.1" - rustbn.js@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/rustbn.js/-/rustbn.js-0.2.0.tgz#8082cb886e707155fd1cb6f23bd591ab8d55d0ca" @@ -19010,7 +18695,7 @@ snarkjs@0.5.0: logplease "^1.2.15" r1csfile "0.0.41" -snarkjs@^0.7.0, snarkjs@^0.7.3: +snarkjs@^0.7.0: version "0.7.3" resolved "https://registry.yarnpkg.com/snarkjs/-/snarkjs-0.7.3.tgz#7f703d05b810235255f2d0a70d8a9b8b3ea916e5" integrity sha512-cDLpWqdqEJSCQNc+cXYX1XTKdUZBtYEisuOsgmXf/HUsN5WmGN+FO7HfCS+cMQT1Nzbm1a9gAEpKH6KRtDtS1Q== @@ -19026,6 +18711,22 @@ snarkjs@^0.7.0, snarkjs@^0.7.3: logplease "^1.2.15" r1csfile "0.0.47" +snarkjs@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/snarkjs/-/snarkjs-0.7.4.tgz#b9ad5813f055ab84d33f1831a6f1f34a71b6cd46" + integrity sha512-x4cOCR4YXSyBlLtfnUUwfbZrw8wFd/Y0lk83eexJzKwZB8ELdpH+10ts8YtDsm2/a3WK7c7p514bbE8NpqxW8w== + dependencies: + "@iden3/binfileutils" "0.0.12" + bfj "^7.0.2" + blake2b-wasm "^2.4.0" + circom_runtime "0.1.25" + ejs "^3.1.6" + fastfile "0.0.20" + ffjavascript "0.3.0" + js-sha3 "^0.8.0" + logplease "^1.2.15" + r1csfile "0.0.48" + solc@0.7.3: version "0.7.3" resolved "https://registry.yarnpkg.com/solc/-/solc-0.7.3.tgz#04646961bd867a744f63d2b4e3c0701ffdc7d78a" @@ -19346,6 +19047,13 @@ stdin-discarder@^0.1.0: dependencies: bl "^5.0.0" +steno@^0.4.1: + version "0.4.4" + resolved "https://registry.yarnpkg.com/steno/-/steno-0.4.4.tgz#071105bdfc286e6615c0403c27e9d7b5dcb855cb" + integrity sha512-EEHMVYHNXFHfGtgjNITnka0aHhiAlo93F7z2/Pwd+g0teG9CnM3JIINM7hVVB5/rhw9voufD7Wukwgtw2uqh6w== + dependencies: + graceful-fs "^4.1.3" + stream-browserify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" @@ -21003,6 +20711,13 @@ util.promisify@^1.0.0: object.getownpropertydescriptors "^2.1.6" safe-array-concat "^1.0.0" +util@^0.10.3: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== + dependencies: + inherits "2.0.3" + util@^0.12.4, util@^0.12.5: version "0.12.5" resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc"