From 33d62ef5f5b8ed33858efffce15013d858ea2a61 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Tue, 19 Mar 2024 20:27:55 -0400 Subject: [PATCH 01/86] add ClrFundDeployer mapping for subgraph --- subgraph/abis/ClrFundDeployer.json | 237 ++++++++++++++++++ .../config/deployer-arbitrum-sepolia.json | 5 + subgraph/schema-deployer.graphql | 203 +++++++++++++++ subgraph/src/ClrFundDeployerMapping.ts | 27 ++ subgraph/subgraph-deployer.template.yaml | 226 +++++++++++++++++ 5 files changed, 698 insertions(+) create mode 100644 subgraph/abis/ClrFundDeployer.json create mode 100644 subgraph/config/deployer-arbitrum-sepolia.json create mode 100644 subgraph/schema-deployer.graphql create mode 100644 subgraph/src/ClrFundDeployerMapping.ts create mode 100644 subgraph/subgraph-deployer.template.yaml diff --git a/subgraph/abis/ClrFundDeployer.json b/subgraph/abis/ClrFundDeployer.json new file mode 100644 index 000000000..68b32d168 --- /dev/null +++ b/subgraph/abis/ClrFundDeployer.json @@ -0,0 +1,237 @@ +[ + { + "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" + }, + { + "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/config/deployer-arbitrum-sepolia.json b/subgraph/config/deployer-arbitrum-sepolia.json new file mode 100644 index 000000000..a7f2170c0 --- /dev/null +++ b/subgraph/config/deployer-arbitrum-sepolia.json @@ -0,0 +1,5 @@ +{ + "network": "arbitrum-sepolia", + "address": "0xC0F9054083D42b61C9bbA8EB3533fF3f0208C1fb", + "startBlock": 24627080 +} diff --git a/subgraph/schema-deployer.graphql b/subgraph/schema-deployer.graphql new file mode 100644 index 000000000..70e868ca3 --- /dev/null +++ b/subgraph/schema-deployer.graphql @@ -0,0 +1,203 @@ +type ClrFundDeployer @entity { + id: ID! + clrFunds: [ClrFund!] @derivedFrom(field: "clrFundDeployer") + createdAt: String + lastUpdatedAt: String +} + +type ClrFund @entity { + id: ID! + owner: Bytes + clrFundDeployer: ClrFundDeployer! + 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! + fundingRound: FundingRound + 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 + + 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..c04392dac --- /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.transaction.to! + 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/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 From 26b5d4f7516fb220f7250cda4889de9bc936e870 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Mon, 25 Mar 2024 13:43:03 -0400 Subject: [PATCH 02/86] add optimism for etherscan --- contracts/hardhat.config.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contracts/hardhat.config.ts b/contracts/hardhat.config.ts index 2a22d5e5b..bdb626f58 100644 --- a/contracts/hardhat.config.ts +++ b/contracts/hardhat.config.ts @@ -86,8 +86,10 @@ export default { arbitrum: process.env.ARBISCAN_API_KEY || 'YOUR_ARBISCAN_API_KEY', 'arbitrum-sepolia': process.env.ARBISCAN_API_KEY || 'YOUR_ARBISCAN_API_KEY', + optimisticEthereum: + process.env.OPTIMISMSCAN_API_KEY || 'YOUR_OPTIMISMSCAN_API_KEY', 'optimism-sepolia': - process.env.OPTIMISMSCAN_API_KEY || 'YOUR_ARBISCAN_API_KEY', + process.env.OPTIMISMSCAN_API_KEY || 'YOUR_OPTIMISMSCAN_API_KEY', }, customChains: [ { From 653b483a47e7660836938393ce182d8218faf33b Mon Sep 17 00:00:00 2001 From: yuetloo Date: Mon, 25 Mar 2024 17:32:31 -0400 Subject: [PATCH 03/86] consolidate subgraph template --- subgraph/config/arbitrum-goerli.json | 6 -- subgraph/config/arbitrum-rinkeby.json | 6 -- subgraph/config/arbitrum-sepolia.json | 2 +- subgraph/config/arbitrum.json | 2 +- .../config/deployer-arbitrum-sepolia.json | 5 +- subgraph/config/goerli.json | 6 -- subgraph/config/hardhat.json | 2 +- subgraph/config/optimism-sepolia.json | 2 +- subgraph/config/xdai.json | 2 +- ...ployer.graphql => schema.template.graphql} | 4 + subgraph/subgraph.template.yaml | 83 ++++++++++++++++++- 11 files changed, 94 insertions(+), 26 deletions(-) delete mode 100644 subgraph/config/arbitrum-goerli.json delete mode 100644 subgraph/config/arbitrum-rinkeby.json delete mode 100644 subgraph/config/goerli.json rename subgraph/{schema-deployer.graphql => schema.template.graphql} (97%) 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 index a7f2170c0..858db0f32 100644 --- a/subgraph/config/deployer-arbitrum-sepolia.json +++ b/subgraph/config/deployer-arbitrum-sepolia.json @@ -1,5 +1,6 @@ { "network": "arbitrum-sepolia", - "address": "0xC0F9054083D42b61C9bbA8EB3533fF3f0208C1fb", - "startBlock": 24627080 + "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/schema-deployer.graphql b/subgraph/schema.template.graphql similarity index 97% rename from subgraph/schema-deployer.graphql rename to subgraph/schema.template.graphql index 70e868ca3..af4e1689d 100644 --- a/subgraph/schema-deployer.graphql +++ b/subgraph/schema.template.graphql @@ -1,3 +1,4 @@ +{{#clrFundDeployerAddress}} type ClrFundDeployer @entity { id: ID! clrFunds: [ClrFund!] @derivedFrom(field: "clrFundDeployer") @@ -5,10 +6,13 @@ type ClrFundDeployer @entity { lastUpdatedAt: String } +{{/clrFundDeployerAddress}} type ClrFund @entity { id: ID! owner: Bytes + {{#clrFundDeployerAddress}} clrFundDeployer: ClrFundDeployer! + {{/clrFundDeployerAddress}} coordinator: Bytes nativeToken: Bytes nativeTokenInfo: Token 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}} From b2ce1438ba93335ec913761c5be5ab8a06233f92 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Mon, 25 Mar 2024 17:33:50 -0400 Subject: [PATCH 04/86] add clrfundAddress param in GetRounds query --- vue-app/src/api/rounds.ts | 10 +- vue-app/src/graphql/API.ts | 352 ++++++++---------- vue-app/src/graphql/queries/GetRounds.graphql | 4 +- vue-app/src/views/RoundList.vue | 3 +- 4 files changed, 173 insertions(+), 196 deletions(-) diff --git a/vue-app/src/api/rounds.ts b/vue-app/src/api/rounds.ts index a33feff1e..302883e5e 100644 --- a/vue-app/src/api/rounds.ts +++ b/vue-app/src/api/rounds.ts @@ -19,11 +19,15 @@ function toRoundId({ network, address }: { network: string; address: string }): return `${network}-${address}`.toLowerCase() } -//TODO: update to take ClrFund address as a parameter -export async function getRounds(): Promise { +/** + * Get a list of funding rounds created by the clrFund contract + * @param clrFundAddress The ClrFund contract address + * @returns A list of funding rounds + */ +export async function getRounds(clrFundAddress: string): Promise { let data try { - data = await sdk.GetRounds() + data = await sdk.GetRounds({ clrFundAddress: clrFundAddress.toLowerCase() }) } catch { return [] } diff --git a/vue-app/src/graphql/API.ts b/vue-app/src/graphql/API.ts index e808386ca..fc61e9d4f 100644 --- a/vue-app/src/graphql/API.ts +++ b/vue-app/src/graphql/API.ts @@ -532,7 +532,6 @@ export type Contributor = { id: Scalars['ID']; lastUpdatedAt: Maybe; verifiedTimeStamp: Maybe; - votes: Maybe>; }; @@ -553,15 +552,6 @@ export type ContributorFundingRoundsArgs = { where: InputMaybe; }; - -export type ContributorVotesArgs = { - first?: InputMaybe; - orderBy: InputMaybe; - orderDirection: InputMaybe; - skip?: InputMaybe; - where: InputMaybe; -}; - export type ContributorRegistry = { __typename?: 'ContributorRegistry'; clrFund: ClrFund; @@ -824,7 +814,6 @@ export type Contributor_Filter = { verifiedTimeStamp_not_starts_with_nocase: InputMaybe; verifiedTimeStamp_starts_with: InputMaybe; verifiedTimeStamp_starts_with_nocase: InputMaybe; - votes_: InputMaybe; }; export enum Contributor_OrderBy { @@ -840,8 +829,7 @@ export enum Contributor_OrderBy { FundingRounds = 'fundingRounds', Id = 'id', LastUpdatedAt = 'lastUpdatedAt', - VerifiedTimeStamp = 'verifiedTimeStamp', - Votes = 'votes' + VerifiedTimeStamp = 'verifiedTimeStamp' } export type Coordinator = { @@ -1100,7 +1088,6 @@ export type FundingRound = { totalVotes: Maybe; voiceCreditFactor: Maybe; voteOptionTreeDepth: Maybe; - votes: Maybe>; votingDeadline: Maybe; }; @@ -1140,15 +1127,6 @@ export type FundingRoundRecipientsArgs = { where: InputMaybe; }; - -export type FundingRoundVotesArgs = { - first?: InputMaybe; - orderBy: InputMaybe; - orderDirection: InputMaybe; - skip?: InputMaybe; - where: InputMaybe; -}; - export type FundingRound_Filter = { /** Filter for the block changed event. */ _change_block: InputMaybe; @@ -1500,7 +1478,6 @@ export type FundingRound_Filter = { voteOptionTreeDepth_lte: InputMaybe; voteOptionTreeDepth_not: InputMaybe; voteOptionTreeDepth_not_in: InputMaybe>; - votes_: InputMaybe; votingDeadline: InputMaybe; votingDeadline_gt: InputMaybe; votingDeadline_gte: InputMaybe; @@ -1579,7 +1556,6 @@ export enum FundingRound_OrderBy { TotalVotes = 'totalVotes', VoiceCreditFactor = 'voiceCreditFactor', VoteOptionTreeDepth = 'voteOptionTreeDepth', - Votes = 'votes', VotingDeadline = 'votingDeadline' } @@ -1590,6 +1566,7 @@ export type Message = { fundingRound: Maybe; id: Scalars['ID']; msgType: Scalars['BigInt']; + poll: Maybe; publicKey: Maybe; submittedBy: Maybe; timestamp: Maybe; @@ -1652,6 +1629,27 @@ export type Message_Filter = { msgType_not: InputMaybe; msgType_not_in: InputMaybe>; or: InputMaybe>>; + poll: InputMaybe; + poll_: InputMaybe; + poll_contains: InputMaybe; + poll_contains_nocase: InputMaybe; + poll_ends_with: InputMaybe; + poll_ends_with_nocase: InputMaybe; + poll_gt: InputMaybe; + poll_gte: InputMaybe; + poll_in: InputMaybe>; + poll_lt: InputMaybe; + poll_lte: InputMaybe; + poll_not: InputMaybe; + poll_not_contains: InputMaybe; + poll_not_contains_nocase: InputMaybe; + poll_not_ends_with: InputMaybe; + poll_not_ends_with_nocase: InputMaybe; + poll_not_in: InputMaybe>; + poll_not_starts_with: InputMaybe; + poll_not_starts_with_nocase: InputMaybe; + poll_starts_with: InputMaybe; + poll_starts_with_nocase: InputMaybe; publicKey: InputMaybe; publicKey_: InputMaybe; publicKey_contains: InputMaybe; @@ -1747,6 +1745,8 @@ export enum Message_OrderBy { FundingRoundVotingDeadline = 'fundingRound__votingDeadline', Id = 'id', MsgType = 'msgType', + Poll = 'poll', + PollId = 'poll__id', PublicKey = 'publicKey', PublicKeyId = 'publicKey__id', PublicKeyStateIndex = 'publicKey__stateIndex', @@ -1764,6 +1764,93 @@ export enum OrderDirection { Desc = 'desc' } +export type Poll = { + __typename?: 'Poll'; + fundingRound: FundingRound; + id: Scalars['ID']; + messages: Maybe>; +}; + + +export type PollMessagesArgs = { + first?: InputMaybe; + orderBy: InputMaybe; + orderDirection: InputMaybe; + skip?: InputMaybe; + where: InputMaybe; +}; + +export type Poll_Filter = { + /** Filter for the block changed event. */ + _change_block: InputMaybe; + and: InputMaybe>>; + fundingRound: InputMaybe; + fundingRound_: InputMaybe; + fundingRound_contains: InputMaybe; + fundingRound_contains_nocase: InputMaybe; + fundingRound_ends_with: InputMaybe; + fundingRound_ends_with_nocase: InputMaybe; + fundingRound_gt: InputMaybe; + fundingRound_gte: InputMaybe; + fundingRound_in: InputMaybe>; + fundingRound_lt: InputMaybe; + fundingRound_lte: InputMaybe; + fundingRound_not: InputMaybe; + fundingRound_not_contains: InputMaybe; + fundingRound_not_contains_nocase: InputMaybe; + fundingRound_not_ends_with: InputMaybe; + fundingRound_not_ends_with_nocase: InputMaybe; + fundingRound_not_in: InputMaybe>; + fundingRound_not_starts_with: InputMaybe; + fundingRound_not_starts_with_nocase: InputMaybe; + fundingRound_starts_with: InputMaybe; + fundingRound_starts_with_nocase: InputMaybe; + id: InputMaybe; + id_gt: InputMaybe; + id_gte: InputMaybe; + id_in: InputMaybe>; + id_lt: InputMaybe; + id_lte: InputMaybe; + id_not: InputMaybe; + id_not_in: InputMaybe>; + messages_: InputMaybe; + or: InputMaybe>>; +}; + +export enum Poll_OrderBy { + FundingRound = 'fundingRound', + FundingRoundContributorCount = 'fundingRound__contributorCount', + FundingRoundContributorRegistryAddress = 'fundingRound__contributorRegistryAddress', + FundingRoundCoordinator = 'fundingRound__coordinator', + FundingRoundCoordinatorPubKeyX = 'fundingRound__coordinatorPubKeyX', + FundingRoundCoordinatorPubKeyY = 'fundingRound__coordinatorPubKeyY', + FundingRoundCreatedAt = 'fundingRound__createdAt', + FundingRoundId = 'fundingRound__id', + FundingRoundIsCancelled = 'fundingRound__isCancelled', + FundingRoundIsFinalized = 'fundingRound__isFinalized', + FundingRoundLastUpdatedAt = 'fundingRound__lastUpdatedAt', + FundingRoundMaci = 'fundingRound__maci', + FundingRoundMaciTxHash = 'fundingRound__maciTxHash', + FundingRoundMatchingPoolSize = 'fundingRound__matchingPoolSize', + FundingRoundMessageTreeDepth = 'fundingRound__messageTreeDepth', + FundingRoundNativeToken = 'fundingRound__nativeToken', + FundingRoundPollAddress = 'fundingRound__pollAddress', + FundingRoundPollId = 'fundingRound__pollId', + FundingRoundRecipientCount = 'fundingRound__recipientCount', + FundingRoundRecipientRegistryAddress = 'fundingRound__recipientRegistryAddress', + FundingRoundSignUpDeadline = 'fundingRound__signUpDeadline', + FundingRoundStartTime = 'fundingRound__startTime', + FundingRoundStateTreeDepth = 'fundingRound__stateTreeDepth', + FundingRoundTallyHash = 'fundingRound__tallyHash', + FundingRoundTotalSpent = 'fundingRound__totalSpent', + FundingRoundTotalVotes = 'fundingRound__totalVotes', + FundingRoundVoiceCreditFactor = 'fundingRound__voiceCreditFactor', + FundingRoundVoteOptionTreeDepth = 'fundingRound__voteOptionTreeDepth', + FundingRoundVotingDeadline = 'fundingRound__votingDeadline', + Id = 'id', + Messages = 'messages' +} + export type PublicKey = { __typename?: 'PublicKey'; fundingRound: Maybe; @@ -1911,6 +1998,8 @@ export type Query = { fundingRounds: Array; message: Maybe; messages: Array; + poll: Maybe; + polls: Array; publicKey: Maybe; publicKeys: Array; recipient: Maybe; @@ -1919,8 +2008,6 @@ export type Query = { recipients: Array; token: Maybe; tokens: Array; - vote: Maybe; - votes: Array; }; @@ -2073,6 +2160,24 @@ export type QueryMessagesArgs = { }; +export type QueryPollArgs = { + block: InputMaybe; + id: Scalars['ID']; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QueryPollsArgs = { + block: InputMaybe; + first?: InputMaybe; + orderBy: InputMaybe; + orderDirection: InputMaybe; + skip?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; + where: InputMaybe; +}; + + export type QueryPublicKeyArgs = { block: InputMaybe; id: Scalars['ID']; @@ -2144,24 +2249,6 @@ export type QueryTokensArgs = { where: InputMaybe; }; - -export type QueryVoteArgs = { - block: InputMaybe; - id: Scalars['ID']; - subgraphError?: _SubgraphErrorPolicy_; -}; - - -export type QueryVotesArgs = { - block: InputMaybe; - first?: InputMaybe; - orderBy: InputMaybe; - orderDirection: InputMaybe; - skip?: InputMaybe; - subgraphError?: _SubgraphErrorPolicy_; - where: InputMaybe; -}; - export type Recipient = { __typename?: 'Recipient'; createdAt: Maybe; @@ -2635,6 +2722,8 @@ export type Subscription = { fundingRounds: Array; message: Maybe; messages: Array; + poll: Maybe; + polls: Array; publicKey: Maybe; publicKeys: Array; recipient: Maybe; @@ -2643,8 +2732,6 @@ export type Subscription = { recipients: Array; token: Maybe; tokens: Array; - vote: Maybe; - votes: Array; }; @@ -2797,6 +2884,24 @@ export type SubscriptionMessagesArgs = { }; +export type SubscriptionPollArgs = { + block: InputMaybe; + id: Scalars['ID']; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptionPollsArgs = { + block: InputMaybe; + first?: InputMaybe; + orderBy: InputMaybe; + orderDirection: InputMaybe; + skip?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; + where: InputMaybe; +}; + + export type SubscriptionPublicKeyArgs = { block: InputMaybe; id: Scalars['ID']; @@ -2868,24 +2973,6 @@ export type SubscriptionTokensArgs = { where: InputMaybe; }; - -export type SubscriptionVoteArgs = { - block: InputMaybe; - id: Scalars['ID']; - subgraphError?: _SubgraphErrorPolicy_; -}; - - -export type SubscriptionVotesArgs = { - block: InputMaybe; - first?: InputMaybe; - orderBy: InputMaybe; - orderDirection: InputMaybe; - skip?: InputMaybe; - subgraphError?: _SubgraphErrorPolicy_; - where: InputMaybe; -}; - export type Token = { __typename?: 'Token'; createdAt: Maybe; @@ -2998,127 +3085,6 @@ export enum Token_OrderBy { TokenAddress = 'tokenAddress' } -export type Vote = { - __typename?: 'Vote'; - contributor: Maybe; - fundingRound: Maybe; - id: Scalars['ID']; - secret: Maybe; - voterAddress: Maybe; -}; - -export type Vote_Filter = { - /** Filter for the block changed event. */ - _change_block: InputMaybe; - and: InputMaybe>>; - contributor: InputMaybe; - contributor_: InputMaybe; - contributor_contains: InputMaybe; - contributor_contains_nocase: InputMaybe; - contributor_ends_with: InputMaybe; - contributor_ends_with_nocase: InputMaybe; - contributor_gt: InputMaybe; - contributor_gte: InputMaybe; - contributor_in: InputMaybe>; - contributor_lt: InputMaybe; - contributor_lte: InputMaybe; - contributor_not: InputMaybe; - contributor_not_contains: InputMaybe; - contributor_not_contains_nocase: InputMaybe; - contributor_not_ends_with: InputMaybe; - contributor_not_ends_with_nocase: InputMaybe; - contributor_not_in: InputMaybe>; - contributor_not_starts_with: InputMaybe; - contributor_not_starts_with_nocase: InputMaybe; - contributor_starts_with: InputMaybe; - contributor_starts_with_nocase: InputMaybe; - fundingRound: InputMaybe; - fundingRound_: InputMaybe; - fundingRound_contains: InputMaybe; - fundingRound_contains_nocase: InputMaybe; - fundingRound_ends_with: InputMaybe; - fundingRound_ends_with_nocase: InputMaybe; - fundingRound_gt: InputMaybe; - fundingRound_gte: InputMaybe; - fundingRound_in: InputMaybe>; - fundingRound_lt: InputMaybe; - fundingRound_lte: InputMaybe; - fundingRound_not: InputMaybe; - fundingRound_not_contains: InputMaybe; - fundingRound_not_contains_nocase: InputMaybe; - fundingRound_not_ends_with: InputMaybe; - fundingRound_not_ends_with_nocase: InputMaybe; - fundingRound_not_in: InputMaybe>; - fundingRound_not_starts_with: InputMaybe; - fundingRound_not_starts_with_nocase: InputMaybe; - fundingRound_starts_with: InputMaybe; - fundingRound_starts_with_nocase: InputMaybe; - id: InputMaybe; - id_gt: InputMaybe; - id_gte: InputMaybe; - id_in: InputMaybe>; - id_lt: InputMaybe; - id_lte: InputMaybe; - id_not: InputMaybe; - id_not_in: InputMaybe>; - or: InputMaybe>>; - secret: InputMaybe; - secret_in: InputMaybe>; - secret_not: InputMaybe; - secret_not_in: InputMaybe>; - voterAddress: InputMaybe; - voterAddress_contains: InputMaybe; - voterAddress_gt: InputMaybe; - voterAddress_gte: InputMaybe; - voterAddress_in: InputMaybe>; - voterAddress_lt: InputMaybe; - voterAddress_lte: InputMaybe; - voterAddress_not: InputMaybe; - voterAddress_not_contains: InputMaybe; - voterAddress_not_in: InputMaybe>; -}; - -export enum Vote_OrderBy { - Contributor = 'contributor', - ContributorContributorAddress = 'contributor__contributorAddress', - ContributorCreatedAt = 'contributor__createdAt', - ContributorId = 'contributor__id', - ContributorLastUpdatedAt = 'contributor__lastUpdatedAt', - ContributorVerifiedTimeStamp = 'contributor__verifiedTimeStamp', - FundingRound = 'fundingRound', - FundingRoundContributorCount = 'fundingRound__contributorCount', - FundingRoundContributorRegistryAddress = 'fundingRound__contributorRegistryAddress', - FundingRoundCoordinator = 'fundingRound__coordinator', - FundingRoundCoordinatorPubKeyX = 'fundingRound__coordinatorPubKeyX', - FundingRoundCoordinatorPubKeyY = 'fundingRound__coordinatorPubKeyY', - FundingRoundCreatedAt = 'fundingRound__createdAt', - FundingRoundId = 'fundingRound__id', - FundingRoundIsCancelled = 'fundingRound__isCancelled', - FundingRoundIsFinalized = 'fundingRound__isFinalized', - FundingRoundLastUpdatedAt = 'fundingRound__lastUpdatedAt', - FundingRoundMaci = 'fundingRound__maci', - FundingRoundMaciTxHash = 'fundingRound__maciTxHash', - FundingRoundMatchingPoolSize = 'fundingRound__matchingPoolSize', - FundingRoundMessageTreeDepth = 'fundingRound__messageTreeDepth', - FundingRoundNativeToken = 'fundingRound__nativeToken', - FundingRoundPollAddress = 'fundingRound__pollAddress', - FundingRoundPollId = 'fundingRound__pollId', - FundingRoundRecipientCount = 'fundingRound__recipientCount', - FundingRoundRecipientRegistryAddress = 'fundingRound__recipientRegistryAddress', - FundingRoundSignUpDeadline = 'fundingRound__signUpDeadline', - FundingRoundStartTime = 'fundingRound__startTime', - FundingRoundStateTreeDepth = 'fundingRound__stateTreeDepth', - FundingRoundTallyHash = 'fundingRound__tallyHash', - FundingRoundTotalSpent = 'fundingRound__totalSpent', - FundingRoundTotalVotes = 'fundingRound__totalVotes', - FundingRoundVoiceCreditFactor = 'fundingRound__voiceCreditFactor', - FundingRoundVoteOptionTreeDepth = 'fundingRound__voteOptionTreeDepth', - FundingRoundVotingDeadline = 'fundingRound__votingDeadline', - Id = 'id', - Secret = 'secret', - VoterAddress = 'voterAddress' -} - export type _Block_ = { __typename?: '_Block_'; /** The hash of the block */ @@ -3259,7 +3225,9 @@ export type GetRoundInfoQueryVariables = Exact<{ export type GetRoundInfoQuery = { __typename?: 'Query', fundingRound: { __typename?: 'FundingRound', id: string, maci: any | null, pollId: any | null, pollAddress: any | null, recipientRegistryAddress: any | null, contributorRegistryAddress: any | null, voiceCreditFactor: any | null, isFinalized: boolean | null, isCancelled: boolean | null, contributorCount: any, totalSpent: any | null, matchingPoolSize: any | null, startTime: any | null, signUpDeadline: any | null, votingDeadline: any | null, coordinatorPubKeyX: any | null, coordinatorPubKeyY: any | null, stateTreeDepth: number | null, messageTreeDepth: number | null, voteOptionTreeDepth: number | null, nativeTokenInfo: { __typename?: 'Token', tokenAddress: any | null, symbol: string | null, decimals: any | null } | null } | null }; -export type GetRoundsQueryVariables = Exact<{ [key: string]: never; }>; +export type GetRoundsQueryVariables = Exact<{ + clrFundAddress: Scalars['String']; +}>; export type GetRoundsQuery = { __typename?: 'Query', fundingRounds: Array<{ __typename?: 'FundingRound', id: string, isFinalized: boolean | null, isCancelled: boolean | null, startTime: any | null, votingDeadline: any | null }> }; @@ -3475,8 +3443,12 @@ export const GetRoundInfoDocument = gql` } `; export const GetRoundsDocument = gql` - query GetRounds { - fundingRounds(orderBy: startTime, orderDirection: asc) { + query GetRounds($clrFundAddress: String!) { + fundingRounds( + where: {clrFund: $clrFundAddress} + orderBy: startTime + orderDirection: desc + ) { id isFinalized isCancelled @@ -3553,7 +3525,7 @@ export function getSdk(client: GraphQLClient, withWrapper: SdkFunctionWrapper = GetRoundInfo(variables: GetRoundInfoQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { return withWrapper((wrappedRequestHeaders) => client.request(GetRoundInfoDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'GetRoundInfo', 'query'); }, - GetRounds(variables?: GetRoundsQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { + GetRounds(variables: GetRoundsQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { return withWrapper((wrappedRequestHeaders) => client.request(GetRoundsDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'GetRounds', 'query'); }, GetTokenInfo(variables: GetTokenInfoQueryVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise { diff --git a/vue-app/src/graphql/queries/GetRounds.graphql b/vue-app/src/graphql/queries/GetRounds.graphql index e13bdceb3..15d768ed4 100644 --- a/vue-app/src/graphql/queries/GetRounds.graphql +++ b/vue-app/src/graphql/queries/GetRounds.graphql @@ -1,5 +1,5 @@ -query GetRounds { - fundingRounds(orderBy: startTime, orderDirection: asc) { +query GetRounds($clrFundAddress: String!) { + fundingRounds(where:{clrFund: $clrFundAddress}, orderBy: startTime, orderDirection: desc) { id isFinalized isCancelled diff --git a/vue-app/src/views/RoundList.vue b/vue-app/src/views/RoundList.vue index 5c5e8f44a..501f65678 100644 --- a/vue-app/src/views/RoundList.vue +++ b/vue-app/src/views/RoundList.vue @@ -41,11 +41,12 @@ import { onMounted, ref } from 'vue' import { type Round, getRounds } from '@/api/rounds' import Links from '@/components/Links.vue' import { DateTime } from 'luxon' +import { clrfundContractAddress } from '@/api/core' const rounds = ref([]) onMounted(async () => { - rounds.value = (await getRounds()).reverse() + rounds.value = (await getRounds(clrfundContractAddress)).reverse() }) From 1de0fa8ccc161f94116977b2f578d13a16046046 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Mon, 25 Mar 2024 22:07:43 -0400 Subject: [PATCH 05/86] add ClrFundDeployer deployment guide --- docs/deploy-clrFundDeployer.md | 18 ++++++++++++++++++ docs/deployment.md | 20 ++++++++++++-------- 2 files changed, 30 insertions(+), 8 deletions(-) create mode 100644 docs/deploy-clrFundDeployer.md 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..4ddb0ccc1 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -73,9 +73,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 +127,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 From 62680933f352bbfc4cb6ca3140847573cba19c2c Mon Sep 17 00:00:00 2001 From: yuetloo Date: Sat, 30 Mar 2024 13:57:40 -0400 Subject: [PATCH 06/86] do not wait for synchronization with subgraph --- vue-app/src/locales/cn.json | 4 ++-- vue-app/src/locales/en.json | 4 ++-- vue-app/src/locales/es.json | 4 ++-- vue-app/src/utils/contracts.ts | 33 ------------------------------ vue-app/src/views/JoinView.vue | 10 +++------ vue-app/src/views/ProjectAdded.vue | 22 ++++++++------------ 6 files changed, 17 insertions(+), 60 deletions(-) diff --git a/vue-app/src/locales/cn.json b/vue-app/src/locales/cn.json index 693ba2260..a95b93b08 100644 --- a/vue-app/src/locales/cn.json +++ b/vue-app/src/locales/cn.json @@ -728,8 +728,8 @@ "div1": "您快要参加这筹款活动了。", "li1": "您的项目只需要经过一些最终检查来确保它符合筹款标准。您可以在这里", "link1": "了解更多关于注册流程的信息。", - "li2": "完成后,您的项目页面将上线。", - "li3": " 如果您的项目未通过检查,我们将电邮通知您并退回您的押金。", + "li2": "完成后,您的项目页面将上线, 我们将退还您的押金。", + "li3": " 如果您的项目未通过检查,我们将退回您的押金。", "linkProjects": "查看项目", "link2": "查看项目", "link3": "回首页" diff --git a/vue-app/src/locales/en.json b/vue-app/src/locales/en.json index 89dd5781e..8db5b2e14 100644 --- a/vue-app/src/locales/en.json +++ b/vue-app/src/locales/en.json @@ -728,8 +728,8 @@ "div1": "You’re almost on board this funding round.", "li1": "Your project just needs to go through some final checks to ensure it meets round criteria. You can", "link1": "learn more about the registration process here.", - "li2": "Once that's complete, your project page will go live.", - "li3": " If your project fails any checks, we'll let you know by email and return your deposit.", + "li2": "Once that's complete, your project page will go live and we'll refund your deposit.", + "li3": " If your project fails any checks, we'll return your deposit.", "linkProjects": "View projects", "link2": "View project", "link3": "Go home" diff --git a/vue-app/src/locales/es.json b/vue-app/src/locales/es.json index 54b0f04dc..704996105 100644 --- a/vue-app/src/locales/es.json +++ b/vue-app/src/locales/es.json @@ -728,8 +728,8 @@ "div1": "Estás casi listo para unirte a esta ronda de financiamiento.", "li1": "Tu proyecto solo necesita pasar por algunas verificaciones finales para asegurarse de que cumpla con los criterios de la ronda. Puedes", "link1": "obtener más información sobre el proceso de registro aquí.", - "li2": "Una vez que se complete, la página de tu proyecto se publicará.", - "li3": "Si tu proyecto no pasa alguna verificación, te lo haremos saber por correo electrónico y te devolveremos tu depósito.", + "li2": "Una vez que se complete, la página de tu proyecto se publicará y te devolveremos tu depósito.", + "li3": "Si tu proyecto no pasa alguna verificación, te devolveremos tu depósito.", "linkProjects": "Ver proyectos", "link2": "Ver proyecto", "link3": "Ir a inicio" diff --git a/vue-app/src/utils/contracts.ts b/vue-app/src/utils/contracts.ts index 6df726b50..640152451 100644 --- a/vue-app/src/utils/contracts.ts +++ b/vue-app/src/utils/contracts.ts @@ -47,39 +47,6 @@ export async function waitForTransaction( return transactionReceipt } -/** - * Wait for transaction to be mined and available on the subgraph - * @param pendingTransaction transaction to wait and check for - * @param checkFn the check function - * @param onTransactionHash callback function with the transaction hash - * @returns transaction receipt - */ -export async function waitForTransactionAndCheck( - pendingTransaction: Promise, - checkFn: (receipt: TransactionReceipt) => Promise, - onTransactionHash?: (hash: string) => void, -): Promise { - const receipt = await waitForTransaction(pendingTransaction, onTransactionHash) - - return new Promise(resolve => { - async function checkAndWait(depth = 0) { - if (await checkFn(receipt)) { - resolve(receipt) - } else { - if (depth > MAX_WAIT_DEPTH) { - throw new Error('Time out waiting for transaction ' + receipt.hash) - } - - const timeoutMs = 2 ** depth * 10 - await new Promise(res => setTimeout(res, timeoutMs)) - checkAndWait(depth + 1) - } - } - - checkAndWait() - }) -} - export async function isTransactionMined(hash: string): Promise { const receipt = await provider.getTransactionReceipt(hash) return !!receipt diff --git a/vue-app/src/views/JoinView.vue b/vue-app/src/views/JoinView.vue index 547658557..d87736942 100644 --- a/vue-app/src/views/JoinView.vue +++ b/vue-app/src/views/JoinView.vue @@ -717,12 +717,11 @@ import { useVuelidate } from '@vuelidate/core' import { required, requiredIf, email, maxLength, url, helpers } from '@vuelidate/validators' import type { RecipientApplicationData } from '@/api/types' import type { Project } from '@/api/projects' -import { isTransactionInSubgraph } from '@/api/subgraph' import { formToProjectInterface } from '@/api/projects' -import { chain, showComplianceRequirement, isOptimisticRecipientRegistry } from '@/api/core' +import { chain, showComplianceRequirement } from '@/api/core' import { DateTime } from 'luxon' import { useRecipientStore, useAppStore, useUserStore } from '@/stores' -import { waitForTransactionAndCheck } from '@/utils/contracts' +import { waitForTransaction } from '@/utils/contracts' import { addRecipient as _addRecipient } from '@/api/recipient-registry' import { isValidEthAddress, resolveEns } from '@/utils/accounts' import { toReactive } from '@vueuse/core' @@ -942,11 +941,8 @@ async function addRecipient() { } const signer = await userStore.getSigner() - await waitForTransactionAndCheck( + await waitForTransaction( _addRecipient(recipientRegistryAddress.value, recipient.value, recipientRegistryInfo.value.deposit, signer), - receipt => { - return isOptimisticRecipientRegistry ? isTransactionInSubgraph(receipt) : Promise.resolve(true) - }, hash => (txHash.value = hash), ) diff --git a/vue-app/src/views/ProjectAdded.vue b/vue-app/src/views/ProjectAdded.vue index 59fe6290c..f59065d37 100644 --- a/vue-app/src/views/ProjectAdded.vue +++ b/vue-app/src/views/ProjectAdded.vue @@ -2,9 +2,9 @@
- +
- +
🎉
@@ -23,12 +23,6 @@
- - {{ $t('projectAdded.linkProjects') }} {{ $t('projectAdded.link3') }}
@@ -121,7 +115,7 @@ ul { height: calc(100vh - 113px); @media (max-width: $breakpoint-m) { padding: 2rem 0rem; - padding-bottom: 16rem; + flex-direction: column; } img { @@ -130,21 +124,21 @@ ul { right: 0; width: 66%; @media (max-width: $breakpoint-m) { + position: relative; right: 0; - width: 100%; + width: 90%; } } .content { position: relative; z-index: 1; - padding: $content-space; - width: min(100%, 512px); + width: min(80%, 512px); margin-left: 2rem; margin-top: 3rem; @media (max-width: $breakpoint-m) { - width: 100%; - margin: 0; + width: 90%; + padding: 0; } .flex-title { From 71b9fbdae26cd3cfebcda315addaa6a28dce267a Mon Sep 17 00:00:00 2001 From: yuetloo Date: Sat, 30 Mar 2024 14:00:42 -0400 Subject: [PATCH 07/86] remove unused translation --- vue-app/src/locales/cn.json | 2 -- vue-app/src/locales/en.json | 2 -- vue-app/src/locales/es.json | 2 -- 3 files changed, 6 deletions(-) diff --git a/vue-app/src/locales/cn.json b/vue-app/src/locales/cn.json index a95b93b08..dbc945f34 100644 --- a/vue-app/src/locales/cn.json +++ b/vue-app/src/locales/cn.json @@ -730,8 +730,6 @@ "link1": "了解更多关于注册流程的信息。", "li2": "完成后,您的项目页面将上线, 我们将退还您的押金。", "li3": " 如果您的项目未通过检查,我们将退回您的押金。", - "linkProjects": "查看项目", - "link2": "查看项目", "link3": "回首页" }, "projectList": { diff --git a/vue-app/src/locales/en.json b/vue-app/src/locales/en.json index 8db5b2e14..3811acfbc 100644 --- a/vue-app/src/locales/en.json +++ b/vue-app/src/locales/en.json @@ -730,8 +730,6 @@ "link1": "learn more about the registration process here.", "li2": "Once that's complete, your project page will go live and we'll refund your deposit.", "li3": " If your project fails any checks, we'll return your deposit.", - "linkProjects": "View projects", - "link2": "View project", "link3": "Go home" }, "projectList": { diff --git a/vue-app/src/locales/es.json b/vue-app/src/locales/es.json index 704996105..ae103f13e 100644 --- a/vue-app/src/locales/es.json +++ b/vue-app/src/locales/es.json @@ -730,8 +730,6 @@ "link1": "obtener más información sobre el proceso de registro aquí.", "li2": "Una vez que se complete, la página de tu proyecto se publicará y te devolveremos tu depósito.", "li3": "Si tu proyecto no pasa alguna verificación, te devolveremos tu depósito.", - "linkProjects": "Ver proyectos", - "link2": "Ver proyecto", "link3": "Ir a inicio" }, "projectList": { From d20877af26e06e719589a662a967d11e49e3cfda Mon Sep 17 00:00:00 2001 From: yuetloo Date: Tue, 2 Apr 2024 23:30:29 -0400 Subject: [PATCH 08/86] break the tally script into multiple smaller scripts --- contracts/tasks/index.ts | 4 + contracts/tasks/runners/genProofs.ts | 185 ++++++++++++++++++ contracts/tasks/runners/proveOnChain.ts | 99 ++++++++++ .../tasks/runners/publishTallyResults.ts | 163 +++++++++++++++ contracts/tasks/runners/resetTally.ts | 51 +++++ contracts/utils/contracts.ts | 29 ++- 6 files changed, 530 insertions(+), 1 deletion(-) create mode 100644 contracts/tasks/runners/genProofs.ts create mode 100644 contracts/tasks/runners/proveOnChain.ts create mode 100644 contracts/tasks/runners/publishTallyResults.ts create mode 100644 contracts/tasks/runners/resetTally.ts diff --git a/contracts/tasks/index.ts b/contracts/tasks/index.ts index 5bcc7e4fc..934d30612 100644 --- a/contracts/tasks/index.ts +++ b/contracts/tasks/index.ts @@ -23,3 +23,7 @@ import './runners/addRecipients' import './runners/findStorageSlot' import './runners/verifyTallyFile' import './runners/verifyAll' +import './runners/genProofs' +import './runners/proveOnChain' +import './runners/publishTallyResults' +import './runners/resetTally' diff --git a/contracts/tasks/runners/genProofs.ts b/contracts/tasks/runners/genProofs.ts new file mode 100644 index 000000000..55c9d5521 --- /dev/null +++ b/contracts/tasks/runners/genProofs.ts @@ -0,0 +1,185 @@ +/** + * Script for generating MACI proofs + * + * Pass --maci-tx-hash if this is the first time running the script and you + * want to get MACI logs starting from the block as recorded in the MACI creation + * transaction hash + * + * Pass --maci-state-file if you have previously ran the script and have + * the maci-state file (maci-state.json) + * + * 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 tally --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 } from '../../utils/misc' +import { EContracts } from '../../utils/types' +import { Subtask } from '../helpers/Subtask' +import { getCurrentFundingRoundContract } from '../../utils/contracts' + +task('gen-proofs', 'Generate MACI proofs offchain') + .addParam('clrfund', 'FundingRound contract address') + .addParam('proofDir', 'The proof output directory') + .addOptionalParam('maciTxHash', 'MACI creation transaction hash') + .addOptionalParam( + 'maciStartBlock', + 'MACI creation block', + undefined, + types.int + ) + .addOptionalParam('maciStateFile', 'MACI state file') + .addFlag('manageNonce', 'Whether to manually manage transaction nonce') + .addOptionalParam('rapidsnark', 'The rapidsnark prover path') + .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, + maciStateFile, + proofDir, + blocksPerBatch, + rapidsnark, + numQueueOps, + sleep, + manageNonce, + }, + hre + ) => { + console.log('Verbose logging enabled:', !quiet) + + const { ethers, network } = hre + const subtask = Subtask.getInstance(hre) + subtask.setHre(hre) + + if (!maciStateFile && !maciTxHash && maciStartBlock == undefined) { + throw new Error('Please provide --maci-start-block or --maci-tx-hash') + } + + 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.getConfigField( + EContracts.VkRegistry, + 'circuit' + ) + const circuitDirectory = subtask.getConfigField( + EContracts.VkRegistry, + 'paramsDirectory' + ) + + await subtask.logStart() + + const fundingRoundContract = await getCurrentFundingRoundContract( + clrfund, + coordinator, + ethers + ) + console.log('Funding round contract', fundingRoundContract.target) + + const pollId = await fundingRoundContract.pollId() + console.log('PollId', pollId) + + const maciAddress = await fundingRoundContract.maci() + + const providerUrl = (network.config as any).url + + await mergeMaciSubtrees({ + maciAddress, + pollId, + numQueueOps, + signer: coordinator, + quiet, + }) + + const maciStateFilePath = maciStateFile + ? maciStateFile + : getMaciStateFilePath(proofDir) + + if (!maciStateFile) { + await genLocalState({ + quiet, + outputPath: maciStateFilePath, + pollId, + maciContractAddress: 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), + maciTxHash, + maciStateFile: maciStateFilePath, + signer: coordinator, + quiet, + }) + await genProofs(genProofArgs) + + const success = true + await subtask.finish(success) + } + ) diff --git a/contracts/tasks/runners/proveOnChain.ts b/contracts/tasks/runners/proveOnChain.ts new file mode 100644 index 000000000..b1eb499de --- /dev/null +++ b/contracts/tasks/runners/proveOnChain.ts @@ -0,0 +1,99 @@ +/** + * 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' + +/** + * 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') + .addParam('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 } = hre + 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 fundingRoundContract = await getCurrentFundingRoundContract( + clrfund, + 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, + subsidyEnabled: false, + 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..46f535f8b --- /dev/null +++ b/contracts/tasks/runners/publishTallyResults.ts @@ -0,0 +1,163 @@ +/** + * 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 + * + * Sample usage: + * + * yarn hardhat publish-tally-results --clrfund + * --proof-dir --network + * + */ +import { BaseContract, getNumber, NonceManager } from 'ethers' +import { task, types } from 'hardhat/config' + +import { getIpfsHash } 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 { getCurrentFundingRoundContract } from '../../utils/contracts' +import { getTalyFilePath } from '../../utils/misc' + +/** + * 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()) +} + +/** + * 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) +} + +task('publish-tally-results', 'Publish tally results') + .addParam('clrfund', 'ClrFund contract address') + .addParam('proofDir', 'The proof output directory') + .addOptionalParam( + 'batchSize', + 'The batch size to upload tally result on-chain', + 10, + 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 } = hre + 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()) + + await subtask.logStart() + + const fundingRoundContract = await getCurrentFundingRoundContract( + clrfund, + 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, + }) + + // Publish tally hash if it is not already published + await publishTallyHash(fundingRoundContract, tallyData) + + // 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..e3283434d --- /dev/null +++ b/contracts/tasks/runners/resetTally.ts @@ -0,0 +1,51 @@ +/** + * 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 { + 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/utils/contracts.ts b/contracts/utils/contracts.ts index e60d11a76..45250e3fb 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,7 +10,7 @@ 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' @@ -89,4 +90,30 @@ 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 +} export { getEventArg } From 4b513e87de8590d26bf8a28cbd718cd37d4173cc Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 3 Apr 2024 00:34:31 -0400 Subject: [PATCH 09/86] adjust tally scripts for testing purposes --- contracts/sh/runScriptTests.sh | 10 ++++++---- contracts/tasks/runners/genProofs.ts | 10 +++++++--- contracts/tasks/runners/proveOnChain.ts | 10 +++++++--- contracts/tasks/runners/publishTallyResults.ts | 10 +++++++--- 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/contracts/sh/runScriptTests.sh b/contracts/sh/runScriptTests.sh index f03a47bf9..b17de7b2f 100755 --- a/contracts/sh/runScriptTests.sh +++ b/contracts/sh/runScriptTests.sh @@ -33,13 +33,15 @@ 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 \ +yarn hardhat gen-proofs \ --rapidsnark ${RAPID_SNARK} \ - --batch-size 8 \ - --output-dir ${OUTPUT_DIR} \ + --proof-dir ${OUTPUT_DIR} \ + --maci-start-block 0 \ --network "${HARDHAT_NETWORK}" +yarn hardhat prove-on-chain --proof-dir ${OUTPUT_DIR} --network "${HARDHAT_NETWORK}" +yarn hardhat publish-tally-results --proof-dir ${OUTPUT_DIR} --network "${HARDHAT_NETWORK}" # finalize the round yarn hardhat finalize --tally-file ${TALLY_FILE} --network ${HARDHAT_NETWORK} diff --git a/contracts/tasks/runners/genProofs.ts b/contracts/tasks/runners/genProofs.ts index 55c9d5521..c9da580f3 100644 --- a/contracts/tasks/runners/genProofs.ts +++ b/contracts/tasks/runners/genProofs.ts @@ -15,7 +15,7 @@ * * Sample usage: * - * yarn hardhat tally --clrfund --proof-dir \ + * yarn hardhat gen-proofs --clrfund --proof-dir \ * --maci-tx-hash --network * */ @@ -36,9 +36,10 @@ import { getMaciStateFilePath } from '../../utils/misc' import { EContracts } from '../../utils/types' import { Subtask } from '../helpers/Subtask' import { getCurrentFundingRoundContract } from '../../utils/contracts' +import { ContractStorage } from '../helpers/ContractStorage' task('gen-proofs', 'Generate MACI proofs offchain') - .addParam('clrfund', 'FundingRound contract address') + .addOptionalParam('clrfund', 'FundingRound contract address') .addParam('proofDir', 'The proof output directory') .addOptionalParam('maciTxHash', 'MACI creation transaction hash') .addOptionalParam( @@ -89,6 +90,7 @@ task('gen-proofs', 'Generate MACI proofs offchain') console.log('Verbose logging enabled:', !quiet) const { ethers, network } = hre + const storage = ContractStorage.getInstance() const subtask = Subtask.getInstance(hre) subtask.setHre(hre) @@ -121,8 +123,10 @@ task('gen-proofs', 'Generate MACI proofs offchain') await subtask.logStart() + const clrfundContractAddress = + clrfund ?? storage.mustGetAddress(EContracts.ClrFund, network.name) const fundingRoundContract = await getCurrentFundingRoundContract( - clrfund, + clrfundContractAddress, coordinator, ethers ) diff --git a/contracts/tasks/runners/proveOnChain.ts b/contracts/tasks/runners/proveOnChain.ts index b1eb499de..af777ed12 100644 --- a/contracts/tasks/runners/proveOnChain.ts +++ b/contracts/tasks/runners/proveOnChain.ts @@ -19,6 +19,7 @@ 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 @@ -40,7 +41,7 @@ async function getMessageProcessorAddress( } task('prove-on-chain', 'Prove on chain with the MACI proofs') - .addParam('clrfund', 'ClrFund contract address') + .addOptionalParam('clrfund', 'ClrFund contract address') .addParam('proofDir', 'The proof output directory') .addFlag('manageNonce', 'Whether to manually manage transaction nonce') .addOptionalParam( @@ -52,7 +53,8 @@ task('prove-on-chain', 'Prove on chain with the MACI proofs') .setAction(async ({ clrfund, quiet, manageNonce, proofDir }, hre) => { console.log('Verbose logging enabled:', !quiet) - const { ethers } = hre + const { ethers, network } = hre + const storage = ContractStorage.getInstance() const subtask = Subtask.getInstance(hre) subtask.setHre(hre) @@ -67,8 +69,10 @@ task('prove-on-chain', 'Prove on chain with the MACI proofs') await subtask.logStart() + const clrfundContractAddress = + clrfund ?? storage.mustGetAddress(EContracts.ClrFund, network.name) const fundingRoundContract = await getCurrentFundingRoundContract( - clrfund, + clrfundContractAddress, coordinator, ethers ) diff --git a/contracts/tasks/runners/publishTallyResults.ts b/contracts/tasks/runners/publishTallyResults.ts index 46f535f8b..d2fef14f1 100644 --- a/contracts/tasks/runners/publishTallyResults.ts +++ b/contracts/tasks/runners/publishTallyResults.ts @@ -24,6 +24,7 @@ import { EContracts } from '../../utils/types' import { Subtask } from '../helpers/Subtask' import { 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 @@ -94,7 +95,7 @@ async function getRecipientTreeDepth( } task('publish-tally-results', 'Publish tally results') - .addParam('clrfund', 'ClrFund contract address') + .addOptionalParam('clrfund', 'ClrFund contract address') .addParam('proofDir', 'The proof output directory') .addOptionalParam( 'batchSize', @@ -106,7 +107,8 @@ task('publish-tally-results', 'Publish tally results') .addFlag('quiet', 'Whether to log on the console') .setAction( async ({ clrfund, proofDir, batchSize, manageNonce, quiet }, hre) => { - const { ethers } = hre + const { ethers, network } = hre + const storage = ContractStorage.getInstance() const subtask = Subtask.getInstance(hre) subtask.setHre(hre) @@ -119,8 +121,10 @@ task('publish-tally-results', 'Publish tally results') await subtask.logStart() + const clrfundContractAddress = + clrfund ?? storage.mustGetAddress(EContracts.ClrFund, network.name) const fundingRoundContract = await getCurrentFundingRoundContract( - clrfund, + clrfundContractAddress, coordinator, ethers ) From 2a8fa9097f2043c3063d6393c136ae4fbf163f9d Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 3 Apr 2024 00:52:18 -0400 Subject: [PATCH 10/86] add missing start --- contracts/tasks/runners/resetTally.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/tasks/runners/resetTally.ts b/contracts/tasks/runners/resetTally.ts index e3283434d..adc9ebb4e 100644 --- a/contracts/tasks/runners/resetTally.ts +++ b/contracts/tasks/runners/resetTally.ts @@ -21,6 +21,8 @@ task('reset-tally', 'Reset the tally contract') let success = false try { + await subtask.logStart() + const [coordinator] = await hre.ethers.getSigners() console.log('Coordinator address: ', await coordinator.getAddress()) From 83023b7c5a0a1429ed4c076fd92cc825c2219c49 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 3 Apr 2024 02:01:15 -0400 Subject: [PATCH 11/86] update documentation with new commands for votes tallying --- docs/tally-verify.md | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/docs/tally-verify.md b/docs/tally-verify.md index b2edd2a50..a2d2d66b0 100644 --- a/docs/tally-verify.md +++ b/docs/tally-verify.md @@ -20,22 +20,34 @@ WALLET_MNEMONIC= WALLET_PRIVATE_KEY ``` -Decrypt messages and tally the votes: +Decrypt messages, tally the votes and generate proofs: ``` -yarn hardhat tally --rapidsnark {RAPID_SNARK} --output-dir {OUTPUT_DIR} --network {network} +yarn hardhat gen-proofs --clrfund {CLRFUND_CONTRACT_ADDRESS} --maci-tx-hash {MACI_CREATION_TRANSACTION_HASH} --proof-dir {OUTPUT_DIR} --rapidsnark {RAPID_SNARK} --network {network} ``` You only need to provide `--rapidsnark` if you are running the `tally` command on an intel chip. +If `gen-proofs` failed, you can rerun the command with the same parameters. If the maci-state.json file has been created, you can skip fetching MACI logs by providing the MACI state file as follow: -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. +``` +yarn hardhat gen-proofs --clrfund {CLRFUND_CONTRACT_ADDRESS} --maci-state-file {MACI_STATE_FILE_PATH} --proof-dir {OUTPUT_DIR} --rapidsnark {RAPID_SNARK} --network {network} +``` + + +** Make a backup of the {OUTPUT_DIR} before continuing to the next step ** + +Upload the proofs on chain: ``` -# for rerun -yarn hardhat tally --maci-state-file {maci-state.json} --tally-file {tally.json} --output-dir {OUTPUT_DIR} --network {network} +yarn hardhat prove-on-chain --clrfund {CLRFUND_CONTRACT_ADDRESS} --proof-dir {OUTPUT_DIR} --network {network} +yarn hardhat publish-tally-results --clrfund {CLRFUND_CONTRACT_ADDRESS} --proof-dir {OUTPUT_DIR} --network localhost ``` -Result will be saved to `tally.json` file, which must then be published via IPFS. +If there's error running `prove-on-chain` or `publish-tally-resuls`, simply rerun the commands with the same parameters. + + + +Result will be saved to `{OUTPUT_DIR}/tally.json` file, which must then be published via IPFS. **Using [command line](https://docs.ipfs.tech/reference/kubo/cli/#ipfs)** From 214e3958ebbebdc1e274d1f59c8ebae6fbf6e389 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 3 Apr 2024 02:35:08 -0400 Subject: [PATCH 12/86] upload smaller batches to avoid socket error on linux --- contracts/tasks/runners/publishTallyResults.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/tasks/runners/publishTallyResults.ts b/contracts/tasks/runners/publishTallyResults.ts index d2fef14f1..91699fa94 100644 --- a/contracts/tasks/runners/publishTallyResults.ts +++ b/contracts/tasks/runners/publishTallyResults.ts @@ -100,7 +100,7 @@ task('publish-tally-results', 'Publish tally results') .addOptionalParam( 'batchSize', 'The batch size to upload tally result on-chain', - 10, + 8, types.int ) .addFlag('manageNonce', 'Whether to manually manage transaction nonce') From 8e3a1a25d179f9d9dae220dd1dbab0010d2b9e5a Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 3 Apr 2024 09:56:24 -0400 Subject: [PATCH 13/86] add --round-address optino --- contracts/tasks/runners/claim.ts | 86 +++++++++++++++++--------------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/contracts/tasks/runners/claim.ts b/contracts/tasks/runners/claim.ts index acce6d3a2..bf90576e2 100644 --- a/contracts/tasks/runners/claim.ts +++ b/contracts/tasks/runners/claim.ts @@ -18,6 +18,7 @@ import { EContracts } from '../../utils/types' import { ContractStorage } from '../helpers/ContractStorage' task('claim', 'Claim funnds for test recipients') + .addOptionalParam('roundAddress', 'Funding round contract address') .addParam( 'recipient', 'The recipient index in the tally file', @@ -25,52 +26,55 @@ task('claim', 'Claim funnds for test recipients') types.int ) .addParam('tallyFile', 'The tally file') - .setAction(async ({ tallyFile, recipient }, { ethers, network }) => { - if (!isPathExist(tallyFile)) { - throw new Error(`Path ${tallyFile} does not exist`) - } + .setAction( + async ({ tallyFile, recipient, roundAddress }, { ethers, network }) => { + if (!isPathExist(tallyFile)) { + throw new Error(`Path ${tallyFile} does not exist`) + } - 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 = storage.mustGetAddress( - EContracts.FundingRound, - network.name - ) + const storage = ContractStorage.getInstance() + const fundingRound = + roundAddress ?? + storage.mustGetAddress(EContracts.FundingRound, network.name) - const tally = JSONFile.read(tallyFile) + const tally = JSONFile.read(tallyFile) - const fundingRoundContract = await ethers.getContractAt( - EContracts.FundingRound, - fundingRound - ) + const fundingRoundContract = await ethers.getContractAt( + EContracts.FundingRound, + fundingRound + ) - const recipientStatus = await fundingRoundContract.recipients(recipient) - if (recipientStatus.fundsClaimed) { - throw new Error(`Recipient already claimed funds`) - } + const recipientStatus = await fundingRoundContract.recipients(recipient) + if (recipientStatus.fundsClaimed) { + throw new Error(`Recipient already claimed funds`) + } - const pollAddress = await fundingRoundContract.poll() - console.log('pollAddress', pollAddress) + const pollAddress = await fundingRoundContract.poll() + console.log('pollAddress', pollAddress) - const poll = await ethers.getContractAt(EContracts.Poll, pollAddress) - const treeDepths = await poll.treeDepths() - const recipientTreeDepth = getNumber(treeDepths.voteOptionTreeDepth) + const poll = await ethers.getContractAt(EContracts.Poll, pollAddress) + 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.`) - }) + // 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.`) + } + ) From 86eaa2665bd7abb0afff021d4e106e128fc576b6 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 3 Apr 2024 10:12:37 -0400 Subject: [PATCH 14/86] temporary remove snapshop user test --- contracts/tests/userRegistrySnapshot.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 From 7b705835da7c8e25b13cd7b3aa80e7de192d8ca5 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 3 Apr 2024 20:18:57 -0400 Subject: [PATCH 15/86] use consistent network name to get etherscan api key --- contracts/hardhat.config.ts | 2 +- contracts/utils/providers/EtherscanProvider.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/hardhat.config.ts b/contracts/hardhat.config.ts index e9fcb6931..0a30c06b2 100644 --- a/contracts/hardhat.config.ts +++ b/contracts/hardhat.config.ts @@ -59,7 +59,7 @@ export default { 'https://sepolia-rollup.arbitrum.io/rpc', accounts, }, - optimism: { + optimisticEthereum: { url: process.env.JSONRPC_HTTP_URL || 'https://mainnet.optimism.io', accounts, }, diff --git a/contracts/utils/providers/EtherscanProvider.ts b/contracts/utils/providers/EtherscanProvider.ts index 5a35ac557..efa0cadb0 100644 --- a/contracts/utils/providers/EtherscanProvider.ts +++ b/contracts/utils/providers/EtherscanProvider.ts @@ -6,7 +6,7 @@ const EtherscanApiUrl: Record = { arbitrum: 'https://api.arbiscan.io', 'arbitrum-goerli': 'https://api-goerli.arbiscan.io', 'arbitrum-sepolia': 'https://api-sepolia.arbiscan.io', - optimism: 'https://api-optimistic.etherscan.io', + optimisticEthereum: 'https://api-optimistic.etherscan.io', 'optimism-sepolia': 'https://api-sepolia-optimistic.etherscan.io', } From e7df7a8a0311f5853b567b13551f97945e7f246c Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 3 Apr 2024 20:56:38 -0400 Subject: [PATCH 16/86] map hardhat network name to etherscan name to retrieve the etherscan api key --- contracts/hardhat.config.ts | 2 +- contracts/tasks/runners/exportRound.ts | 12 +++++++++++- contracts/utils/providers/EtherscanProvider.ts | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/contracts/hardhat.config.ts b/contracts/hardhat.config.ts index 0a30c06b2..e9fcb6931 100644 --- a/contracts/hardhat.config.ts +++ b/contracts/hardhat.config.ts @@ -59,7 +59,7 @@ export default { 'https://sepolia-rollup.arbitrum.io/rpc', accounts, }, - optimisticEthereum: { + optimism: { url: process.env.JSONRPC_HTTP_URL || 'https://mainnet.optimism.io', accounts, }, diff --git a/contracts/tasks/runners/exportRound.ts b/contracts/tasks/runners/exportRound.ts index 4eadf9818..da14269c1 100644 --- a/contracts/tasks/runners/exportRound.ts +++ b/contracts/tasks/runners/exportRound.ts @@ -29,6 +29,11 @@ type RoundListEntry = { isFinalized: boolean } +// Map hardhat network name to the etherscan api network name in the hardhat.config +const ETHERSCAN_NETWORKS: Record = { + optimism: 'optimisticEthereum', +} + const toUndefined = () => undefined const toString = (val: bigint) => BigInt(val).toString() const toZero = () => BigInt(0) @@ -41,13 +46,18 @@ function roundListFileName(directory: string): string { return path.join(directory, 'rounds.json') } +function toEtherscanNetworkName(network: string): string { + return ETHERSCAN_NETWORKS[network] ?? network +} + 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] + const etherscanNetwork = toEtherscanNetworkName(network) + etherscanApiKey = config.etherscan.apiKey[etherscanNetwork] } } diff --git a/contracts/utils/providers/EtherscanProvider.ts b/contracts/utils/providers/EtherscanProvider.ts index efa0cadb0..5a35ac557 100644 --- a/contracts/utils/providers/EtherscanProvider.ts +++ b/contracts/utils/providers/EtherscanProvider.ts @@ -6,7 +6,7 @@ const EtherscanApiUrl: Record = { arbitrum: 'https://api.arbiscan.io', 'arbitrum-goerli': 'https://api-goerli.arbiscan.io', 'arbitrum-sepolia': 'https://api-sepolia.arbiscan.io', - optimisticEthereum: 'https://api-optimistic.etherscan.io', + optimism: 'https://api-optimistic.etherscan.io', 'optimism-sepolia': 'https://api-sepolia-optimistic.etherscan.io', } From 3df43e0763d01224e86ce9376a7cc948ce1203b8 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Thu, 4 Apr 2024 14:03:12 -0400 Subject: [PATCH 17/86] remove tally script --- .github/workflows/finalize-round.yml | 18 +- contracts/.env.example | 2 +- contracts/tasks/index.ts | 1 - contracts/tasks/runners/tally.ts | 353 --------------------------- docs/tally-verify.md | 2 +- 5 files changed, 15 insertions(+), 361 deletions(-) delete mode 100644 contracts/tasks/runners/tally.ts diff --git a/.github/workflows/finalize-round.yml b/.github/workflows/finalize-round.yml index adfcdfdfc..a1d903269 100644 --- a/.github/workflows/finalize-round.yml +++ b/.github/workflows/finalize-round.yml @@ -79,14 +79,22 @@ jobs: export BLOCKS_PER_BATCH=${{ github.event.inputs.blocks_per_batch }} export RAPID_SNARK="$GITHUB_WORKSPACE/rapidsnark/package/bin/prover" export CIRCUIT_DIRECTORY=$GITHUB_WORKSPACE/params + export PROOF_OUTPUT_DIR=./proof_output # tally and finalize cd monorepo/contracts - mkdir -p proof_output - yarn hardhat tally --clrfund "${CLRFUND_ADDRESS}" --network "${NETWORK}" \ - --rapidsnark ${RAPID_SNARK} \ - --circuit-directory ${CIRCUIT_DIRECTORY} \ + mkdir -p ${PROOF_OUTPUT_DIR} + yarn gen-proofs --clrfund "${CLRFUND_ADDRESS}" \ --blocks-per-batch ${BLOCKS_PER_BATCH} \ - --maci-tx-hash "${MACI_TX_HASH}" --output-dir "./proof_output" + --rapidsnark ${RAPID_SNARK} \ + --maci-tx-hash "${MACI_TX_HASH}" \ + --proof-dir ${PROOF_OUTPUT_DIR} \ + --network "${NETWORK}" + yarn hardhat prove-on-chain --clrfund "${CLRFUND_ADDRESS}" \ + --proof-dir ${PROOF_OUTPUT_DIR} \ + --network "${NETWORK}" + yarn hardhat publish-tally-results --clrfund "${CLRFUND_ADDRESS}" \ + --proof-dir ${PROOF_OUTPUT_DIR} \ + --network "${NETWORK}" curl --location --request POST 'https://api.pinata.cloud/pinning/pinFileToIPFS' \ --header "Authorization: Bearer ${{ secrets.PINATA_JWT }}" \ --form 'file=@"./proof_output/tally.json"' diff --git a/contracts/.env.example b/contracts/.env.example index 5ace336a7..bdede7da1 100644 --- a/contracts/.env.example +++ b/contracts/.env.example @@ -6,7 +6,7 @@ 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) diff --git a/contracts/tasks/index.ts b/contracts/tasks/index.ts index 934d30612..227256785 100644 --- a/contracts/tasks/index.ts +++ b/contracts/tasks/index.ts @@ -10,7 +10,6 @@ import './runners/setMaciParameters' import './runners/setToken' import './runners/setUserRegistry' import './runners/setStorageRoot' -import './runners/tally' import './runners/finalize' import './runners/claim' import './runners/cancel' diff --git a/contracts/tasks/runners/tally.ts b/contracts/tasks/runners/tally.ts deleted file mode 100644 index eb135b3e8..000000000 --- a/contracts/tasks/runners/tally.ts +++ /dev/null @@ -1,353 +0,0 @@ -/** - * 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 - * - * Sample usage: - * - * yarn hardhat tally --clrfund --maci-tx-hash --network - * - * To rerun: - * - * yarn hardhat tally --clrfund --maci-state-file \ - * --tally-file --network - */ -import { BaseContract, getNumber, Signer, NonceManager } from 'ethers' -import { task, types } from 'hardhat/config' - -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 { 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') - .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, - types.int - ) - .addParam('outputDir', 'The proof output directory', './proof_output') - .addOptionalParam('rapidsnark', 'The rapidsnark prover path') - .addOptionalParam( - 'numQueueOps', - 'The number of operations for MACI tree merging', - getNumber(DEFAULT_SR_QUEUE_OPS), - types.int - ) - .addOptionalParam( - 'blocksPerBatch', - 'The number of blocks per batch of logs to fetch on-chain', - DEFAULT_GET_LOG_BATCH_SIZE, - 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, - maciTxHash, - quiet, - maciStateFile, - outputDir, - numQueueOps, - tallyFile, - blocksPerBatch, - rapidsnark, - sleep, - batchSize, - 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.getConfigField( - EContracts.VkRegistry, - 'circuit' - ) - const circuitDirectory = subtask.getConfigField( - EContracts.VkRegistry, - 'paramsDirectory' - ) - - 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 - ) - - const pollId = await fundingRoundContract.pollId() - console.log('PollId', pollId) - - const maciAddress = await fundingRoundContract.maci() - const maciTransactionHash = - maciTxHash ?? storage.getTxHash(maciAddress, network.name) - console.log('MACI address', maciAddress) - - const tallyAddress = await fundingRoundContract.tally() - const messageProcessorAddress = await getMessageProcessorAddress( - tallyAddress, - ethers - ) - - const providerUrl = (network.config as any).url - - const outputPath = maciStateFile - ? maciStateFile - : getMaciStateFilePath(outputDir) - - await mergeMaciSubtrees({ - maciAddress, - pollId, - numQueueOps, - signer: coordinator, - 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, - 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 - ) - - const success = true - await subtask.finish(success) - } - ) diff --git a/docs/tally-verify.md b/docs/tally-verify.md index a2d2d66b0..61139360e 100644 --- a/docs/tally-verify.md +++ b/docs/tally-verify.md @@ -34,7 +34,7 @@ yarn hardhat gen-proofs --clrfund {CLRFUND_CONTRACT_ADDRESS} --maci-state-file { ``` -** Make a backup of the {OUTPUT_DIR} before continuing to the next step ** +**Make a backup of the {OUTPUT_DIR} before continuing to the next step** Upload the proofs on chain: From ac777d71bafb6eb60573ee49909d97cff16e0498 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Fri, 5 Apr 2024 13:45:55 -0400 Subject: [PATCH 18/86] add tally script back --- .github/workflows/finalize-round.yml | 18 ++-- contracts/tasks/index.ts | 1 + contracts/tasks/runners/genProofs.ts | 115 +++++++++++++------------ contracts/tasks/runners/tally.ts | 122 +++++++++++++++++++++++++++ contracts/utils/maci.ts | 5 +- contracts/utils/misc.ts | 9 +- 6 files changed, 195 insertions(+), 75 deletions(-) create mode 100644 contracts/tasks/runners/tally.ts diff --git a/.github/workflows/finalize-round.yml b/.github/workflows/finalize-round.yml index a1d903269..d0af1ab9f 100644 --- a/.github/workflows/finalize-round.yml +++ b/.github/workflows/finalize-round.yml @@ -79,22 +79,14 @@ jobs: export BLOCKS_PER_BATCH=${{ github.event.inputs.blocks_per_batch }} export RAPID_SNARK="$GITHUB_WORKSPACE/rapidsnark/package/bin/prover" export CIRCUIT_DIRECTORY=$GITHUB_WORKSPACE/params - export PROOF_OUTPUT_DIR=./proof_output # tally and finalize cd monorepo/contracts - mkdir -p ${PROOF_OUTPUT_DIR} - yarn gen-proofs --clrfund "${CLRFUND_ADDRESS}" \ - --blocks-per-batch ${BLOCKS_PER_BATCH} \ + mkdir -p proof_output + yarn hardhat tally --clrfund "${CLRFUND_ADDRESS}" --network "${NETWORK}" \ --rapidsnark ${RAPID_SNARK} \ - --maci-tx-hash "${MACI_TX_HASH}" \ - --proof-dir ${PROOF_OUTPUT_DIR} \ - --network "${NETWORK}" - yarn hardhat prove-on-chain --clrfund "${CLRFUND_ADDRESS}" \ - --proof-dir ${PROOF_OUTPUT_DIR} \ - --network "${NETWORK}" - yarn hardhat publish-tally-results --clrfund "${CLRFUND_ADDRESS}" \ - --proof-dir ${PROOF_OUTPUT_DIR} \ - --network "${NETWORK}" + --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"' diff --git a/contracts/tasks/index.ts b/contracts/tasks/index.ts index 227256785..934d30612 100644 --- a/contracts/tasks/index.ts +++ b/contracts/tasks/index.ts @@ -10,6 +10,7 @@ import './runners/setMaciParameters' import './runners/setToken' import './runners/setUserRegistry' import './runners/setStorageRoot' +import './runners/tally' import './runners/finalize' import './runners/claim' import './runners/cancel' diff --git a/contracts/tasks/runners/genProofs.ts b/contracts/tasks/runners/genProofs.ts index c9da580f3..a0656e650 100644 --- a/contracts/tasks/runners/genProofs.ts +++ b/contracts/tasks/runners/genProofs.ts @@ -1,13 +1,6 @@ /** * Script for generating MACI proofs * - * Pass --maci-tx-hash if this is the first time running the script and you - * want to get MACI logs starting from the block as recorded in the MACI creation - * transaction hash - * - * Pass --maci-state-file if you have previously ran the script and have - * the maci-state file (maci-state.json) - * * 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 @@ -32,11 +25,17 @@ import { genLocalState, mergeMaciSubtrees, } from '../../utils/maci' -import { getMaciStateFilePath } from '../../utils/misc' +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' task('gen-proofs', 'Generate MACI proofs offchain') .addOptionalParam('clrfund', 'FundingRound contract address') @@ -48,9 +47,9 @@ task('gen-proofs', 'Generate MACI proofs offchain') undefined, types.int ) - .addOptionalParam('maciStateFile', 'MACI state file') .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', @@ -77,8 +76,8 @@ task('gen-proofs', 'Generate MACI proofs offchain') maciStartBlock, maciTxHash, quiet, - maciStateFile, proofDir, + paramsDir, blocksPerBatch, rapidsnark, numQueueOps, @@ -94,10 +93,6 @@ task('gen-proofs', 'Generate MACI proofs offchain') const subtask = Subtask.getInstance(hre) subtask.setHre(hre) - if (!maciStateFile && !maciTxHash && maciStartBlock == undefined) { - throw new Error('Please provide --maci-start-block or --maci-tx-hash') - } - const [coordinatorSigner] = await ethers.getSigners() if (!coordinatorSigner) { throw new Error('Env. variable WALLET_PRIVATE_KEY not set') @@ -112,14 +107,15 @@ task('gen-proofs', 'Generate MACI proofs offchain') throw new Error('Env. variable COORDINATOR_MACISK not set') } - const circuit = subtask.getConfigField( - EContracts.VkRegistry, - 'circuit' - ) - const circuitDirectory = subtask.getConfigField( - EContracts.VkRegistry, - 'paramsDirectory' - ) + const circuit = + subtask.tryGetConfigField(EContracts.VkRegistry, 'circuit') || + DEFAULT_CIRCUIT + + const circuitDirectory = + subtask.tryGetConfigField( + EContracts.VkRegistry, + 'paramsDirectory' + ) || paramsDir await subtask.logStart() @@ -136,9 +132,6 @@ task('gen-proofs', 'Generate MACI proofs offchain') console.log('PollId', pollId) const maciAddress = await fundingRoundContract.maci() - - const providerUrl = (network.config as any).url - await mergeMaciSubtrees({ maciAddress, pollId, @@ -147,42 +140,54 @@ task('gen-proofs', 'Generate MACI proofs offchain') quiet, }) - const maciStateFilePath = maciStateFile - ? maciStateFile - : getMaciStateFilePath(proofDir) + if (!isPathExist(proofDir)) { + makeDirectory(proofDir) + } + + const tallyFile = getTalyFilePath(proofDir) + const maciStateFile = getMaciStateFilePath(proofDir) + const providerUrl = (network.config as any).url - if (!maciStateFile) { - await genLocalState({ - quiet, - outputPath: maciStateFilePath, + if (!isPathExist(tallyFile)) { + 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, + maciContractAddress: maciAddress, + coordinatorPrivateKey: coordinatorMacisk, + ethereumProvider: providerUrl, + transactionHash: maciTxHash, + startBlock: maciStartBlock, + blockPerBatch: blocksPerBatch, + signer: coordinator, + sleep, + }) + } + + const genProofArgs = getGenProofArgs({ + maciAddress, pollId, - maciContractAddress: maciAddress, - coordinatorPrivateKey: coordinatorMacisk, - ethereumProvider: providerUrl, - transactionHash: maciTxHash, - startBlock: maciStartBlock, - blockPerBatch: blocksPerBatch, + coordinatorMacisk, + rapidsnark, + circuitType: circuit, + circuitDirectory, + outputDir: proofDir, + blocksPerBatch: getNumber(blocksPerBatch), + maciStateFile, + tallyFile, signer: coordinator, - sleep, + quiet, }) + await genProofs(genProofArgs) } - const genProofArgs = getGenProofArgs({ - maciAddress, - pollId, - coordinatorMacisk, - rapidsnark, - circuitType: circuit, - circuitDirectory, - outputDir: proofDir, - blocksPerBatch: getNumber(blocksPerBatch), - maciTxHash, - maciStateFile: maciStateFilePath, - signer: coordinator, - quiet, - }) - await genProofs(genProofArgs) - const success = true await subtask.finish(success) } diff --git a/contracts/tasks/runners/tally.ts b/contracts/tasks/runners/tally.ts new file mode 100644 index 000000000..f524dda72 --- /dev/null +++ b/contracts/tasks/runners/tally.ts @@ -0,0 +1,122 @@ +/** + * Script for tallying votes which involves fetching MACI logs, generating proofs, + * proving on chain, and uploading tally results on chain + * + * Sample usage: + * yarn hardhat tally --clrfund --maci-tx-hash --network + * + * This script can be re-run with the same input parameters + */ +import { getNumber } from 'ethers' +import { task, types } from 'hardhat/config' + +import { + DEFAULT_SR_QUEUE_OPS, + DEFAULT_GET_LOG_BATCH_SIZE, +} from '../../utils/constants' +import { EContracts } from '../../utils/types' +import { ContractStorage } from '../helpers/ContractStorage' +import { Subtask } from '../helpers/Subtask' + +task('tally', 'Tally votes') + .addOptionalParam('clrfund', 'ClrFund contract address') + .addOptionalParam('maciTxHash', 'MACI creation transaction hash') + .addOptionalParam( + 'maciStartBlock', + 'MACI creation block', + undefined, + types.int + ) + .addFlag('manageNonce', 'Whether to manually manage transaction nonce') + .addOptionalParam( + 'batchSize', + 'The batch size to upload tally result on-chain', + 8, + types.int + ) + .addParam('proofDir', 'The proof output directory', './proof_output') + .addParam('paramsDir', 'The circuit zkeys directory', './params') + .addOptionalParam('rapidsnark', 'The rapidsnark prover path') + .addOptionalParam( + 'numQueueOps', + 'The number of operations for MACI tree merging', + getNumber(DEFAULT_SR_QUEUE_OPS), + types.int + ) + .addOptionalParam( + 'blocksPerBatch', + 'The number of blocks per batch of logs to fetch on-chain', + DEFAULT_GET_LOG_BATCH_SIZE, + 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, + maciTxHash, + maciStartBlock, + quiet, + proofDir, + paramsDir, + numQueueOps, + blocksPerBatch, + rapidsnark, + sleep, + batchSize, + manageNonce, + }, + hre + ) => { + console.log('Verbose logging enabled:', !quiet) + + const storage = ContractStorage.getInstance() + const subtask = Subtask.getInstance(hre) + subtask.setHre(hre) + + await subtask.logStart() + + const clrfundContractAddress = + clrfund ?? storage.mustGetAddress(EContracts.ClrFund, hre.network.name) + + await hre.run('gen-proofs', { + clrfund: clrfundContractAddress, + maciStartBlock, + maciTxHash, + numQueueOps, + blocksPerBatch, + rapidsnark, + sleep, + proofDir, + paramsDir, + manageNonce, + quiet, + }) + + // proveOnChain if not already processed + await hre.run('prove-on-chain', { + clrfund: clrfundContractAddress, + proofDir, + manageNonce, + quiet, + }) + + // Publish tally hash if it is not already published + await hre.run('publish-tally-results', { + clrfund: clrfundContractAddress, + proofDir, + batchSize, + manageNonce, + quiet, + }) + + const success = true + await subtask.finish(success) + } + ) diff --git a/contracts/utils/maci.ts b/contracts/utils/maci.ts index 6065f383d..bb3e3bb0b 100644 --- a/contracts/utils/maci.ts +++ b/contracts/utils/maci.ts @@ -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, diff --git a/contracts/utils/misc.ts b/contracts/utils/misc.ts index 34bb53482..029a455de 100644 --- a/contracts/utils/misc.ts +++ b/contracts/utils/misc.ts @@ -29,10 +29,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) } From d70d4147285420f06706168907ee34bc6f6df684 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Fri, 5 Apr 2024 22:06:02 -0400 Subject: [PATCH 19/86] refactor the tally script to re-run without extra inputs --- .github/workflows/finalize-round.yml | 9 +- contracts/.env.example | 4 + contracts/e2e/index.ts | 4 + contracts/package.json | 1 + contracts/sh/runScriptTests.sh | 10 +- contracts/tasks/runners/claim.ts | 30 +++--- contracts/tasks/runners/finalize.ts | 26 +++--- contracts/tasks/runners/genProofs.ts | 92 ++++++++++++------- .../tasks/runners/publishTallyResults.ts | 28 ++++-- contracts/tasks/runners/tally.ts | 33 ++++++- contracts/utils/ipfs.ts | 28 +++++- contracts/utils/misc.ts | 25 ++++- docs/tally-verify.md | 41 ++------- yarn.lock | 69 +++++++++++++- 14 files changed, 287 insertions(+), 113 deletions(-) diff --git a/.github/workflows/finalize-round.yml b/.github/workflows/finalize-round.yml index d0af1ab9f..fd972749f 100644 --- a/.github/workflows/finalize-round.yml +++ b/.github/workflows/finalize-round.yml @@ -86,8 +86,7 @@ jobs: --rapidsnark ${RAPID_SNARK} \ --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/contracts/.env.example b/contracts/.env.example index bdede7da1..2db7006e4 100644 --- a/contracts/.env.example +++ b/contracts/.env.example @@ -13,6 +13,10 @@ COORDINATOR_MACISK= # 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/e2e/index.ts b/contracts/e2e/index.ts index 5a22205dd..76e21525c 100644 --- a/contracts/e2e/index.ts +++ b/contracts/e2e/index.ts @@ -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 } @@ -359,6 +360,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 +371,7 @@ describe('End-to-end Tests', function () { circuitType: circuit, circuitDirectory, outputDir, + tallyFile, blocksPerBatch: DEFAULT_GET_LOG_BATCH_SIZE, maciTxHash: maciTransactionHash, signer: coordinator, diff --git a/contracts/package.json b/contracts/package.json index 7bbbb8133..a52b79d4f 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -16,6 +16,7 @@ }, "dependencies": { "@openzeppelin/contracts": "4.9.0", + "@pinata/sdk": "^2.1.0", "dotenv": "^8.2.0", "maci-contracts": "^1.2.0", "solidity-rlp": "2.0.8" diff --git a/contracts/sh/runScriptTests.sh b/contracts/sh/runScriptTests.sh index b17de7b2f..11cde09a2 100755 --- a/contracts/sh/runScriptTests.sh +++ b/contracts/sh/runScriptTests.sh @@ -35,17 +35,15 @@ yarn hardhat time-travel --seconds ${ROUND_DURATION} --network ${HARDHAT_NETWORK # tally the votes NODE_OPTIONS="--max-old-space-size=4096" -yarn hardhat gen-proofs \ +yarn hardhat tally \ --rapidsnark ${RAPID_SNARK} \ --proof-dir ${OUTPUT_DIR} \ --maci-start-block 0 \ --network "${HARDHAT_NETWORK}" -yarn hardhat prove-on-chain --proof-dir ${OUTPUT_DIR} --network "${HARDHAT_NETWORK}" -yarn hardhat publish-tally-results --proof-dir ${OUTPUT_DIR} --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/runners/claim.ts b/contracts/tasks/runners/claim.ts index bf90576e2..e5135aa24 100644 --- a/contracts/tasks/runners/claim.ts +++ b/contracts/tasks/runners/claim.ts @@ -2,16 +2,17 @@ * 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 { 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' @@ -25,13 +26,9 @@ task('claim', 'Claim funnds for test recipients') undefined, types.int ) - .addParam('tallyFile', 'The tally file') + .addParam('proofDir', 'The proof output directory', './proof_output') .setAction( - async ({ tallyFile, recipient, roundAddress }, { ethers, network }) => { - if (!isPathExist(tallyFile)) { - throw new Error(`Path ${tallyFile} does not exist`) - } - + async ({ proofDir, recipient, roundAddress }, { ethers, network }) => { if (recipient <= 0) { throw new Error('Recipient must be greater than 0') } @@ -41,6 +38,17 @@ task('claim', 'Claim funnds for test recipients') roundAddress ?? storage.mustGetAddress(EContracts.FundingRound, network.name) + const proofDirForRound = getProofDirForRound( + proofDir, + network.name, + fundingRound + ) + + const tallyFile = getTalyFilePath(proofDirForRound) + if (!isPathExist(tallyFile)) { + throw new Error(`Path ${tallyFile} does not exist`) + } + const tally = JSONFile.read(tallyFile) const fundingRoundContract = await ethers.getContractAt( diff --git a/contracts/tasks/runners/finalize.ts b/contracts/tasks/runners/finalize.ts index 0240ba16b..e48a6c2b6 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,13 @@ 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' 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) @@ -63,6 +56,17 @@ task('finalize', 'Finalize a funding round') 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 index a0656e650..ed3061edb 100644 --- a/contracts/tasks/runners/genProofs.ts +++ b/contracts/tasks/runners/genProofs.ts @@ -36,6 +36,29 @@ 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') @@ -148,46 +171,49 @@ task('gen-proofs', 'Generate MACI proofs offchain') const maciStateFile = getMaciStateFilePath(proofDir) const providerUrl = (network.config as any).url - if (!isPathExist(tallyFile)) { - 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, - maciContractAddress: maciAddress, - coordinatorPrivateKey: coordinatorMacisk, - ethereumProvider: providerUrl, - transactionHash: maciTxHash, - startBlock: maciStartBlock, - blockPerBatch: blocksPerBatch, - signer: coordinator, - sleep, - }) + 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' + ) } - const genProofArgs = getGenProofArgs({ - maciAddress, + await genLocalState({ + quiet, + outputPath: maciStateFile, pollId, - coordinatorMacisk, - rapidsnark, - circuitType: circuit, - circuitDirectory, - outputDir: proofDir, - blocksPerBatch: getNumber(blocksPerBatch), - maciStateFile, - tallyFile, + maciContractAddress: maciAddress, + coordinatorPrivateKey: coordinatorMacisk, + ethereumProvider: providerUrl, + transactionHash: maciTxHash, + startBlock: maciStartBlock, + blockPerBatch: blocksPerBatch, signer: coordinator, - quiet, + sleep, }) - await genProofs(genProofArgs) } + 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/publishTallyResults.ts b/contracts/tasks/runners/publishTallyResults.ts index 91699fa94..5651ac353 100644 --- a/contracts/tasks/runners/publishTallyResults.ts +++ b/contracts/tasks/runners/publishTallyResults.ts @@ -5,6 +5,8 @@ * 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: * @@ -15,7 +17,7 @@ import { BaseContract, getNumber, NonceManager } from 'ethers' import { task, types } from 'hardhat/config' -import { getIpfsHash } from '../../utils/ipfs' +import { Ipfs } from '../../utils/ipfs' import { JSONFile } from '../../utils/JSONFile' import { addTallyResultsBatch, TallyData, verify } from '../../utils/maci' import { FundingRound, Poll } from '../../typechain-types' @@ -25,17 +27,17 @@ import { Subtask } from '../helpers/Subtask' import { getCurrentFundingRoundContract } from '../../utils/contracts' import { getTalyFilePath } from '../../utils/misc' import { ContractStorage } from '../helpers/ContractStorage' +import { PINATA_PINNING_URL } from '../../utils/constants' /** * Publish the tally IPFS hash on chain if it's not already published * @param fundingRoundContract Funding round contract - * @param tallyData Tally data + * @param tallyHash Tally hash */ async function publishTallyHash( fundingRoundContract: FundingRound, - tallyData: TallyData + tallyHash: string ) { - const tallyHash = await getIpfsHash(tallyData) console.log(`Tally hash is ${tallyHash}`) const tallyHashOnChain = await fundingRoundContract.tallyHash() @@ -63,7 +65,9 @@ async function submitTallyResults( ) { const startIndex = await fundingRoundContract.totalTallyResults() const total = tallyData.results.tally.length - console.log('Uploading tally results in batches of', batchSize) + if (startIndex < total) { + console.log('Uploading tally results in batches of', batchSize) + } const addTallyGas = await addTallyResultsBatch( fundingRoundContract, recipientTreeDepth, @@ -119,6 +123,16 @@ task('publish-tally-results', 'Publish tally results') 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 = @@ -149,8 +163,10 @@ task('publish-tally-results', 'Publish tally results') quiet, }) + const tallyHash = await Ipfs.pinFile(tallyFile, apiKey, secretApiKey) + // Publish tally hash if it is not already published - await publishTallyHash(fundingRoundContract, tallyData) + await publishTallyHash(fundingRoundContract, tallyHash) // Submit tally results to the funding round contract // This function can be re-run from where it left off diff --git a/contracts/tasks/runners/tally.ts b/contracts/tasks/runners/tally.ts index f524dda72..94482b679 100644 --- a/contracts/tasks/runners/tally.ts +++ b/contracts/tasks/runners/tally.ts @@ -9,11 +9,13 @@ */ 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 { getProofDirForRound } from '../../utils/misc' import { EContracts } from '../../utils/types' import { ContractStorage } from '../helpers/ContractStorage' import { Subtask } from '../helpers/Subtask' @@ -76,6 +78,16 @@ task('tally', 'Tally votes') ) => { console.log('Verbose logging enabled:', !quiet) + 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') + } + const storage = ContractStorage.getInstance() const subtask = Subtask.getInstance(hre) subtask.setHre(hre) @@ -85,6 +97,21 @@ task('tally', 'Tally votes') const clrfundContractAddress = clrfund ?? storage.mustGetAddress(EContracts.ClrFund, hre.network.name) + const clrfundContract = subtask.getContract({ + name: EContracts.ClrFund, + address: clrfundContractAddress, + }) + + const fundingRoundContractAddress = await ( + await clrfundContract + ).getCurrentRound() + + const outputDir = getProofDirForRound( + proofDir, + hre.network.name, + fundingRoundContractAddress + ) + await hre.run('gen-proofs', { clrfund: clrfundContractAddress, maciStartBlock, @@ -93,7 +120,7 @@ task('tally', 'Tally votes') blocksPerBatch, rapidsnark, sleep, - proofDir, + proofDir: outputDir, paramsDir, manageNonce, quiet, @@ -102,7 +129,7 @@ task('tally', 'Tally votes') // proveOnChain if not already processed await hre.run('prove-on-chain', { clrfund: clrfundContractAddress, - proofDir, + proofDir: outputDir, manageNonce, quiet, }) @@ -110,7 +137,7 @@ task('tally', 'Tally votes') // Publish tally hash if it is not already published await hre.run('publish-tally-results', { clrfund: clrfundContractAddress, - proofDir, + proofDir: outputDir, batchSize, manageNonce, quiet, 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/misc.ts b/contracts/utils/misc.ts index 029a455de..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 @@ -33,5 +56,5 @@ export function isPathExist(path: string): boolean { * @param directory The directory to create */ export function makeDirectory(directory: string): void { - fs.mkdirSync(directory) + fs.mkdirSync(directory, { recursive: true }) } diff --git a/docs/tally-verify.md b/docs/tally-verify.md index 61139360e..9ce6bc7dd 100644 --- a/docs/tally-verify.md +++ b/docs/tally-verify.md @@ -18,46 +18,23 @@ COORDINATOR_MACISK= # private key for interacting with contracts WALLET_MNEMONIC= WALLET_PRIVATE_KEY -``` - -Decrypt messages, tally the votes and generate proofs: -``` -yarn hardhat gen-proofs --clrfund {CLRFUND_CONTRACT_ADDRESS} --maci-tx-hash {MACI_CREATION_TRANSACTION_HASH} --proof-dir {OUTPUT_DIR} --rapidsnark {RAPID_SNARK} --network {network} +# credential to upload tally result to IPFS +PINATA_API_KEY= +PINATA_SECRET_API_KEY= ``` -You only need to provide `--rapidsnark` if you are running the `tally` command on an intel chip. -If `gen-proofs` failed, you can rerun the command with the same parameters. If the maci-state.json file has been created, you can skip fetching MACI logs by providing the MACI state file as follow: +Decrypt messages, tally the votes: ``` -yarn hardhat gen-proofs --clrfund {CLRFUND_CONTRACT_ADDRESS} --maci-state-file {MACI_STATE_FILE_PATH} --proof-dir {OUTPUT_DIR} --rapidsnark {RAPID_SNARK} --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} ``` - -**Make a backup of the {OUTPUT_DIR} before continuing to the next step** - - -Upload the proofs on chain: -``` -yarn hardhat prove-on-chain --clrfund {CLRFUND_CONTRACT_ADDRESS} --proof-dir {OUTPUT_DIR} --network {network} -yarn hardhat publish-tally-results --clrfund {CLRFUND_CONTRACT_ADDRESS} --proof-dir {OUTPUT_DIR} --network localhost -``` - -If there's error running `prove-on-chain` or `publish-tally-resuls`, simply rerun the commands with the same parameters. - - - -Result will be saved to `{OUTPUT_DIR}/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 @@ -72,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 diff --git a/yarn.lock b/yarn.lock index 11e8b7f78..86e13a1f9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3409,6 +3409,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" @@ -6830,7 +6840,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== @@ -10984,7 +10994,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== @@ -12507,6 +12517,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" @@ -13200,6 +13215,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" @@ -14968,6 +14995,13 @@ macos-release@^3.1.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" @@ -15646,6 +15680,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 +15736,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== @@ -17063,6 +17109,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" @@ -17431,7 +17485,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== @@ -21003,6 +21057,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" From 88f8898c1666a33a310a0600070e69cfa3d82ec8 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Fri, 5 Apr 2024 22:32:36 -0400 Subject: [PATCH 20/86] add PINATA env variables --- .github/workflows/finalize-round.yml | 2 ++ .github/workflows/test-scripts.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/finalize-round.yml b/.github/workflows/finalize-round.yml index fd972749f..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: 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: From 00cb623dd17c29cb102080a3f5f34d5ea38e3a42 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Fri, 12 Apr 2024 17:33:45 -0400 Subject: [PATCH 21/86] verify ClrFund contract by address --- .../tasks/helpers/ConstructorArguments.ts | 339 ++++++++++++++++ contracts/tasks/helpers/ContractStorage.ts | 20 + contracts/tasks/helpers/ContractVerifier.ts | 6 +- contracts/tasks/index.ts | 1 + contracts/tasks/runners/newClrFund.ts | 12 +- contracts/tasks/runners/newDeployer.ts | 11 +- contracts/tasks/runners/setToken.ts | 8 +- contracts/tasks/runners/verifyAll.ts | 368 ++++++++++++++---- contracts/tasks/runners/verifyDeployer.ts | 34 ++ contracts/tests/maciFactory.ts | 2 +- contracts/utils/testutils.ts | 2 +- contracts/utils/types.ts | 2 + 12 files changed, 715 insertions(+), 90 deletions(-) create mode 100644 contracts/tasks/helpers/ConstructorArguments.ts create mode 100644 contracts/tasks/runners/verifyDeployer.ts diff --git a/contracts/tasks/helpers/ConstructorArguments.ts b/contracts/tasks/helpers/ConstructorArguments.ts new file mode 100644 index 000000000..6f9f3d5b4 --- /dev/null +++ b/contracts/tasks/helpers/ConstructorArguments.ts @@ -0,0 +1,339 @@ +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' + +/** 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.subsidyFactory(), + 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 ethers.getContractAt( + EContracts.Poll, + address + )) as BaseContract as Poll + + 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(), + ]) + + 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(), + ]) + + 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 contractArtifact = this.hre.artifacts.readArtifactSync(name) + 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/index.ts b/contracts/tasks/index.ts index 5bcc7e4fc..297320679 100644 --- a/contracts/tasks/index.ts +++ b/contracts/tasks/index.ts @@ -23,3 +23,4 @@ import './runners/addRecipients' import './runners/findStorageSlot' import './runners/verifyTallyFile' import './runners/verifyAll' +import './runners/verifyDeployer' 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/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/verifyAll.ts b/contracts/tasks/runners/verifyAll.ts index ab4647563..6425bf5eb 100644 --- a/contracts/tasks/runners/verifyAll.ts +++ b/contracts/tasks/runners/verifyAll.ts @@ -1,108 +1,334 @@ /* 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' + +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 + } +} + +/** + * 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 + } - const instances = storage.getInstances(hre.network.name) + // 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 + } - instances.forEach(([key, entry]) => { - if (entry.id.includes('Poseidon')) { - return - } + // 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 + } - addEntry(key, entry) + return EContracts.SimpleUserRegistry +} + +/** + * Get the list of contracts to verify + * @param clrfund The ClrFund contract address + * @param ethers The Hardhat Ethers helper + * @param etherscanProvider The Etherscan provider + * @returns The list of contracts to verify + */ +async function getContractList( + clrfund: string, + ethers: HardhatEthersHelpers +): Promise { + const contractList: ContractInfo[] = [ + { + name: EContracts.ClrFund, + address: clrfund, + }, + ] + + const clrfundContract = (await ethers.getContractAt( + EContracts.ClrFund, + clrfund + )) as BaseContract as ClrFund + + 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 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======================================================================' + // 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( - `[${i}/${addressList.length}] Verify contract: ${entry.id} ${address}` + 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) { + const name = await getUserRegistryName(userRegistryAddress, ethers) + contractList.push({ + name, + address: userRegistryAddress, + }) + } + + // Recipient Registry + const recipientRegistryAddress = await fundingRound.recipientRegistry() + if (recipientRegistryAddress !== ZERO_ADDRESS) { + const name = await getRecipientRegistryName( + recipientRegistryAddress, + ethers ) - console.log('\tArgs:', params?.args) + contractList.push({ + name, + address: recipientRegistryAddress, + }) + } + } - 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, config, 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..a2fad0cf6 --- /dev/null +++ b/contracts/tasks/runners/verifyDeployer.ts @@ -0,0 +1,34 @@ +import { task } from 'hardhat/config' +import { EContracts } from '../../utils/types' +import { EtherscanProvider } from '../../utils/providers/EtherscanProvider' +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/tests/maciFactory.ts b/contracts/tests/maciFactory.ts index 44296bbf9..3f23d58ad 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' diff --git a/contracts/utils/testutils.ts b/contracts/utils/testutils.ts index db63401ec..e5ace7da7 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' 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', From e7ded06adb82128bf59f694d6f76442baf20c324 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Tue, 16 Apr 2024 17:07:27 -0400 Subject: [PATCH 22/86] refactor etherscan provider to extract API key from custom config --- contracts/tasks/runners/exportRound.ts | 35 ++++-------- contracts/tasks/runners/verifyAll.ts | 1 - contracts/tasks/runners/verifyDeployer.ts | 1 - .../utils/RecipientRegistryLogProcessor.ts | 7 ++- contracts/utils/abi.ts | 11 ++++ .../utils/providers/EtherscanProvider.ts | 57 +++++++++++++++---- contracts/utils/providers/ProviderFactory.ts | 10 ++-- 7 files changed, 78 insertions(+), 44 deletions(-) diff --git a/contracts/tasks/runners/exportRound.ts b/contracts/tasks/runners/exportRound.ts index 4eadf9818..fa3e332b1 100644 --- a/contracts/tasks/runners/exportRound.ts +++ b/contracts/tasks/runners/exportRound.ts @@ -16,7 +16,7 @@ import { Contract, formatUnits, getNumber } from 'ethers' import { Ipfs } from '../../utils/ipfs' import { 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' @@ -41,19 +41,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 +63,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 +127,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 @@ -237,7 +231,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 +346,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 +372,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/verifyAll.ts b/contracts/tasks/runners/verifyAll.ts index 6425bf5eb..c010df8ff 100644 --- a/contracts/tasks/runners/verifyAll.ts +++ b/contracts/tasks/runners/verifyAll.ts @@ -132,7 +132,6 @@ async function getUserRegistryName( * Get the list of contracts to verify * @param clrfund The ClrFund contract address * @param ethers The Hardhat Ethers helper - * @param etherscanProvider The Etherscan provider * @returns The list of contracts to verify */ async function getContractList( diff --git a/contracts/tasks/runners/verifyDeployer.ts b/contracts/tasks/runners/verifyDeployer.ts index a2fad0cf6..284689063 100644 --- a/contracts/tasks/runners/verifyDeployer.ts +++ b/contracts/tasks/runners/verifyDeployer.ts @@ -1,6 +1,5 @@ import { task } from 'hardhat/config' import { EContracts } from '../../utils/types' -import { EtherscanProvider } from '../../utils/providers/EtherscanProvider' import { ContractVerifier } from '../helpers/ContractVerifier' import { ConstructorArguments } from '../helpers/ConstructorArguments' 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/providers/EtherscanProvider.ts b/contracts/utils/providers/EtherscanProvider.ts index 5a35ac557..8534156ae 100644 --- a/contracts/utils/providers/EtherscanProvider.ts +++ b/contracts/utils/providers/EtherscanProvider.ts @@ -1,5 +1,6 @@ import { BaseProvider, FetchLogArgs, Log } from './BaseProvider' import { FetchRequest } from 'ethers' +import { HardhatConfig } from 'hardhat/types' const EtherscanApiUrl: Record = { xdai: 'https://api.gnosisscan.io', @@ -10,14 +11,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 +69,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) } } From 6dfaeb476b51cca488f42945a86be0b4f0b2aa13 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 17 Apr 2024 11:55:00 -0400 Subject: [PATCH 23/86] Refactor modal and not allow close on click or esc. --- vue-app/src/App.vue | 1 + vue-app/src/components.d.ts | 1 + vue-app/src/components/BaseModal.vue | 9 +++++++++ vue-app/src/components/Cart.vue | 2 +- vue-app/src/components/ClaimModal.vue | 6 ++---- vue-app/src/components/ContributionModal.vue | 6 ++---- vue-app/src/components/ErrorModal.vue | 6 ++---- vue-app/src/components/MatchingFundsModal.vue | 5 ++--- vue-app/src/components/ReallocationModal.vue | 6 ++---- vue-app/src/components/SignatureModal.vue | 6 ++---- vue-app/src/components/TransactionModal.vue | 6 ++---- vue-app/src/components/WalletModal.vue | 5 ++--- vue-app/src/components/WithdrawalModal.vue | 6 ++---- 13 files changed, 30 insertions(+), 35 deletions(-) create mode 100644 vue-app/src/components/BaseModal.vue diff --git a/vue-app/src/App.vue b/vue-app/src/App.vue index 019d15523..923ff52d0 100644 --- a/vue-app/src/App.vue +++ b/vue-app/src/App.vue @@ -486,6 +486,7 @@ summary:focus { padding: $modal-space; text-align: center; box-shadow: var(--box-shadow); + border: 2px solid rgba(115, 117, 166, 0.3); width: 400px; .loader { margin: $modal-space auto; diff --git a/vue-app/src/components.d.ts b/vue-app/src/components.d.ts index 1cef45f0e..d4d8a573b 100644 --- a/vue-app/src/components.d.ts +++ b/vue-app/src/components.d.ts @@ -11,6 +11,7 @@ declare module '@vue/runtime-core' { AddToCartButton: typeof import('./components/AddToCartButton.vue')['default'] BackLink: typeof import('./components/BackLink.vue')['default'] BalanceItem: typeof import('./components/BalanceItem.vue')['default'] + BaseModal: typeof import('./components/BaseModal.vue')['default'] Breadcrumbs: typeof import('./components/Breadcrumbs.vue')['default'] BrightIdWidget: typeof import('./components/BrightIdWidget.vue')['default'] CallToActionCard: typeof import('./components/CallToActionCard.vue')['default'] diff --git a/vue-app/src/components/BaseModal.vue b/vue-app/src/components/BaseModal.vue new file mode 100644 index 000000000..fef021f8b --- /dev/null +++ b/vue-app/src/components/BaseModal.vue @@ -0,0 +1,9 @@ + + + diff --git a/vue-app/src/components/Cart.vue b/vue-app/src/components/Cart.vue index 0169f6fc3..cb10c454a 100644 --- a/vue-app/src/components/Cart.vue +++ b/vue-app/src/components/Cart.vue @@ -605,7 +605,7 @@ function submitCart(event: any) { } const canWithdrawContribution = computed( - () => currentRound.value?.status === RoundStatus.Cancelled && !contribution.value, + () => currentRound.value?.status === RoundStatus.Cancelled && contribution.value > 0n, ) const showCollapseCart = computed(() => route.name !== 'cart') diff --git a/vue-app/src/components/ClaimModal.vue b/vue-app/src/components/ClaimModal.vue index d6c2cd29c..9f0b3f2e3 100644 --- a/vue-app/src/components/ClaimModal.vue +++ b/vue-app/src/components/ClaimModal.vue @@ -1,5 +1,5 @@ diff --git a/vue-app/src/locales/cn.json b/vue-app/src/locales/cn.json index dbc945f34..2a15e8262 100644 --- a/vue-app/src/locales/cn.json +++ b/vue-app/src/locales/cn.json @@ -719,6 +719,7 @@ "tooltip2": "{chain} 链上钱包余额", "h2_3": "项目", "div1": "正在审核", + "withdraw_button": "取回 {contribution} {tokenSymbol}", "btn2_1": "预览", "btn2_2": "查看", "div2": "您尚未提交任何项目" @@ -891,7 +892,6 @@ "div8": "匹配池", "div9": "剩余的将会加入匹配池", "div10": "平均分配 {contribution} {tokenSymbol}", - "button1": "取回 {contribution} {tokenSymbol}", "div11": "不可以", "div11_if2": "重新分配", "div11_if3": "捐赠", diff --git a/vue-app/src/locales/en.json b/vue-app/src/locales/en.json index 3811acfbc..891ec0dd0 100644 --- a/vue-app/src/locales/en.json +++ b/vue-app/src/locales/en.json @@ -719,6 +719,7 @@ "tooltip2": "Balance of wallet on {chain} chain", "h2_3": "Projects", "div1": "Under review", + "withdraw_button": "Withdraw {contribution} {tokenSymbol}", "btn2_1": "Preview", "btn2_2": "View", "div2": "You haven't submitted any projects" @@ -891,7 +892,6 @@ "div8": "Matching pool", "div9": "Remaining funds go to matching pool", "div10": "Split {contribution} {tokenSymbol} evenly", - "button1": "Withdraw {contribution} {tokenSymbol}", "div11": "Can't", "div11_if2": "reallocate", "div11_if3": "contribute", diff --git a/vue-app/src/locales/es.json b/vue-app/src/locales/es.json index ae103f13e..c0226917f 100644 --- a/vue-app/src/locales/es.json +++ b/vue-app/src/locales/es.json @@ -719,6 +719,7 @@ "tooltip2": "Saldo de la billetera en la cadena {chain}", "h2_3": "Proyectos", "div1": "En revisión", + "withdraw_button": "Retirar {contribution} {tokenSymbol}", "btn2_1": "Vista previa", "btn2_2": "Ver", "div2": "No has enviado ningún proyecto" @@ -891,7 +892,6 @@ "div8": "Matching pool", "div9": "Los fondos restantes se destinarán al matching pool", "div10": "Distribuir {contribution} {tokenSymbol} de manera uniforme", - "button1": "Retirar {contribution} {tokenSymbol}", "div11": "No puedes", "div11_if2": "reasignar", "div11_if3": "contribuir", diff --git a/vue-app/src/router/index.ts b/vue-app/src/router/index.ts index e6e415a07..86a75d5b9 100644 --- a/vue-app/src/router/index.ts +++ b/vue-app/src/router/index.ts @@ -1,6 +1,6 @@ import { createRouter, createWebHashHistory } from 'vue-router' import type { RouteRecordRaw } from 'vue-router' -import { isUserRegistrationRequired, isOptimisticRecipientRegistry } from '@/api/core' +import { isUserRegistrationRequired, isOptimisticRecipientRegistry, isActiveApp } from '@/api/core' const Landing = () => import('@/views/Landing.vue') const JoinLanding = () => import('@/views/JoinLanding.vue') @@ -262,7 +262,7 @@ if (isUserRegistrationRequired) { ) } -if (isOptimisticRecipientRegistry) { +if (isOptimisticRecipientRegistry && isActiveApp) { routes.push({ path: '/recipients', name: 'recipients', diff --git a/vue-app/src/stores/app.ts b/vue-app/src/stores/app.ts index 39e39948c..d977e04b7 100644 --- a/vue-app/src/stores/app.ts +++ b/vue-app/src/stores/app.ts @@ -497,6 +497,9 @@ export const useAppStore = defineStore('app', { maxRecipients = currentRoundInfo.maxRecipients } } + if (!this.clrFund) { + this.clrFund = await getClrFundInfo() + } await this.loadMACIFactoryInfo(maxRecipients) }, async loadClrFundInfo() { diff --git a/vue-app/src/views/Profile.vue b/vue-app/src/views/Profile.vue index 768352a67..6dd20f285 100644 --- a/vue-app/src/views/Profile.vue +++ b/vue-app/src/views/Profile.vue @@ -56,6 +56,16 @@
+
+ +

{{ $t('profile.h2_3') }}

@@ -93,13 +103,19 @@ import CopyButton from '@/components/CopyButton.vue' import Loader from '@/components/Loader.vue' import FundsNeededWarning from '@/components/FundsNeededWarning.vue' -import { userRegistryType, UserRegistryType, chain } from '@/api/core' -import { type Project, getProjects } from '@/api/projects' +import { userRegistryType, UserRegistryType, chain, isActiveApp } from '@/api/core' +import { type Project, getProjects, staticDataToProjectInterface } from '@/api/projects' import { isSameAddress } from '@/utils/accounts' import { getTokenLogo } from '@/utils/tokens' import { useAppStore, useUserStore, useRecipientStore, useWalletStore } from '@/stores' import { storeToRefs } from 'pinia' import { useRouter } from 'vue-router' +import { getLeaderboardData } from '@/api/leaderboard' +import { formatAmount } from '@/utils/amounts' + +import WithdrawalModal from '@/components/WithdrawalModal.vue' +import { useModal } from 'vue-final-modal' +import { RoundStatus } from '@/api/round' interface Props { balance: string @@ -111,7 +127,14 @@ const emit = defineEmits(['close']) const router = useRouter() const appStore = useAppStore() -const { hasContributionPhaseEnded, nativeTokenSymbol, currentRound } = storeToRefs(appStore) +const { + hasContributionPhaseEnded, + nativeTokenSymbol, + nativeTokenDecimals, + currentRound, + hasUserContributed, + contribution, +} = storeToRefs(appStore) const userStore = useUserStore() const { currentUser } = storeToRefs(userStore) const recipientStore = useRecipientStore() @@ -139,17 +162,41 @@ const displayAddress = computed(() => { return currentUser.value.ensName ?? currentUser.value.walletAddress }) +const canWithdrawContribution = computed( + () => currentRound.value?.status === RoundStatus.Cancelled && hasUserContributed, +) + +const { open: openWithdrawalModal, close: closeWithdrawalModal } = useModal({ + component: WithdrawalModal, + attrs: { + onClose() { + closeWithdrawalModal() + }, + }, +}) + watch(recipientRegistryAddress, () => loadProjects()) async function loadProjects(): Promise { - if (!recipientRegistryAddress.value) return - isLoading.value = true - const _projects: Project[] = await getProjects( - recipientRegistryAddress.value, - currentRound.value?.startTime.toSeconds(), - currentRound.value?.votingDeadline.toSeconds(), - ) + let _projects: Project[] = [] + + if (isActiveApp) { + if (!recipientRegistryAddress.value) return + _projects = await getProjects( + recipientRegistryAddress.value, + currentRound.value?.startTime.toSeconds(), + currentRound.value?.votingDeadline.toSeconds(), + ) + } else { + const currentRoundAddress = currentRound.value?.fundingRoundAddress || '' + const network = currentRound.value?.network || '' + const data = await getLeaderboardData(currentRoundAddress, network) + if (data) { + _projects = data.projects.map(p => staticDataToProjectInterface(p)) + } + } + const userProjects: Project[] = _projects.filter( ({ address, requester }) => isSameAddress(address, currentUser.value?.walletAddress as string) || From 65629e1f3651b5a4e508c487e8083938be01e068 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Mon, 22 Apr 2024 16:39:14 -0400 Subject: [PATCH 29/86] fix MACI references --- vue-app/src/views/AboutMaci.vue | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/vue-app/src/views/AboutMaci.vue b/vue-app/src/views/AboutMaci.vue index af12e822b..6e4b4b773 100644 --- a/vue-app/src/views/AboutMaci.vue +++ b/vue-app/src/views/AboutMaci.vue @@ -82,7 +82,7 @@

{{ $t('maci.helps.how.p3_t1') }} - {{ + {{ $t('maci.helps.how.p3_link') }}

@@ -108,7 +108,7 @@

- {{ $t('maci.helps.how.link') }} + {{ $t('maci.helps.how.link') }}

{{ $t('maci.constraints.h3') }}

@@ -127,15 +127,13 @@

{{ $t('maci.more.h3_1') }}

  • - {{ $t('maci.more.l1') }} + {{ $t('maci.more.l1') }}
  • - {{ $t('maci.more.l2') }} + {{ $t('maci.more.l2') }}
  • - {{ - $t('maci.more.l3') - }} + {{ $t('maci.more.l3') }}

{{ $t('maci.more.h3_2') }}

From 5f6e2a5ec6b618a1e13fba0e4f7de0742fb7b82f Mon Sep 17 00:00:00 2001 From: yuetloo Date: Mon, 22 Apr 2024 19:28:11 -0400 Subject: [PATCH 30/86] catch error querying round contributors information --- vue-app/src/api/user.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/vue-app/src/api/user.ts b/vue-app/src/api/user.ts index f65069a26..f2ed80189 100644 --- a/vue-app/src/api/user.ts +++ b/vue-app/src/api/user.ts @@ -54,8 +54,12 @@ export async function isVerifiedUser(userRegistryAddress: string, walletAddress: export async function isRegisteredUser(fundingRoundAddress: string, walletAddress: string): Promise { const round = new Contract(fundingRoundAddress, FundingRound, provider) - const contributor = await round.contributors(walletAddress) - return contributor.isRegistered + try { + const contributor = await round.contributors(walletAddress) + return contributor.isRegistered + } catch { + return false + } } export async function getTokenBalance(tokenAddress: string, walletAddress: string): Promise { From 51ddc9971e3df4107ab33d8a96b95c5a45feca8b Mon Sep 17 00:00:00 2001 From: yuetloo Date: Mon, 22 Apr 2024 20:23:12 -0400 Subject: [PATCH 31/86] remove console log --- vue-app/src/components/ClaimButton.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/vue-app/src/components/ClaimButton.vue b/vue-app/src/components/ClaimButton.vue index bdff5ae11..5db5eba51 100644 --- a/vue-app/src/components/ClaimButton.vue +++ b/vue-app/src/components/ClaimButton.vue @@ -81,7 +81,6 @@ async function checkAllocation() { } if (tally.value) { - console.log('tally.value', tally.value) allocatedAmount.value = await getAllocatedAmount( currentRound.value.fundingRoundAddress, currentRound.value.nativeTokenDecimals, From 2454097009aff2062f544536db2e378ba5b85abc Mon Sep 17 00:00:00 2001 From: yuetloo Date: Mon, 22 Apr 2024 20:25:49 -0400 Subject: [PATCH 32/86] fix error displaying project profile page --- vue-app/src/api/projects.ts | 16 +++++++++++++++ vue-app/src/api/rounds.ts | 3 ++- vue-app/src/components/ProjectListItem.vue | 24 +++++++++++++++------- vue-app/src/views/Profile.vue | 7 ++----- vue-app/src/views/ProjectList.vue | 15 +++++++++++--- vue-app/src/views/RoundList.vue | 3 +-- 6 files changed, 50 insertions(+), 18 deletions(-) diff --git a/vue-app/src/api/projects.ts b/vue-app/src/api/projects.ts index edc75abf4..2795ad82e 100644 --- a/vue-app/src/api/projects.ts +++ b/vue-app/src/api/projects.ts @@ -291,3 +291,19 @@ export function staticDataToProjectInterface(project: any): Project { isLocked: false, } } + +/** + * Get the list of projects for a static round + * @param roundAddress The funding round contract address + * @param network The network + * @returns Array of projects + */ +export async function getProjectsForStaticRound(roundAddress: string, network: string): Promise { + const data = await getLeaderboardData(roundAddress, network) + if (!data) { + return [] + } + + const projects = data.projects.map(staticDataToProjectInterface) + return projects +} diff --git a/vue-app/src/api/rounds.ts b/vue-app/src/api/rounds.ts index e83661d47..952523d0c 100644 --- a/vue-app/src/api/rounds.ts +++ b/vue-app/src/api/rounds.ts @@ -1,5 +1,6 @@ import sdk from '@/graphql/sdk' import extraRounds from '@/rounds/rounds.json' +import { getNumber } from 'ethers' import { chain, voidedRounds, isActiveApp, clrfundContractAddress } from './core' export interface Round { @@ -36,7 +37,7 @@ export async function getRounds(): Promise { } const rounds: Round[] = extraRounds.map(({ address, network, startTime, votingDeadline }, index): Round => { - return { index, address, network, hasLeaderboard: true, startTime, votingDeadline } + return { index, address, network, hasLeaderboard: true, startTime: getNumber(startTime), votingDeadline } }) const leaderboardRounds = new Set(rounds.map(r => toRoundId({ network: r.network || '', address: r.address }))) diff --git a/vue-app/src/components/ProjectListItem.vue b/vue-app/src/components/ProjectListItem.vue index 6b7435811..009502493 100644 --- a/vue-app/src/components/ProjectListItem.vue +++ b/vue-app/src/components/ProjectListItem.vue @@ -36,10 +36,12 @@ import { markdown } from '@/utils/markdown' import { useRoute, type RouteLocationRaw } from 'vue-router' import { useAppStore } from '@/stores' import { storeToRefs } from 'pinia' +import { isActiveApp } from '@/api/core' const route = useRoute() const appStore = useAppStore() -const { isRoundContributionPhase, canUserReallocate, currentRoundAddress, categoryLocaleKey } = storeToRefs(appStore) +const { isRoundContributionPhase, canUserReallocate, currentRoundAddress, categoryLocaleKey, currentRound } = + storeToRefs(appStore) interface Props { project: Project roundAddress: string @@ -81,12 +83,20 @@ const shouldShowCartInput = computed(() => { }) const projectRoute = computed(() => { - return route.name === 'round' - ? { - name: 'round-project', - params: { address: props.roundAddress, id: props.project.id }, - } - : { name: 'project', params: { id: props.project.id } } + if (isActiveApp) { + return route.name === 'round' + ? { + name: 'round-project', + params: { address: props.roundAddress, id: props.project.id }, + } + : { name: 'project', params: { id: props.project.id } } + } else { + const network = currentRound.value?.network || '' + return { + name: 'leaderboard-project', + params: { address: props.roundAddress, network, id: props.project.id }, + } + } }) diff --git a/vue-app/src/views/Profile.vue b/vue-app/src/views/Profile.vue index 6dd20f285..b4c6612e9 100644 --- a/vue-app/src/views/Profile.vue +++ b/vue-app/src/views/Profile.vue @@ -104,7 +104,7 @@ import Loader from '@/components/Loader.vue' import FundsNeededWarning from '@/components/FundsNeededWarning.vue' import { userRegistryType, UserRegistryType, chain, isActiveApp } from '@/api/core' -import { type Project, getProjects, staticDataToProjectInterface } from '@/api/projects' +import { type Project, getProjects, getProjectsForStaticRound } from '@/api/projects' import { isSameAddress } from '@/utils/accounts' import { getTokenLogo } from '@/utils/tokens' import { useAppStore, useUserStore, useRecipientStore, useWalletStore } from '@/stores' @@ -191,10 +191,7 @@ async function loadProjects(): Promise { } else { const currentRoundAddress = currentRound.value?.fundingRoundAddress || '' const network = currentRound.value?.network || '' - const data = await getLeaderboardData(currentRoundAddress, network) - if (data) { - _projects = data.projects.map(p => staticDataToProjectInterface(p)) - } + _projects = await getProjectsForStaticRound(currentRoundAddress, network) } const userProjects: Project[] = _projects.filter( diff --git a/vue-app/src/views/ProjectList.vue b/vue-app/src/views/ProjectList.vue index d6345fb3b..2bf0fc69f 100644 --- a/vue-app/src/views/ProjectList.vue +++ b/vue-app/src/views/ProjectList.vue @@ -60,7 +60,7 @@ import { ref, computed, onMounted } from 'vue' import { getCurrentRound, getRoundInfo } from '@/api/round' -import { type Project, getProjects, getRecipientRegistryAddress } from '@/api/projects' +import { type Project, getProjects, getRecipientRegistryAddress, getProjectsForStaticRound } from '@/api/projects' import CallToActionCard from '@/components/CallToActionCard.vue' import ProjectListItem from '@/components/ProjectListItem.vue' @@ -70,6 +70,7 @@ import { useRoute } from 'vue-router' import { useAppStore, useUserStore } from '@/stores' import { storeToRefs } from 'pinia' import { DateTime } from 'luxon' +import { isActiveApp } from '@/api/core' type ProjectRoundInfo = { recipientRegistryAddress: string @@ -119,8 +120,16 @@ onMounted(async () => { try { roundAddress.value = (route.params.address as string) || currentRoundAddress.value || (await getCurrentRound()) || '' - const round = await loadProjectRoundInfo(roundAddress.value) - await loadProjects(round) + if (isActiveApp) { + const round = await loadProjectRoundInfo(roundAddress.value) + await loadProjects(round) + } else { + await appStore.loadStaticClrFundInfo() + const network = currentRound.value?.network || '' + const visibleProjects = await getProjectsForStaticRound(roundAddress.value, network) + shuffleArray(visibleProjects) + projects.value = visibleProjects + } } catch (err) { /* eslint-disable-next-line no-console */ console.error('Error loading projects', err) diff --git a/vue-app/src/views/RoundList.vue b/vue-app/src/views/RoundList.vue index 774fb753a..eb1ac6273 100644 --- a/vue-app/src/views/RoundList.vue +++ b/vue-app/src/views/RoundList.vue @@ -41,12 +41,11 @@ import { onMounted, ref } from 'vue' import { type Round, getRounds } from '@/api/rounds' import Links from '@/components/Links.vue' import { DateTime } from 'luxon' -import { clrfundContractAddress } from '@/api/core' const rounds = ref([]) onMounted(async () => { - rounds.value = await getRounds(clrfundContractAddress) + rounds.value = await getRounds() }) From 55c95bced1caf072f4ceae1d6e99ad796a76f557 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Mon, 22 Apr 2024 21:07:03 -0400 Subject: [PATCH 33/86] code refactoring --- vue-app/src/views/ProjectList.vue | 38 +++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/vue-app/src/views/ProjectList.vue b/vue-app/src/views/ProjectList.vue index 2bf0fc69f..8bc21b7c5 100644 --- a/vue-app/src/views/ProjectList.vue +++ b/vue-app/src/views/ProjectList.vue @@ -71,11 +71,14 @@ import { useAppStore, useUserStore } from '@/stores' import { storeToRefs } from 'pinia' import { DateTime } from 'luxon' import { isActiveApp } from '@/api/core' +import { getSecondsFromNow } from '@/utils/dates' type ProjectRoundInfo = { + fundingRoundAddress: string recipientRegistryAddress: string startTime: number votingDeadline: number + network: string } const SHUFFLE_RANDOM_SEED = Math.random() @@ -120,16 +123,11 @@ onMounted(async () => { try { roundAddress.value = (route.params.address as string) || currentRoundAddress.value || (await getCurrentRound()) || '' - if (isActiveApp) { - const round = await loadProjectRoundInfo(roundAddress.value) - await loadProjects(round) - } else { - await appStore.loadStaticClrFundInfo() - const network = currentRound.value?.network || '' - const visibleProjects = await getProjectsForStaticRound(roundAddress.value, network) - shuffleArray(visibleProjects) - projects.value = visibleProjects - } + + const round = isActiveApp + ? await loadProjectRoundInfo(roundAddress.value) + : await loadStaticRoundInfo(roundAddress.value) + await loadProjects(round) } catch (err) { /* eslint-disable-next-line no-console */ console.error('Error loading projects', err) @@ -157,11 +155,27 @@ async function loadProjectRoundInfo(roundAddress: string): Promise { + await appStore.loadClrFundInfo() + const network = currentRound.value?.network || '' + const recipientRegistryAddress = currentRound.value?.recipientRegistryAddress || '' + const startTime = getSecondsFromNow(currentRound.value?.startTime || DateTime.now()) + const votingDeadline = getSecondsFromNow(currentRound.value?.votingDeadline || DateTime.now()) + return { recipientRegistryAddress, startTime, votingDeadline, fundingRoundAddress: roundAddress, network } } async function loadProjects(round: ProjectRoundInfo) { - const _projects = await getProjects(round.recipientRegistryAddress, round.startTime, round.votingDeadline) + const _projects = isActiveApp + ? await getProjects(round.recipientRegistryAddress, round.startTime, round.votingDeadline) + : await getProjectsForStaticRound(roundAddress.value, round.network) const visibleProjects = _projects.filter(project => { return !project.isHidden && !project.isLocked }) From 8489b006c08cad675e7b128ff2a1db26dc392a38 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Mon, 22 Apr 2024 23:14:20 -0400 Subject: [PATCH 34/86] fix filename case issue --- vue-app/src/api/leaderboard.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vue-app/src/api/leaderboard.ts b/vue-app/src/api/leaderboard.ts index cc10e5615..a09b0d0d6 100644 --- a/vue-app/src/api/leaderboard.ts +++ b/vue-app/src/api/leaderboard.ts @@ -14,5 +14,5 @@ export async function getLeaderboardData(roundAddress: string, network: string) return r.address.toLowerCase() === lowercaseRoundAddress && r.network.toLowerCase() === lowercaseNetwork }) - return found ? import(`../rounds/${lowercaseNetwork}/${lowercaseRoundAddress}.json`) : null + return found ? import(`../rounds/${found.network}/${found.address}.json`) : null } From ec6f0d6e2e275ec52ce050e35b47f12eb7428248 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Mon, 22 Apr 2024 23:41:20 -0400 Subject: [PATCH 35/86] fix incorrect round index --- vue-app/src/api/rounds.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vue-app/src/api/rounds.ts b/vue-app/src/api/rounds.ts index 952523d0c..a4e7d9ecd 100644 --- a/vue-app/src/api/rounds.ts +++ b/vue-app/src/api/rounds.ts @@ -62,11 +62,12 @@ export async function getRounds(): Promise { } } + const lastIndex = rounds.length - 1 return rounds .sort((a, b) => b.startTime - a.startTime) .map((r, index) => { return { - index, + index: lastIndex - index, address: r.address, hasLeaderboard: r.hasLeaderboard, startTime: r.startTime, From 716ccd305eb8e0df709a166605955743c380368d Mon Sep 17 00:00:00 2001 From: yuetloo Date: Tue, 23 Apr 2024 15:08:25 -0400 Subject: [PATCH 36/86] remove redirect to leaderboard page --- vue-app/src/components/StaticApp.vue | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/vue-app/src/components/StaticApp.vue b/vue-app/src/components/StaticApp.vue index 9567e0cce..68accedfb 100644 --- a/vue-app/src/components/StaticApp.vue +++ b/vue-app/src/components/StaticApp.vue @@ -28,16 +28,6 @@ const { user: walletUser } = storeToRefs(wallet) onMounted(async () => { await appStore.loadStaticClrFundInfo() appStore.isAppReady = true - - if (currentRound.value) { - router.push({ - name: 'leaderboard', - params: { - network: currentRound.value.network, - address: currentRound.value.fundingRoundAddress, - }, - }) - } }) watch(walletUser, async () => { From 7d31cd8bc6d6bd20ab1b8237fd236cc48235c439 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 24 Apr 2024 13:38:35 -0400 Subject: [PATCH 37/86] remove brightid sponsorship as sponsorship is done in the BrightID app now --- vue-app/src/locales/cn.json | 7 +-- vue-app/src/locales/en.json | 7 +-- vue-app/src/locales/es.json | 7 +-- vue-app/src/views/Verify.vue | 104 +---------------------------------- 4 files changed, 5 insertions(+), 120 deletions(-) diff --git a/vue-app/src/locales/cn.json b/vue-app/src/locales/cn.json index dbc945f34..63d63539e 100644 --- a/vue-app/src/locales/cn.json +++ b/vue-app/src/locales/cn.json @@ -803,15 +803,10 @@ "p7": "为了防止受贿和欺诈,您需要将您的钱包地址添加到智能合约注册表中。完成后,您就可以参加筹款活动了!", "btn": " 成为捐赠者", "next": "下一步", - "previous": "前一步", "copy_link": "复制", "verification_status": "您的钱包地址没有连接到 BrightID 的户口。 这可能需要几分钟的时间,稍等候后点击按钮再试。", "getting_proof": "正在获取验证证明...", - "not_authorized": "您没有权限注册", - "skip_sponsorship": "跳过", - "get_sponsored_header": "赞助", - "get_sponsored_text": "您需要一个赞助令牌才能为 BrightID 认证。这有助于支持 BrightID 作为去中心化平台。您只需这样做一次, 就可以应用任何 BrightID APPS。检查 BrightID 移动应用程序,看看您是否受到赞助。如果没有,请点击按钮提交赞助请求。如果您已受到赞助,您可跳过这一步。", - "get_sponsored_cta": "赞助" + "not_authorized": "您没有权限注册" }, "verifyLanding": { "h1": "证明您只使用一个帐户", diff --git a/vue-app/src/locales/en.json b/vue-app/src/locales/en.json index 3811acfbc..8462655d5 100644 --- a/vue-app/src/locales/en.json +++ b/vue-app/src/locales/en.json @@ -803,15 +803,10 @@ "p7": "To protect the round from bribery and fraud, you need to add your wallet address to a smart contract registry. Once you’re done, you can join the funding round!", "btn": " Become a contributor", "next": "Next", - "previous": "Previous", "copy_link": "Copy Link", "verification_status": "Your wallet address is not linked with BrightID. It may take a few minutes to verify the connection, please wait and click the button later to check the status.", "getting_proof": "Retrieving the verification proof...", - "not_authorized": "You are not authorized to register", - "skip_sponsorship": "Skip", - "get_sponsored_header": "Get sponsored", - "get_sponsored_text": "You need a sponsorship token to connect your wallet address with BrightID. This helps support BrightID as a decentralized platform. You’ll only ever need to do this once and it covers you for any other app that works with BrightID. Check the BrightID mobile app to see if you're sponsored. Get sponsored by submitting a sponsorship transaction or skip to the next step.", - "get_sponsored_cta": "Get Sponsored" + "not_authorized": "You are not authorized to register" }, "verifyLanding": { "h1": "Prove you’re only using one account", diff --git a/vue-app/src/locales/es.json b/vue-app/src/locales/es.json index ae103f13e..d76cba03a 100644 --- a/vue-app/src/locales/es.json +++ b/vue-app/src/locales/es.json @@ -803,15 +803,10 @@ "p7": "Para proteger la ronda de sobornos y fraudes, debes agregar la dirección de tu billetera a un registro de contrato inteligente. ¡Una vez que hayas terminado, puedes unirte a la ronda de financiamiento!", "btn": "Conviértete en colaborador", "next": "Siguiente", - "previous": "Anterior", "copy_link": "Copiar Enlace", "verification_status": "Tu dirección de billetera no está vinculada con BrightID. Puede tomar unos minutos verificar la conexión, por favor espera y haz clic en el botón más tarde para verificar el estado.", "getting_proof": "Recuperando la prueba de verificación...", - "not_authorized": "No está autorizado/a para registrarse", - "skip_sponsorship": "Saltar", - "get_sponsored_header": "Obtén un patrocinio", - "get_sponsored_text": "Necesitas un token de patrocinio para conectar tu dirección de billetera con BrightID. Esto ayuda a apoyar a BrightID como una plataforma descentralizada. Solo necesitarás hacer esto una vez y te cubrirá para cualquier otra aplicación que funcione con BrightID. Verifica en la aplicación móvil de BrightID si estás patrocinado. Obtén patrocinio al enviar una transacción de patrocinio o salta al siguiente paso.", - "get_sponsored_cta": "Obtener Patrocinio" + "not_authorized": "No está autorizado/a para registrarse" }, "verifyLanding": { "h1": "Demuestra que solo usas una cuenta", diff --git a/vue-app/src/views/Verify.vue b/vue-app/src/views/Verify.vue index c3ea80179..de2c99b65 100644 --- a/vue-app/src/views/Verify.vue +++ b/vue-app/src/views/Verify.vue @@ -56,30 +56,6 @@
-
-

{{ $t('verify.get_sponsored_header') }}

-

- {{ $t('verify.get_sponsored_text') }} -

-
-
-
- - -
-
{{ sponsorTxError }}
-
-
-

{{ $t('verify.h2_1') }}

@@ -88,16 +64,8 @@

{{ $t('verify.click_next') }}

- -
- +

{{ $t('verify.p4') }} @@ -124,14 +92,6 @@

- @@ -195,9 +155,7 @@ interface VerificationStep { function getVerificationSteps(): Array { switch (userRegistryType) { case UserRegistryType.BRIGHT_ID: - return brightIdSponsorUrl - ? [{ page: 'connect' }, { page: 'registration' }] - : [{ page: 'sponsorship' }, { page: 'connect' }, { page: 'registration' }] + return [{ page: 'connect' }, { page: 'registration' }] default: return [{ page: 'registration' }] } @@ -224,11 +182,7 @@ const registrationTxError = ref('') const notAuthorized = ref(false) const loadingTx = ref(false) const gettingProof = ref(false) -const isSponsoring = ref(!brightIdSponsorUrl) const showVerificationStatus = ref(false) -const autoSponsorError = ref('') -const sponsorTxError = ref('') -const selfSponsorTxHash = ref('') const brightId = computed(() => currentUser.value?.brightId) @@ -237,9 +191,6 @@ const currentStep = computed(() => { if (!brightId.value) { return 0 } - if (isSponsoring.value) { - return stepNumbers['sponsorship'] - } if (!brightId.value.isVerified) { return stepNumbers['connect'] } @@ -255,19 +206,6 @@ const currentPage = computed(() => { return steps[currentStep.value].page }) -// if the sponsor url is not defined, we are doing self sponsorship, show the button -// to allow users to go back to that page -const showBackToSponsorshipButton = !brightIdSponsorUrl - -function backToSponsorship() { - isSponsoring.value = true - showVerificationStatus.value = false -} - -function skipSponsorship() { - isSponsoring.value = false -} - async function checkVerificationStatus() { showVerificationStatus.value = false await userStore.loadBrightID() @@ -295,24 +233,8 @@ onMounted(async () => { // mounted if (isBrightIdRequired && currentUser.value && !brightId.value?.isVerified) { const walletAddress = currentUser.value.walletAddress - // send sponsorship request if automatic sponsoring is enabled - if (brightIdSponsorUrl) { - try { - const res = await sponsorUser(walletAddress) - if (!res.hash) { - autoSponsorError.value = res.error ? res.error : JSON.stringify(res) - return - } - } catch (err) { - const errorMessage = (err as Error).message - autoSponsorError.value = - 'Unable to sponsor user. Make sure the brightId node is setup correctly.' + errorMessage - return - } - } // Present app link and QR code - appLink.value = getBrightIdUniversalLink(walletAddress) const qrcodeLink = getBrightIdLink(walletAddress) QRCode.toDataURL(qrcodeLink, (error, url: string) => { @@ -329,26 +251,6 @@ watch(currentUser, () => { } }) -async function selfSponsorAndWait() { - if (!userRegistryAddress.value) { - sponsorTxError.value = 'Missing the user registry address' - return - } - - const signer = await userStore.getSigner() - loadingTx.value = true - sponsorTxError.value = '' - - try { - await waitForTransaction(selfSponsor(userRegistryAddress.value, signer), hash => (selfSponsorTxHash.value = hash)) - isSponsoring.value = false - } catch (error) { - sponsorTxError.value = (error as Error).message - } finally { - loadingTx.value = false - } -} - async function register() { const signer = await userStore.getSigner() @@ -418,8 +320,6 @@ function isStepUnlocked(step: number): boolean { const stepName = steps[step].page switch (stepName) { - case 'sponsorship': - return !isSponsoring.value case 'connect': return !!currentUser.value?.brightId?.isVerified case 'registration': From 45fe06d61d63bdbaa66d81e3e940bf102192957d Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 24 Apr 2024 15:07:59 -0400 Subject: [PATCH 38/86] remove brightid sponsorship logic --- contracts/deploy-config-example.json | 8 +- .../tasks/subtasks/user/03-brightidSponsor.ts | 62 ------ .../subtasks/user/04-brightidUserRegistry.ts | 14 +- vue-app/.env.example | 9 - vue-app/src/api/bright-id.ts | 177 +----------------- vue-app/src/api/core.ts | 4 +- vue-app/src/lambda/sponsor.mts | 137 -------------- vue-app/src/views/Verify.vue | 6 +- 8 files changed, 11 insertions(+), 406 deletions(-) delete mode 100644 contracts/tasks/subtasks/user/03-brightidSponsor.ts delete mode 100644 vue-app/src/lambda/sponsor.mts 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/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/vue-app/.env.example b/vue-app/.env.example index b7a9357e4..d0a44456f 100644 --- a/vue-app/.env.example +++ b/vue-app/.env.example @@ -28,20 +28,11 @@ VITE_USER_REGISTRY_TYPE=simple 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 diff --git a/vue-app/src/api/bright-id.ts b/vue-app/src/api/bright-id.ts index 0aba9a8ad..10330c6fe 100644 --- a/vue-app/src/api/bright-id.ts +++ b/vue-app/src/api/bright-id.ts @@ -2,7 +2,7 @@ import { Contract, encodeBytes32String, toUtf8Bytes, decodeBase64, encodeBase64 import type { TransactionResponse, Signer } from 'ethers' import { BrightIdUserRegistry } from './abi' -import { brightIdSponsorKey, brightIdNodeUrl } from './core' +import { brightIdNodeUrl } from './core' import nacl from 'tweetnacl' const BRIGHTID_APP_URL = 'https://app.brightid.org' @@ -44,55 +44,6 @@ export interface Verification { app: string } -export interface Sponsorship { - timestamp: number - app: string - appHasAuthorized: boolean - spendRequested: boolean -} - -type AppData = { - id: string - name: string - context?: string - verification: string - verifications?: string[] - verificationsUrl: string - logo?: string - url?: string - assignedSponsorships?: number - unusedSponsorships?: number - testing?: boolean - idAsHex?: boolean - usingBlindSig?: boolean - verificationExpirationLength?: number - sponsorPublicKey?: string - nodeUrl?: string - soulbound: boolean - callbackUrl?: string -} - -type SponsorOperation = { - name: string - app: string - appUserId: string - timestamp: number - v: number - sig?: string -} - -type SponsorData = { - hash?: string - error?: string -} - -export async function selfSponsor(registryAddress: string, signer: Signer): Promise { - const registry = new Contract(registryAddress, BrightIdUserRegistry, signer) - const userAddress = await signer.getAddress() - const transaction = await registry.sponsor(userAddress) - return transaction -} - // This link is for generating QR code export function getBrightIdLink(userAddress: string): string { const deepLink = `brightid://link-verification/${CONTEXT}/${userAddress}` @@ -166,129 +117,3 @@ export async function getBrightId(contextId: string): Promise { } return brightId } - -/** - * Get the unused sponsorship amount - * @param context - the context to retrieve unused sponsorships for - * - * @returns Returns the number of sponsorships available to the specified `context` - */ -async function unusedSponsorships(context: string): Promise { - const endpoint = `${NODE_URL}/apps/${context}` - const response = await fetch(endpoint) - const json = await response.json() - - if (json['errorMessage']) { - throw new Error(JSON.stringify(json)) - } - - const data = json['data'] as AppData - return data.unusedSponsorships || 0 -} - -/** - * Call the BrightID sponsor operation endpoint to put a sponsorship request for the user - * @param userAddress user wallet address - * @returns sponsporship result or error - */ -export async function brightIdSponsor(userAddress: string): Promise { - const endpoint = `${NODE_URL}/operations` - - if (!brightIdSponsorKey) { - return { error: 'BrightId sponsor key not set' } - } - - const sponsorships = await unusedSponsorships(CONTEXT) - if (typeof sponsorships === 'number' && sponsorships < 1) { - return { error: 'BrightID sponsorships not available' } - } - - if (typeof sponsorships !== 'number') { - return { error: 'Invalid BrightID sponsorship' } - } - - const timestamp = Date.now() - - // these fields must be in alphabetical because - // BrightID nodes use 'fast-json-stable-stringify' that sorts fields - const op: SponsorOperation = { - app: CONTEXT, - appUserId: userAddress, - name: 'Sponsor', - timestamp, - v: 6, - } - - const message = JSON.stringify(op) - const arrayedMessage = toUtf8Bytes(message) - const arrayedKey = decodeBase64(brightIdSponsorKey) - const signature = nacl.sign.detached(arrayedMessage, arrayedKey) - op.sig = encodeBase64(signature) - - const res = await fetch(endpoint, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(op), - }) - const json = await res.json() - - if (json['error']) { - if (canIgnoreError(json.errorNum)) { - // sponsorship already sent recently, ignore this error - return { hash: '0x0' } - } - return { error: json['errorMessage'] } - } else { - return json['data'] - } -} - -/** - * Call the netlify function to invoke the BrightId sponsor api - * @param userAddress user wallet address - * @returns sponsorship data or error - */ -async function netlifySponsor(userAddress: string): Promise { - const res = await fetch('/.netlify/functions/sponsor', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ userAddress }), - }) - - const json = await res.json() - if (res.status === 200) { - return json - } - - if (res.status === 400 && canIgnoreError(json.errorNum)) { - return { hash: '0x0' } - } - - // return the error - return json -} - -/** - * Sponsor a BrightID user using the sponsorship api - * @param userAddress user wallet address - * @returns sponsporship result or error - */ -export async function sponsorUser(userAddress: string): Promise { - if (brightIdSponsorKey) { - return brightIdSponsor(userAddress) - } - - try { - return await netlifySponsor(userAddress) - } catch (err) { - if (err instanceof Error) { - return { error: (err as Error).message } - } else { - return { error: 'Unknown sponsorhip error' } - } - } -} diff --git a/vue-app/src/api/core.ts b/vue-app/src/api/core.ts index 5caa704c6..f120af12f 100644 --- a/vue-app/src/api/core.ts +++ b/vue-app/src/api/core.ts @@ -72,10 +72,8 @@ export const maxDecimals = Number(import.meta.env.VUE_APP_MAX_DECIMAL || 1) // the number of records per batch in the `pending submissions` export file export const exportBatchSize = Number(import.meta.env.VITE_EXPORT_BATCH_SIZE) || 60 -// BrightId sponsorhip stuff, set these parameters to automatically sponsor user using the brightId URL -export const brightIdSponsorKey = import.meta.env.VITE_BRIGHTID_SPONSOR_KEY +// BrightId url for querying user verification export const brightIdNodeUrl = import.meta.env.VITE_BRIGHTID_NODE_URL || 'https://brightid.clr.fund/brightid/v6' -export const brightIdSponsorUrl = import.meta.env.VITE_BRIGHTID_SPONSOR_API_URL // wait for data to sync with the subgraph export const MAX_WAIT_DEPTH = Number(import.meta.env.VITE_MAX_WAIT_DEPTH) || 15 diff --git a/vue-app/src/lambda/sponsor.mts b/vue-app/src/lambda/sponsor.mts deleted file mode 100644 index 5d460e17a..000000000 --- a/vue-app/src/lambda/sponsor.mts +++ /dev/null @@ -1,137 +0,0 @@ -import { decodeBase64, encodeBase64, toUtf8Bytes } from 'ethers' -import nacl from 'tweetnacl' -import type { Handler } from '@netlify/functions' - -const NODE_URL = process.env.VITE_BRIGHTID_NODE_URL || 'https://app.brightid.org/node/v6' - -// these fields must be in alphabetical because -// BrightID nodes use 'fast-json-stable-stringify' that sorts fields -type BrightIDMessage = { - app: string - appUserId: string - name: string - sig?: string - timestamp: number - v: number -} - -/** - * Returns an error object - * @param errorMessage error message - * @returns error object - */ -function makeError(errorMessage: string, errorNum: number) { - const body = JSON.stringify({ error: errorMessage, errorNum }) - return { statusCode: 400, body } -} - -/** - * Returns the result with statusCode and body - * @param result the result - * @returns result object - */ -function makeResult(result: any) { - const body = JSON.stringify(result) - return { statusCode: 200, body } -} - -/** - * Get the unused sponsorship amount - * @param context - the context to retrieve unused sponsorships for - * - * @returns the number of sponsorships available to the specified `context` - */ -async function unusedSponsorships(context: string) { - const endpoint = `${NODE_URL}/apps/${context}` - const response = await fetch(endpoint) - const json = await response.json() - - if (json['errorMessage']) { - throw new Error(JSON.stringify(json)) - } - - const data = json['data'] - return data.unusedSponsorships || 0 -} - -async function handleSponsorRequest(userAddress: string) { - const endpoint = process.env.VITE_BRIGHTID_SPONSOR_API_URL - if (!endpoint) { - throw new Error('Environment variable VITE_BRIGHTID_SPONSOR_API_URL not set') - } - - const brightIdSponsorKey = process.env.VITE_BRIGHTID_SPONSOR_KEY_FOR_NETLIFY - if (!brightIdSponsorKey) { - throw new Error('Environment variable VITE_BRIGHTID_SPONSOR_KEY_FOR_NETLIFY not set') - } - - const CONTEXT = process.env.VITE_BRIGHTID_CONTEXT - if (!CONTEXT) { - throw new Error('Environment variable VITE_BRIGHTID_CONTEXT not set') - } - - const sponsorships = await unusedSponsorships(CONTEXT) - if (typeof sponsorships === 'number' && sponsorships < 1) { - throw new Error('BrightID sponsorships not available') - } - if (typeof sponsorships !== 'number') { - throw new Error('Invalid BrightID sponsorship') - } - - const timestamp = Date.now() - - const op: BrightIDMessage = { - app: CONTEXT, - appUserId: userAddress, - name: 'Sponsor', - timestamp, - v: 6, - } - - const message = JSON.stringify(op) - const arrayedMessage = toUtf8Bytes(message) - const arrayedKey = decodeBase64(brightIdSponsorKey) - const signature = nacl.sign.detached(arrayedMessage, arrayedKey) - op.sig = encodeBase64(signature) - - const res = await fetch(endpoint, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(op), - }) - const json = await res.json() - - if (json.error) { - return makeError(json.errorMessage, json.errorNum) - } - - if (json.data) { - return makeResult({ hash: json.data.hash }) - } - - return makeError('Unexpected result from the BrightID sponsorship API.', 500) -} - -/** - * Submit a sponsorship request using the BrightID api - * @param event contains user address to sponsor - * @returns sponsor data or error - */ -export const handler: Handler = async event => { - if (!event.body) { - return makeError('Missing request body', 400) - } - - try { - const jsonBody = JSON.parse(event.body) - if (!jsonBody.userAddress) { - return makeError('Missing userAddress in request body: ' + event.body, 400) - } - - return await handleSponsorRequest(jsonBody.userAddress) - } catch (err) { - return makeError(err.message, 500) - } -} diff --git a/vue-app/src/views/Verify.vue b/vue-app/src/views/Verify.vue index de2c99b65..9fa25f2f6 100644 --- a/vue-app/src/views/Verify.vue +++ b/vue-app/src/views/Verify.vue @@ -136,7 +136,7 @@ import { ref, computed, onMounted, watch } from 'vue' import ProgressBar from '@/components/ProgressBar.vue' import QRCode from 'qrcode' -import { getBrightIdLink, getBrightIdUniversalLink, registerUser, selfSponsor, sponsorUser } from '@/api/bright-id' +import { getBrightIdLink, getBrightIdUniversalLink, registerUser } from '@/api/bright-id' import { getProofSnapshot, getProofMerkle, registerUserSnapshot, registerUserMerkle } from '@/api/user' import Transaction from '@/components/Transaction.vue' import Loader from '@/components/Loader.vue' @@ -145,11 +145,11 @@ import { waitForTransaction } from '@/utils/contracts' import { useAppStore, useUserStore } from '@/stores' import { storeToRefs } from 'pinia' import { useRouter } from 'vue-router' -import { UserRegistryType, isBrightIdRequired, brightIdSponsorUrl, userRegistryType } from '@/api/core' +import { UserRegistryType, isBrightIdRequired, userRegistryType } from '@/api/core' import { assert } from '@/utils/assert' interface VerificationStep { - page: 'connect' | 'registration' | 'sponsorship' + page: 'connect' | 'registration' } function getVerificationSteps(): Array { From c638d80e3582615829c2c2e407929f93f634a252 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 24 Apr 2024 15:09:47 -0400 Subject: [PATCH 39/86] fix missing duration error --- contracts/sh/deployLocal.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 9dafeb63d58b9541e2a6e70aff15719da299cebe Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 24 Apr 2024 19:10:37 -0400 Subject: [PATCH 40/86] remove goerli and add sepolia --- vue-app/src/utils/chains.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vue-app/src/utils/chains.ts b/vue-app/src/utils/chains.ts index b84942d8b..acab4ecfe 100644 --- a/vue-app/src/utils/chains.ts +++ b/vue-app/src/utils/chains.ts @@ -1,6 +1,6 @@ export enum ChainId { MAINNET = 1, - GOERLI = 5, + SEPOLIA = 11155111, HARDHAT = 31337, ARBITRUM_ONE = 42161, ARBITRUM_RINKEBY = 421611, @@ -36,12 +36,12 @@ export const CHAIN_INFO: ChainInfo = { explorerLogo: 'etherscan.svg', explorerLabel: 'Etherscan', }, - [ChainId.GOERLI]: { - label: 'Goerli', + [ChainId.SEPOLIA]: { + label: 'Sepolia', currency: 'ETH', logo: 'eth.svg', isLayer2: false, - explorer: 'https://goerli.etherscan.io', + explorer: 'https://sepolia.etherscan.io', explorerLogo: 'etherscan.svg', explorerLabel: 'Etherscan', }, From 7b097b04608520c91a00766c82ccb181f13ee397 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 24 Apr 2024 19:30:06 -0400 Subject: [PATCH 41/86] remove BrightId sponsorship instructions --- docs/brightid.md | 39 ++++++++++----------------------------- docs/deployment.md | 9 --------- 2 files changed, 10 insertions(+), 38 deletions(-) diff --git a/docs/brightid.md b/docs/brightid.md index efd01636d..0b03aa3e3 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,27 +54,9 @@ 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 - look for sponsorship event listening error @@ -86,7 +67,7 @@ See the [deployment guide](./deploymnet.md) for special setup to use the sponsor - 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/deployment.md b/docs/deployment.md index 4ddb0ccc1..56ffb6368 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. @@ -161,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 From f04320de3eae26345c3d38144d58de9e855d4a25 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 24 Apr 2024 19:37:47 -0400 Subject: [PATCH 42/86] update numbering --- docs/brightid.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/brightid.md b/docs/brightid.md index 0b03aa3e3..5c84d799e 100644 --- a/docs/brightid.md +++ b/docs/brightid.md @@ -58,12 +58,12 @@ By default, the clrfund app will connect to the BrightId node run by clrfund, ht ### 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 From 6a845566f060115dd949114592dc94b05fc4a711 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 24 Apr 2024 19:39:30 -0400 Subject: [PATCH 43/86] remove special netlify lambda settings --- docs/deployment.md | 4 ---- vue-app/.env.example | 3 --- 2 files changed, 7 deletions(-) diff --git a/docs/deployment.md b/docs/deployment.md index 56ffb6368..284076f84 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -168,10 +168,6 @@ VITE_GOOGLE_SPREADSHEET_ID= 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/vue-app/.env.example b/vue-app/.env.example index d0a44456f..be1b3b535 100644 --- a/vue-app/.env.example +++ b/vue-app/.env.example @@ -66,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 From d5bf85984dccbf4c7451078d85dc39b0b58ffaae Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 24 Apr 2024 22:47:34 -0400 Subject: [PATCH 44/86] do not show verify page if using semaphore user registry --- vue-app/src/api/core.ts | 7 ++++++- vue-app/src/components/CallToActionCard.vue | 4 ++-- vue-app/src/components/Cart.vue | 6 ++---- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/vue-app/src/api/core.ts b/vue-app/src/api/core.ts index 5caa704c6..6d79b2785 100644 --- a/vue-app/src/api/core.ts +++ b/vue-app/src/api/core.ts @@ -45,6 +45,7 @@ export enum UserRegistryType { SIMPLE = 'simple', SNAPSHOT = 'snapshot', MERKLE = 'merkle', + SEMAPHORE = 'semaphore', } if (!Object.values(UserRegistryType).includes(userRegistryType as UserRegistryType)) { @@ -92,7 +93,11 @@ export const showComplianceRequirement = /^yes$/i.test(import.meta.env.VITE_SHOW export const isBrightIdRequired = userRegistryType === 'brightid' export const isOptimisticRecipientRegistry = recipientRegistryType === 'optimistic' -export const isUserRegistrationRequired = userRegistryType !== UserRegistryType.SIMPLE +export const isUserRegistrationRequired = [ + UserRegistryType.BRIGHT_ID, + UserRegistryType.MERKLE, + UserRegistryType.SNAPSHOT, +].includes(userRegistryType) // Try to get the next scheduled start date const nextStartDate = import.meta.env.VITE_NEXT_ROUND_START_DATE diff --git a/vue-app/src/components/CallToActionCard.vue b/vue-app/src/components/CallToActionCard.vue index 7d094a1a6..2d29121d7 100644 --- a/vue-app/src/components/CallToActionCard.vue +++ b/vue-app/src/components/CallToActionCard.vue @@ -55,7 +55,7 @@ import { computed } from 'vue' import BrightIdWidget from '@/components/BrightIdWidget.vue' import Links from '@/components/Links.vue' -import { userRegistryType, UserRegistryType, isBrightIdRequired } from '@/api/core' +import { isUserRegistrationRequired, isBrightIdRequired } from '@/api/core' import { useAppStore, useUserStore } from '@/stores' import { storeToRefs } from 'pinia' @@ -69,7 +69,7 @@ const hasStartedVerification = computed( ) const showUserVerification = computed(() => { return ( - userRegistryType !== UserRegistryType.SIMPLE && + isUserRegistrationRequired && currentRound.value && currentUser.value?.isRegistered !== undefined && !currentUser.value.isRegistered diff --git a/vue-app/src/components/Cart.vue b/vue-app/src/components/Cart.vue index cb10c454a..605a766fc 100644 --- a/vue-app/src/components/Cart.vue +++ b/vue-app/src/components/Cart.vue @@ -237,7 +237,7 @@ import CartItems from '@/components/CartItems.vue' import Links from '@/components/Links.vue' import TimeLeft from '@/components/TimeLeft.vue' import { MAX_CONTRIBUTION_AMOUNT, MAX_CART_SIZE, type CartItem, isContributionAmountValid } from '@/api/contributions' -import { userRegistryType, UserRegistryType, operator } from '@/api/core' +import { userRegistryType, UserRegistryType, operator, isUserRegistrationRequired } from '@/api/core' import { RoundStatus } from '@/api/round' import { formatAmount as _formatAmount } from '@/utils/amounts' import FundsNeededWarning from '@/components/FundsNeededWarning.vue' @@ -477,9 +477,7 @@ const isBrightIdRequired = computed( () => userRegistryType === UserRegistryType.BRIGHT_ID && !currentUser.value?.isRegistered, ) -const isRegistrationRequired = computed( - () => userRegistryType !== UserRegistryType.SIMPLE && !currentUser.value?.isRegistered, -) +const isRegistrationRequired = computed(() => isUserRegistrationRequired && !currentUser.value?.isRegistered) const errorMessage = computed(() => { if (isMessageLimitReached.value) return t('dynamic.cart.error.reached_contribution_limit') From e4d8d20cf841d958d2b0279d02ae74c06f085326 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 24 Apr 2024 22:57:04 -0400 Subject: [PATCH 45/86] add sepolia and remove goerli --- contracts/hardhat.config.ts | 7 ++----- vue-app/src/utils/chains.ts | 8 ++++---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/contracts/hardhat.config.ts b/contracts/hardhat.config.ts index e9fcb6931..470029275 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: [ { diff --git a/vue-app/src/utils/chains.ts b/vue-app/src/utils/chains.ts index b84942d8b..acab4ecfe 100644 --- a/vue-app/src/utils/chains.ts +++ b/vue-app/src/utils/chains.ts @@ -1,6 +1,6 @@ export enum ChainId { MAINNET = 1, - GOERLI = 5, + SEPOLIA = 11155111, HARDHAT = 31337, ARBITRUM_ONE = 42161, ARBITRUM_RINKEBY = 421611, @@ -36,12 +36,12 @@ export const CHAIN_INFO: ChainInfo = { explorerLogo: 'etherscan.svg', explorerLabel: 'Etherscan', }, - [ChainId.GOERLI]: { - label: 'Goerli', + [ChainId.SEPOLIA]: { + label: 'Sepolia', currency: 'ETH', logo: 'eth.svg', isLayer2: false, - explorer: 'https://goerli.etherscan.io', + explorer: 'https://sepolia.etherscan.io', explorerLogo: 'etherscan.svg', explorerLabel: 'Etherscan', }, From 5102e77acd377c82ba7d73bbc1ae0f4f0aba21ec Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 24 Apr 2024 23:17:38 -0400 Subject: [PATCH 46/86] handle user not registered case for semaphore user registry --- vue-app/src/components/Cart.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vue-app/src/components/Cart.vue b/vue-app/src/components/Cart.vue index 605a766fc..1e0301d38 100644 --- a/vue-app/src/components/Cart.vue +++ b/vue-app/src/components/Cart.vue @@ -484,9 +484,9 @@ const errorMessage = computed(() => { if (!currentUser.value) return t('dynamic.cart.error.connect_wallet') if (isBrightIdRequired.value) return t('dynamic.cart.error.need_to_setup_brightid') if (!currentUser.value.isRegistered) { - return userRegistryType === UserRegistryType.SIMPLE - ? t('dynamic.cart.error.user_not_registered', { operator }) - : t('dynamic.cart.error.need_to_register') + return isUserRegistrationRequired + ? t('dynamic.cart.error.need_to_register') + : t('dynamic.cart.error.user_not_registered', { operator }) } if (!isFormValid()) return t('dynamic.cart.error.invalid_contribution_amount') if (cart.value.length > MAX_CART_SIZE) From 08dc551507cc95fc57f38a03433f399822794f90 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 24 Apr 2024 23:21:05 -0400 Subject: [PATCH 47/86] add semaphore user registry --- vue-app/.env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vue-app/.env.example b/vue-app/.env.example index b7a9357e4..26689edf3 100644 --- a/vue-app/.env.example +++ b/vue-app/.env.example @@ -21,7 +21,7 @@ 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 From ef12b74f3cb36a9b4da9f7fcfd0fc055232e0342 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Mon, 6 May 2024 14:25:06 -0400 Subject: [PATCH 48/86] use maci 0.0.0-ci.153326b: do not allow invalid pub key --- common/package.json | 4 +- contracts/package.json | 4 +- yarn.lock | 294 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 297 insertions(+), 5 deletions(-) diff --git a/common/package.json b/common/package.json index ee496d949..bd7caa4fb 100644 --- a/common/package.json +++ b/common/package.json @@ -23,8 +23,8 @@ "dependencies": { "@openzeppelin/merkle-tree": "^1.0.5", "ethers": "^6.11.1", - "maci-crypto": "^1.2.0", - "maci-domainobjs": "^1.2.0" + "maci-crypto": "0.0.0-ci.153326b", + "maci-domainobjs": "0.0.0-ci.153326b" }, "repository": { "type": "git", diff --git a/contracts/package.json b/contracts/package.json index 94bb91a88..4498c8aba 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -18,7 +18,7 @@ "@openzeppelin/contracts": "4.9.0", "@pinata/sdk": "^2.1.0", "dotenv": "^8.2.0", - "maci-contracts": "^1.2.0", + "maci-contracts": "0.0.0-ci.153326b", "solidity-rlp": "2.0.8" }, "devDependencies": { @@ -41,7 +41,7 @@ "ipfs-only-hash": "^2.0.1", "maci-circuits": "^1.2.0", "maci-cli": "^1.2.0", - "maci-domainobjs": "^1.2.0", + "maci-domainobjs": "0.0.0-ci.153326b", "mocha": "^10.2.0", "solidity-coverage": "^0.8.1", "ts-node": "^10.9.2", diff --git a/yarn.lock b/yarn.lock index 86e13a1f9..10adf18a4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1912,6 +1912,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,6 +2682,54 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.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.5": + 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-block@5.0.2": version "5.0.2" resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.2.tgz#13a7968f5964f1697da941281b7f7943b0465d04" @@ -2974,6 +3030,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" @@ -3282,6 +3343,11 @@ 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": + 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" resolved "https://registry.yarnpkg.com/@openzeppelin/merkle-tree/-/merkle-tree-1.0.5.tgz#4836d377777a7e39f31674f06ec3d6909def7913" @@ -4963,6 +5029,20 @@ dependencies: "@zk-kit/utils" "0.1.0" +"@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.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/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.3.0": version "0.3.0" resolved "https://registry.yarnpkg.com/@zk-kit/circuits/-/circuits-0.3.0.tgz#716d932e9b09f33c71c7ff940a507e519ce0a6f4" @@ -4970,6 +5050,22 @@ dependencies: circomlib "^2.0.5" +"@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.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.3.0" + "@zk-kit/utils" "0.8.1" + buffer "6.0.3" + "@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" @@ -4986,11 +5082,38 @@ "@zk-kit/baby-jubjub" "0.1.1" "@zk-kit/utils" "0.1.0" +"@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.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" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.2.tgz#c102371b6ec3a7cf3b847ca00c20bb0fce4c6dea" @@ -6896,7 +7019,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" @@ -7407,6 +7530,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" @@ -7431,6 +7561,16 @@ circomkit@^0.0.24: loglevel "^1.8.1" snarkjs "^0.7.0" +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" + loglevel "^1.8.1" + snarkjs "^0.7.0" + circomlib@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/circomlib/-/circomlib-2.0.5.tgz#183c703e53ed7d011811842dbeeeb9819f4cc1d6" @@ -10182,6 +10322,19 @@ ethers@^6.11.1: tslib "2.4.0" ws "8.5.0" +ethers@^6.12.0: + 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" + "@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" + ethers@^6.9.2: version "6.10.0" resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.10.0.tgz#20f3c63c60d59a993f8090ad423d8a3854b3b1cd" @@ -10708,6 +10861,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" @@ -12016,6 +12178,55 @@ hardhat@^2.20.1: uuid "^8.3.2" ws "^7.4.6" +hardhat@^2.22.3: + version "2.22.3" + resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.22.3.tgz#50605daca6b29862397e446c42ec14c89430bec3" + integrity sha512-k8JV2ECWNchD6ahkg2BR5wKVxY0OiKot7fuxiIpRK0frRqyOljcR2vKwgWSLw6YIeDcNNA4xybj7Og7NSxr2hA== + dependencies: + "@ethersproject/abi" "^5.1.2" + "@metamask/eth-sig-util" "^4.0.0" + "@nomicfoundation/edr" "^0.3.5" + "@nomicfoundation/ethereumjs-common" "4.0.4" + "@nomicfoundation/ethereumjs-tx" "5.0.4" + "@nomicfoundation/ethereumjs-util" "9.0.4" + "@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" + boxen "^5.1.2" + 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" + has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -14917,6 +15128,19 @@ 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@0.0.0-ci.153326b: + version "0.0.0-ci.153326b" + resolved "https://registry.yarnpkg.com/maci-circuits/-/maci-circuits-0.0.0-ci.153326b.tgz#9958949f675b466c8f0fd7da4d12467012ca1dbb" + integrity sha512-9WYp1465Xelujo4GLpiLqgVdsia2VAl7FEpRMZOJeEJlbl8RUYLBTFlR9X9fBL3sNjoPNFSiswrVoCgmiQEi8A== + dependencies: + "@zk-kit/circuits" "^0.4.0" + circomkit "^0.1.0" + circomlib "^2.0.5" + maci-core "0.0.0-ci.153326b" + maci-crypto "0.0.0-ci.153326b" + maci-domainobjs "0.0.0-ci.153326b" + snarkjs "^0.7.4" + maci-circuits@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/maci-circuits/-/maci-circuits-1.2.0.tgz#9b1f9c64d48e4dc3c3c7c8ffc4d0f254d60cce3e" @@ -14948,6 +15172,23 @@ maci-cli@^1.2.0: maci-domainobjs "^1.2.0" prompt "^1.3.0" +maci-contracts@0.0.0-ci.153326b: + version "0.0.0-ci.153326b" + resolved "https://registry.yarnpkg.com/maci-contracts/-/maci-contracts-0.0.0-ci.153326b.tgz#4c1d3cc1c5a89cbbe852439a1e81646e8b0dc302" + integrity sha512-DFo8xLR/Ia/CcSFXYjHfMCfaN/GnhNMxVgcRu1EQBY8DzWMs/MBHEYnH/LBpT/r5QscY0kyk45lMdKA24xHsFA== + dependencies: + "@nomicfoundation/hardhat-ethers" "^3.0.5" + "@nomicfoundation/hardhat-toolbox" "^5.0.0" + "@openzeppelin/contracts" "^5.0.2" + circomlibjs "^0.1.7" + ethers "^6.12.0" + hardhat "^2.22.3" + maci-circuits "0.0.0-ci.153326b" + maci-core "0.0.0-ci.153326b" + maci-crypto "0.0.0-ci.153326b" + maci-domainobjs "0.0.0-ci.153326b" + solidity-docgen "^0.6.0-beta.36" + maci-contracts@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/maci-contracts/-/maci-contracts-1.2.0.tgz#a724b3e757d2402442d822c34a5221660ef43b94" @@ -14965,6 +15206,14 @@ maci-contracts@^1.2.0: maci-domainobjs "^1.2.0" solidity-docgen "^0.6.0-beta.36" +maci-core@0.0.0-ci.153326b: + version "0.0.0-ci.153326b" + resolved "https://registry.yarnpkg.com/maci-core/-/maci-core-0.0.0-ci.153326b.tgz#08cb39ab66b2e528da319d64e2194c4b1c2fca01" + integrity sha512-lrkPm/gIcHbVO3+tuGnvNdc/Gy5jD0+5biG13RmdIfFiXnND0vD7aX5x45HY4mNK1TUrlS8ZMVHSjY4voeiieg== + dependencies: + maci-crypto "0.0.0-ci.153326b" + maci-domainobjs "0.0.0-ci.153326b" + maci-core@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/maci-core/-/maci-core-1.2.0.tgz#57ff4b92c457f42a3043fe5b34cfef98a9ac1cf5" @@ -14973,6 +15222,16 @@ maci-core@^1.2.0: maci-crypto "^1.2.0" maci-domainobjs "^1.2.0" +maci-crypto@0.0.0-ci.153326b: + version "0.0.0-ci.153326b" + resolved "https://registry.yarnpkg.com/maci-crypto/-/maci-crypto-0.0.0-ci.153326b.tgz#4d0d2e72dd0aa6dba30d24e2c873729a5706bb8e" + integrity sha512-80QCpFdMts3rgfUn0fSQq0BFsuALOAYRH+MLWWDVTQXu1LtXZ4ikwq4DvD0ZuUDHjf9GgAmsQGQbi/Raa6q0bQ== + dependencies: + "@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-crypto@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/maci-crypto/-/maci-crypto-1.2.0.tgz#b894810fa2ab379d93f77a2518f55abfe2f22dbe" @@ -14983,6 +15242,13 @@ maci-crypto@^1.2.0: "@zk-kit/poseidon-cipher" "^0.2.1" ethers "^6.11.1" +maci-domainobjs@0.0.0-ci.153326b: + version "0.0.0-ci.153326b" + resolved "https://registry.yarnpkg.com/maci-domainobjs/-/maci-domainobjs-0.0.0-ci.153326b.tgz#546649c1b6e29748bc79c77b46081433a8d22876" + integrity sha512-utPsFPC6a6Q8LwtBqTQvzBOsUroprvFoCHy5sTRoRvKsSGLwTibkcYMzmxF5A+tnFJ4n9CKCrr6UF/6Mzc2dlw== + dependencies: + maci-crypto "0.0.0-ci.153326b" + maci-domainobjs@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/maci-domainobjs/-/maci-domainobjs-1.2.0.tgz#27a6a9e05b3712e54c48dd080dcfc0c1d6035f93" @@ -17827,6 +18093,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" @@ -19080,6 +19356,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" From 3969baca810a1e84643a40d3a4efc4a950a2526a Mon Sep 17 00:00:00 2001 From: yuetloo Date: Thu, 9 May 2024 10:52:11 -0400 Subject: [PATCH 49/86] verify validity of public key using babyjubjub function --- common/package.json | 4 +- contracts/contracts/maci/BabyJubJub.sol | 136 ++++++++ contracts/contracts/maci/Poll.sol | 286 +++++++++++++++++ contracts/contracts/maci/PollFactory.sol | 73 +++++ contracts/e2e/index.ts | 14 +- contracts/package.json | 4 +- .../tasks/helpers/ConstructorArguments.ts | 8 +- contracts/tasks/runners/claim.ts | 9 +- contracts/tasks/runners/contribute.ts | 7 +- contracts/tasks/runners/finalize.ts | 7 +- .../tasks/runners/publishTallyResults.ts | 12 +- contracts/tests/deployer.ts | 14 +- contracts/tests/round.ts | 10 +- contracts/utils/contracts.ts | 44 ++- yarn.lock | 300 +----------------- 15 files changed, 607 insertions(+), 321 deletions(-) create mode 100644 contracts/contracts/maci/BabyJubJub.sol create mode 100644 contracts/contracts/maci/Poll.sol create mode 100644 contracts/contracts/maci/PollFactory.sol diff --git a/common/package.json b/common/package.json index bd7caa4fb..d7f3da4a5 100644 --- a/common/package.json +++ b/common/package.json @@ -23,8 +23,8 @@ "dependencies": { "@openzeppelin/merkle-tree": "^1.0.5", "ethers": "^6.11.1", - "maci-crypto": "0.0.0-ci.153326b", - "maci-domainobjs": "0.0.0-ci.153326b" + "maci-crypto": "1.2.0", + "maci-domainobjs": "1.2.0" }, "repository": { "type": "git", diff --git a/contracts/contracts/maci/BabyJubJub.sol b/contracts/contracts/maci/BabyJubJub.sol new file mode 100644 index 000000000..7d046b624 --- /dev/null +++ b/contracts/contracts/maci/BabyJubJub.sol @@ -0,0 +1,136 @@ +// @note This code was taken from +// https://github.com/privacy-scaling-explorations/maci/blob/dc18e2f046cf160f846f003c04ec4dfac502f6ae/contracts/contracts/crypto/BabyJubJub.sol +// TODO remove this and use MACI npm package when version greater than 1.2.0 is released + +// SPDX-License-Identifier: MIT +pragma solidity 0.8.10; + +library CurveBabyJubJub { + // Curve parameters + // E: 168700x^2 + y^2 = 1 + 168696x^2y^2 + // A = 168700 + uint256 public constant A = 0x292FC; + // D = 168696 + uint256 public constant D = 0x292F8; + // Prime Q = 21888242871839275222246405745257275088548364400416034343698204186575808495617 + uint256 public constant Q = 0x30644E72E131A029B85045B68181585D2833E84879B9709143E1F593F0000001; + + /** + * @dev Add 2 points on baby jubjub curve + * Formula for adding 2 points on a twisted Edwards curve: + * x3 = (x1y2 + y1x2) / (1 + dx1x2y1y2) + * y3 = (y1y2 - ax1x2) / (1 - dx1x2y1y2) + */ + function pointAdd(uint256 _x1, uint256 _y1, uint256 _x2, uint256 _y2) internal view returns (uint256 x3, uint256 y3) { + if (_x1 == 0 && _y1 == 0) { + return (_x2, _y2); + } + + if (_x2 == 0 && _y1 == 0) { + return (_x1, _y1); + } + + uint256 x1x2 = mulmod(_x1, _x2, Q); + uint256 y1y2 = mulmod(_y1, _y2, Q); + uint256 dx1x2y1y2 = mulmod(D, mulmod(x1x2, y1y2, Q), Q); + uint256 x3Num = addmod(mulmod(_x1, _y2, Q), mulmod(_y1, _x2, Q), Q); + uint256 y3Num = submod(y1y2, mulmod(A, x1x2, Q), Q); + + x3 = mulmod(x3Num, inverse(addmod(1, dx1x2y1y2, Q)), Q); + y3 = mulmod(y3Num, inverse(submod(1, dx1x2y1y2, Q)), Q); + } + + /** + * @dev Double a point on baby jubjub curve + * Doubling can be performed with the same formula as addition + */ + function pointDouble(uint256 _x1, uint256 _y1) internal view returns (uint256 x2, uint256 y2) { + return pointAdd(_x1, _y1, _x1, _y1); + } + + /** + * @dev Multiply a point on baby jubjub curve by a scalar + * Use the double and add algorithm + */ + function pointMul(uint256 _x1, uint256 _y1, uint256 _d) internal view returns (uint256 x2, uint256 y2) { + uint256 remaining = _d; + + uint256 px = _x1; + uint256 py = _y1; + uint256 ax = 0; + uint256 ay = 0; + + while (remaining != 0) { + if ((remaining & 1) != 0) { + // Binary digit is 1 so add + (ax, ay) = pointAdd(ax, ay, px, py); + } + + (px, py) = pointDouble(px, py); + + remaining = remaining / 2; + } + + x2 = ax; + y2 = ay; + } + + /** + * @dev Check if a given point is on the curve + * (168700x^2 + y^2) - (1 + 168696x^2y^2) == 0 + */ + function isOnCurve(uint256 _x, uint256 _y) internal pure returns (bool) { + uint256 xSq = mulmod(_x, _x, Q); + uint256 ySq = mulmod(_y, _y, Q); + uint256 lhs = addmod(mulmod(A, xSq, Q), ySq, Q); + uint256 rhs = addmod(1, mulmod(mulmod(D, xSq, Q), ySq, Q), Q); + return submod(lhs, rhs, Q) == 0; + } + + /** + * @dev Perform modular subtraction + */ + function submod(uint256 _a, uint256 _b, uint256 _mod) internal pure returns (uint256) { + uint256 aNN = _a; + + if (_a <= _b) { + aNN += _mod; + } + + return addmod(aNN - _b, 0, _mod); + } + + /** + * @dev Compute modular inverse of a number + */ + function inverse(uint256 _a) internal view returns (uint256) { + // We can use Euler's theorem instead of the extended Euclidean algorithm + // Since m = Q and Q is prime we have: a^-1 = a^(m - 2) (mod m) + return expmod(_a, Q - 2, Q); + } + + /** + * @dev Helper function to call the bigModExp precompile + */ + function expmod(uint256 _b, uint256 _e, uint256 _m) internal view returns (uint256 o) { + assembly { + let memPtr := mload(0x40) + mstore(memPtr, 0x20) // Length of base _b + mstore(add(memPtr, 0x20), 0x20) // Length of exponent _e + mstore(add(memPtr, 0x40), 0x20) // Length of modulus _m + mstore(add(memPtr, 0x60), _b) // Base _b + mstore(add(memPtr, 0x80), _e) // Exponent _e + mstore(add(memPtr, 0xa0), _m) // Modulus _m + + // The bigModExp precompile is at 0x05 + let success := staticcall(gas(), 0x05, memPtr, 0xc0, memPtr, 0x20) + switch success + case 0 { + revert(0x0, 0x0) + } + default { + o := mload(memPtr) + } + } + } +} diff --git a/contracts/contracts/maci/Poll.sol b/contracts/contracts/maci/Poll.sol new file mode 100644 index 000000000..1306c7698 --- /dev/null +++ b/contracts/contracts/maci/Poll.sol @@ -0,0 +1,286 @@ +// @note This code was taken from maci-contracts v1.2.0 with public key validation from +// https://github.com/privacy-scaling-explorations/maci/blob/dc18e2f046cf160f846f003c04ec4dfac502f6ae/contracts/contracts/Poll.sol +// TODO remove this and use MACI npm package when version greater than 1.2.0 is released + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +import { Params } from "maci-contracts/contracts/utilities/Params.sol"; +import { SnarkCommon } from "maci-contracts/contracts/crypto/SnarkCommon.sol"; +import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { EmptyBallotRoots } from "maci-contracts/contracts/trees/EmptyBallotRoots.sol"; +import { IPoll } from "maci-contracts/contracts/interfaces/IPoll.sol"; +import { Utilities } from "maci-contracts/contracts/utilities/Utilities.sol"; +import { CurveBabyJubJub } from "./BabyJubJub.sol"; + +/// @title Poll +/// @notice A Poll contract allows voters to submit encrypted messages +/// which can be either votes, key change messages or topup messages. +/// @dev Do not deploy this directly. Use PollFactory.deploy() which performs some +/// checks on the Poll constructor arguments. +contract Poll is Params, Utilities, SnarkCommon, Ownable, EmptyBallotRoots, IPoll { + using SafeERC20 for ERC20; + + /// @notice Whether the Poll has been initialized + bool internal isInit; + + /// @notice The coordinator's public key + PubKey public coordinatorPubKey; + + /// @notice Hash of the coordinator's public key + uint256 public immutable coordinatorPubKeyHash; + + /// @notice the state root of the state merkle tree + uint256 public mergedStateRoot; + + // The timestamp of the block at which the Poll was deployed + uint256 internal immutable deployTime; + + // The duration of the polling period, in seconds + uint256 internal immutable duration; + + /// @notice Whether the MACI contract's stateAq has been merged by this contract + bool public stateAqMerged; + + /// @notice Get the commitment to the state leaves and the ballots. This is + /// hash3(stateRoot, ballotRoot, salt). + /// Its initial value should be + /// hash(maciStateRootSnapshot, emptyBallotRoot, 0) + /// Each successful invocation of processMessages() should use a different + /// salt to update this value, so that an external observer cannot tell in + /// the case that none of the messages are valid. + uint256 public currentSbCommitment; + + /// @notice The number of messages that have been published + uint256 public numMessages; + + /// @notice The number of signups that have been processed + /// before the Poll ended (stateAq merged) + uint256 public numSignups; + + /// @notice Max values for the poll + MaxValues public maxValues; + + /// @notice Depths of the merkle trees + TreeDepths public treeDepths; + + /// @notice The contracts used by the Poll + ExtContracts public extContracts; + + error VotingPeriodOver(); + error VotingPeriodNotOver(); + error PollAlreadyInit(); + error TooManyMessages(); + error InvalidPubKey(); + error StateAqAlreadyMerged(); + error StateAqSubtreesNeedMerge(); + error InvalidBatchLength(); + + event PublishMessage(Message _message, PubKey _encPubKey); + event TopupMessage(Message _message); + event MergeMaciStateAqSubRoots(uint256 _numSrQueueOps); + event MergeMaciStateAq(uint256 _stateRoot, uint256 _numSignups); + event MergeMessageAqSubRoots(uint256 _numSrQueueOps); + event MergeMessageAq(uint256 _messageRoot); + + /// @notice Each MACI instance can have multiple Polls. + /// When a Poll is deployed, its voting period starts immediately. + /// @param _duration The duration of the voting period, in seconds + /// @param _maxValues The maximum number of messages and vote options + /// @param _treeDepths The depths of the merkle trees + /// @param _coordinatorPubKey The coordinator's public key + /// @param _extContracts The external contracts + constructor( + uint256 _duration, + MaxValues memory _maxValues, + TreeDepths memory _treeDepths, + PubKey memory _coordinatorPubKey, + ExtContracts memory _extContracts + ) payable { + // check that the coordinator public key is valid + if (!CurveBabyJubJub.isOnCurve(_coordinatorPubKey.x, _coordinatorPubKey.y)) { + revert InvalidPubKey(); + } + + // store the pub key as object then calculate the hash + coordinatorPubKey = _coordinatorPubKey; + // we hash it ourselves to ensure we store the correct value + coordinatorPubKeyHash = hashLeftRight(_coordinatorPubKey.x, _coordinatorPubKey.y); + // store the external contracts to interact with + extContracts = _extContracts; + // store duration of the poll + duration = _duration; + // store max values + maxValues = _maxValues; + // store tree depth + treeDepths = _treeDepths; + // Record the current timestamp + deployTime = block.timestamp; + } + + /// @notice A modifier that causes the function to revert if the voting period is + /// not over. + modifier isAfterVotingDeadline() { + uint256 secondsPassed = block.timestamp - deployTime; + if (secondsPassed <= duration) revert VotingPeriodNotOver(); + _; + } + + /// @notice A modifier that causes the function to revert if the voting period is + /// over + modifier isWithinVotingDeadline() { + uint256 secondsPassed = block.timestamp - deployTime; + if (secondsPassed >= duration) revert VotingPeriodOver(); + _; + } + + /// @notice The initialization function. + /// @dev Should be called immediately after Poll creation + /// and messageAq ownership transferred + function init() public { + if (isInit) revert PollAlreadyInit(); + // set to true so it cannot be called again + isInit = true; + + unchecked { + numMessages++; + } + + // init messageAq here by inserting placeholderLeaf + uint256[2] memory dat = [NOTHING_UP_MY_SLEEVE, 0]; + + (Message memory _message, PubKey memory _padKey, uint256 placeholderLeaf) = padAndHashMessage(dat, 1); + extContracts.messageAq.enqueue(placeholderLeaf); + + emit PublishMessage(_message, _padKey); + } + + /// @inheritdoc IPoll + function topup(uint256 stateIndex, uint256 amount) public virtual isWithinVotingDeadline { + // we check that we do not exceed the max number of messages + if (numMessages >= maxValues.maxMessages) revert TooManyMessages(); + + // cannot realistically overflow + unchecked { + numMessages++; + } + + /// @notice topupCredit is a trusted token contract which reverts if the transfer fails + extContracts.topupCredit.transferFrom(msg.sender, address(this), amount); + + uint256[2] memory dat = [stateIndex, amount]; + (Message memory _message, , uint256 messageLeaf) = padAndHashMessage(dat, 2); + + extContracts.messageAq.enqueue(messageLeaf); + + emit TopupMessage(_message); + } + + /// @inheritdoc IPoll + function publishMessage(Message memory _message, PubKey calldata _encPubKey) public virtual isWithinVotingDeadline { + // we check that we do not exceed the max number of messages + if (numMessages >= maxValues.maxMessages) revert TooManyMessages(); + + // validate that the public key is valid + if (!CurveBabyJubJub.isOnCurve(_encPubKey.x, _encPubKey.y)) { + revert InvalidPubKey(); + } + + // cannot realistically overflow + unchecked { + numMessages++; + } + + // we enforce that msgType here is 1 so we don't need checks + // at the circuit level + _message.msgType = 1; + + uint256 messageLeaf = hashMessageAndEncPubKey(_message, _encPubKey); + extContracts.messageAq.enqueue(messageLeaf); + + emit PublishMessage(_message, _encPubKey); + } + + /// @notice submit a message batch + /// @dev Can only be submitted before the voting deadline + /// @param _messages the messages + /// @param _encPubKeys the encrypted public keys + function publishMessageBatch(Message[] calldata _messages, PubKey[] calldata _encPubKeys) external { + if (_messages.length != _encPubKeys.length) { + revert InvalidBatchLength(); + } + + uint256 len = _messages.length; + for (uint256 i = 0; i < len; ) { + // an event will be published by this function already + publishMessage(_messages[i], _encPubKeys[i]); + + unchecked { + i++; + } + } + } + + /// @inheritdoc IPoll + function mergeMaciStateAqSubRoots(uint256 _numSrQueueOps, uint256 _pollId) public onlyOwner isAfterVotingDeadline { + // This function cannot be called after the stateAq was merged + if (stateAqMerged) revert StateAqAlreadyMerged(); + + // merge subroots + extContracts.maci.mergeStateAqSubRoots(_numSrQueueOps, _pollId); + + emit MergeMaciStateAqSubRoots(_numSrQueueOps); + } + + /// @inheritdoc IPoll + function mergeMaciStateAq(uint256 _pollId) public onlyOwner isAfterVotingDeadline { + // This function can only be called once per Poll after the voting + // deadline + if (stateAqMerged) revert StateAqAlreadyMerged(); + + // set merged to true so it cannot be called again + stateAqMerged = true; + + // the subtrees must have been merged first + if (!extContracts.maci.stateAq().subTreesMerged()) revert StateAqSubtreesNeedMerge(); + + mergedStateRoot = extContracts.maci.mergeStateAq(_pollId); + + // Set currentSbCommitment + uint256[3] memory sb; + sb[0] = mergedStateRoot; + sb[1] = emptyBallotRoots[treeDepths.voteOptionTreeDepth - 1]; + sb[2] = uint256(0); + + currentSbCommitment = hash3(sb); + + numSignups = extContracts.maci.numSignUps(); + emit MergeMaciStateAq(mergedStateRoot, numSignups); + } + + /// @inheritdoc IPoll + function mergeMessageAqSubRoots(uint256 _numSrQueueOps) public onlyOwner isAfterVotingDeadline { + extContracts.messageAq.mergeSubRoots(_numSrQueueOps); + emit MergeMessageAqSubRoots(_numSrQueueOps); + } + + /// @inheritdoc IPoll + function mergeMessageAq() public onlyOwner isAfterVotingDeadline { + uint256 root = extContracts.messageAq.merge(treeDepths.messageTreeDepth); + emit MergeMessageAq(root); + } + + /// @inheritdoc IPoll + function getDeployTimeAndDuration() public view returns (uint256 pollDeployTime, uint256 pollDuration) { + pollDeployTime = deployTime; + pollDuration = duration; + } + + /// @inheritdoc IPoll + function numSignUpsAndMessages() public view returns (uint256 numSUps, uint256 numMsgs) { + numSUps = numSignups; + numMsgs = numMessages; + } +} diff --git a/contracts/contracts/maci/PollFactory.sol b/contracts/contracts/maci/PollFactory.sol new file mode 100644 index 000000000..ad91b4305 --- /dev/null +++ b/contracts/contracts/maci/PollFactory.sol @@ -0,0 +1,73 @@ +// @note This code was taken from https://github.com/privacy-scaling-explorations/maci/blob/dc18e2f046cf160f846f003c04ec4dfac502f6ae/contracts/contracts/PollFactory.sol +// TODO remove this and use MACI npm package when version greater than 1.2.0 is released + +// SPDX-License-Identifier: MIT +pragma solidity 0.8.10; + + +import { IMACI } from "maci-contracts/contracts/interfaces/IMACI.sol"; +import { AccQueue } from "maci-contracts/contracts/trees/AccQueue.sol"; +import { AccQueueQuinaryMaci } from "maci-contracts/contracts/trees/AccQueueQuinaryMaci.sol"; +import { TopupCredit } from "maci-contracts/contracts/TopupCredit.sol"; +import { Params } from "maci-contracts/contracts/utilities/Params.sol"; +import { DomainObjs } from "maci-contracts/contracts/utilities/DomainObjs.sol"; +import { Poll } from "./Poll.sol"; +import { IPollFactory } from "maci-contracts/contracts/interfaces/IPollFactory.sol"; + +/// @title PollFactory +/// @notice A factory contract which deploys Poll contracts. It allows the MACI contract +/// size to stay within the limit set by EIP-170. +contract PollFactory is Params, DomainObjs, IPollFactory { + // The number of children each node in the message tree has + uint256 internal constant TREE_ARITY = 5; + + // custom error + error InvalidMaxValues(); + + /// @notice The PollFactory constructor + // solhint-disable-next-line no-empty-blocks + constructor() payable {} + + /// @inheritdoc IPollFactory + function deploy( + uint256 _duration, + MaxValues calldata _maxValues, + TreeDepths calldata _treeDepths, + PubKey calldata _coordinatorPubKey, + address _maci, + TopupCredit _topupCredit, + address _pollOwner + ) public virtual returns (address pollAddr) { + /// @notice Validate _maxValues + /// maxVoteOptions must be less than 2 ** 50 due to circuit limitations; + /// it will be packed as a 50-bit value along with other values as one + /// of the inputs (aka packedVal) + if (_maxValues.maxVoteOptions >= (2 ** 50)) { + revert InvalidMaxValues(); + } + + /// @notice deploy a new AccQueue contract to store messages + AccQueue messageAq = new AccQueueQuinaryMaci(_treeDepths.messageTreeSubDepth); + + /// @notice the smart contracts that a Poll would interact with + ExtContracts memory extContracts = ExtContracts({ + maci: IMACI(_maci), + messageAq: messageAq, + topupCredit: _topupCredit + }); + + // deploy the poll + Poll poll = new Poll(_duration, _maxValues, _treeDepths, _coordinatorPubKey, extContracts); + + // Make the Poll contract own the messageAq contract, so only it can + // run enqueue/merge + messageAq.transferOwnership(address(poll)); + + // init Poll + poll.init(); + + poll.transferOwnership(_pollOwner); + + pollAddr = address(poll); + } +} diff --git a/contracts/e2e/index.ts b/contracts/e2e/index.ts index 76e21525c..f3ad49b7c 100644 --- a/contracts/e2e/index.ts +++ b/contracts/e2e/index.ts @@ -16,7 +16,11 @@ import { DEFAULT_GET_LOG_BATCH_SIZE, DEFAULT_SR_QUEUE_OPS, } from '../utils/constants' -import { getEventArg } from '../utils/contracts' +import { + getContractAt, + getEventArg, + getQualifiedContractName, +} from '../utils/contracts' import { deployPoseidonLibraries, deployMaciFactory } from '../utils/testutils' import { getIpfsHash } from '../utils/ipfs' import { @@ -33,7 +37,7 @@ import { DEFAULT_CIRCUIT } from '../utils/circuits' import { MaciParameters } from '../utils/maciParameters' import { existsSync, mkdirSync } from 'fs' import path from 'path' -import { FundingRound } from '../typechain-types' +import { FundingRound, Poll } from '../typechain-types' import { JSONFile } from '../utils/JSONFile' import { EContracts } from '../utils/types' import { getTalyFilePath } from '../utils/misc' @@ -270,7 +274,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() }) diff --git a/contracts/package.json b/contracts/package.json index 4498c8aba..9a3941562 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -18,7 +18,7 @@ "@openzeppelin/contracts": "4.9.0", "@pinata/sdk": "^2.1.0", "dotenv": "^8.2.0", - "maci-contracts": "0.0.0-ci.153326b", + "maci-contracts": "1.2.0", "solidity-rlp": "2.0.8" }, "devDependencies": { @@ -41,7 +41,7 @@ "ipfs-only-hash": "^2.0.1", "maci-circuits": "^1.2.0", "maci-cli": "^1.2.0", - "maci-domainobjs": "0.0.0-ci.153326b", + "maci-domainobjs": "1.2.0", "mocha": "^10.2.0", "solidity-coverage": "^0.8.1", "ts-node": "^10.9.2", diff --git a/contracts/tasks/helpers/ConstructorArguments.ts b/contracts/tasks/helpers/ConstructorArguments.ts index 6f9f3d5b4..1db4beb22 100644 --- a/contracts/tasks/helpers/ConstructorArguments.ts +++ b/contracts/tasks/helpers/ConstructorArguments.ts @@ -12,6 +12,7 @@ import { Poll, Tally, } from '../../typechain-types' +import { getContractAt } from '../../utils/contracts' /** A list of functions to get contract constructor arguments from the contract */ const ConstructorArgumentsGetters: Record< @@ -89,10 +90,11 @@ async function getPollConstructorArguments( address: string, ethers: HardhatEthersHelpers ): Promise> { - const pollContract = (await ethers.getContractAt( + const pollContract = await getContractAt( EContracts.Poll, - address - )) as BaseContract as Poll + address, + ethers + ) const [, duration] = await pollContract.getDeployTimeAndDuration() const [maxValues, treeDepths, coordinatorPubKey, extContracts] = diff --git a/contracts/tasks/runners/claim.ts b/contracts/tasks/runners/claim.ts index e5135aa24..0f27a2e95 100644 --- a/contracts/tasks/runners/claim.ts +++ b/contracts/tasks/runners/claim.ts @@ -5,7 +5,7 @@ * 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 { @@ -17,6 +17,7 @@ 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') @@ -64,7 +65,11 @@ task('claim', 'Claim funnds for test recipients') const pollAddress = await fundingRoundContract.poll() console.log('pollAddress', pollAddress) - const poll = await ethers.getContractAt(EContracts.Poll, pollAddress) + const poll = await getContractAt( + EContracts.Poll, + pollAddress, + ethers + ) const treeDepths = await poll.treeDepths() const recipientTreeDepth = getNumber(treeDepths.voteOptionTreeDepth) 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/finalize.ts b/contracts/tasks/runners/finalize.ts index e48a6c2b6..74afe85e1 100644 --- a/contracts/tasks/runners/finalize.ts +++ b/contracts/tasks/runners/finalize.ts @@ -17,6 +17,8 @@ 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') @@ -47,9 +49,10 @@ 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) diff --git a/contracts/tasks/runners/publishTallyResults.ts b/contracts/tasks/runners/publishTallyResults.ts index 5651ac353..b9db3404f 100644 --- a/contracts/tasks/runners/publishTallyResults.ts +++ b/contracts/tasks/runners/publishTallyResults.ts @@ -24,10 +24,12 @@ import { FundingRound, Poll } 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 { + getContractAt, + getCurrentFundingRoundContract, +} from '../../utils/contracts' import { getTalyFilePath } from '../../utils/misc' import { ContractStorage } from '../helpers/ContractStorage' -import { PINATA_PINNING_URL } from '../../utils/constants' /** * Publish the tally IPFS hash on chain if it's not already published @@ -92,7 +94,11 @@ async function getRecipientTreeDepth( ethers: HardhatEthersHelpers ): Promise { const pollAddress = await fundingRoundContract.poll() - const pollContract = await ethers.getContractAt(EContracts.Poll, pollAddress) + const pollContract = await getContractAt( + EContracts.Poll, + pollAddress, + ethers + ) const treeDepths = await (pollContract as BaseContract as Poll).treeDepths() const voteOptionTreeDepth = treeDepths.voteOptionTreeDepth return getNumber(voteOptionTreeDepth) diff --git a/contracts/tests/deployer.ts b/contracts/tests/deployer.ts index f21353557..bbe8c027a 100644 --- a/contracts/tests/deployer.ts +++ b/contracts/tests/deployer.ts @@ -6,7 +6,12 @@ import { genRandomSalt } from 'maci-crypto' import { Keypair } from '@clrfund/common' import { TREE_ARITY, ZERO_ADDRESS, UNIT } from '../utils/constants' -import { getGasUsage, getEventArg, deployContract } from '../utils/contracts' +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' @@ -15,6 +20,7 @@ import { ClrFundDeployer, FundingRoundFactory, MACIFactory, + Poll, } from '../typechain-types' import { EContracts } from '../utils/types' @@ -318,7 +324,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) diff --git a/contracts/tests/round.ts b/contracts/tests/round.ts index c0fa4f813..4e480ff34 100644 --- a/contracts/tests/round.ts +++ b/contracts/tests/round.ts @@ -21,7 +21,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, @@ -34,6 +34,7 @@ import { deployTestFundingRound } from '../utils/testutils' // ethStaker test vectors for Quadratic Funding with alpha import smallTallyTestData from './data/testTallySmall.json' import { FundingRound } from '../typechain-types' +import { EContracts } from '../utils/types' const newResultCommitment = hexlify(randomBytes(32)) const perVOSpentVoiceCreditsHash = hexlify(randomBytes(32)) @@ -136,7 +137,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() diff --git a/contracts/utils/contracts.ts b/contracts/utils/contracts.ts index 45250e3fb..c72aac709 100644 --- a/contracts/utils/contracts.ts +++ b/contracts/utils/contracts.ts @@ -27,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() @@ -116,4 +116,46 @@ export async function getCurrentFundingRoundContract( 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 { + let contractName = String(name) + if (contractName.includes('Poseidon')) { + contractName = `:${name}` + } + if (name === EContracts.PollFactory) { + contractName = 'contracts/maci/PollFactory.sol:PollFactory' + } + if (name === EContracts.Poll) { + contractName = 'contracts/maci/Poll.sol:Poll' + } + 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/yarn.lock b/yarn.lock index 10adf18a4..970c4343b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1912,14 +1912,6 @@ 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" @@ -2682,54 +2674,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.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.5": - 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-block@5.0.2": version "5.0.2" resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.2.tgz#13a7968f5964f1697da941281b7f7943b0465d04" @@ -3030,11 +2974,6 @@ 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" @@ -3343,11 +3282,6 @@ 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": - 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" resolved "https://registry.yarnpkg.com/@openzeppelin/merkle-tree/-/merkle-tree-1.0.5.tgz#4836d377777a7e39f31674f06ec3d6909def7913" @@ -5029,20 +4963,6 @@ dependencies: "@zk-kit/utils" "0.1.0" -"@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.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/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.3.0": version "0.3.0" resolved "https://registry.yarnpkg.com/@zk-kit/circuits/-/circuits-0.3.0.tgz#716d932e9b09f33c71c7ff940a507e519ce0a6f4" @@ -5050,22 +4970,6 @@ dependencies: circomlib "^2.0.5" -"@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.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.3.0" - "@zk-kit/utils" "0.8.1" - buffer "6.0.3" - "@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" @@ -5082,38 +4986,11 @@ "@zk-kit/baby-jubjub" "0.1.1" "@zk-kit/utils" "0.1.0" -"@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.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" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.2.tgz#c102371b6ec3a7cf3b847ca00c20bb0fce4c6dea" @@ -7019,7 +6896,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.3, buffer@^6.0.1, buffer@^6.0.3: +"buffer-polyfill@npm: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" @@ -7530,13 +7407,6 @@ 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" @@ -7561,16 +7431,6 @@ circomkit@^0.0.24: loglevel "^1.8.1" snarkjs "^0.7.0" -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" - loglevel "^1.8.1" - snarkjs "^0.7.0" - circomlib@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/circomlib/-/circomlib-2.0.5.tgz#183c703e53ed7d011811842dbeeeb9819f4cc1d6" @@ -10322,19 +10182,6 @@ ethers@^6.11.1: tslib "2.4.0" ws "8.5.0" -ethers@^6.12.0: - 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" - "@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" - ethers@^6.9.2: version "6.10.0" resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.10.0.tgz#20f3c63c60d59a993f8090ad423d8a3854b3b1cd" @@ -10861,15 +10708,6 @@ 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" @@ -12178,55 +12016,6 @@ hardhat@^2.20.1: uuid "^8.3.2" ws "^7.4.6" -hardhat@^2.22.3: - version "2.22.3" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.22.3.tgz#50605daca6b29862397e446c42ec14c89430bec3" - integrity sha512-k8JV2ECWNchD6ahkg2BR5wKVxY0OiKot7fuxiIpRK0frRqyOljcR2vKwgWSLw6YIeDcNNA4xybj7Og7NSxr2hA== - dependencies: - "@ethersproject/abi" "^5.1.2" - "@metamask/eth-sig-util" "^4.0.0" - "@nomicfoundation/edr" "^0.3.5" - "@nomicfoundation/ethereumjs-common" "4.0.4" - "@nomicfoundation/ethereumjs-tx" "5.0.4" - "@nomicfoundation/ethereumjs-util" "9.0.4" - "@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" - boxen "^5.1.2" - 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" - has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -15128,19 +14917,6 @@ 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@0.0.0-ci.153326b: - version "0.0.0-ci.153326b" - resolved "https://registry.yarnpkg.com/maci-circuits/-/maci-circuits-0.0.0-ci.153326b.tgz#9958949f675b466c8f0fd7da4d12467012ca1dbb" - integrity sha512-9WYp1465Xelujo4GLpiLqgVdsia2VAl7FEpRMZOJeEJlbl8RUYLBTFlR9X9fBL3sNjoPNFSiswrVoCgmiQEi8A== - dependencies: - "@zk-kit/circuits" "^0.4.0" - circomkit "^0.1.0" - circomlib "^2.0.5" - maci-core "0.0.0-ci.153326b" - maci-crypto "0.0.0-ci.153326b" - maci-domainobjs "0.0.0-ci.153326b" - snarkjs "^0.7.4" - maci-circuits@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/maci-circuits/-/maci-circuits-1.2.0.tgz#9b1f9c64d48e4dc3c3c7c8ffc4d0f254d60cce3e" @@ -15172,24 +14948,7 @@ maci-cli@^1.2.0: maci-domainobjs "^1.2.0" prompt "^1.3.0" -maci-contracts@0.0.0-ci.153326b: - version "0.0.0-ci.153326b" - resolved "https://registry.yarnpkg.com/maci-contracts/-/maci-contracts-0.0.0-ci.153326b.tgz#4c1d3cc1c5a89cbbe852439a1e81646e8b0dc302" - integrity sha512-DFo8xLR/Ia/CcSFXYjHfMCfaN/GnhNMxVgcRu1EQBY8DzWMs/MBHEYnH/LBpT/r5QscY0kyk45lMdKA24xHsFA== - dependencies: - "@nomicfoundation/hardhat-ethers" "^3.0.5" - "@nomicfoundation/hardhat-toolbox" "^5.0.0" - "@openzeppelin/contracts" "^5.0.2" - circomlibjs "^0.1.7" - ethers "^6.12.0" - hardhat "^2.22.3" - maci-circuits "0.0.0-ci.153326b" - maci-core "0.0.0-ci.153326b" - maci-crypto "0.0.0-ci.153326b" - maci-domainobjs "0.0.0-ci.153326b" - solidity-docgen "^0.6.0-beta.36" - -maci-contracts@^1.2.0: +maci-contracts@1.2.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== @@ -15206,14 +14965,6 @@ maci-contracts@^1.2.0: maci-domainobjs "^1.2.0" solidity-docgen "^0.6.0-beta.36" -maci-core@0.0.0-ci.153326b: - version "0.0.0-ci.153326b" - resolved "https://registry.yarnpkg.com/maci-core/-/maci-core-0.0.0-ci.153326b.tgz#08cb39ab66b2e528da319d64e2194c4b1c2fca01" - integrity sha512-lrkPm/gIcHbVO3+tuGnvNdc/Gy5jD0+5biG13RmdIfFiXnND0vD7aX5x45HY4mNK1TUrlS8ZMVHSjY4voeiieg== - dependencies: - maci-crypto "0.0.0-ci.153326b" - maci-domainobjs "0.0.0-ci.153326b" - maci-core@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/maci-core/-/maci-core-1.2.0.tgz#57ff4b92c457f42a3043fe5b34cfef98a9ac1cf5" @@ -15222,17 +14973,7 @@ maci-core@^1.2.0: maci-crypto "^1.2.0" maci-domainobjs "^1.2.0" -maci-crypto@0.0.0-ci.153326b: - version "0.0.0-ci.153326b" - resolved "https://registry.yarnpkg.com/maci-crypto/-/maci-crypto-0.0.0-ci.153326b.tgz#4d0d2e72dd0aa6dba30d24e2c873729a5706bb8e" - integrity sha512-80QCpFdMts3rgfUn0fSQq0BFsuALOAYRH+MLWWDVTQXu1LtXZ4ikwq4DvD0ZuUDHjf9GgAmsQGQbi/Raa6q0bQ== - dependencies: - "@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-crypto@^1.2.0: +maci-crypto@1.2.0, 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== @@ -15242,14 +14983,7 @@ maci-crypto@^1.2.0: "@zk-kit/poseidon-cipher" "^0.2.1" ethers "^6.11.1" -maci-domainobjs@0.0.0-ci.153326b: - version "0.0.0-ci.153326b" - resolved "https://registry.yarnpkg.com/maci-domainobjs/-/maci-domainobjs-0.0.0-ci.153326b.tgz#546649c1b6e29748bc79c77b46081433a8d22876" - integrity sha512-utPsFPC6a6Q8LwtBqTQvzBOsUroprvFoCHy5sTRoRvKsSGLwTibkcYMzmxF5A+tnFJ4n9CKCrr6UF/6Mzc2dlw== - dependencies: - maci-crypto "0.0.0-ci.153326b" - -maci-domainobjs@^1.2.0: +maci-domainobjs@1.2.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== @@ -18093,16 +17827,6 @@ 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" @@ -19356,22 +19080,6 @@ 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" From bcdd62cb96b926355d6b4453420c9257485f9eda Mon Sep 17 00:00:00 2001 From: yuetloo Date: Thu, 9 May 2024 12:50:57 -0400 Subject: [PATCH 50/86] use qualified contract name --- contracts/tasks/helpers/Subtask.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 } From 4e3d72ae9bc79325d5d3d7d95ec9b2b951fbe346 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Thu, 9 May 2024 16:56:42 +0000 Subject: [PATCH 51/86] v5.2.0 --- contracts/package.json | 2 +- subgraph/package.json | 2 +- vue-app/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/package.json b/contracts/package.json index 94bb91a88..90e5f730c 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -1,6 +1,6 @@ { "name": "@clrfund/contracts", - "version": "5.1.1", + "version": "5.2.0", "license": "GPL-3.0", "scripts": { "hardhat": "hardhat", diff --git a/subgraph/package.json b/subgraph/package.json index e764fefc9..8efc48965 100644 --- a/subgraph/package.json +++ b/subgraph/package.json @@ -1,6 +1,6 @@ { "name": "@clrfund/subgraph", - "version": "5.1.1", + "version": "5.2.0", "repository": "https://github.com/clrfund/monorepo/subgraph", "keywords": [ "clr.fund", diff --git a/vue-app/package.json b/vue-app/package.json index 1c7267fbd..48e8b4efc 100644 --- a/vue-app/package.json +++ b/vue-app/package.json @@ -1,6 +1,6 @@ { "name": "@clrfund/vue-app", - "version": "5.1.1", + "version": "5.2.0", "private": true, "license": "GPL-3.0", "type": "module", From 2ff9b0b1de19393a1c21887056f95e9441414724 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Thu, 9 May 2024 13:21:00 -0400 Subject: [PATCH 52/86] use qualified name for Poll --- contracts/tasks/runners/exportRound.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/contracts/tasks/runners/exportRound.ts b/contracts/tasks/runners/exportRound.ts index fa3e332b1..27be1e51b 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, 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 @@ -216,7 +218,11 @@ 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) From e78fc12adb2bf1a768272fcc1fc63c2a011444bd Mon Sep 17 00:00:00 2001 From: yuetloo Date: Thu, 9 May 2024 13:24:30 -0400 Subject: [PATCH 53/86] make script maci-pubkey available --- contracts/tasks/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/tasks/index.ts b/contracts/tasks/index.ts index 59f1c9699..b25d56890 100644 --- a/contracts/tasks/index.ts +++ b/contracts/tasks/index.ts @@ -28,3 +28,4 @@ import './runners/genProofs' import './runners/proveOnChain' import './runners/publishTallyResults' import './runners/resetTally' +import './runners/maciPubkey' From 6bbd012dd4c6082a5ee8c778ca680285b69992cd Mon Sep 17 00:00:00 2001 From: yuetloo Date: Fri, 10 May 2024 11:09:44 -0400 Subject: [PATCH 54/86] validate key using the serialize function --- common/src/keypair.ts | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/common/src/keypair.ts b/common/src/keypair.ts index 8e02ab52f..649ef4b9f 100644 --- a/common/src/keypair.ts +++ b/common/src/keypair.ts @@ -1,37 +1,34 @@ 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) + const keypair = new Keypair(privKey) + + // this will throw 'Invalid public key' if key is not on the Baby Jubjub elliptic curve + keypair.pubKey.serialize() + + 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) } From 0ff9b2b7cd212e004867ab1b82448fd4b621aaff Mon Sep 17 00:00:00 2001 From: yuetloo Date: Mon, 13 May 2024 12:31:48 -0400 Subject: [PATCH 55/86] add test for common package --- common/src/__tests__/keypair.spec.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 common/src/__tests__/keypair.spec.ts diff --git a/common/src/__tests__/keypair.spec.ts b/common/src/__tests__/keypair.spec.ts new file mode 100644 index 000000000..47f1cba72 --- /dev/null +++ b/common/src/__tests__/keypair.spec.ts @@ -0,0 +1,20 @@ +import { expect } from 'chai' +import { Keypair, PubKey } from '../keypair' +import { Wallet, sha256, randomBytes } from 'ethers' + +describe.only('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', () => { + const pubKey = new PubKey([1n, 1n]) + expect(() => pubKey.serialize()).to.throw('Invalid public key') + }) +}) From b031c8edde8e2ff5b57698e9f45291160cce91be Mon Sep 17 00:00:00 2001 From: yuetloo Date: Mon, 13 May 2024 12:32:50 -0400 Subject: [PATCH 56/86] add test common to pre push script --- .husky/pre-push | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.husky/pre-push b/.husky/pre-push index c0bc1da1c..c0d892312 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -11,4 +11,4 @@ export VITE_RECIPIENT_REGISTRY_TYPE=simple export VITE_USER_REGISTRY_TYPE=simple export VITE_WALLET_CONNECT_PROJECT_ID=1 -yarn test:format && yarn test:web && yarn test:lint-i18n +yarn test:format && yarn test:common && yarn test:web && yarn test:lint-i18n From 2f980e27122ca016b7a98e0b61bdb5e7e44277bd Mon Sep 17 00:00:00 2001 From: yuetloo Date: Mon, 13 May 2024 12:55:49 -0400 Subject: [PATCH 57/86] add test:common script --- package.json | 1 + 1 file changed, 1 insertion(+) 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", From 37247636510834661947c4c7b9581a6d5a01b8bb Mon Sep 17 00:00:00 2001 From: yuetloo Date: Mon, 13 May 2024 12:56:02 -0400 Subject: [PATCH 58/86] fix contract verification error --- contracts/tasks/helpers/ConstructorArguments.ts | 5 +++-- contracts/utils/contracts.ts | 8 +++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/contracts/tasks/helpers/ConstructorArguments.ts b/contracts/tasks/helpers/ConstructorArguments.ts index 1db4beb22..751a8bbc4 100644 --- a/contracts/tasks/helpers/ConstructorArguments.ts +++ b/contracts/tasks/helpers/ConstructorArguments.ts @@ -12,7 +12,7 @@ import { Poll, Tally, } from '../../typechain-types' -import { getContractAt } from '../../utils/contracts' +import { getContractAt, getQualifiedContractName } from '../../utils/contracts' /** A list of functions to get contract constructor arguments from the contract */ const ConstructorArgumentsGetters: Record< @@ -312,7 +312,8 @@ export class ConstructorArguments { address: string, ethers: HardhatEthersHelpers ): Promise> { - const contractArtifact = this.hre.artifacts.readArtifactSync(name) + 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 diff --git a/contracts/utils/contracts.ts b/contracts/utils/contracts.ts index c72aac709..77a2bc72d 100644 --- a/contracts/utils/contracts.ts +++ b/contracts/utils/contracts.ts @@ -124,15 +124,13 @@ export async function getCurrentFundingRoundContract( * @param name The contract name * @returns The qualified contract name */ -export function getQualifiedContractName(name: EContracts): string { +export function getQualifiedContractName(name: EContracts | string): string { let contractName = String(name) if (contractName.includes('Poseidon')) { contractName = `:${name}` - } - if (name === EContracts.PollFactory) { + } else if (name === EContracts.PollFactory) { contractName = 'contracts/maci/PollFactory.sol:PollFactory' - } - if (name === EContracts.Poll) { + } else if (name === EContracts.Poll) { contractName = 'contracts/maci/Poll.sol:Poll' } return contractName From d8cd50ca00108896cfe5746291a56509b91b05a8 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Thu, 16 May 2024 06:04:03 -0400 Subject: [PATCH 59/86] use MACI v1.2.1 --- common/package.json | 4 +- common/src/__tests__/keypair.spec.ts | 7 +- common/src/keypair.ts | 5 +- contracts/contracts/AnyOldERC20Token.sol | 2 +- contracts/contracts/CloneFactory.sol | 2 +- contracts/contracts/ClrFund.sol | 2 +- contracts/contracts/ClrFundDeployer.sol | 4 +- contracts/contracts/ExternalContacts.sol | 3 +- contracts/contracts/FundingRound.sol | 12 +- contracts/contracts/FundingRoundFactory.sol | 2 +- contracts/contracts/MACICommon.sol | 2 +- contracts/contracts/MACIFactory.sol | 24 +- contracts/contracts/OwnableUpgradeable.sol | 2 +- contracts/contracts/TopupToken.sol | 4 +- contracts/contracts/interfaces/IClrFund.sol | 2 +- .../contracts/interfaces/IFundingRound.sol | 2 +- .../interfaces/IFundingRoundFactory.sol | 2 +- .../contracts/interfaces/IMACIFactory.sol | 2 +- contracts/contracts/maci/BabyJubJub.sol | 136 ----- contracts/contracts/maci/Poll.sol | 286 ---------- contracts/contracts/maci/PollFactory.sol | 73 --- .../BaseRecipientRegistry.sol | 2 +- .../recipientRegistry/IKlerosGTCR.sol | 2 +- .../recipientRegistry/IRecipientRegistry.sol | 2 +- .../recipientRegistry/KlerosGTCRAdapter.sol | 2 +- .../recipientRegistry/KlerosGTCRMock.sol | 4 +- .../OptimisticRecipientRegistry.sol | 4 +- .../PermissionedRecipientRegistry.sol | 4 +- .../SimpleRecipientRegistry.sol | 4 +- .../userRegistry/BrightIdSponsor.sol | 2 +- .../userRegistry/BrightIdUserRegistry.sol | 4 +- .../contracts/userRegistry/IUserRegistry.sol | 2 +- .../userRegistry/MerkleUserRegistry.sol | 4 +- .../userRegistry/SemaphoreUserRegistry.sol | 4 +- .../userRegistry/SimpleUserRegistry.sol | 4 +- .../userRegistry/SnapshotUserRegistry.sol | 4 +- .../MerklePatriciaProofVerifier.sol | 2 +- .../utils/cryptography/MerkleProof.sol | 2 +- .../utils/cryptography/StateProofVerifier.sol | 2 +- contracts/hardhat.config.ts | 7 +- contracts/package.json | 18 +- contracts/tasks/runners/genProofs.ts | 2 +- .../subtasks/clrfund/03-setVkRegsitry.ts | 7 +- .../subtasks/coordinator/01-coordinator.ts | 23 +- .../tasks/subtasks/round/02-deploy-round.ts | 6 +- contracts/utils/contracts.ts | 7 +- contracts/utils/maci.ts | 6 +- subgraph/abis/MACI.json | 62 +- subgraph/abis/Poll.json | 34 +- subgraph/generated/ClrFund/MACI.ts | 59 +- subgraph/generated/templates/MACI/MACI.ts | 59 +- yarn.lock | 539 +++++++++--------- 52 files changed, 473 insertions(+), 988 deletions(-) delete mode 100644 contracts/contracts/maci/BabyJubJub.sol delete mode 100644 contracts/contracts/maci/Poll.sol delete mode 100644 contracts/contracts/maci/PollFactory.sol diff --git a/common/package.json b/common/package.json index d7f3da4a5..713437020 100644 --- a/common/package.json +++ b/common/package.json @@ -23,8 +23,8 @@ "dependencies": { "@openzeppelin/merkle-tree": "^1.0.5", "ethers": "^6.11.1", - "maci-crypto": "1.2.0", - "maci-domainobjs": "1.2.0" + "maci-crypto": "1.2.1", + "maci-domainobjs": "1.2.1" }, "repository": { "type": "git", diff --git a/common/src/__tests__/keypair.spec.ts b/common/src/__tests__/keypair.spec.ts index 47f1cba72..7dbc6e195 100644 --- a/common/src/__tests__/keypair.spec.ts +++ b/common/src/__tests__/keypair.spec.ts @@ -2,7 +2,7 @@ import { expect } from 'chai' import { Keypair, PubKey } from '../keypair' import { Wallet, sha256, randomBytes } from 'ethers' -describe.only('keypair', function () { +describe('keypair', function () { for (let i = 0; i < 10; i++) { it(`should generate key ${i} from seed successfully`, function () { const wallet = Wallet.createRandom() @@ -14,7 +14,8 @@ describe.only('keypair', function () { } it('should throw if pubKey is invalid', () => { - const pubKey = new PubKey([1n, 1n]) - expect(() => pubKey.serialize()).to.throw('Invalid public key') + expect(() => { + new PubKey([1n, 1n]) + }).to.throw('PubKey not on curve') }) }) diff --git a/common/src/keypair.ts b/common/src/keypair.ts index 649ef4b9f..c6c9ea165 100644 --- a/common/src/keypair.ts +++ b/common/src/keypair.ts @@ -17,11 +17,8 @@ function genPrivKey(hash: string): PrivKey { for (let counter = 1; pubKey === null; counter++) { try { const privKey = new PrivKey(rawPrivKey) - const keypair = new Keypair(privKey) - // this will throw 'Invalid public key' if key is not on the Baby Jubjub elliptic curve - keypair.pubKey.serialize() - + const keypair = new Keypair(privKey) pubKey = keypair.pubKey } catch { const data = concat([toBeArray(rawPrivKey), toBeArray(counter)]) 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..4f5ad30bc 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'; 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..9f8fe143b 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, @@ -221,10 +221,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); } 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..05762874e 100644 --- a/contracts/contracts/MACICommon.sol +++ b/contracts/contracts/MACICommon.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.10; +pragma solidity 0.8.20; /** * @dev a contract that holds common MACI structures diff --git a/contracts/contracts/MACIFactory.sol b/contracts/contracts/MACIFactory.sol index 1fb0b800b..2bccc4655 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; @@ -135,7 +135,8 @@ contract MACIFactory is Ownable, Params, SnarkCommon, DomainObjs, MACICommon { _stateTreeDepth, _treeDepths.messageTreeDepth, _treeDepths.voteOptionTreeDepth, - messageBatchSize) + messageBatchSize, + Mode.QV) ) { revert ProcessVkNotSet(); } @@ -143,7 +144,8 @@ contract MACIFactory is Ownable, Params, SnarkCommon, DomainObjs, MACICommon { if (!vkRegistry.hasTallyVk( _stateTreeDepth, _treeDepths.intStateTreeDepth, - _treeDepths.voteOptionTreeDepth) + _treeDepths.voteOptionTreeDepth, + Mode.QV) ) { revert TallyVkNotSet(); } @@ -175,7 +177,8 @@ contract MACIFactory is Ownable, Params, SnarkCommon, DomainObjs, MACICommon { stateTreeDepth, treeDepths.messageTreeDepth, treeDepths.voteOptionTreeDepth, - messageBatchSize) + messageBatchSize, + Mode.QV) ) { revert ProcessVkNotSet(); } @@ -183,7 +186,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 +195,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 +208,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..eacfd7df2 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'; diff --git a/contracts/contracts/maci/BabyJubJub.sol b/contracts/contracts/maci/BabyJubJub.sol deleted file mode 100644 index 7d046b624..000000000 --- a/contracts/contracts/maci/BabyJubJub.sol +++ /dev/null @@ -1,136 +0,0 @@ -// @note This code was taken from -// https://github.com/privacy-scaling-explorations/maci/blob/dc18e2f046cf160f846f003c04ec4dfac502f6ae/contracts/contracts/crypto/BabyJubJub.sol -// TODO remove this and use MACI npm package when version greater than 1.2.0 is released - -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - -library CurveBabyJubJub { - // Curve parameters - // E: 168700x^2 + y^2 = 1 + 168696x^2y^2 - // A = 168700 - uint256 public constant A = 0x292FC; - // D = 168696 - uint256 public constant D = 0x292F8; - // Prime Q = 21888242871839275222246405745257275088548364400416034343698204186575808495617 - uint256 public constant Q = 0x30644E72E131A029B85045B68181585D2833E84879B9709143E1F593F0000001; - - /** - * @dev Add 2 points on baby jubjub curve - * Formula for adding 2 points on a twisted Edwards curve: - * x3 = (x1y2 + y1x2) / (1 + dx1x2y1y2) - * y3 = (y1y2 - ax1x2) / (1 - dx1x2y1y2) - */ - function pointAdd(uint256 _x1, uint256 _y1, uint256 _x2, uint256 _y2) internal view returns (uint256 x3, uint256 y3) { - if (_x1 == 0 && _y1 == 0) { - return (_x2, _y2); - } - - if (_x2 == 0 && _y1 == 0) { - return (_x1, _y1); - } - - uint256 x1x2 = mulmod(_x1, _x2, Q); - uint256 y1y2 = mulmod(_y1, _y2, Q); - uint256 dx1x2y1y2 = mulmod(D, mulmod(x1x2, y1y2, Q), Q); - uint256 x3Num = addmod(mulmod(_x1, _y2, Q), mulmod(_y1, _x2, Q), Q); - uint256 y3Num = submod(y1y2, mulmod(A, x1x2, Q), Q); - - x3 = mulmod(x3Num, inverse(addmod(1, dx1x2y1y2, Q)), Q); - y3 = mulmod(y3Num, inverse(submod(1, dx1x2y1y2, Q)), Q); - } - - /** - * @dev Double a point on baby jubjub curve - * Doubling can be performed with the same formula as addition - */ - function pointDouble(uint256 _x1, uint256 _y1) internal view returns (uint256 x2, uint256 y2) { - return pointAdd(_x1, _y1, _x1, _y1); - } - - /** - * @dev Multiply a point on baby jubjub curve by a scalar - * Use the double and add algorithm - */ - function pointMul(uint256 _x1, uint256 _y1, uint256 _d) internal view returns (uint256 x2, uint256 y2) { - uint256 remaining = _d; - - uint256 px = _x1; - uint256 py = _y1; - uint256 ax = 0; - uint256 ay = 0; - - while (remaining != 0) { - if ((remaining & 1) != 0) { - // Binary digit is 1 so add - (ax, ay) = pointAdd(ax, ay, px, py); - } - - (px, py) = pointDouble(px, py); - - remaining = remaining / 2; - } - - x2 = ax; - y2 = ay; - } - - /** - * @dev Check if a given point is on the curve - * (168700x^2 + y^2) - (1 + 168696x^2y^2) == 0 - */ - function isOnCurve(uint256 _x, uint256 _y) internal pure returns (bool) { - uint256 xSq = mulmod(_x, _x, Q); - uint256 ySq = mulmod(_y, _y, Q); - uint256 lhs = addmod(mulmod(A, xSq, Q), ySq, Q); - uint256 rhs = addmod(1, mulmod(mulmod(D, xSq, Q), ySq, Q), Q); - return submod(lhs, rhs, Q) == 0; - } - - /** - * @dev Perform modular subtraction - */ - function submod(uint256 _a, uint256 _b, uint256 _mod) internal pure returns (uint256) { - uint256 aNN = _a; - - if (_a <= _b) { - aNN += _mod; - } - - return addmod(aNN - _b, 0, _mod); - } - - /** - * @dev Compute modular inverse of a number - */ - function inverse(uint256 _a) internal view returns (uint256) { - // We can use Euler's theorem instead of the extended Euclidean algorithm - // Since m = Q and Q is prime we have: a^-1 = a^(m - 2) (mod m) - return expmod(_a, Q - 2, Q); - } - - /** - * @dev Helper function to call the bigModExp precompile - */ - function expmod(uint256 _b, uint256 _e, uint256 _m) internal view returns (uint256 o) { - assembly { - let memPtr := mload(0x40) - mstore(memPtr, 0x20) // Length of base _b - mstore(add(memPtr, 0x20), 0x20) // Length of exponent _e - mstore(add(memPtr, 0x40), 0x20) // Length of modulus _m - mstore(add(memPtr, 0x60), _b) // Base _b - mstore(add(memPtr, 0x80), _e) // Exponent _e - mstore(add(memPtr, 0xa0), _m) // Modulus _m - - // The bigModExp precompile is at 0x05 - let success := staticcall(gas(), 0x05, memPtr, 0xc0, memPtr, 0x20) - switch success - case 0 { - revert(0x0, 0x0) - } - default { - o := mload(memPtr) - } - } - } -} diff --git a/contracts/contracts/maci/Poll.sol b/contracts/contracts/maci/Poll.sol deleted file mode 100644 index 1306c7698..000000000 --- a/contracts/contracts/maci/Poll.sol +++ /dev/null @@ -1,286 +0,0 @@ -// @note This code was taken from maci-contracts v1.2.0 with public key validation from -// https://github.com/privacy-scaling-explorations/maci/blob/dc18e2f046cf160f846f003c04ec4dfac502f6ae/contracts/contracts/Poll.sol -// TODO remove this and use MACI npm package when version greater than 1.2.0 is released - -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -import { Params } from "maci-contracts/contracts/utilities/Params.sol"; -import { SnarkCommon } from "maci-contracts/contracts/crypto/SnarkCommon.sol"; -import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import { EmptyBallotRoots } from "maci-contracts/contracts/trees/EmptyBallotRoots.sol"; -import { IPoll } from "maci-contracts/contracts/interfaces/IPoll.sol"; -import { Utilities } from "maci-contracts/contracts/utilities/Utilities.sol"; -import { CurveBabyJubJub } from "./BabyJubJub.sol"; - -/// @title Poll -/// @notice A Poll contract allows voters to submit encrypted messages -/// which can be either votes, key change messages or topup messages. -/// @dev Do not deploy this directly. Use PollFactory.deploy() which performs some -/// checks on the Poll constructor arguments. -contract Poll is Params, Utilities, SnarkCommon, Ownable, EmptyBallotRoots, IPoll { - using SafeERC20 for ERC20; - - /// @notice Whether the Poll has been initialized - bool internal isInit; - - /// @notice The coordinator's public key - PubKey public coordinatorPubKey; - - /// @notice Hash of the coordinator's public key - uint256 public immutable coordinatorPubKeyHash; - - /// @notice the state root of the state merkle tree - uint256 public mergedStateRoot; - - // The timestamp of the block at which the Poll was deployed - uint256 internal immutable deployTime; - - // The duration of the polling period, in seconds - uint256 internal immutable duration; - - /// @notice Whether the MACI contract's stateAq has been merged by this contract - bool public stateAqMerged; - - /// @notice Get the commitment to the state leaves and the ballots. This is - /// hash3(stateRoot, ballotRoot, salt). - /// Its initial value should be - /// hash(maciStateRootSnapshot, emptyBallotRoot, 0) - /// Each successful invocation of processMessages() should use a different - /// salt to update this value, so that an external observer cannot tell in - /// the case that none of the messages are valid. - uint256 public currentSbCommitment; - - /// @notice The number of messages that have been published - uint256 public numMessages; - - /// @notice The number of signups that have been processed - /// before the Poll ended (stateAq merged) - uint256 public numSignups; - - /// @notice Max values for the poll - MaxValues public maxValues; - - /// @notice Depths of the merkle trees - TreeDepths public treeDepths; - - /// @notice The contracts used by the Poll - ExtContracts public extContracts; - - error VotingPeriodOver(); - error VotingPeriodNotOver(); - error PollAlreadyInit(); - error TooManyMessages(); - error InvalidPubKey(); - error StateAqAlreadyMerged(); - error StateAqSubtreesNeedMerge(); - error InvalidBatchLength(); - - event PublishMessage(Message _message, PubKey _encPubKey); - event TopupMessage(Message _message); - event MergeMaciStateAqSubRoots(uint256 _numSrQueueOps); - event MergeMaciStateAq(uint256 _stateRoot, uint256 _numSignups); - event MergeMessageAqSubRoots(uint256 _numSrQueueOps); - event MergeMessageAq(uint256 _messageRoot); - - /// @notice Each MACI instance can have multiple Polls. - /// When a Poll is deployed, its voting period starts immediately. - /// @param _duration The duration of the voting period, in seconds - /// @param _maxValues The maximum number of messages and vote options - /// @param _treeDepths The depths of the merkle trees - /// @param _coordinatorPubKey The coordinator's public key - /// @param _extContracts The external contracts - constructor( - uint256 _duration, - MaxValues memory _maxValues, - TreeDepths memory _treeDepths, - PubKey memory _coordinatorPubKey, - ExtContracts memory _extContracts - ) payable { - // check that the coordinator public key is valid - if (!CurveBabyJubJub.isOnCurve(_coordinatorPubKey.x, _coordinatorPubKey.y)) { - revert InvalidPubKey(); - } - - // store the pub key as object then calculate the hash - coordinatorPubKey = _coordinatorPubKey; - // we hash it ourselves to ensure we store the correct value - coordinatorPubKeyHash = hashLeftRight(_coordinatorPubKey.x, _coordinatorPubKey.y); - // store the external contracts to interact with - extContracts = _extContracts; - // store duration of the poll - duration = _duration; - // store max values - maxValues = _maxValues; - // store tree depth - treeDepths = _treeDepths; - // Record the current timestamp - deployTime = block.timestamp; - } - - /// @notice A modifier that causes the function to revert if the voting period is - /// not over. - modifier isAfterVotingDeadline() { - uint256 secondsPassed = block.timestamp - deployTime; - if (secondsPassed <= duration) revert VotingPeriodNotOver(); - _; - } - - /// @notice A modifier that causes the function to revert if the voting period is - /// over - modifier isWithinVotingDeadline() { - uint256 secondsPassed = block.timestamp - deployTime; - if (secondsPassed >= duration) revert VotingPeriodOver(); - _; - } - - /// @notice The initialization function. - /// @dev Should be called immediately after Poll creation - /// and messageAq ownership transferred - function init() public { - if (isInit) revert PollAlreadyInit(); - // set to true so it cannot be called again - isInit = true; - - unchecked { - numMessages++; - } - - // init messageAq here by inserting placeholderLeaf - uint256[2] memory dat = [NOTHING_UP_MY_SLEEVE, 0]; - - (Message memory _message, PubKey memory _padKey, uint256 placeholderLeaf) = padAndHashMessage(dat, 1); - extContracts.messageAq.enqueue(placeholderLeaf); - - emit PublishMessage(_message, _padKey); - } - - /// @inheritdoc IPoll - function topup(uint256 stateIndex, uint256 amount) public virtual isWithinVotingDeadline { - // we check that we do not exceed the max number of messages - if (numMessages >= maxValues.maxMessages) revert TooManyMessages(); - - // cannot realistically overflow - unchecked { - numMessages++; - } - - /// @notice topupCredit is a trusted token contract which reverts if the transfer fails - extContracts.topupCredit.transferFrom(msg.sender, address(this), amount); - - uint256[2] memory dat = [stateIndex, amount]; - (Message memory _message, , uint256 messageLeaf) = padAndHashMessage(dat, 2); - - extContracts.messageAq.enqueue(messageLeaf); - - emit TopupMessage(_message); - } - - /// @inheritdoc IPoll - function publishMessage(Message memory _message, PubKey calldata _encPubKey) public virtual isWithinVotingDeadline { - // we check that we do not exceed the max number of messages - if (numMessages >= maxValues.maxMessages) revert TooManyMessages(); - - // validate that the public key is valid - if (!CurveBabyJubJub.isOnCurve(_encPubKey.x, _encPubKey.y)) { - revert InvalidPubKey(); - } - - // cannot realistically overflow - unchecked { - numMessages++; - } - - // we enforce that msgType here is 1 so we don't need checks - // at the circuit level - _message.msgType = 1; - - uint256 messageLeaf = hashMessageAndEncPubKey(_message, _encPubKey); - extContracts.messageAq.enqueue(messageLeaf); - - emit PublishMessage(_message, _encPubKey); - } - - /// @notice submit a message batch - /// @dev Can only be submitted before the voting deadline - /// @param _messages the messages - /// @param _encPubKeys the encrypted public keys - function publishMessageBatch(Message[] calldata _messages, PubKey[] calldata _encPubKeys) external { - if (_messages.length != _encPubKeys.length) { - revert InvalidBatchLength(); - } - - uint256 len = _messages.length; - for (uint256 i = 0; i < len; ) { - // an event will be published by this function already - publishMessage(_messages[i], _encPubKeys[i]); - - unchecked { - i++; - } - } - } - - /// @inheritdoc IPoll - function mergeMaciStateAqSubRoots(uint256 _numSrQueueOps, uint256 _pollId) public onlyOwner isAfterVotingDeadline { - // This function cannot be called after the stateAq was merged - if (stateAqMerged) revert StateAqAlreadyMerged(); - - // merge subroots - extContracts.maci.mergeStateAqSubRoots(_numSrQueueOps, _pollId); - - emit MergeMaciStateAqSubRoots(_numSrQueueOps); - } - - /// @inheritdoc IPoll - function mergeMaciStateAq(uint256 _pollId) public onlyOwner isAfterVotingDeadline { - // This function can only be called once per Poll after the voting - // deadline - if (stateAqMerged) revert StateAqAlreadyMerged(); - - // set merged to true so it cannot be called again - stateAqMerged = true; - - // the subtrees must have been merged first - if (!extContracts.maci.stateAq().subTreesMerged()) revert StateAqSubtreesNeedMerge(); - - mergedStateRoot = extContracts.maci.mergeStateAq(_pollId); - - // Set currentSbCommitment - uint256[3] memory sb; - sb[0] = mergedStateRoot; - sb[1] = emptyBallotRoots[treeDepths.voteOptionTreeDepth - 1]; - sb[2] = uint256(0); - - currentSbCommitment = hash3(sb); - - numSignups = extContracts.maci.numSignUps(); - emit MergeMaciStateAq(mergedStateRoot, numSignups); - } - - /// @inheritdoc IPoll - function mergeMessageAqSubRoots(uint256 _numSrQueueOps) public onlyOwner isAfterVotingDeadline { - extContracts.messageAq.mergeSubRoots(_numSrQueueOps); - emit MergeMessageAqSubRoots(_numSrQueueOps); - } - - /// @inheritdoc IPoll - function mergeMessageAq() public onlyOwner isAfterVotingDeadline { - uint256 root = extContracts.messageAq.merge(treeDepths.messageTreeDepth); - emit MergeMessageAq(root); - } - - /// @inheritdoc IPoll - function getDeployTimeAndDuration() public view returns (uint256 pollDeployTime, uint256 pollDuration) { - pollDeployTime = deployTime; - pollDuration = duration; - } - - /// @inheritdoc IPoll - function numSignUpsAndMessages() public view returns (uint256 numSUps, uint256 numMsgs) { - numSUps = numSignups; - numMsgs = numMessages; - } -} diff --git a/contracts/contracts/maci/PollFactory.sol b/contracts/contracts/maci/PollFactory.sol deleted file mode 100644 index ad91b4305..000000000 --- a/contracts/contracts/maci/PollFactory.sol +++ /dev/null @@ -1,73 +0,0 @@ -// @note This code was taken from https://github.com/privacy-scaling-explorations/maci/blob/dc18e2f046cf160f846f003c04ec4dfac502f6ae/contracts/contracts/PollFactory.sol -// TODO remove this and use MACI npm package when version greater than 1.2.0 is released - -// SPDX-License-Identifier: MIT -pragma solidity 0.8.10; - - -import { IMACI } from "maci-contracts/contracts/interfaces/IMACI.sol"; -import { AccQueue } from "maci-contracts/contracts/trees/AccQueue.sol"; -import { AccQueueQuinaryMaci } from "maci-contracts/contracts/trees/AccQueueQuinaryMaci.sol"; -import { TopupCredit } from "maci-contracts/contracts/TopupCredit.sol"; -import { Params } from "maci-contracts/contracts/utilities/Params.sol"; -import { DomainObjs } from "maci-contracts/contracts/utilities/DomainObjs.sol"; -import { Poll } from "./Poll.sol"; -import { IPollFactory } from "maci-contracts/contracts/interfaces/IPollFactory.sol"; - -/// @title PollFactory -/// @notice A factory contract which deploys Poll contracts. It allows the MACI contract -/// size to stay within the limit set by EIP-170. -contract PollFactory is Params, DomainObjs, IPollFactory { - // The number of children each node in the message tree has - uint256 internal constant TREE_ARITY = 5; - - // custom error - error InvalidMaxValues(); - - /// @notice The PollFactory constructor - // solhint-disable-next-line no-empty-blocks - constructor() payable {} - - /// @inheritdoc IPollFactory - function deploy( - uint256 _duration, - MaxValues calldata _maxValues, - TreeDepths calldata _treeDepths, - PubKey calldata _coordinatorPubKey, - address _maci, - TopupCredit _topupCredit, - address _pollOwner - ) public virtual returns (address pollAddr) { - /// @notice Validate _maxValues - /// maxVoteOptions must be less than 2 ** 50 due to circuit limitations; - /// it will be packed as a 50-bit value along with other values as one - /// of the inputs (aka packedVal) - if (_maxValues.maxVoteOptions >= (2 ** 50)) { - revert InvalidMaxValues(); - } - - /// @notice deploy a new AccQueue contract to store messages - AccQueue messageAq = new AccQueueQuinaryMaci(_treeDepths.messageTreeSubDepth); - - /// @notice the smart contracts that a Poll would interact with - ExtContracts memory extContracts = ExtContracts({ - maci: IMACI(_maci), - messageAq: messageAq, - topupCredit: _topupCredit - }); - - // deploy the poll - Poll poll = new Poll(_duration, _maxValues, _treeDepths, _coordinatorPubKey, extContracts); - - // Make the Poll contract own the messageAq contract, so only it can - // run enqueue/merge - messageAq.transferOwnership(address(poll)); - - // init Poll - poll.init(); - - poll.transferOwnership(_pollOwner); - - pollAddr = address(poll); - } -} 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..82fc0c4a9 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. 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/hardhat.config.ts b/contracts/hardhat.config.ts index 470029275..7837be09c 100644 --- a/contracts/hardhat.config.ts +++ b/contracts/hardhat.config.ts @@ -119,7 +119,7 @@ export default { disambiguatePaths: false, }, solidity: { - version: '0.8.10', + version: '0.8.20', settings: { optimizer: { enabled: true, @@ -128,7 +128,6 @@ export default { }, overrides: { 'contracts/FundingRoundFactory.sol': { - version: '0.8.10', settings: { optimizer: { enabled: true, @@ -137,7 +136,6 @@ export default { }, }, 'contracts/FundingRound.sol': { - version: '0.8.10', settings: { optimizer: { enabled: true, @@ -146,7 +144,6 @@ export default { }, }, 'contracts/recipientRegistry/OptimisticRecipientRegistry.sol': { - version: '0.8.10', settings: { optimizer: { enabled: true, @@ -155,7 +152,6 @@ export default { }, }, 'contracts/userRegistry/SimpleUserRegistry.sol': { - version: '0.8.10', settings: { optimizer: { enabled: true, @@ -164,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 9a3941562..2f70d0f24 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -15,18 +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.1", "solidity-rlp": "2.0.8" }, "devDependencies": { "@clrfund/common": "^0.0.1", "@clrfund/waffle-mock-contract": "^0.0.4", "@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", @@ -34,14 +34,16 @@ "@typechain/ethers-v6": "^0.5.1", "@typechain/hardhat": "^9.1.0", "@types/mocha": "^10.0.6", - "ethers": "^6.11.1", + "chai": "4", + "ethers": "^6.12.1", "hardhat": "^2.19.4", "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", + "lowdb": "1.0.0", + "maci-circuits": "1.2.1", + "maci-cli": "1.2.1", + "maci-domainobjs": "1.2.1", "mocha": "^10.2.0", "solidity-coverage": "^0.8.1", "ts-node": "^10.9.2", diff --git a/contracts/tasks/runners/genProofs.ts b/contracts/tasks/runners/genProofs.ts index ed3061edb..708573980 100644 --- a/contracts/tasks/runners/genProofs.ts +++ b/contracts/tasks/runners/genProofs.ts @@ -187,7 +187,7 @@ task('gen-proofs', 'Generate MACI proofs offchain') quiet, outputPath: maciStateFile, pollId, - maciContractAddress: maciAddress, + maciAddress, coordinatorPrivateKey: coordinatorMacisk, ethereumProvider: providerUrl, transactionHash: maciTxHash, 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/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/utils/contracts.ts b/contracts/utils/contracts.ts index 77a2bc72d..3c26cf5d8 100644 --- a/contracts/utils/contracts.ts +++ b/contracts/utils/contracts.ts @@ -12,7 +12,7 @@ import { } from '@nomicfoundation/hardhat-ethers/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 @@ -54,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 ) @@ -128,10 +129,6 @@ export function getQualifiedContractName(name: EContracts | string): string { let contractName = String(name) if (contractName.includes('Poseidon')) { contractName = `:${name}` - } else if (name === EContracts.PollFactory) { - contractName = 'contracts/maci/PollFactory.sol:PollFactory' - } else if (name === EContracts.Poll) { - contractName = 'contracts/maci/Poll.sol:Poll' } return contractName } diff --git a/contracts/utils/maci.ts b/contracts/utils/maci.ts index bb3e3bb0b..caa8467ba 100644 --- a/contracts/utils/maci.ts +++ b/contracts/utils/maci.ts @@ -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' @@ -303,7 +303,7 @@ export async function mergeMaciSubtrees({ await mergeMessages({ pollId, - maciContractAddress: maciAddress, + maciAddress, numQueueOps, signer, quiet, @@ -311,7 +311,7 @@ export async function mergeMaciSubtrees({ await mergeSignups({ pollId, - maciContractAddress: maciAddress, + maciAddress, numQueueOps, signer, quiet, 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/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/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/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/yarn.lock b/yarn.lock index 970c4343b..025a4e9ea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -631,10 +631,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" @@ -1912,6 +1912,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,6 +2682,54 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.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-block@5.0.2": version "5.0.2" resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.2.tgz#13a7968f5964f1697da941281b7f7943b0465d04" @@ -2687,18 +2743,6 @@ 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" @@ -2718,22 +2762,6 @@ 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" @@ -2761,17 +2789,6 @@ 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" @@ -2786,20 +2803,6 @@ 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" @@ -2822,20 +2825,6 @@ 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" @@ -2847,18 +2836,6 @@ 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" @@ -2898,16 +2875,6 @@ "@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" @@ -2927,27 +2894,10 @@ 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 +2912,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 +2932,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 +3235,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" @@ -3544,7 +3502,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== @@ -3964,13 +3922,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" @@ -4091,11 +4042,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" @@ -4956,40 +4902,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" @@ -6464,7 +6432,7 @@ bfj@^7.0.2: jsonpath "^1.1.1" tryer "^1.0.1" -bigint-crypto-utils@^3.0.23, bigint-crypto-utils@^3.2.2: +bigint-crypto-utils@^3.0.23: 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== @@ -6896,7 +6864,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" @@ -7180,7 +7148,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== @@ -7407,6 +7375,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" @@ -7421,10 +7396,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" @@ -10182,6 +10157,19 @@ ethers@^6.11.1: tslib "2.4.0" ws "8.5.0" +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" + "@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" + ethers@^6.9.2: version "6.10.0" resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.10.0.tgz#20f3c63c60d59a993f8090ad423d8a3854b3b1cd" @@ -10708,6 +10696,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" @@ -11960,24 +11957,17 @@ hardhat@^2.19.4: 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== +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.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" @@ -13328,6 +13318,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" @@ -14714,16 +14709,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" @@ -14837,6 +14832,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" @@ -14873,11 +14879,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" @@ -14917,78 +14918,78 @@ 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.1, maci-circuits@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/maci-circuits/-/maci-circuits-1.2.1.tgz#8012ac317736c7324af492eaf6e25e34b8e44519" + integrity sha512-Rch7UFOlrt9ENT8E8QQuAH7vNRVaMFcsk6Eg3C/BRQqKwb+f2A+PSb8qFEGGrqj51DaVEVZWL5KDPDbFpW5DoQ== 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.1" + maci-crypto "^1.2.1" + maci-domainobjs "^1.2.1" + 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.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/maci-cli/-/maci-cli-1.2.1.tgz#0a23092163c24d215ddb392b98834f1d526e8340" + integrity sha512-48XZzRKONc4NGVJB1dnqL0Jou+f0WdMkwn7uP5PUhXBTbUY9lySZuHzWFUtWJ9ooW8s1acYgjAhpbmkHZatL4Q== 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.1" + maci-contracts "^1.2.1" + maci-core "^1.2.1" + maci-crypto "^1.2.1" + maci-domainobjs "^1.2.1" prompt "^1.3.0" -maci-contracts@1.2.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.1, maci-contracts@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/maci-contracts/-/maci-contracts-1.2.1.tgz#ac9f44dc895573d8fe026f19a21edb255fe822ea" + integrity sha512-/B5P82nZgKpSBvxZ3xUoF1mTPDZRMviCWG0ItF93TLnxPTJSMBqFrqJy3mXOHS7sK2/7M5E4NXC1TQ/oFVUATg== 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" + maci-circuits "^1.2.1" + maci-core "^1.2.1" + maci-crypto "^1.2.1" + maci-domainobjs "^1.2.1" 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.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/maci-core/-/maci-core-1.2.1.tgz#546f5a4ea0df0e1525df0ccfb3c54c4bb569c81f" + integrity sha512-8AXzvgcmQFdq5oQCvVZClK7FmTVLzPMDNgKAkc8waTtxLJIhP7Of3SMxfX5zu9Gay1ZGc9YMbC4NVdvdJTsC7g== dependencies: - maci-crypto "^1.2.0" - maci-domainobjs "^1.2.0" + maci-crypto "^1.2.1" + maci-domainobjs "^1.2.1" -maci-crypto@1.2.0, 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.1, maci-crypto@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/maci-crypto/-/maci-crypto-1.2.1.tgz#46999c233f43556960a50bec60c5437443dcd108" + integrity sha512-NERlCuBXYBsTSrE4GMozEgP9x8cL0Wk5ng9XZ/aBp4ib2HAJWyJC78gslRpwhjNNiRFw7TsYH0fcHqHjQ7YCKg== 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, 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.1, maci-domainobjs@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/maci-domainobjs/-/maci-domainobjs-1.2.1.tgz#7bb0ecc6131ed11aba1e73ad6112d7ad6ad807ac" + integrity sha512-oA/Qgigvr8UAvlBx+avNnN2QYd7tREW/SjMiNtHrhnn64cHCqrnuWGSylGYFec0CUaYHQ5RGho1tvHdce1xBLA== dependencies: - maci-crypto "^1.2.0" + maci-crypto "^1.2.1" macos-release@^3.1.0: version "3.2.0" @@ -17173,6 +17174,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" @@ -17827,6 +17833,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" @@ -18491,18 +18507,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" @@ -19064,7 +19068,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== @@ -19080,6 +19084,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" @@ -19400,6 +19420,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" From bb48206d91b09bb2f0db4723c3c1169faaa26311 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Thu, 16 May 2024 07:35:21 -0400 Subject: [PATCH 60/86] use hardhat ^v2.22.3 to fix Invalid Chai property: revertedWith --- contracts/package.json | 2 +- contracts/tests/maciFactory.ts | 5 +- contracts/tests/recipientRegistry.ts | 12 +- contracts/tests/round.ts | 14 +- contracts/tests/userRegistry.ts | 14 +- contracts/tests/userRegistryMerkle.ts | 5 +- contracts/tests/userRegistrySemaphore.ts | 12 +- contracts/utils/testutils.ts | 5 +- yarn.lock | 351 +---------------------- 9 files changed, 53 insertions(+), 367 deletions(-) diff --git a/contracts/package.json b/contracts/package.json index 2f70d0f24..c4b870f22 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -36,7 +36,7 @@ "@types/mocha": "^10.0.6", "chai": "4", "ethers": "^6.12.1", - "hardhat": "^2.19.4", + "hardhat": "^2.22.3", "hardhat-contract-sizer": "^2.10.0", "hardhat-gas-reporter": "^1.0.8", "ipfs-only-hash": "^2.0.1", diff --git a/contracts/tests/maciFactory.ts b/contracts/tests/maciFactory.ts index 3f23d58ad..fcaf8d483 100644 --- a/contracts/tests/maciFactory.ts +++ b/contracts/tests/maciFactory.ts @@ -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 4e480ff34..887e9224a 100644 --- a/contracts/tests/round.ts +++ b/contracts/tests/round.ts @@ -249,7 +249,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 () => { @@ -750,7 +750,10 @@ describe('Funding Round', () => { newResultCommitment, perVOSpentVoiceCreditsHash ) - ).to.be.revertedWith('Ownable: caller is not the owner') + ).to.be.revertedWithCustomError( + fundingRoundAsCoordinator, + 'OwnableUnauthorizedAccount' + ) }) }) @@ -811,8 +814,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' ) }) }) 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/utils/testutils.ts b/contracts/utils/testutils.ts index e5ace7da7..e423421fd 100644 --- a/contracts/utils/testutils.ts +++ b/contracts/utils/testutils.ts @@ -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 @@ -236,7 +237,6 @@ export async function deployTestFundingRound( factories.pollFactory, factories.messageProcessorFactory, factories.tallyFactory, - factories.subsidyFactory, fundingRound.target, fundingRound.target, topupToken.target, @@ -254,8 +254,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/yarn.lock b/yarn.lock index 025a4e9ea..3b91a1800 100644 --- a/yarn.lock +++ b/yarn.lock @@ -578,42 +578,6 @@ 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" @@ -1157,7 +1121,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== @@ -2730,46 +2694,6 @@ "@nomicfoundation/edr-linux-x64-musl" "0.3.7" "@nomicfoundation/edr-win32-x64-msvc" "0.3.7" -"@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-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-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/ethereumjs-common@4.0.4": version "4.0.4" resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.4.tgz#9901f513af2d4802da87c66d6f255b510bef5acb" @@ -2777,77 +2701,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-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-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-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-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" @@ -2858,15 +2716,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" @@ -2875,25 +2724,6 @@ "@nomicfoundation/ethereumjs-rlp" "5.0.4" ethereum-cryptography "0.1.3" -"@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/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" @@ -4103,14 +3933,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" @@ -4997,19 +4819,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" @@ -6432,11 +6241,6 @@ bfj@^7.0.2: jsonpath "^1.1.1" tryer "^1.0.1" -bigint-crypto-utils@^3.0.23: - 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" @@ -6702,16 +6506,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" @@ -7114,21 +6908,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" @@ -7443,17 +7227,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" @@ -8442,7 +8215,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== @@ -10108,7 +9881,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== @@ -11903,60 +11676,6 @@ 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== - 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.22.3: version "2.22.4" resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.22.4.tgz#766227b6cefca5dbf4fd15ab5b5a68138fa13baf" @@ -13019,11 +12738,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" @@ -13690,11 +13404,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" @@ -14279,11 +13988,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" @@ -14291,14 +13995,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" @@ -14326,14 +14022,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" @@ -15106,11 +14794,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" @@ -15176,15 +14859,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" @@ -15605,11 +15279,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" @@ -15857,11 +15526,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" @@ -17783,7 +17447,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== @@ -18493,13 +18157,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" From 4194fea493104ff61b20cfe9301ef1dccf95d9ed Mon Sep 17 00:00:00 2001 From: yuetloo Date: Thu, 16 May 2024 09:27:48 -0400 Subject: [PATCH 61/86] use MACI v1.2.2 --- common/package.json | 4 +-- contracts/package.json | 8 ++--- yarn.lock | 81 +++++++++++++++++++++--------------------- 3 files changed, 47 insertions(+), 46 deletions(-) diff --git a/common/package.json b/common/package.json index 713437020..fe0e1c90e 100644 --- a/common/package.json +++ b/common/package.json @@ -23,8 +23,8 @@ "dependencies": { "@openzeppelin/merkle-tree": "^1.0.5", "ethers": "^6.11.1", - "maci-crypto": "1.2.1", - "maci-domainobjs": "1.2.1" + "maci-crypto": "1.2.2", + "maci-domainobjs": "1.2.2" }, "repository": { "type": "git", diff --git a/contracts/package.json b/contracts/package.json index c4b870f22..9706cfdbe 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -18,7 +18,7 @@ "@openzeppelin/contracts": "5.0.2", "@pinata/sdk": "^2.1.0", "dotenv": "^8.2.0", - "maci-contracts": "1.2.1", + "maci-contracts": "1.2.2", "solidity-rlp": "2.0.8" }, "devDependencies": { @@ -41,9 +41,9 @@ "hardhat-gas-reporter": "^1.0.8", "ipfs-only-hash": "^2.0.1", "lowdb": "1.0.0", - "maci-circuits": "1.2.1", - "maci-cli": "1.2.1", - "maci-domainobjs": "1.2.1", + "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/yarn.lock b/yarn.lock index 3b91a1800..d013c2646 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14520,7 +14520,7 @@ loupe@^2.3.6: dependencies: get-func-name "^2.0.1" -lowdb@1.0.0: +lowdb@1.0.0, 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== @@ -14606,23 +14606,23 @@ 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.1, maci-circuits@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/maci-circuits/-/maci-circuits-1.2.1.tgz#8012ac317736c7324af492eaf6e25e34b8e44519" - integrity sha512-Rch7UFOlrt9ENT8E8QQuAH7vNRVaMFcsk6Eg3C/BRQqKwb+f2A+PSb8qFEGGrqj51DaVEVZWL5KDPDbFpW5DoQ== +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.4.0" circomkit "^0.1.0" circomlib "^2.0.5" - maci-core "^1.2.1" - maci-crypto "^1.2.1" - maci-domainobjs "^1.2.1" + maci-core "^1.2.2" + maci-crypto "^1.2.2" + maci-domainobjs "^1.2.2" snarkjs "^0.7.4" -maci-cli@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/maci-cli/-/maci-cli-1.2.1.tgz#0a23092163c24d215ddb392b98834f1d526e8340" - integrity sha512-48XZzRKONc4NGVJB1dnqL0Jou+f0WdMkwn7uP5PUhXBTbUY9lySZuHzWFUtWJ9ooW8s1acYgjAhpbmkHZatL4Q== +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.1" "@nomicfoundation/hardhat-toolbox" "^5.0.0" @@ -14630,17 +14630,17 @@ maci-cli@1.2.1: dotenv "^16.4.5" ethers "^6.12.0" hardhat "^2.22.3" - maci-circuits "^1.2.1" - maci-contracts "^1.2.1" - maci-core "^1.2.1" - maci-crypto "^1.2.1" - maci-domainobjs "^1.2.1" + 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.1, maci-contracts@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/maci-contracts/-/maci-contracts-1.2.1.tgz#ac9f44dc895573d8fe026f19a21edb255fe822ea" - integrity sha512-/B5P82nZgKpSBvxZ3xUoF1mTPDZRMviCWG0ItF93TLnxPTJSMBqFrqJy3mXOHS7sK2/7M5E4NXC1TQ/oFVUATg== +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" "^5.0.0" @@ -14648,36 +14648,37 @@ maci-contracts@1.2.1, maci-contracts@^1.2.1: circomlibjs "^0.1.7" ethers "^6.12.0" hardhat "^2.22.3" - maci-circuits "^1.2.1" - maci-core "^1.2.1" - maci-crypto "^1.2.1" - maci-domainobjs "^1.2.1" + 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.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/maci-core/-/maci-core-1.2.1.tgz#546f5a4ea0df0e1525df0ccfb3c54c4bb569c81f" - integrity sha512-8AXzvgcmQFdq5oQCvVZClK7FmTVLzPMDNgKAkc8waTtxLJIhP7Of3SMxfX5zu9Gay1ZGc9YMbC4NVdvdJTsC7g== +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.1" - maci-domainobjs "^1.2.1" + maci-crypto "^1.2.2" + maci-domainobjs "^1.2.2" -maci-crypto@1.2.1, maci-crypto@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/maci-crypto/-/maci-crypto-1.2.1.tgz#46999c233f43556960a50bec60c5437443dcd108" - integrity sha512-NERlCuBXYBsTSrE4GMozEgP9x8cL0Wk5ng9XZ/aBp4ib2HAJWyJC78gslRpwhjNNiRFw7TsYH0fcHqHjQ7YCKg== +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.3.0" "@zk-kit/eddsa-poseidon" "^0.11.0" "@zk-kit/poseidon-cipher" "^0.3.0" ethers "^6.12.0" -maci-domainobjs@1.2.1, maci-domainobjs@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/maci-domainobjs/-/maci-domainobjs-1.2.1.tgz#7bb0ecc6131ed11aba1e73ad6112d7ad6ad807ac" - integrity sha512-oA/Qgigvr8UAvlBx+avNnN2QYd7tREW/SjMiNtHrhnn64cHCqrnuWGSylGYFec0CUaYHQ5RGho1tvHdce1xBLA== +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.1" + maci-crypto "^1.2.2" macos-release@^3.1.0: version "3.2.0" From e3ff6058ea2bef815baf8ceb9de5a0e38dc628ff Mon Sep 17 00:00:00 2001 From: yuetloo Date: Thu, 16 May 2024 21:23:34 -0400 Subject: [PATCH 62/86] remove unused variable --- contracts/tasks/runners/verifyAll.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/tasks/runners/verifyAll.ts b/contracts/tasks/runners/verifyAll.ts index c010df8ff..74972fe0c 100644 --- a/contracts/tasks/runners/verifyAll.ts +++ b/contracts/tasks/runners/verifyAll.ts @@ -286,7 +286,7 @@ 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, config, network } = hre + const { ethers, network } = hre const storage = ContractStorage.getInstance() const clrfundContractAddress = From 5d5d67e1b4d6f5a39ff6dc13572279b96a0a3993 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Thu, 16 May 2024 21:36:57 -0400 Subject: [PATCH 63/86] remove lowdb since it is added in maci-contracts now --- contracts/package.json | 1 - yarn.lock | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/package.json b/contracts/package.json index 9706cfdbe..a762f7d4a 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -40,7 +40,6 @@ "hardhat-contract-sizer": "^2.10.0", "hardhat-gas-reporter": "^1.0.8", "ipfs-only-hash": "^2.0.1", - "lowdb": "1.0.0", "maci-circuits": "1.2.2", "maci-cli": "1.2.2", "maci-domainobjs": "1.2.2", diff --git a/yarn.lock b/yarn.lock index d013c2646..108db9ee4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14520,7 +14520,7 @@ loupe@^2.3.6: dependencies: get-func-name "^2.0.1" -lowdb@1.0.0, lowdb@^1.0.0: +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== From 3a5143684ef1eec9cb834527a3ae48338422e538 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Thu, 16 May 2024 21:37:43 -0400 Subject: [PATCH 64/86] use ethers 6.12.1 --- vue-app/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vue-app/package.json b/vue-app/package.json index 1c7267fbd..5d05ae141 100644 --- a/vue-app/package.json +++ b/vue-app/package.json @@ -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", From 916e5e2c3d9c72629c62b4bbc736ba8005ff305a Mon Sep 17 00:00:00 2001 From: yuetloo Date: Fri, 17 May 2024 16:14:20 -0400 Subject: [PATCH 65/86] update waffle-mock-contract to v0.0.11 --- contracts/package.json | 2 +- yarn.lock | 28 +++++----------------------- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/contracts/package.json b/contracts/package.json index a762f7d4a..1bb19275e 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -23,7 +23,7 @@ }, "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.6", "@nomicfoundation/hardhat-ethers": "^3.0.6", diff --git a/yarn.lock b/yarn.lock index 108db9ee4..2e8eb68ed 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,12 +573,12 @@ resolved "https://registry.yarnpkg.com/@bugsnag/safe-json-stringify/-/safe-json-stringify-6.0.0.tgz#22abdcd83e008c369902976730c34c150148a758" integrity sha512-htzFO1Zc57S8kgdRK9mLcPVTW1BY2ijfH7Dk2CeZmspTWKdKqSo1iwmqrq2WtRjFlo8aRZYgLX0wFrDXF/9DLA== -"@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" @@ -9943,19 +9938,6 @@ ethers@^6.12.0, ethers@^6.12.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" From 8f79a271817608f456379a91f2defb6e477ee936 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Sat, 18 May 2024 21:16:53 -0400 Subject: [PATCH 66/86] use ethers v6.12.1 --- common/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/package.json b/common/package.json index fe0e1c90e..9e3d72dc2 100644 --- a/common/package.json +++ b/common/package.json @@ -22,7 +22,7 @@ }, "dependencies": { "@openzeppelin/merkle-tree": "^1.0.5", - "ethers": "^6.11.1", + "ethers": "^6.12.1", "maci-crypto": "1.2.2", "maci-domainobjs": "1.2.2" }, From 98611cea39d51e5bcb745de7e8a00946c9abd32b Mon Sep 17 00:00:00 2001 From: yuetloo Date: Sat, 18 May 2024 21:17:56 -0400 Subject: [PATCH 67/86] update for MACI v1.2.2 interface change --- contracts/contracts/MACICommon.sol | 3 -- contracts/contracts/MACIFactory.sol | 1 - contracts/e2e/index.ts | 10 +---- .../tasks/helpers/ConstructorArguments.ts | 1 - contracts/tasks/runners/proveOnChain.ts | 1 - .../tasks/subtasks/clrfund/08-maciFactory.ts | 2 - contracts/utils/testutils.ts | 2 - subgraph/abis/MACIFactory.json | 42 ++++++++++--------- yarn.lock | 13 ------ 9 files changed, 24 insertions(+), 51 deletions(-) diff --git a/contracts/contracts/MACICommon.sol b/contracts/contracts/MACICommon.sol index 05762874e..f41843794 100644 --- a/contracts/contracts/MACICommon.sol +++ b/contracts/contracts/MACICommon.sol @@ -16,9 +16,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 2bccc4655..16a6f6e48 100644 --- a/contracts/contracts/MACIFactory.sol +++ b/contracts/contracts/MACIFactory.sol @@ -41,7 +41,6 @@ contract MACIFactory is Ownable(msg.sender), Params, SnarkCommon, DomainObjs, MA error InvalidVkRegistry(); error InvalidPollFactory(); error InvalidTallyFactory(); - error InvalidSubsidyFactory(); error InvalidMessageProcessorFactory(); error InvalidVerifier(); diff --git a/contracts/e2e/index.ts b/contracts/e2e/index.ts index f3ad49b7c..52d949abe 100644 --- a/contracts/e2e/index.ts +++ b/contracts/e2e/index.ts @@ -16,11 +16,7 @@ import { DEFAULT_GET_LOG_BATCH_SIZE, DEFAULT_SR_QUEUE_OPS, } from '../utils/constants' -import { - getContractAt, - getEventArg, - getQualifiedContractName, -} from '../utils/contracts' +import { getContractAt, getEventArg } from '../utils/contracts' import { deployPoseidonLibraries, deployMaciFactory } from '../utils/testutils' import { getIpfsHash } from '../utils/ipfs' import { @@ -37,7 +33,7 @@ import { DEFAULT_CIRCUIT } from '../utils/circuits' import { MaciParameters } from '../utils/maciParameters' import { existsSync, mkdirSync } from 'fs' import path from 'path' -import { FundingRound, Poll } from '../typechain-types' +import { FundingRound } from '../typechain-types' import { JSONFile } from '../utils/JSONFile' import { EContracts } from '../utils/types' import { getTalyFilePath } from '../utils/misc' @@ -398,7 +394,6 @@ describe('End-to-end Tests', function () { await proveOnChain({ pollId, proofDir: genProofArgs.outputDir, - subsidyEnabled: false, maciAddress, messageProcessorAddress, tallyAddress, @@ -418,7 +413,6 @@ describe('End-to-end Tests', function () { await proveOnChain({ pollId, proofDir: genProofArgs.outputDir, - subsidyEnabled: false, maciAddress, messageProcessorAddress, tallyAddress, diff --git a/contracts/tasks/helpers/ConstructorArguments.ts b/contracts/tasks/helpers/ConstructorArguments.ts index 751a8bbc4..3f77d336b 100644 --- a/contracts/tasks/helpers/ConstructorArguments.ts +++ b/contracts/tasks/helpers/ConstructorArguments.ts @@ -70,7 +70,6 @@ async function getMaciConstructorArguments( maci.pollFactory(), maci.messageProcessorFactory(), maci.tallyFactory(), - maci.subsidyFactory(), maci.signUpGatekeeper(), maci.initialVoiceCreditProxy(), maci.topupCredit(), diff --git a/contracts/tasks/runners/proveOnChain.ts b/contracts/tasks/runners/proveOnChain.ts index af777ed12..40946ba62 100644 --- a/contracts/tasks/runners/proveOnChain.ts +++ b/contracts/tasks/runners/proveOnChain.ts @@ -90,7 +90,6 @@ task('prove-on-chain', 'Prove on chain with the MACI proofs') await proveOnChain({ pollId, proofDir, - subsidyEnabled: false, maciAddress, messageProcessorAddress, tallyAddress, 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/utils/testutils.ts b/contracts/utils/testutils.ts index e423421fd..8a306cf41 100644 --- a/contracts/utils/testutils.ts +++ b/contracts/utils/testutils.ts @@ -128,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, } diff --git a/subgraph/abis/MACIFactory.json b/subgraph/abis/MACIFactory.json index c8ab362b8..7f3ae7c07 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", @@ -52,11 +47,6 @@ "name": "InvalidPollFactory", "type": "error" }, - { - "inputs": [], - "name": "InvalidSubsidyFactory", - "type": "error" - }, { "inputs": [], "name": "InvalidTallyFactory", @@ -77,6 +67,28 @@ "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", @@ -224,11 +236,6 @@ "internalType": "address", "name": "tally", "type": "address" - }, - { - "internalType": "address", - "name": "subsidy", - "type": "address" } ], "internalType": "struct MACI.PollContracts", @@ -253,11 +260,6 @@ "name": "tallyFactory", "type": "address" }, - { - "internalType": "address", - "name": "subsidyFactory", - "type": "address" - }, { "internalType": "address", "name": "messageProcessorFactory", diff --git a/yarn.lock b/yarn.lock index 2e8eb68ed..0f640e5d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9912,19 +9912,6 @@ ethers@^5.0.3, ethers@^5.5.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== - dependencies: - "@adraffy/ens-normalize" "1.10.1" - "@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" - ethers@^6.12.0, ethers@^6.12.1: version "6.12.1" resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.12.1.tgz#517ff6d66d4fd5433e38e903051da3e57c87ff37" From d7173562bede3f5f807d8ecc624a7ba688546614 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Sat, 18 May 2024 22:43:32 -0400 Subject: [PATCH 68/86] fix decode recipient metadata error --- vue-app/src/api/recipient-registry-simple.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vue-app/src/api/recipient-registry-simple.ts b/vue-app/src/api/recipient-registry-simple.ts index 852e85f4c..8b8f581db 100644 --- a/vue-app/src/api/recipient-registry-simple.ts +++ b/vue-app/src/api/recipient-registry-simple.ts @@ -6,6 +6,7 @@ import { provider, ipfsGatewayUrl } from './core' import type { Project } from './projects' import type { RegistryInfo, RecipientApplicationData } from './types' import { formToRecipientData } from './recipient' +import { getNumber } from 'ethers' function decodeRecipientAdded(event: EventLog): Project { const args = event.args as any @@ -28,7 +29,7 @@ function decodeRecipientAdded(event: EventLog): Project { discordUrl: metadata.discordUrl, bannerImageUrl: `${ipfsGatewayUrl}/ipfs/${metadata.bannerImageHash}`, thumbnailImageUrl: `${ipfsGatewayUrl}/ipfs/${metadata.thumbnailImageHash}`, - index: args._index.toNumber(), + index: getNumber(args._index), isHidden: false, isLocked: false, } From 43b161d8b8604e9944672cbba18e2b7b60e4cc7b Mon Sep 17 00:00:00 2001 From: yuetloo Date: Sun, 19 May 2024 20:55:58 -0400 Subject: [PATCH 69/86] remove an issue already fixed in MACI --- docs/tally-verify.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/tally-verify.md b/docs/tally-verify.md index 9ce6bc7dd..080d219c1 100644 --- a/docs/tally-verify.md +++ b/docs/tally-verify.md @@ -87,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. From 30a38a3c856fe044bc63a8cd2d072766f703beb5 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Mon, 20 May 2024 22:10:24 -0400 Subject: [PATCH 70/86] fix incorrect maxContributors, maxMessages and maxVoteOptions --- common/src/utils.ts | 16 +++- contracts/tests/round.ts | 80 ++++++++++++++++--- contracts/utils/maci.ts | 4 +- contracts/utils/testutils.ts | 26 ++++-- subgraph/generated/ClrFund/MACIFactory.ts | 40 ++-------- subgraph/generated/schema.ts | 34 ++++++++ subgraph/schema.graphql | 3 + subgraph/schema.template.graphql | 3 + subgraph/src/ClrFundMapping.ts | 6 ++ vue-app/src/api/round.ts | 22 +++-- vue-app/src/graphql/API.ts | 37 ++++++++- .../src/graphql/queries/GetRoundInfo.graphql | 2 + 12 files changed, 209 insertions(+), 64 deletions(-) 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/tests/round.ts b/contracts/tests/round.ts index 887e9224a..52f0bf12a 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 { @@ -29,11 +31,14 @@ 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)) @@ -66,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 @@ -101,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 @@ -115,7 +147,7 @@ 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) @@ -205,8 +237,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 () => { diff --git a/contracts/utils/maci.ts b/contracts/utils/maci.ts index caa8467ba..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, @@ -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) { diff --git a/contracts/utils/testutils.ts b/contracts/utils/testutils.ts index 8a306cf41..6d80b7a71 100644 --- a/contracts/utils/testutils.ts +++ b/contracts/utils/testutils.ts @@ -169,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], @@ -208,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, diff --git a/subgraph/generated/ClrFund/MACIFactory.ts b/subgraph/generated/ClrFund/MACIFactory.ts index c9f330074..7c1fbe71b 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; } } @@ -269,7 +253,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 +284,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 +312,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 +320,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,7 +338,6 @@ export class MACIFactory extends ethereum.SmartContract { value[0].toAddress(), value[1].toAddress(), value[2].toAddress(), - value[3].toAddress(), ), ); } @@ -534,12 +516,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 +609,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 { diff --git a/subgraph/generated/schema.ts b/subgraph/generated/schema.ts index 97e62f0d3..b3f92c01b 100644 --- a/subgraph/generated/schema.ts +++ b/subgraph/generated/schema.ts @@ -1020,6 +1020,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/schema.graphql b/subgraph/schema.graphql index 147b3225f..3d9b3610a 100644 --- a/subgraph/schema.graphql +++ b/subgraph/schema.graphql @@ -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 index af4e1689d..44b3d2127 100644 --- a/subgraph/schema.template.graphql +++ b/subgraph/schema.template.graphql @@ -85,6 +85,9 @@ type FundingRound @entity { messageTreeDepth: Int voteOptionTreeDepth: Int + maxMessages: BigInt + maxVoteOptions: BigInt + coordinatorPubKeyX: BigInt coordinatorPubKeyY: BigInt coordinator: Bytes diff --git a/subgraph/src/ClrFundMapping.ts b/subgraph/src/ClrFundMapping.ts index f26e32586..85cbe3170 100644 --- a/subgraph/src/ClrFundMapping.ts +++ b/subgraph/src/ClrFundMapping.ts @@ -289,6 +289,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/vue-app/src/api/round.ts b/vue-app/src/api/round.ts index bc724117c..219dbecad 100644 --- a/vue-app/src/api/round.ts +++ b/vue-app/src/api/round.ts @@ -1,6 +1,6 @@ -import { Contract, toNumber, getAddress, hexlify, randomBytes } from 'ethers' +import { Contract, getAddress, hexlify, randomBytes, getNumber } from 'ethers' import { DateTime } from 'luxon' -import { PubKey, type Tally } from '@clrfund/common' +import { PubKey, type Tally, getMaxContributors } from '@clrfund/common' import { FundingRound, Poll } from './abi' import { provider, clrFundContract, isActiveApp } from './core' @@ -174,8 +174,9 @@ export async function getRoundInfo( isFinalized, isCancelled, stateTreeDepth, - messageTreeDepth, voteOptionTreeDepth, + maxMessages: maxMessagesBigInt, + maxVoteOptions: maxVoteOptionsBigInt, startTime: startTimeInSeconds, signUpDeadline: signUpDeadlineInSeconds, votingDeadline: votingDeadlineInSeconds, @@ -193,8 +194,8 @@ export async function getRoundInfo( const nativeTokenSymbol = data.fundingRound.nativeTokenInfo?.symbol || '' const nativeTokenDecimals = Number(data.fundingRound.nativeTokenInfo?.decimals || '') - const maxContributors = stateTreeDepth ? 2 ** stateTreeDepth - 1 : 0 - const maxMessages = messageTreeDepth ? 2 ** messageTreeDepth - 1 : 0 + const maxContributors = getMaxContributors(stateTreeDepth || 0) + const maxMessages = getNumber(maxMessagesBigInt) || 0 const now = DateTime.local() const startTime = DateTime.fromSeconds(Number(startTimeInSeconds || 0)) const signUpDeadline = DateTime.fromSeconds(Number(signUpDeadlineInSeconds || 0)) @@ -217,9 +218,10 @@ export async function getRoundInfo( contributions = contributionsInfo.amount matchingPool = await clrFundContract.getMatchingFunds(nativeTokenAddress) } else { - if (now < signUpDeadline && contributors < maxContributors) { + if (now < votingDeadline && contributors < maxContributors) { status = RoundStatus.Contributing } else if (now < votingDeadline) { + // Too many contributors, do not allow new contributors, allow reallocation only status = RoundStatus.Reallocating } else { status = RoundStatus.Tallying @@ -231,6 +233,10 @@ export async function getRoundInfo( const totalFunds = matchingPool + contributions + // recipient 0 is reserved, so maxRecipients is 1 fewer than the maxVoteOptions + const maxVoteOptions = getNumber(maxVoteOptionsBigInt) + const maxRecipients = maxVoteOptions > 0 ? maxVoteOptions - 1 : 0 + return { fundingRoundAddress, recipientRegistryAddress: getAddress(recipientRegistryAddress), @@ -239,7 +245,7 @@ export async function getRoundInfo( pollId: BigInt(pollId || 0), recipientTreeDepth: voteOptionTreeDepth || 1, maxContributors, - maxRecipients: voteOptionTreeDepth ? 5 ** voteOptionTreeDepth - 1 : 0, + maxRecipients, maxMessages, coordinatorPubKey, nativeTokenAddress: getAddress(nativeTokenAddress), @@ -254,6 +260,6 @@ export async function getRoundInfo( matchingPool, contributions, contributors, - messages: toNumber(messages), + messages: getNumber(messages), } } diff --git a/vue-app/src/graphql/API.ts b/vue-app/src/graphql/API.ts index fc61e9d4f..72b5be6c3 100644 --- a/vue-app/src/graphql/API.ts +++ b/vue-app/src/graphql/API.ts @@ -17,6 +17,7 @@ export type Scalars = { BigInt: any; Bytes: any; Int8: any; + Timestamp: any; }; export enum Aggregation_Interval { @@ -334,6 +335,8 @@ export enum ClrFund_OrderBy { CurrentRoundMaci = 'currentRound__maci', CurrentRoundMaciTxHash = 'currentRound__maciTxHash', CurrentRoundMatchingPoolSize = 'currentRound__matchingPoolSize', + CurrentRoundMaxMessages = 'currentRound__maxMessages', + CurrentRoundMaxVoteOptions = 'currentRound__maxVoteOptions', CurrentRoundMessageTreeDepth = 'currentRound__messageTreeDepth', CurrentRoundNativeToken = 'currentRound__nativeToken', CurrentRoundPollAddress = 'currentRound__pollAddress', @@ -503,6 +506,8 @@ export enum Contribution_OrderBy { FundingRoundMaci = 'fundingRound__maci', FundingRoundMaciTxHash = 'fundingRound__maciTxHash', FundingRoundMatchingPoolSize = 'fundingRound__matchingPoolSize', + FundingRoundMaxMessages = 'fundingRound__maxMessages', + FundingRoundMaxVoteOptions = 'fundingRound__maxVoteOptions', FundingRoundMessageTreeDepth = 'fundingRound__messageTreeDepth', FundingRoundNativeToken = 'fundingRound__nativeToken', FundingRoundPollAddress = 'fundingRound__pollAddress', @@ -1031,6 +1036,8 @@ export enum Donation_OrderBy { FundingRoundMaci = 'fundingRound__maci', FundingRoundMaciTxHash = 'fundingRound__maciTxHash', FundingRoundMatchingPoolSize = 'fundingRound__matchingPoolSize', + FundingRoundMaxMessages = 'fundingRound__maxMessages', + FundingRoundMaxVoteOptions = 'fundingRound__maxVoteOptions', FundingRoundMessageTreeDepth = 'fundingRound__messageTreeDepth', FundingRoundNativeToken = 'fundingRound__nativeToken', FundingRoundPollAddress = 'fundingRound__pollAddress', @@ -1070,6 +1077,8 @@ export type FundingRound = { maci: Maybe; maciTxHash: Maybe; matchingPoolSize: Maybe; + maxMessages: Maybe; + maxVoteOptions: Maybe; messageTreeDepth: Maybe; messages: Maybe>; nativeToken: Maybe; @@ -1303,6 +1312,22 @@ export type FundingRound_Filter = { matchingPoolSize_lte: InputMaybe; matchingPoolSize_not: InputMaybe; matchingPoolSize_not_in: InputMaybe>; + maxMessages: InputMaybe; + maxMessages_gt: InputMaybe; + maxMessages_gte: InputMaybe; + maxMessages_in: InputMaybe>; + maxMessages_lt: InputMaybe; + maxMessages_lte: InputMaybe; + maxMessages_not: InputMaybe; + maxMessages_not_in: InputMaybe>; + maxVoteOptions: InputMaybe; + maxVoteOptions_gt: InputMaybe; + maxVoteOptions_gte: InputMaybe; + maxVoteOptions_in: InputMaybe>; + maxVoteOptions_lt: InputMaybe; + maxVoteOptions_lte: InputMaybe; + maxVoteOptions_not: InputMaybe; + maxVoteOptions_not_in: InputMaybe>; messageTreeDepth: InputMaybe; messageTreeDepth_gt: InputMaybe; messageTreeDepth_gte: InputMaybe; @@ -1524,6 +1549,8 @@ export enum FundingRound_OrderBy { Maci = 'maci', MaciTxHash = 'maciTxHash', MatchingPoolSize = 'matchingPoolSize', + MaxMessages = 'maxMessages', + MaxVoteOptions = 'maxVoteOptions', MessageTreeDepth = 'messageTreeDepth', Messages = 'messages', NativeToken = 'nativeToken', @@ -1728,6 +1755,8 @@ export enum Message_OrderBy { FundingRoundMaci = 'fundingRound__maci', FundingRoundMaciTxHash = 'fundingRound__maciTxHash', FundingRoundMatchingPoolSize = 'fundingRound__matchingPoolSize', + FundingRoundMaxMessages = 'fundingRound__maxMessages', + FundingRoundMaxVoteOptions = 'fundingRound__maxVoteOptions', FundingRoundMessageTreeDepth = 'fundingRound__messageTreeDepth', FundingRoundNativeToken = 'fundingRound__nativeToken', FundingRoundPollAddress = 'fundingRound__pollAddress', @@ -1832,6 +1861,8 @@ export enum Poll_OrderBy { FundingRoundMaci = 'fundingRound__maci', FundingRoundMaciTxHash = 'fundingRound__maciTxHash', FundingRoundMatchingPoolSize = 'fundingRound__matchingPoolSize', + FundingRoundMaxMessages = 'fundingRound__maxMessages', + FundingRoundMaxVoteOptions = 'fundingRound__maxVoteOptions', FundingRoundMessageTreeDepth = 'fundingRound__messageTreeDepth', FundingRoundNativeToken = 'fundingRound__nativeToken', FundingRoundPollAddress = 'fundingRound__pollAddress', @@ -1955,6 +1986,8 @@ export enum PublicKey_OrderBy { FundingRoundMaci = 'fundingRound__maci', FundingRoundMaciTxHash = 'fundingRound__maciTxHash', FundingRoundMatchingPoolSize = 'fundingRound__matchingPoolSize', + FundingRoundMaxMessages = 'fundingRound__maxMessages', + FundingRoundMaxVoteOptions = 'fundingRound__maxVoteOptions', FundingRoundMessageTreeDepth = 'fundingRound__messageTreeDepth', FundingRoundNativeToken = 'fundingRound__nativeToken', FundingRoundPollAddress = 'fundingRound__pollAddress', @@ -3223,7 +3256,7 @@ export type GetRoundInfoQueryVariables = Exact<{ }>; -export type GetRoundInfoQuery = { __typename?: 'Query', fundingRound: { __typename?: 'FundingRound', id: string, maci: any | null, pollId: any | null, pollAddress: any | null, recipientRegistryAddress: any | null, contributorRegistryAddress: any | null, voiceCreditFactor: any | null, isFinalized: boolean | null, isCancelled: boolean | null, contributorCount: any, totalSpent: any | null, matchingPoolSize: any | null, startTime: any | null, signUpDeadline: any | null, votingDeadline: any | null, coordinatorPubKeyX: any | null, coordinatorPubKeyY: any | null, stateTreeDepth: number | null, messageTreeDepth: number | null, voteOptionTreeDepth: number | null, nativeTokenInfo: { __typename?: 'Token', tokenAddress: any | null, symbol: string | null, decimals: any | null } | null } | null }; +export type GetRoundInfoQuery = { __typename?: 'Query', fundingRound: { __typename?: 'FundingRound', id: string, maci: any | null, pollId: any | null, pollAddress: any | null, recipientRegistryAddress: any | null, contributorRegistryAddress: any | null, voiceCreditFactor: any | null, isFinalized: boolean | null, isCancelled: boolean | null, contributorCount: any, totalSpent: any | null, matchingPoolSize: any | null, startTime: any | null, signUpDeadline: any | null, votingDeadline: any | null, coordinatorPubKeyX: any | null, coordinatorPubKeyY: any | null, maxMessages: any | null, maxVoteOptions: any | null, stateTreeDepth: number | null, messageTreeDepth: number | null, voteOptionTreeDepth: number | null, nativeTokenInfo: { __typename?: 'Token', tokenAddress: any | null, symbol: string | null, decimals: any | null } | null } | null }; export type GetRoundsQueryVariables = Exact<{ clrFundAddress: Scalars['String']; @@ -3436,6 +3469,8 @@ export const GetRoundInfoDocument = gql` votingDeadline coordinatorPubKeyX coordinatorPubKeyY + maxMessages + maxVoteOptions stateTreeDepth messageTreeDepth voteOptionTreeDepth diff --git a/vue-app/src/graphql/queries/GetRoundInfo.graphql b/vue-app/src/graphql/queries/GetRoundInfo.graphql index d5995c8ff..73f2cb9fb 100644 --- a/vue-app/src/graphql/queries/GetRoundInfo.graphql +++ b/vue-app/src/graphql/queries/GetRoundInfo.graphql @@ -22,6 +22,8 @@ query GetRoundInfo($fundingRoundAddress: ID!) { votingDeadline coordinatorPubKeyX coordinatorPubKeyY + maxMessages + maxVoteOptions stateTreeDepth messageTreeDepth voteOptionTreeDepth From 465a116bf3dbca77b39c76a7a9532e7290aff822 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Tue, 21 May 2024 19:52:32 -0400 Subject: [PATCH 71/86] votingDuration is obsolete post MACI v1 --- contracts/tasks/runners/exportRound.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/tasks/runners/exportRound.ts b/contracts/tasks/runners/exportRound.ts index 27be1e51b..42c3638f2 100644 --- a/contracts/tasks/runners/exportRound.ts +++ b/contracts/tasks/runners/exportRound.ts @@ -227,7 +227,6 @@ async function getRoundInfo( await pollContract.getDeployTimeAndDuration() startTime = getNumber(roundStartTime) signUpDuration = roundDuration - votingDuration = roundDuration endTime = startTime + getNumber(roundDuration) pollId = await roundContract.pollId() From f9d90abc55db015d719293cffddaa6f35387018e Mon Sep 17 00:00:00 2001 From: yuetloo Date: Tue, 21 May 2024 20:01:13 -0400 Subject: [PATCH 72/86] remove hardcoding of TREE_ARITY as its value can change between MACI versions --- contracts/contracts/ClrFund.sol | 32 ++- contracts/contracts/FundingRound.sol | 33 ++- contracts/contracts/MACICommon.sol | 3 - contracts/contracts/MACIFactory.sol | 25 +- .../contracts/interfaces/IMACIFactory.sol | 5 +- .../recipientRegistry/IRecipientRegistry.sol | 1 + contracts/tasks/index.ts | 1 + contracts/tasks/runners/simulateContribute.ts | 214 ++++++++++++++++++ contracts/tests/deployer.ts | 50 +++- contracts/tests/round.ts | 6 +- contracts/utils/circuits.ts | 10 +- contracts/utils/constants.ts | 1 - contracts/utils/maciParameters.ts | 17 +- subgraph/abis/ClrFund.json | 55 +++-- subgraph/abis/ClrFundDeployer.json | 22 ++ subgraph/abis/FundingRound.json | 83 +++++-- subgraph/abis/MACIFactory.json | 64 ++++-- subgraph/generated/ClrFund/ClrFund.ts | 23 -- subgraph/generated/ClrFund/FundingRound.ts | 19 -- subgraph/generated/ClrFund/MACIFactory.ts | 62 ++--- .../templates/FundingRound/FundingRound.ts | 19 -- .../generated/templates/MACI/FundingRound.ts | 19 -- .../generated/templates/Poll/FundingRound.ts | 19 -- subgraph/src/ClrFundMapping.ts | 2 +- subgraph/src/RecipientRegistry.ts | 19 +- 25 files changed, 531 insertions(+), 273 deletions(-) create mode 100644 contracts/tasks/runners/simulateContribute.ts diff --git a/contracts/contracts/ClrFund.sol b/contracts/contracts/ClrFund.sol index 4f5ad30bc..3927ab2c1 100644 --- a/contracts/contracts/ClrFund.sol +++ b/contracts/contracts/ClrFund.sol @@ -60,8 +60,8 @@ contract ClrFund is OwnableUpgradeable, DomainObjs, Params { error InvalidFundingRoundFactory(); error InvalidMaciFactory(); error RecipientRegistryNotSet(); + error MaxRecipientsNotSet(); error NotInitialized(); - error VoteOptionTreeDepthNotSet(); /** @@ -128,20 +128,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. @@ -155,6 +141,15 @@ contract ClrFund is OwnableUpgradeable, DomainObjs, Params { emit UserRegistryChanged(address(_userRegistry)); } + /** + * @dev Set the max recipients in the recipient registry + */ + function _setMaxRecipients() private { + if (address(maciFactory) == address(0)) revert NotInitialized(); + if (maciFactory.maxRecipients() == 0) revert MaxRecipientsNotSet(); + recipientRegistry.setMaxRecipients(maciFactory.maxRecipients()); + } + /** * @dev Set recipient registry. * @param _recipientRegistry Address of a recipient registry. @@ -163,9 +158,9 @@ contract ClrFund is OwnableUpgradeable, DomainObjs, Params { external onlyOwner { + recipientRegistry = _recipientRegistry; - uint256 maxRecipients = getMaxRecipients(); - recipientRegistry.setMaxRecipients(maxRecipients); + _setMaxRecipients(); emit RecipientRegistryChanged(address(_recipientRegistry)); } @@ -229,8 +224,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); + _setMaxRecipients(); // Deploy funding round and MACI contracts address newRound = roundFactory.deploy(duration, address(this)); diff --git a/contracts/contracts/FundingRound.sol b/contracts/contracts/FundingRound.sol index 9f8fe143b..701872a8f 100644 --- a/contracts/contracts/FundingRound.sol +++ b/contracts/contracts/FundingRound.sol @@ -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 @@ -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/MACICommon.sol b/contracts/contracts/MACICommon.sol index f41843794..01224230b 100644 --- a/contracts/contracts/MACICommon.sol +++ b/contracts/contracts/MACICommon.sol @@ -6,9 +6,6 @@ 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. diff --git a/contracts/contracts/MACIFactory.sol b/contracts/contracts/MACIFactory.sol index 16a6f6e48..f3952280d 100644 --- a/contracts/contracts/MACIFactory.sol +++ b/contracts/contracts/MACIFactory.sol @@ -29,6 +29,8 @@ contract MACIFactory is Ownable(msg.sender), Params, SnarkCommon, DomainObjs, MA // circuit parameters uint8 public stateTreeDepth; TreeDepths public treeDepths; + uint256 public messageBatchSize; + uint256 public maxRecipients; // Events event MaciParametersChanged(); @@ -38,11 +40,15 @@ contract MACIFactory is Ownable(msg.sender), Params, SnarkCommon, DomainObjs, MA error NotInitialized(); error ProcessVkNotSet(); error TallyVkNotSet(); + error VoteOptionTreeDepthNotSet(); error InvalidVkRegistry(); error InvalidPollFactory(); error InvalidTallyFactory(); error InvalidMessageProcessorFactory(); error InvalidVerifier(); + error InvalidMaxRecipients(); + error InvalidMessageBatchSize(); + error InvalidVoteOptionTreeDepth(); constructor( address _vkRegistry, @@ -60,14 +66,6 @@ contract MACIFactory is Ownable(msg.sender), Params, SnarkCommon, DomainObjs, MA 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 */ @@ -122,13 +120,19 @@ contract MACIFactory is Ownable(msg.sender), Params, SnarkCommon, DomainObjs, MA */ 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, @@ -155,6 +159,7 @@ contract MACIFactory is Ownable(msg.sender), Params, SnarkCommon, DomainObjs, MA emit MaciParametersChanged(); } + /** * @dev Deploy new MACI instance. */ @@ -170,8 +175,6 @@ contract MACIFactory is Ownable(msg.sender), Params, SnarkCommon, DomainObjs, MA external returns (MACI _maci, MACI.PollContracts memory _pollContracts) { - uint256 messageBatchSize = getMessageBatchSize(treeDepths.messageTreeSubDepth); - if (!vkRegistry.hasProcessVk( stateTreeDepth, treeDepths.messageTreeDepth, diff --git a/contracts/contracts/interfaces/IMACIFactory.sol b/contracts/contracts/interfaces/IMACIFactory.sol index eacfd7df2..7e207afe8 100644 --- a/contracts/contracts/interfaces/IMACIFactory.sol +++ b/contracts/contracts/interfaces/IMACIFactory.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/IRecipientRegistry.sol b/contracts/contracts/recipientRegistry/IRecipientRegistry.sol index 82fc0c4a9..edfbc5029 100644 --- a/contracts/contracts/recipientRegistry/IRecipientRegistry.sol +++ b/contracts/contracts/recipientRegistry/IRecipientRegistry.sol @@ -17,6 +17,7 @@ pragma solidity 0.8.20; */ 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/tasks/index.ts b/contracts/tasks/index.ts index b25d56890..19050a901 100644 --- a/contracts/tasks/index.ts +++ b/contracts/tasks/index.ts @@ -29,3 +29,4 @@ import './runners/proveOnChain' import './runners/publishTallyResults' import './runners/resetTally' import './runners/maciPubkey' +import './runners/simulateContribute' 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/tests/deployer.ts b/contracts/tests/deployer.ts index bbe8c027a..3eace1611 100644 --- a/contracts/tests/deployer.ts +++ b/contracts/tests/deployer.ts @@ -1,11 +1,11 @@ -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 { ZERO_ADDRESS, UNIT } from '../utils/constants' import { getGasUsage, getEventArg, @@ -18,6 +18,7 @@ import { HardhatEthersSigner } from '@nomicfoundation/hardhat-ethers/signers' import { ClrFund, ClrFundDeployer, + FundingRound, FundingRoundFactory, MACIFactory, Poll, @@ -199,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) ) }) @@ -453,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( @@ -461,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( @@ -474,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 () => { @@ -485,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, @@ -493,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 () => { @@ -503,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, @@ -511,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/round.ts b/contracts/tests/round.ts index 52f0bf12a..fd6e8095b 100644 --- a/contracts/tests/round.ts +++ b/contracts/tests/round.ts @@ -153,6 +153,7 @@ describe('Funding Round', () => { 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( @@ -695,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 }) @@ -1494,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, @@ -1506,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/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/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/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 index 68b32d168..3dd329580 100644 --- a/subgraph/abis/ClrFundDeployer.json +++ b/subgraph/abis/ClrFundDeployer.json @@ -40,6 +40,28 @@ "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": [ 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/MACIFactory.json b/subgraph/abis/MACIFactory.json index 7f3ae7c07..3488fff8d 100644 --- a/subgraph/abis/MACIFactory.json +++ b/subgraph/abis/MACIFactory.json @@ -37,6 +37,16 @@ "stateMutability": "nonpayable", "type": "constructor" }, + { + "inputs": [], + "name": "InvalidMaxRecipients", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidMessageBatchSize", + "type": "error" + }, { "inputs": [], "name": "InvalidMessageProcessorFactory", @@ -62,6 +72,11 @@ "name": "InvalidVkRegistry", "type": "error" }, + { + "inputs": [], + "name": "InvalidVoteOptionTreeDepth", + "type": "error" + }, { "inputs": [], "name": "NotInitialized", @@ -99,6 +114,11 @@ "name": "TallyVkNotSet", "type": "error" }, + { + "inputs": [], + "name": "VoteOptionTreeDepthNotSet", + "type": "error" + }, { "anonymous": false, "inputs": [ @@ -150,19 +170,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "TREE_ARITY", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -270,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" }, { @@ -315,6 +329,16 @@ "name": "_stateTreeDepth", "type": "uint8" }, + { + "internalType": "uint256", + "name": "_messageBatchSize", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxRecipients", + "type": "uint256" + }, { "components": [ { 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/MACIFactory.ts b/subgraph/generated/ClrFund/MACIFactory.ts index 7c1fbe71b..0f6f79fc3 100644 --- a/subgraph/generated/ClrFund/MACIFactory.ts +++ b/subgraph/generated/ClrFund/MACIFactory.ts @@ -227,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, @@ -342,23 +327,40 @@ export class MACIFactory extends ethereum.SmartContract { ); } - 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(); @@ -658,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/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/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/src/ClrFundMapping.ts b/subgraph/src/ClrFundMapping.ts index 85cbe3170..02c978eb3 100644 --- a/subgraph/src/ClrFundMapping.ts +++ b/subgraph/src/ClrFundMapping.ts @@ -132,7 +132,7 @@ function createOrUpdateClrFund( let recipientRegistryId = recipientRegistryAddress.toHexString() let recipientRegistry = RecipientRegistry.load(recipientRegistryId) if (!recipientRegistry) { - createRecipientRegistry(clrFundId, recipientRegistryAddress) + createRecipientRegistry(recipientRegistryAddress) } let contributorRegistryAddress = clrFundContract.userRegistry() 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 From dd028f90cfd12bc28f1c70cf9471b6b2474088e4 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Tue, 21 May 2024 20:27:04 -0400 Subject: [PATCH 73/86] fix incorrect entity id mapping when contract was called from another contract --- subgraph/src/ClrFundDeployerMapping.ts | 2 +- subgraph/src/MACIMapping.ts | 2 +- subgraph/src/PollMapping.ts | 12 ++---------- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/subgraph/src/ClrFundDeployerMapping.ts b/subgraph/src/ClrFundDeployerMapping.ts index c04392dac..840ccf8c8 100644 --- a/subgraph/src/ClrFundDeployerMapping.ts +++ b/subgraph/src/ClrFundDeployerMapping.ts @@ -5,7 +5,7 @@ import { ClrFundDeployer, ClrFund } from '../generated/schema' import { ClrFund as ClrFundTemplate } from '../generated/templates' export function handleNewInstance(event: NewInstance): void { - let clrfundDeployerAddress = event.transaction.to! + let clrfundDeployerAddress = event.address let clrfundDeployerId = clrfundDeployerAddress.toHex() let clrFundDeployer = ClrFundDeployer.load(clrfundDeployerId) diff --git a/subgraph/src/MACIMapping.ts b/subgraph/src/MACIMapping.ts index 75da4929b..e1cbdb28f 100644 --- a/subgraph/src/MACIMapping.ts +++ b/subgraph/src/MACIMapping.ts @@ -21,7 +21,7 @@ import { makePublicKeyId } from './PublicKey' // - contract.verifier(...) export function handleSignUp(event: SignUp): void { - let fundingRoundAddress = event.transaction.to! + let fundingRoundAddress = event.address let fundingRoundId = fundingRoundAddress.toHex() let publicKeyId = makePublicKeyId( diff --git a/subgraph/src/PollMapping.ts b/subgraph/src/PollMapping.ts index 99aa537fb..e3c6fe043 100644 --- a/subgraph/src/PollMapping.ts +++ b/subgraph/src/PollMapping.ts @@ -1,19 +1,11 @@ import { log } from '@graphprotocol/graph-ts' import { PublishMessage } from '../generated/templates/Poll/Poll' -import { FundingRound, Poll, Message, PublicKey } from '../generated/schema' +import { 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 {}', [ From c71e354526fcd549a55437db5686069495365ae0 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Tue, 21 May 2024 21:11:27 -0400 Subject: [PATCH 74/86] update recipient registry address --- subgraph/src/ClrFundMapping.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/subgraph/src/ClrFundMapping.ts b/subgraph/src/ClrFundMapping.ts index 02c978eb3..92f408fdd 100644 --- a/subgraph/src/ClrFundMapping.ts +++ b/subgraph/src/ClrFundMapping.ts @@ -131,7 +131,10 @@ function createOrUpdateClrFund( let recipientRegistryAddress = clrFundContract.recipientRegistry() let recipientRegistryId = recipientRegistryAddress.toHexString() let recipientRegistry = RecipientRegistry.load(recipientRegistryId) - if (!recipientRegistry) { + if (recipientRegistry) { + recipientRegistry.clrFund = clrFundId + recipientRegistry.save() + } else { createRecipientRegistry(recipientRegistryAddress) } From 3d47629493a1a619f1b7d0eba6954c9d39e91a30 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Tue, 21 May 2024 21:30:00 -0400 Subject: [PATCH 75/86] update clrfund with recipient registry address --- subgraph/src/ClrFundMapping.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/subgraph/src/ClrFundMapping.ts b/subgraph/src/ClrFundMapping.ts index 92f408fdd..3e97056c8 100644 --- a/subgraph/src/ClrFundMapping.ts +++ b/subgraph/src/ClrFundMapping.ts @@ -131,12 +131,11 @@ function createOrUpdateClrFund( let recipientRegistryAddress = clrFundContract.recipientRegistry() let recipientRegistryId = recipientRegistryAddress.toHexString() let recipientRegistry = RecipientRegistry.load(recipientRegistryId) - if (recipientRegistry) { - recipientRegistry.clrFund = clrFundId - recipientRegistry.save() - } else { - createRecipientRegistry(recipientRegistryAddress) + if (!recipientRegistry) { + recipientRegistry = createRecipientRegistry(recipientRegistryAddress) } + recipientRegistry.clrFund = clrFundId + recipientRegistry.save() let contributorRegistryAddress = clrFundContract.userRegistry() let contributorRegistryId = contributorRegistryAddress.toHexString() From 729eadcc193df0dc00f7cd975b3cec24d5bf19c3 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Wed, 22 May 2024 11:21:24 -0300 Subject: [PATCH 76/86] refactor code for readability --- contracts/contracts/ClrFund.sol | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/contracts/contracts/ClrFund.sol b/contracts/contracts/ClrFund.sol index 3927ab2c1..499994383 100644 --- a/contracts/contracts/ClrFund.sol +++ b/contracts/contracts/ClrFund.sol @@ -63,6 +63,12 @@ contract ClrFund is OwnableUpgradeable, DomainObjs, Params { error MaxRecipientsNotSet(); error NotInitialized(); + modifier maciFactoryInitialized() { + if (address(maciFactory) == address(0)) revert InvalidMaciFactory(); + if (maciFactory.maxRecipients() == 0) revert MaxRecipientsNotSet(); + _; + } + /** * @dev Initialize clrfund instance with MACI factory and round factory @@ -141,15 +147,6 @@ contract ClrFund is OwnableUpgradeable, DomainObjs, Params { emit UserRegistryChanged(address(_userRegistry)); } - /** - * @dev Set the max recipients in the recipient registry - */ - function _setMaxRecipients() private { - if (address(maciFactory) == address(0)) revert NotInitialized(); - if (maciFactory.maxRecipients() == 0) revert MaxRecipientsNotSet(); - recipientRegistry.setMaxRecipients(maciFactory.maxRecipients()); - } - /** * @dev Set recipient registry. * @param _recipientRegistry Address of a recipient registry. @@ -157,10 +154,13 @@ contract ClrFund is OwnableUpgradeable, DomainObjs, Params { function setRecipientRegistry(IRecipientRegistry _recipientRegistry) external onlyOwner + maciFactoryInitialized { recipientRegistry = _recipientRegistry; - _setMaxRecipients(); + + // Make sure that the max number of recipients is set correctly + recipientRegistry.setMaxRecipients(maciFactory.maxRecipients()); emit RecipientRegistryChanged(address(_recipientRegistry)); } @@ -215,6 +215,7 @@ contract ClrFund is OwnableUpgradeable, DomainObjs, Params { ) external onlyOwner + maciFactoryInitialized { IFundingRound currentRound = getCurrentRound(); if (address(currentRound) != address(0) && !currentRound.isFinalized()) { @@ -224,7 +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 - _setMaxRecipients(); + recipientRegistry.setMaxRecipients(maciFactory.maxRecipients()); // Deploy funding round and MACI contracts address newRound = roundFactory.deploy(duration, address(this)); From 9aea7fe14ca7d286d213b097910c82eccde15693 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Fri, 24 May 2024 12:06:49 -0300 Subject: [PATCH 77/86] fix typescript error by building on the same job --- .github/workflows/create-version.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) 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 }} From 47ae670da2e38bd9dd456c8e6834a6eeb34bd7e8 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Fri, 24 May 2024 12:20:31 -0300 Subject: [PATCH 78/86] remove test common due to mocha error --- .husky/pre-push | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.husky/pre-push b/.husky/pre-push index c0d892312..c0bc1da1c 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -11,4 +11,4 @@ export VITE_RECIPIENT_REGISTRY_TYPE=simple export VITE_USER_REGISTRY_TYPE=simple export VITE_WALLET_CONNECT_PROJECT_ID=1 -yarn test:format && yarn test:common && yarn test:web && yarn test:lint-i18n +yarn test:format && yarn test:web && yarn test:lint-i18n From 418f53b9ba544d5d87136a2f78b2a281f723ec82 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Fri, 24 May 2024 15:25:14 +0000 Subject: [PATCH 79/86] v5.2.1 --- contracts/package.json | 2 +- subgraph/package.json | 2 +- vue-app/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/package.json b/contracts/package.json index 795dc7ef2..6aae0c54a 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -1,6 +1,6 @@ { "name": "@clrfund/contracts", - "version": "5.2.0", + "version": "5.2.1", "license": "GPL-3.0", "scripts": { "hardhat": "hardhat", diff --git a/subgraph/package.json b/subgraph/package.json index 8efc48965..9c47ed39f 100644 --- a/subgraph/package.json +++ b/subgraph/package.json @@ -1,6 +1,6 @@ { "name": "@clrfund/subgraph", - "version": "5.2.0", + "version": "5.2.1", "repository": "https://github.com/clrfund/monorepo/subgraph", "keywords": [ "clr.fund", diff --git a/vue-app/package.json b/vue-app/package.json index 87ff3524f..65410d750 100644 --- a/vue-app/package.json +++ b/vue-app/package.json @@ -1,6 +1,6 @@ { "name": "@clrfund/vue-app", - "version": "5.2.0", + "version": "5.2.1", "private": true, "license": "GPL-3.0", "type": "module", From 58b93b47e4d08bb45bae7f6621c108288a4d6e01 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Fri, 24 May 2024 16:07:29 +0000 Subject: [PATCH 80/86] v6.0.0 --- contracts/package.json | 2 +- subgraph/package.json | 2 +- vue-app/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/package.json b/contracts/package.json index 6aae0c54a..126d0a1ec 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -1,6 +1,6 @@ { "name": "@clrfund/contracts", - "version": "5.2.1", + "version": "6.0.0", "license": "GPL-3.0", "scripts": { "hardhat": "hardhat", diff --git a/subgraph/package.json b/subgraph/package.json index 9c47ed39f..3da61b629 100644 --- a/subgraph/package.json +++ b/subgraph/package.json @@ -1,6 +1,6 @@ { "name": "@clrfund/subgraph", - "version": "5.2.1", + "version": "6.0.0", "repository": "https://github.com/clrfund/monorepo/subgraph", "keywords": [ "clr.fund", diff --git a/vue-app/package.json b/vue-app/package.json index 65410d750..ccd226c26 100644 --- a/vue-app/package.json +++ b/vue-app/package.json @@ -1,6 +1,6 @@ { "name": "@clrfund/vue-app", - "version": "5.2.1", + "version": "6.0.0", "private": true, "license": "GPL-3.0", "type": "module", From 1d8a6eb20bd437524d1a78cb8da96971274470ec Mon Sep 17 00:00:00 2001 From: yuetloo Date: Tue, 4 Jun 2024 00:21:33 -0400 Subject: [PATCH 81/86] fix missing arguments --- contracts/tasks/helpers/ConstructorArguments.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/tasks/helpers/ConstructorArguments.ts b/contracts/tasks/helpers/ConstructorArguments.ts index 3f77d336b..9997e9683 100644 --- a/contracts/tasks/helpers/ConstructorArguments.ts +++ b/contracts/tasks/helpers/ConstructorArguments.ts @@ -150,6 +150,7 @@ async function getTallyConstructorArguments( tallyContract.vkRegistry(), tallyContract.poll(), tallyContract.messageProcessor(), + tallyContract.mode(), ]) return args @@ -174,6 +175,7 @@ async function getMessageProcessorConstructorArguments( messageProcesor.verifier(), messageProcesor.vkRegistry(), messageProcesor.poll(), + messageProcesor.mode(), ]) return args From 29900ee1315e517549513b5f022a244b6fd57019 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Tue, 4 Jun 2024 00:22:24 -0400 Subject: [PATCH 82/86] add missing user and recipient registries --- contracts/tasks/runners/verifyAll.ts | 51 +++++++++++++++++++--------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/contracts/tasks/runners/verifyAll.ts b/contracts/tasks/runners/verifyAll.ts index 74972fe0c..7aa910b72 100644 --- a/contracts/tasks/runners/verifyAll.ts +++ b/contracts/tasks/runners/verifyAll.ts @@ -16,6 +16,7 @@ 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 @@ -138,6 +139,8 @@ async function getContractList( clrfund: string, ethers: HardhatEthersHelpers ): Promise { + const userRegistries = new Set() + const recipientRegistries = new Set() const contractList: ContractInfo[] = [ { name: EContracts.ClrFund, @@ -145,10 +148,11 @@ async function getContractList( }, ] - const clrfundContract = (await ethers.getContractAt( + const clrfundContract = await getContractAt( EContracts.ClrFund, - clrfund - )) as BaseContract as ClrFund + clrfund, + ethers + ) const fundingRoundFactoryAddress = await clrfundContract.roundFactory() if (fundingRoundFactoryAddress !== ZERO_ADDRESS) { @@ -192,6 +196,16 @@ async function getContractList( }) } + 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({ @@ -255,27 +269,32 @@ async function getContractList( // User Registry const userRegistryAddress = await fundingRound.userRegistry() if (userRegistryAddress !== ZERO_ADDRESS) { - const name = await getUserRegistryName(userRegistryAddress, ethers) - contractList.push({ - name, - address: userRegistryAddress, - }) + userRegistries.add(userRegistryAddress) } // Recipient Registry const recipientRegistryAddress = await fundingRound.recipientRegistry() if (recipientRegistryAddress !== ZERO_ADDRESS) { - const name = await getRecipientRegistryName( - recipientRegistryAddress, - ethers - ) - contractList.push({ - name, - address: recipientRegistryAddress, - }) + 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, + }) + } + return contractList } From 1d08b13809c31dd2058219436360e5cd6b03a75f Mon Sep 17 00:00:00 2001 From: yuetloo Date: Tue, 4 Jun 2024 00:22:50 -0400 Subject: [PATCH 83/86] add missing sepolia etherscan url --- contracts/utils/providers/EtherscanProvider.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/utils/providers/EtherscanProvider.ts b/contracts/utils/providers/EtherscanProvider.ts index 8534156ae..047ccdbea 100644 --- a/contracts/utils/providers/EtherscanProvider.ts +++ b/contracts/utils/providers/EtherscanProvider.ts @@ -3,6 +3,7 @@ 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', From 12a46430e0be178de0503ebba73c134752c141ff Mon Sep 17 00:00:00 2001 From: yuetloo Date: Tue, 4 Jun 2024 03:27:26 -0400 Subject: [PATCH 84/86] fix reallocation error due to incorrect subgraph mapping for public key --- subgraph/generated/schema.ts | 14 ++-- subgraph/schema.graphql | 2 +- subgraph/schema.template.graphql | 2 +- subgraph/src/MACIMapping.ts | 15 +--- subgraph/src/PollMapping.ts | 21 +++-- subgraph/src/PublicKey.ts | 8 +- vue-app/src/api/contributions.ts | 15 ++-- vue-app/src/graphql/API.ts | 81 ++++++------------- .../queries/GetContributorIndex.graphql | 3 +- vue-app/src/stores/app.ts | 2 +- 10 files changed, 63 insertions(+), 100 deletions(-) diff --git a/subgraph/generated/schema.ts b/subgraph/generated/schema.ts index b3f92c01b..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 { diff --git a/subgraph/schema.graphql b/subgraph/schema.graphql index 3d9b3610a..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! diff --git a/subgraph/schema.template.graphql b/subgraph/schema.template.graphql index 44b3d2127..e8f1db50d 100644 --- a/subgraph/schema.template.graphql +++ b/subgraph/schema.template.graphql @@ -49,7 +49,7 @@ type Message @entity { type PublicKey @entity { id: ID! - fundingRound: FundingRound + maci: String! messages: [Message!] @derivedFrom(field: "publicKey") x: BigInt! y: BigInt! diff --git a/subgraph/src/MACIMapping.ts b/subgraph/src/MACIMapping.ts index e1cbdb28f..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.address - 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 e3c6fe043..e566813e6 100644 --- a/subgraph/src/PollMapping.ts +++ b/subgraph/src/PollMapping.ts @@ -1,7 +1,7 @@ import { log } from '@graphprotocol/graph-ts' import { PublishMessage } from '../generated/templates/Poll/Poll' -import { Poll, Message, PublicKey } from '../generated/schema' +import { FundingRound, Poll, Message, PublicKey } from '../generated/schema' import { makePublicKeyId } from './PublicKey' export function handlePublishMessage(event: PublishMessage): void { @@ -17,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() + '-' + @@ -37,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 ) @@ -48,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/vue-app/src/api/contributions.ts b/vue-app/src/api/contributions.ts index 5e0618447..d25775dd2 100644 --- a/vue-app/src/api/contributions.ts +++ b/vue-app/src/api/contributions.ts @@ -27,13 +27,13 @@ export interface Contributor { /** * get the id of the subgraph public key entity from the pubKey value - * @param fundingRoundAddress funding round address + * @param maciAddress MACI address * @param pubKey MACI public key * @returns the id for the subgraph public key entity */ -function getPubKeyId(fundingRoundAddress = '', pubKey: PubKey): string { +function getPubKeyId(maciAddress = '', pubKey: PubKey): string { const pubKeyPair = pubKey.asContractParam() - return id(fundingRoundAddress.toLowerCase() + '.' + pubKeyPair.x + '.' + pubKeyPair.y) + return id(maciAddress.toLowerCase() + '.' + pubKeyPair.x + '.' + pubKeyPair.y) } export function getCartStorageKey(roundAddress: string): string { @@ -141,17 +141,16 @@ export function isContributionAmountValid(value: string, currentRound: RoundInfo /** * Get the MACI contributor state index - * @param fundingRoundAddress Funding round contract address + * @param maciAddress MACI contract address * @param pubKey Contributor public key * @returns Contributor stateIndex returned from MACI */ -export async function getContributorIndex(fundingRoundAddress: string, pubKey: PubKey): Promise { - if (!fundingRoundAddress) { +export async function getContributorIndex(maciAddress: string, pubKey: PubKey): Promise { + if (!maciAddress) { return null } - const id = getPubKeyId(fundingRoundAddress, pubKey) + const id = getPubKeyId(maciAddress, pubKey) const data = await sdk.GetContributorIndex({ - fundingRoundAddress: fundingRoundAddress.toLowerCase(), publicKeyId: id, }) diff --git a/vue-app/src/graphql/API.ts b/vue-app/src/graphql/API.ts index 72b5be6c3..121c59320 100644 --- a/vue-app/src/graphql/API.ts +++ b/vue-app/src/graphql/API.ts @@ -1778,6 +1778,7 @@ export enum Message_OrderBy { PollId = 'poll__id', PublicKey = 'publicKey', PublicKeyId = 'publicKey__id', + PublicKeyMaci = 'publicKey__maci', PublicKeyStateIndex = 'publicKey__stateIndex', PublicKeyVoiceCreditBalance = 'publicKey__voiceCreditBalance', PublicKeyX = 'publicKey__x', @@ -1884,8 +1885,8 @@ export enum Poll_OrderBy { export type PublicKey = { __typename?: 'PublicKey'; - fundingRound: Maybe; id: Scalars['ID']; + maci: Scalars['String']; messages: Maybe>; stateIndex: Maybe; voiceCreditBalance: Maybe; @@ -1906,27 +1907,6 @@ export type PublicKey_Filter = { /** Filter for the block changed event. */ _change_block: InputMaybe; and: InputMaybe>>; - fundingRound: InputMaybe; - fundingRound_: InputMaybe; - fundingRound_contains: InputMaybe; - fundingRound_contains_nocase: InputMaybe; - fundingRound_ends_with: InputMaybe; - fundingRound_ends_with_nocase: InputMaybe; - fundingRound_gt: InputMaybe; - fundingRound_gte: InputMaybe; - fundingRound_in: InputMaybe>; - fundingRound_lt: InputMaybe; - fundingRound_lte: InputMaybe; - fundingRound_not: InputMaybe; - fundingRound_not_contains: InputMaybe; - fundingRound_not_contains_nocase: InputMaybe; - fundingRound_not_ends_with: InputMaybe; - fundingRound_not_ends_with_nocase: InputMaybe; - fundingRound_not_in: InputMaybe>; - fundingRound_not_starts_with: InputMaybe; - fundingRound_not_starts_with_nocase: InputMaybe; - fundingRound_starts_with: InputMaybe; - fundingRound_starts_with_nocase: InputMaybe; id: InputMaybe; id_gt: InputMaybe; id_gte: InputMaybe; @@ -1935,6 +1915,26 @@ export type PublicKey_Filter = { id_lte: InputMaybe; id_not: InputMaybe; id_not_in: InputMaybe>; + maci: InputMaybe; + maci_contains: InputMaybe; + maci_contains_nocase: InputMaybe; + maci_ends_with: InputMaybe; + maci_ends_with_nocase: InputMaybe; + maci_gt: InputMaybe; + maci_gte: InputMaybe; + maci_in: InputMaybe>; + maci_lt: InputMaybe; + maci_lte: InputMaybe; + maci_not: InputMaybe; + maci_not_contains: InputMaybe; + maci_not_contains_nocase: InputMaybe; + maci_not_ends_with: InputMaybe; + maci_not_ends_with_nocase: InputMaybe; + maci_not_in: InputMaybe>; + maci_not_starts_with: InputMaybe; + maci_not_starts_with_nocase: InputMaybe; + maci_starts_with: InputMaybe; + maci_starts_with_nocase: InputMaybe; messages_: InputMaybe; or: InputMaybe>>; stateIndex: InputMaybe; @@ -1972,38 +1972,8 @@ export type PublicKey_Filter = { }; export enum PublicKey_OrderBy { - FundingRound = 'fundingRound', - FundingRoundContributorCount = 'fundingRound__contributorCount', - FundingRoundContributorRegistryAddress = 'fundingRound__contributorRegistryAddress', - FundingRoundCoordinator = 'fundingRound__coordinator', - FundingRoundCoordinatorPubKeyX = 'fundingRound__coordinatorPubKeyX', - FundingRoundCoordinatorPubKeyY = 'fundingRound__coordinatorPubKeyY', - FundingRoundCreatedAt = 'fundingRound__createdAt', - FundingRoundId = 'fundingRound__id', - FundingRoundIsCancelled = 'fundingRound__isCancelled', - FundingRoundIsFinalized = 'fundingRound__isFinalized', - FundingRoundLastUpdatedAt = 'fundingRound__lastUpdatedAt', - FundingRoundMaci = 'fundingRound__maci', - FundingRoundMaciTxHash = 'fundingRound__maciTxHash', - FundingRoundMatchingPoolSize = 'fundingRound__matchingPoolSize', - FundingRoundMaxMessages = 'fundingRound__maxMessages', - FundingRoundMaxVoteOptions = 'fundingRound__maxVoteOptions', - FundingRoundMessageTreeDepth = 'fundingRound__messageTreeDepth', - FundingRoundNativeToken = 'fundingRound__nativeToken', - FundingRoundPollAddress = 'fundingRound__pollAddress', - FundingRoundPollId = 'fundingRound__pollId', - FundingRoundRecipientCount = 'fundingRound__recipientCount', - FundingRoundRecipientRegistryAddress = 'fundingRound__recipientRegistryAddress', - FundingRoundSignUpDeadline = 'fundingRound__signUpDeadline', - FundingRoundStartTime = 'fundingRound__startTime', - FundingRoundStateTreeDepth = 'fundingRound__stateTreeDepth', - FundingRoundTallyHash = 'fundingRound__tallyHash', - FundingRoundTotalSpent = 'fundingRound__totalSpent', - FundingRoundTotalVotes = 'fundingRound__totalVotes', - FundingRoundVoiceCreditFactor = 'fundingRound__voiceCreditFactor', - FundingRoundVoteOptionTreeDepth = 'fundingRound__voteOptionTreeDepth', - FundingRoundVotingDeadline = 'fundingRound__votingDeadline', Id = 'id', + Maci = 'maci', Messages = 'messages', StateIndex = 'stateIndex', VoiceCreditBalance = 'voiceCreditBalance', @@ -3170,7 +3140,6 @@ export type GetContributionsAmountQueryVariables = Exact<{ export type GetContributionsAmountQuery = { __typename?: 'Query', contributions: Array<{ __typename?: 'Contribution', amount: any | null }> }; export type GetContributorIndexQueryVariables = Exact<{ - fundingRoundAddress: Scalars['String']; publicKeyId: Scalars['ID']; }>; @@ -3303,8 +3272,8 @@ export const GetContributionsAmountDocument = gql` } `; export const GetContributorIndexDocument = gql` - query GetContributorIndex($fundingRoundAddress: String!, $publicKeyId: ID!) { - publicKeys(where: {id: $publicKeyId, fundingRound: $fundingRoundAddress}) { + query GetContributorIndex($publicKeyId: ID!) { + publicKeys(where: {id: $publicKeyId}) { id stateIndex } diff --git a/vue-app/src/graphql/queries/GetContributorIndex.graphql b/vue-app/src/graphql/queries/GetContributorIndex.graphql index c3954dac6..d240e6b13 100644 --- a/vue-app/src/graphql/queries/GetContributorIndex.graphql +++ b/vue-app/src/graphql/queries/GetContributorIndex.graphql @@ -1,8 +1,7 @@ query GetContributorIndex( - $fundingRoundAddress: String! $publicKeyId: ID! ) { - publicKeys(where: {id: $publicKeyId, fundingRound: $fundingRoundAddress}) { + publicKeys(where: {id: $publicKeyId}) { id stateIndex } diff --git a/vue-app/src/stores/app.ts b/vue-app/src/stores/app.ts index d977e04b7..65b7fc494 100644 --- a/vue-app/src/stores/app.ts +++ b/vue-app/src/stores/app.ts @@ -458,7 +458,7 @@ export const useAppStore = defineStore('app', { } const contributorKeypair = Keypair.createFromSeed(userStore.currentUser.encryptionKey) - const stateIndex = await getContributorIndex(this.currentRound.fundingRoundAddress, contributorKeypair.pubKey) + const stateIndex = await getContributorIndex(this.currentRound.maciAddress, contributorKeypair.pubKey) if (!stateIndex) { // if no contributor index, user has not contributed From 07644d2d6d88436a26408f4ac0a379203421f8f9 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Tue, 4 Jun 2024 09:12:33 -0400 Subject: [PATCH 85/86] generate subgraph pubKeyId using maciAddress --- vue-app/src/api/cart.ts | 5 ++--- vue-app/src/api/contributions.ts | 11 +++++------ vue-app/src/graphql/API.ts | 5 ++--- .../graphql/queries/GetContributorMessages.graphql | 2 -- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/vue-app/src/api/cart.ts b/vue-app/src/api/cart.ts index c95993530..fd5c3ca62 100644 --- a/vue-app/src/api/cart.ts +++ b/vue-app/src/api/cart.ts @@ -17,15 +17,14 @@ export async function getCommittedCart( encryptionKey: string, contributorAddress: string, ): Promise { - const { coordinatorPubKey, fundingRoundAddress, voiceCreditFactor, nativeTokenDecimals, recipientRegistryAddress } = - round + const { coordinatorPubKey, maciAddress, voiceCreditFactor, nativeTokenDecimals, recipientRegistryAddress } = round const encKeypair = await Keypair.createFromSeed(encryptionKey) const sharedKey = Keypair.genEcdhSharedKey(encKeypair.privKey, coordinatorPubKey) const messages = await getContributorMessages({ - fundingRoundAddress, + maciAddress, contributorKey: encKeypair, coordinatorPubKey, contributorAddress, diff --git a/vue-app/src/api/contributions.ts b/vue-app/src/api/contributions.ts index d25775dd2..a6aed99ef 100644 --- a/vue-app/src/api/contributions.ts +++ b/vue-app/src/api/contributions.ts @@ -177,29 +177,28 @@ function getMaciMessage(type: any, data: any[] | null): Message { /** * Get the latest set of vote messages submitted by contributor - * @param fundingRoundAddress Funding round contract address + * @param maciAddress MACI contract address * @param contributorKey Contributor key used to encrypt messages * @param coordinatorPubKey Coordinator public key * @returns MACI messages */ export async function getContributorMessages({ - fundingRoundAddress, + maciAddress, contributorKey, coordinatorPubKey, contributorAddress, }: { - fundingRoundAddress: string + maciAddress: string contributorKey: Keypair coordinatorPubKey: PubKey contributorAddress: string }): Promise { - if (!fundingRoundAddress) { + if (!maciAddress) { return [] } - const key = getPubKeyId(fundingRoundAddress, contributorKey.pubKey) + const key = getPubKeyId(maciAddress, contributorKey.pubKey) const result = await sdk.GetContributorMessages({ - fundingRoundAddress: fundingRoundAddress.toLowerCase(), pubKey: key, contributorAddress: contributorAddress.toLowerCase(), }) diff --git a/vue-app/src/graphql/API.ts b/vue-app/src/graphql/API.ts index 121c59320..36ba4ad46 100644 --- a/vue-app/src/graphql/API.ts +++ b/vue-app/src/graphql/API.ts @@ -3147,7 +3147,6 @@ export type GetContributorIndexQueryVariables = Exact<{ export type GetContributorIndexQuery = { __typename?: 'Query', publicKeys: Array<{ __typename?: 'PublicKey', id: string, stateIndex: any | null }> }; export type GetContributorMessagesQueryVariables = Exact<{ - fundingRoundAddress: Scalars['String']; pubKey: Scalars['String']; contributorAddress: Scalars['Bytes']; }>; @@ -3280,9 +3279,9 @@ export const GetContributorIndexDocument = gql` } `; export const GetContributorMessagesDocument = gql` - query GetContributorMessages($fundingRoundAddress: String!, $pubKey: String!, $contributorAddress: Bytes!) { + query GetContributorMessages($pubKey: String!, $contributorAddress: Bytes!) { messages( - where: {fundingRound: $fundingRoundAddress, publicKey: $pubKey, submittedBy: $contributorAddress} + where: {publicKey: $pubKey, submittedBy: $contributorAddress} first: 1000 orderBy: blockNumber orderDirection: desc diff --git a/vue-app/src/graphql/queries/GetContributorMessages.graphql b/vue-app/src/graphql/queries/GetContributorMessages.graphql index d163b923b..5a3acbac4 100644 --- a/vue-app/src/graphql/queries/GetContributorMessages.graphql +++ b/vue-app/src/graphql/queries/GetContributorMessages.graphql @@ -1,11 +1,9 @@ query GetContributorMessages( - $fundingRoundAddress: String! $pubKey: String! $contributorAddress: Bytes! ) { messages( where: { - fundingRound: $fundingRoundAddress, publicKey: $pubKey, submittedBy: $contributorAddress }, From 65dc41ba450850e05b18349f8aeca288662f60f8 Mon Sep 17 00:00:00 2001 From: yuetloo Date: Tue, 4 Jun 2024 09:16:29 -0400 Subject: [PATCH 86/86] remove incorrect subgraph id calculation --- contracts/tasks/runners/maciPubkey.ts | 4 ---- 1 file changed, 4 deletions(-) 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}`) } })