Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into cohort/gnosis
Browse files Browse the repository at this point in the history
  • Loading branch information
yuetloo committed Aug 21, 2023
2 parents 050c5dc + b5f68a0 commit 5986aa9
Show file tree
Hide file tree
Showing 17 changed files with 89 additions and 56 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The clr.fund smart contracts consist of a factory contract that deploys a new co
3. **Contributor:** Any address that contributes tokens to the funding round.
4. **Recipient:** Any address that is registered as funding recipient.

The clr.fund application can use any [EVM-compatible chain](https://ethereum.org/) as a backend. The application can be hosted on [IPFS](https://ipfs.io/) and can also run locally.
The clr.fund application can use any [EVM-compatible chain](https://ethereum.org/) as a backend. The application can be hosted on [IPFS](https://ipfs.tech/) and can also run locally.

For more details, see the [sequence diagram](docs/clrfund.svg) and [clr.fund constitution](https://github.com/clrfund/constitution).

Expand Down
4 changes: 4 additions & 0 deletions contracts/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,7 @@ ETHERSCAN_API_KEY=
# ZK proof circuit type, based on MACI v0.10.1 circuit type as defined in utils/deployment.ts
# e.g. test, small, medium, x32, prod
CIRCUIT_TYPE=prod


# The IPFS gateway url used by the prepare-results.ts script
IPFS_GATEWAY_URL=
2 changes: 1 addition & 1 deletion contracts/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@clrfund/contracts",
"version": "4.2.5",
"version": "4.2.6",
"license": "GPL-3.0",
"scripts": {
"hardhat": "hardhat",
Expand Down
3 changes: 2 additions & 1 deletion contracts/scripts/prepare-results.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import fetch from 'node-fetch'
import { ethers } from 'hardhat'
import { Event } from 'ethers'
import { gtcrDecode } from '@kleros/gtcr-encoder'
import { DEFAULT_IPFS_GATEWAY } from '../utils/constants'

const ipfsGatewayUrl = 'https://ipfs.io/'
const ipfsGatewayUrl = process.env.IPFS_GATEWAY_URL || DEFAULT_IPFS_GATEWAY

interface Project {
id: string
Expand Down
22 changes: 11 additions & 11 deletions contracts/tasks/auditTally.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
/**
* This script is used for auditing the tally result for a round
*
* Sample usage:
* yarn hardhat audit-tally --round-address 0x4a2d90844eb9c815ef10db0371726f0ceb2848b0 --network arbitrum --output ./ethcolombia.json
*/

import { task, types } from 'hardhat/config'
import { utils, providers, Contract, BigNumber } from 'ethers'
import { EventFilter, Log } from '@ethersproject/abstract-provider'
import { Ipfs } from '../utils/ipfs'
import fs from 'fs'

interface Project {
Expand All @@ -21,12 +29,6 @@ function isRemoval(state: number): boolean {
return state === 1
}

async function fetchTally(tallyHash: string): Promise<any> {
const url = `https://ipfs.io/ipfs/${tallyHash}`
const result = utils.fetchJson(url)
return result
}

async function fetchLogs({
provider,
filter,
Expand Down Expand Up @@ -152,12 +154,10 @@ function tsvStringify(projects: Project[]): string {
return outputString
}

/**
* Audit the tally result for a round
*/
task('audit-tally', 'Audit the tally result for a round')
.addParam('roundAddress', 'Funding round contract address')
.addParam('output', 'Output file path')
.addOptionalParam('ipfs', 'The IPFS gateway url')
.addOptionalParam(
'tsv',
'Create tab seperated values as output file format, default JSON format',
Expand All @@ -184,7 +184,7 @@ task('audit-tally', 'Audit the tally result for a round')
)
.setAction(
async (
{ roundAddress, output, tsv, startBlock, endBlock, blocksPerBatch },
{ roundAddress, output, tsv, ipfs, startBlock, endBlock, blocksPerBatch },
{ ethers, network }
) => {
console.log('Processing on ', network.name)
Expand Down Expand Up @@ -243,7 +243,7 @@ task('audit-tally', 'Audit the tally result for a round')
})

const tallyHash = await round.tallyHash()
const tally = await fetchTally(tallyHash)
const tally = await Ipfs.fetchJson(tallyHash, ipfs)

console.log('Merging projects and tally results...')
const projects: Project[] = []
Expand Down
22 changes: 17 additions & 5 deletions contracts/tasks/fetchRound.ts → contracts/tasks/exportRound.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
/**
* Export all the round data after finalization to generate the leaderboard view
*
* Sample usage:
*
* yarn hardhat export-round --round-address <address> --out-dir ../vue-app/src/rounds --operator <operator> --ipfs <ipfs-gateway-url> --start-block <recipient-registry-start-block> --network <network>
*
* To generate the leaderboard view, deploy the clrfund website with the generated round data in the vue-app/src/rounds folder
*/

import { task, types } from 'hardhat/config'
import { HardhatConfig } from 'hardhat/types'
import { utils, Contract, BigNumber } from 'ethers'
Expand Down Expand Up @@ -245,21 +255,22 @@ async function getRoundInfo(
}

/**
* Fetch all the round data for static site
* Export all the round data for the leaderboard
*/
task('fetch-round', 'Fetch round data')
task('export-round', 'Export round data for the leaderboard')
.addParam('roundAddress', 'Funding round contract address')
.addParam('outputDir', 'Output directory')
.addParam('operator', 'Funding round operator, e.g. ETHColombia')
.addOptionalParam('ipfs', 'The IPFS gateway url')
.addOptionalParam(
'startBlock',
'First block to process from the recipient registry contract',
'First block to process events from the recipient registry contract',
0,
types.int
)
.addOptionalParam(
'endBlock',
'Last block to process from the recipient registry',
'Last block to process events from the recipient registry',
undefined,
types.int
)
Expand All @@ -278,6 +289,7 @@ task('fetch-round', 'Fetch round data')
endBlock,
blocksPerBatch,
operator,
ipfs,
},
{ ethers, network, config }
) => {
Expand Down Expand Up @@ -328,7 +340,7 @@ task('fetch-round', 'Fetch round data')
}

try {
tally = await Ipfs.fetchJson(round.tallyHash)
tally = await Ipfs.fetchJson(round.tallyHash, ipfs)
} catch (err) {
console.log('Failed to get tally file', round.tallyHash, err)
throw err
Expand Down
2 changes: 1 addition & 1 deletion contracts/tasks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import './verifyAll'
import './cancelRound'
import './evmIncreaseTime'
import './auditTally'
import './fetchRound'
import './exportRound'
import './mergeAllocations'
import './setDurations'
import './deploySponsor'
Expand Down
16 changes: 10 additions & 6 deletions contracts/tasks/mergeAllocations.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/**
* For cancelled rounds, merge the allocation data to the round JSON file
* This task must be run after the export-round task as this is merging
* data into the output file of the export-round task
*
* Sample usage:
* yarn hardhat merge-allocations --allocation-file /tmp/downloads/clr.fund-round8.tsv --round-file ../vue-app/src/rounds/xdai/0xd07aa7faeba14efde87f2538699c0d6c9a566c20.json
*/

import { task, types } from 'hardhat/config'
import { utils, BigNumber } from 'ethers'
import fs from 'fs'
Expand Down Expand Up @@ -104,13 +113,8 @@ function readAllocationFile(
return allocations
}

/**
* For cancelled rounds, merge the allocation data to the round JSON file
* This task must be run after the fetch-round task as this is merging
* data into the output file of the fetch-round task
*/
task('merge-allocations', 'Merge the allocations data into the round JSON file')
.addParam('roundFile', 'The JSON file exported from the fetch-round task')
.addParam('roundFile', 'The JSON file exported from the export-round task')
.addParam('allocationFile', 'The allocation file in tab separated format')
.addOptionalParam(
'skipAllocationRows',
Expand Down
45 changes: 28 additions & 17 deletions contracts/tasks/tally.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type TallyArgs = {
maciStateFile: string
providerUrl: string
voteOptionTreeDepth: number
shouldFetchLogs: boolean
}

async function main(args: TallyArgs) {
Expand All @@ -48,17 +49,42 @@ async function main(args: TallyArgs) {
maciStateFile,
providerUrl,
voteOptionTreeDepth,
shouldFetchLogs,
startBlock,
numBlocksPerRequest,
} = args

console.log('funding round address', fundingRound.address)
const maciAddress = await fundingRound.maci()
console.log('maci address', maciAddress)

const publishedTallyHash = await fundingRound.tallyHash()
console.log('publishedTallyHash', publishedTallyHash)

let tally

if (!publishedTallyHash) {
const maciAddress = await fundingRound.maci()
console.log('maci address', maciAddress)

if (shouldFetchLogs) {
// Fetch Maci logs
console.log('Fetching MACI logs from block', startBlock)
try {
await fetchLogs({
contract: maciAddress,
eth_provider: providerUrl,
privkey: coordinatorMaciPrivKey,
start_block: startBlock,
num_blocks_per_request: numBlocksPerRequest,
output: logsFile,
})
console.log('MACI logs generated at', logsFile)
} catch (err) {
console.log('Failed to fetchLogs', err)
throw err
}
}

// Process messages and tally votes
const results = await genProofs({
contract: maciAddress,
Expand Down Expand Up @@ -210,22 +236,6 @@ task('tally', 'Tally votes for the current round')

const timeMs = new Date().getTime()
const logsFile = maciLogs ? maciLogs : `maci_logs_${timeMs}.json`
if (!maciLogs) {
const maciAddress = await fundingRound.maci()
console.log('maci address', maciAddress)

// Fetch Maci logs
console.log('Fetching MACI logs from block', startBlock)
await fetchLogs({
contract: maciAddress,
eth_provider: (network.config as any).url,
privkey: coordinatorMaciPrivKey,
start_block: startBlock,
num_blocks_per_request: numBlocksPerRequest,
output: logsFile,
})
console.log('MACI logs generated at', logsFile)
}

await main({
fundingRound,
Expand All @@ -237,6 +247,7 @@ task('tally', 'Tally votes for the current round')
voteOptionTreeDepth: Number(voteOptionTreeDepth),
logsFile,
providerUrl,
shouldFetchLogs: !maciLogs,
maciStateFile: maciStateFile
? maciStateFile
: `maci_state_${timeMs}.json`,
Expand Down
1 change: 1 addition & 0 deletions contracts/utils/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { BigNumber } from 'ethers'

export const DEFAULT_IPFS_GATEWAY = 'https://ipfs.io'
export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
export const UNIT = BigNumber.from(10).pow(BigNumber.from(18))
export const VOICE_CREDIT_FACTOR = BigNumber.from(10).pow(4 + 18 - 9)
Expand Down
5 changes: 2 additions & 3 deletions contracts/utils/ipfs.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const Hash = require('ipfs-only-hash')
import { utils } from 'ethers'

const IPFS_BASE_URL = 'https://ipfs.io'
import { DEFAULT_IPFS_GATEWAY } from './constants'

export async function getIpfsHash(object: any): Promise<string> {
const data = Buffer.from(JSON.stringify(object, null, 4))
Expand All @@ -11,7 +10,7 @@ export async function getIpfsHash(object: any): Promise<string> {

export class Ipfs {
static async fetchJson(hash: string, gatewayUrl?: string): Promise<any> {
const url = `${gatewayUrl || IPFS_BASE_URL}/ipfs/${hash}`
const url = `${gatewayUrl || DEFAULT_IPFS_GATEWAY}/ipfs/${hash}`
const result = utils.fetchJson(url)
return result
}
Expand Down
6 changes: 3 additions & 3 deletions docs/tally-verify.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ The Ethereum private key (`eth-private-key`) can be any private key that control

The process may take several hours. Results can be found in `tally.json` file, which must then be published via IPFS.

Finally, the [CID](https://ipfs.io/ipns/docs.ipfs.io/concepts/content-addressing/) of tally file must be submitted to `FundingRound` contract:
Finally, the [CID](https://docs.ipfs.tech/concepts/content-addressing/) of tally file must be submitted to `FundingRound` contract:

```
await fundingRound.publishTallyHash('<CID>')
Expand Down Expand Up @@ -199,7 +199,7 @@ If there's error and the tally task was stopped prematurely, it can be resumed b

Result will be saved to `tally.json` file, which must then be published via IPFS.

**Using [command line](https://docs.ipfs.io/reference/cli/)**
**Using [command line](https://docs.ipfs.tech/reference/kubo/cli/#ipfs)**

```
# start ipfs daemon in one terminal
Expand Down Expand Up @@ -254,7 +254,7 @@ After finalizing the round, enable the leaderboard view in the vue-app by export
```sh
cd contracts

yarn hardhat fetch-round --output-dir ../vue-app/src/rounds --network xdai --round-address <round address> --operator <operator>
yarn hardhat export-round --output-dir ../vue-app/src/rounds --network <network> --round-address <round address> --operator <operator> --start-block <recipient-registry-start-block> --ipfs <ipfs-gateway-url>

```
3) Build and deploy the app
Expand Down
2 changes: 1 addition & 1 deletion subgraph/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@clrfund/subgraph",
"version": "4.2.5",
"version": "4.2.6",
"repository": "https://github.com/clrfund/monorepo/subgraph",
"keywords": [
"clr.fund",
Expand Down
2 changes: 1 addition & 1 deletion vue-app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@clrfund/vue-app",
"version": "4.2.5",
"version": "4.2.6",
"private": true,
"license": "GPL-3.0",
"scripts": {
Expand Down
3 changes: 2 additions & 1 deletion vue-app/src/components/IpfsCopyWidget.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { ipfsGatewayUrl } from '@/api/core'
const { t } = useI18n()
Expand All @@ -25,7 +26,7 @@ interface Props {
const props = defineProps<Props>()
const isCopied = ref(false)
const ipfsUrl = computed(() => `https://ipfs.io/ipfs/${props.hash}`)
const ipfsUrl = computed(() => `${ipfsGatewayUrl}/ipfs/${props.hash}`)
const renderCopiedOrHash = computed(() => {
return isCopied.value ? t('copied').toString() : props.hash
Expand Down
6 changes: 3 additions & 3 deletions vue-app/src/rounds/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Static Rounds

This folder is used to store the static round files, which can be generated once a round is finalized.
This folder is used to store the round data generated once a round is finalized. The leaderboard is populated with data from these round data files.

The app will load round tally information from this file if it exists, otherwise, it will load dynamically from the subgraph or the smart contracts.

Expand All @@ -11,7 +11,7 @@ cd contracts
# make sure the JSONRPC_HTTP_URL environment variable is set to
# the arbitrum provider in the .env file
# extract the EthColombia round data into the rounds folder
yarn hardhat fetch-round --operator ETHColombia --output-dir ../vue-app/src/rounds --round-address 0x4a2d90844eb9c815ef10db0371726f0ceb2848b0 --network arbitrum
# export the clr.fund round 9 data into the rounds folder
yarn hardhat export-round --operator Clr.fund --output-dir ../vue-app/src/rounds --round-address 0x806F08B7DD31fE0267e8c70C4bF8C4BfbBddE760 --ipfs 'https://ipfs.io' --start-block 96912490 --network arbitrum
```
2 changes: 1 addition & 1 deletion vue-app/src/views/JoinView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@
<h2 class="step-title">{{ $t('join.step4.h2') }}</h2>
<p>
{{ $t('join.step4.p1') }}
<links to="https://ipfs.io/#how">{{ $t('join.step4.link1') }}</links>
<links to="https://ipfs.tech/#how">{{ $t('join.step4.link1') }}</links>
</p>
<div class="inputs">
<div class="form-background">
Expand Down

0 comments on commit 5986aa9

Please sign in to comment.