diff --git a/README.md b/README.md index fb2965b23..2ed33f01b 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ In a future version, we plan to address this by routing ETH and token contributi - [How to tally votes](docs/coordinator.md) - [How to verify results](docs/trusted-setup.md) - [Running the subgraph](docs/subgraph.md) +- [Deployment](docs/deployment.md) ## Development diff --git a/contracts/.env.example b/contracts/.env.example index 02a201220..c3d5100d8 100644 --- a/contracts/.env.example +++ b/contracts/.env.example @@ -8,12 +8,18 @@ BRIGHTID_CONTEXT=clr.fund # BrightId node addr that signs verifications. Node One uses this one BRIGHTID_VERIFIER_ADDR=0xb1d71F62bEe34E9Fc349234C201090c33BCdF6DB -RINKEBY_JSONRPC_HTTP_URL=https://eth-rinkeby.alchemyapi.io/v2/ADD_API_KEY -XDAI_JSONRPC_HTTP_URL=https://rpc.xdaichain.com -RINKARBY_JSONRPC_HTTP_URL= +# JSON-RPC endpoint to the selected network +JSONRPC_HTTP_URL=https://eth-rinkeby.alchemyapi.io/v2/ADD_API_KEY +# One of the two options WALLET_MNEMONIC= WALLET_PRIVATE_KEY= # Token address for funding round .setToken NATIVE_TOKEN_ADDRESS= + +# Required to use in the tally and finalize scripts +FACTORY_ADDRESS= +ROUND_ADDRESS= +COORDINATOR_PK= +COORDINATOR_ETH_PK= \ No newline at end of file diff --git a/contracts/hardhat.config.ts b/contracts/hardhat.config.ts index b159f0bcc..7db976b3b 100644 --- a/contracts/hardhat.config.ts +++ b/contracts/hardhat.config.ts @@ -10,8 +10,16 @@ import 'hardhat-contract-sizer' dotenv.config() const GAS_LIMIT = 20000000 -const WALLET_MNEMONIC = process.env.WALLET_MNEMONIC || '' -const WALLET_PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY || undefined +const WALLET_MNEMONIC = process.env.WALLET_MNEMONIC +const WALLET_PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY + +let accounts +if (WALLET_MNEMONIC) { + accounts = { mnemonic: WALLET_MNEMONIC } +} +if (WALLET_PRIVATE_KEY) { + accounts = [WALLET_PRIVATE_KEY] +} const config: HardhatUserConfig = { networks: { @@ -31,17 +39,21 @@ const config: HardhatUserConfig = { gasLimit: GAS_LIMIT, } as any, rinkeby: { - url: process.env.RINKEBY_JSONRPC_HTTP_URL || 'http://127.0.0.1:8545', - accounts: WALLET_PRIVATE_KEY ? [WALLET_PRIVATE_KEY] : 'remote', + url: process.env.JSONRPC_HTTP_URL || 'http://127.0.0.1:8545', + accounts, }, xdai: { - url: process.env.XDAI_JSONRPC_HTTP_URL || 'https://rpc.xdaichain.com', + url: process.env.JSONRPC_HTTP_URL || 'https://rpc.xdaichain.com', timeout: 60000, - accounts: { mnemonic: WALLET_MNEMONIC }, + accounts, }, rinkarby: { - url: process.env.RINKARBY_JSONRPC_HTTP_URL || 'http://127.0.0.1:8545', - accounts: { mnemonic: WALLET_MNEMONIC }, + url: process.env.JSONRPC_HTTP_URL || 'https://rinkeby.arbitrum.io/rpc', + accounts, + }, + arbitrum: { + url: process.env.JSONRPC_HTTP_URL || 'https://arb1.arbitrum.io/rpc', + accounts, }, }, paths: { diff --git a/contracts/package.json b/contracts/package.json index 779699612..93cb21fa4 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -7,6 +7,7 @@ "build": "hardhat compile", "node": "hardhat node --port 18545 --hostname 0.0.0.0", "deploy:local": "yarn clean && yarn build && hardhat run --network localhost scripts/deploy.ts", + "deploy:arbitrum": "hardhat run --network arbitrum scripts/deployRound.ts", "deployTestRound:local": "hardhat run --network localhost scripts/deployTestRound.ts", "contribute:local": "hardhat run --network localhost scripts/contribute.ts", "vote:local": "hardhat run --network localhost scripts/vote.ts", diff --git a/contracts/scripts/finalize.ts b/contracts/scripts/finalize.ts index 0745bb483..6242866b4 100644 --- a/contracts/scripts/finalize.ts +++ b/contracts/scripts/finalize.ts @@ -1,18 +1,31 @@ import fs from 'fs' -import { ethers } from 'hardhat' +import { Wallet } from 'ethers' +import { ethers, network } from 'hardhat' async function main() { - const [deployer] = await ethers.getSigners() - const state = JSON.parse(fs.readFileSync('state.json').toString()) + let factoryAddress, coordinator + if (network.name === 'localhost') { + const state = JSON.parse(fs.readFileSync('state.json').toString()) + factoryAddress = state.factory + + const signers = await ethers.getSigners() + coordinator = signers[1] + } else { + factoryAddress = process.env.FACTORY_ADDRESS || '' + const coordinatorEthPrivKey = process.env.COORDINATOR_ETH_PK || '' + coordinator = new Wallet(coordinatorEthPrivKey, ethers.provider) + } + const tally = JSON.parse(fs.readFileSync('tally.json').toString()) const factory = await ethers.getContractAt( 'FundingRoundFactory', - state.factory, - deployer + factoryAddress, + coordinator ) const totalSpent = parseInt(tally.totalVoiceCredits.spent) const totalSpentSalt = tally.totalVoiceCredits.salt - await factory.transferMatchingFunds(totalSpent, totalSpentSalt) + const tx = await factory.transferMatchingFunds(totalSpent, totalSpentSalt) + await tx.wait() console.log('Round finalized, totals verified.') } diff --git a/docs/coordinator.md b/docs/coordinator.md index 19d0d44cc..3530def10 100644 --- a/docs/coordinator.md +++ b/docs/coordinator.md @@ -2,24 +2,27 @@ ## Coordinate using MACI CLI -Clone the [MACI repo](https://github.com/appliedzkp/maci/) and switch to version v0.9.4: +Clone the [MACI repo](https://github.com/appliedzkp/maci/) and switch to version v0.10.1: ``` git clone https://github.com/appliedzkp/maci.git cd maci/ -git checkout v0.9.4 +git checkout v0.10.1 ``` Follow instructions in README.md to install necessary dependencies. ### Medium Circuits + Download [zkSNARK parameters](https://gateway.pinata.cloud/ipfs/QmRzp3vkFPNHPpXiu7iKpPqVnZB97wq7gyih2mp6pa5bmD) for 'medium' circuits into `circuits/params/` directory and rebuild the keys: ``` cd circuits ./scripts/buildSnarksMedium.sh ``` + ### x32 Circuits + Download [zkSNARK parameters](https://gateway.pinata.cloud/ipfs/QmWSxPBNYDtsK23KwYdMtcDaJg3gWS3LBsqMnENrVG6nmc) for 'x32' circuits into `circuits/params/` directory and rebuild the keys: ``` @@ -45,14 +48,25 @@ A single key can be used to coordinate multiple rounds. ### Tally votes -Decrypt messages and tally the votes: +Download the logs: ``` cd ../cli -node build/index.js genProofs \ - --eth-provider \ - --contract \ - --privkey \ +node build/index.js fetchLogs \ + --eth-provider \ + --contract \ + --start-block \ + --num-blocks-per-request \ + --output logs +``` + +Decrypt messages and tally the votes: + +``` +node build/index.js proveOnChain \ + --eth-provider \ + --contract \ + --privkey \ --output proofs.json \ --tally-file tally.json ``` @@ -79,6 +93,38 @@ Finally, the [CID](https://ipfs.io/ipns/docs.ipfs.io/concepts/content-addressing await fundingRound.publishTallyHash('') ``` +## Coordinate using Docker + +In case you are in a different OS than Linux, you can run all the previous MACI CLI commands by running the Docker image located in the MACI repo. + +**Note:** the [x32 params](https://gateway.pinata.cloud/ipfs/QmWSxPBNYDtsK23KwYdMtcDaJg3gWS3LBsqMnENrVG6nmc) have been tested using Ubuntu 21.04 + Node 15.8.0. + +### Use the docker image + +First, install [docker](https://docs.docker.com/engine/install/) and [docker-componse](https://docs.docker.com/compose/install/) + +Inside the maci repo, run: + +``` +docker-componse up +``` + +Once the container is built, in a different terminal, grab the container id: + +``` +docker container ls +``` + +Get inside the container and execute the scripts you want: + +``` +docker exec -it {CONTAINER_ID} bash + +# inside the container +cd cli/ +node build/index.js genProofs ... +``` + ## Coordinate using clrfund scripts ### Generate coordinator key @@ -112,10 +158,43 @@ Set the path to downloaded parameter files and also the path to `zkutil` binary export NODE_CONFIG='{"snarkParamsPath": "../../../contracts/snark-params/", "zkutil_bin": "/usr/bin/zkutil"}' ``` +Set the following env vars in `.env`: + +``` +ROUND_ADDRESS= +COORDINATOR_PK= +COORDINATOR_ETH_PK= +``` + Decrypt messages and tally the votes: ``` -COORDINATOR_PK= COORDINATOR_ETH_PK= ROUND_ADDRESS= yarn hardhat run --network xdai scripts/tally.ts +yarn hardhat run --network {network} scripts/tally.ts ``` Result will be saved to `tally.json` file, which must then be published via IPFS. + +**Using [command line](https://docs.ipfs.io/reference/cli/)** + +``` +# 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 +``` + +### Finalize round + +Make sure you have the following env vars in `.env`. Ignore this if you are running a local test round in `localhost`, the script will know these values itself. + +``` +FACTORY_ADDRESS= +COORDINATOR_ETH_PK= +``` + +Once you have the `tally.json` from the tally script, run: + +``` +yarn hardhat run --network {network} scripts/finalize.ts +``` diff --git a/docs/deployment.md b/docs/deployment.md new file mode 100644 index 000000000..e0a584177 --- /dev/null +++ b/docs/deployment.md @@ -0,0 +1,40 @@ +# Deploy to a network + +## Using the deployment scripts + +### x32 Circuits + +Download the [zkSNARK contracts](https://gateway.pinata.cloud/ipfs/QmWSxPBNYDtsK23KwYdMtcDaJg3gWS3LBsqMnENrVG6nmc) for 'x32' circuits and copy them into `/contracts/contracts/snarkVerifiers`. + +- `BatchUpdateStateTreeVerifier32.sol` +- `QuadVoteTallyVerifier32.sol` + +### Edit the `/contracts/.env` file + +E.g. + +``` +RECIPIENT_REGISTRY_TYPE=simple +USER_REGISTRY_TYPE=brightid +BRIGHTID_CONTEXT=clr.fund.test +BRIGHTID_VERIFIER_ADDR=0xb1d71F62bEe34E9Fc349234C201090c33BCdF6DB +JSONRPC_HTTP_URL=https://NETWORK.alchemyapi.io/v2/ADD_API_KEY +WALLET_PRIVATE_KEY= +NATIVE_TOKEN_ADDRESS= +``` + +### Run the deploy script + +1. Adjust the `/contracts/scripts/deployRound.ts` as you wish. By default, it will deploy a new round with two random recipients. +2. Run `npx hardhat run --network {network} scripts/deployRound.ts` or use one of the `yarn deploy:{network}` available in `/contracts/package.json`. + +### Deploy the subgraph + +Currently, we are using the [Hosted Service](https://thegraph.com/docs/en/hosted-service/what-is-hosted-service/). First, check out the official instructions to authenicate using the Graph CLI https://thegraph.com/docs/legacyexplorer/deploy-subgraph-hosted and create a new subgraph. + +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` + - Run `yarn prepare:{network}` +2. Deploy it by running `graph deploy --product hosted-service USERNAME/SUBGRAPH` diff --git a/docs/subgraph.md b/docs/subgraph.md index 2053afb8c..2d38823df 100644 --- a/docs/subgraph.md +++ b/docs/subgraph.md @@ -69,12 +69,3 @@ yarn start:subgraph - **M1 Macbook Error**: When using docker with the M1 Apple products you will need to use a different image in the docker-compose. Fix found here: https://github.com/graphprotocol/graph-node/issues/2325. To implement fix, go to `docker-compose.yml` in `cd graph-node/docker` and change the `image` to: `image: graphprotocol/graph-node:2c23cce` for the graph-node service - **Subgraph Queries returning null**: Check that your .env is setup properly with the right VUE_APP_SUBGRAPH_URL. If locally developing use: VUE_APP_SUBGRAPH_URL=http://localhost:8000/subgraphs/name/daodesigner/clrfund - -# Deployment - -Currently, we are using the Hosted Service. First, check out the official instructions to authenicate using the Graph CLI https://thegraph.com/docs/legacyexplorer/deploy-subgraph-hosted - -1. Prepare the `subgraph.yaml` with the correct network data - - Update the JSON file that you want to use, located in `/subgraph/config` - - Inside the `/subgraph` folder, run `yarn prepare:{network}` -2. Run `yarn deploy:subgraph` diff --git a/docs/trusted-setup.md b/docs/trusted-setup.md index 2b14715e9..3c3be55f8 100644 --- a/docs/trusted-setup.md +++ b/docs/trusted-setup.md @@ -4,12 +4,12 @@ ### Verify using MACI CLI -Clone the [MACI repo](https://github.com/appliedzkp/maci/) and switch to version v0.9.4: +Clone the [MACI repo](https://github.com/appliedzkp/maci/) and switch to version v0.10.1: ``` git clone https://github.com/appliedzkp/maci.git cd maci/ -git checkout v0.9.4 +git checkout v0.10.1 ``` Follow instructions in README.md to install necessary dependencies. @@ -44,10 +44,21 @@ cd ../contracts npm run compileSol ``` -Generate proofs: +Download the logs: ``` cd cli +node build/index.js fetchLogs \ + --eth-provider \ + --contract \ + --start-block \ + --num-blocks-per-request \ + --output logs +``` + +Generate proofs: + +``` node build/index.js genProofs \ --eth-provider \ --contract \ @@ -77,6 +88,12 @@ Download [zkSNARK parameters](https://gateway.pinata.cloud/ipfs/QmRzp3vkFPNHPpXi ipfs get --output snark-params QmRzp3vkFPNHPpXiu7iKpPqVnZB97wq7gyih2mp6pa5bmD ``` +Or download [zkSNARK parameters](https://gateway.pinata.cloud/ipfs/QmWSxPBNYDtsK23KwYdMtcDaJg3gWS3LBsqMnENrVG6nmc) for 'x32' circuits to `snark-params` directory. Example: + +``` +ipfs get --output snark-params QmWSxPBNYDtsK23KwYdMtcDaJg3gWS3LBsqMnENrVG6nmc +``` + Set the path to downloaded parameter files: ``` diff --git a/subgraph/config/arbitrum.json b/subgraph/config/arbitrum.json new file mode 100644 index 000000000..8f72d1d1f --- /dev/null +++ b/subgraph/config/arbitrum.json @@ -0,0 +1,6 @@ +{ + "network": "arbitrum-one", + "address": "0x2e89494a8fE02891511a43f7877b726787E0C160", + "factoryStartBlock": 3461582, + "recipientRegistryStartBlock": 3461582 +} diff --git a/subgraph/package.json b/subgraph/package.json index 77585e068..66ed7fcec 100644 --- a/subgraph/package.json +++ b/subgraph/package.json @@ -15,6 +15,7 @@ "private": true, "scripts": { "prepare:hardhat": "mustache config/hardhat.json subgraph.template.yaml > subgraph.yaml", + "prepare:arbitrum": "mustache config/arbitrum.json subgraph.template.yaml > subgraph.yaml", "prepare:arbitrum-rinkeby": "mustache config/arbitrum-rinkeby.json subgraph.template.yaml > subgraph.yaml", "prepare:xdai": "mustache config/xdai.json subgraph.template.yaml > subgraph.yaml", "codegen": "graph codegen",