Skip to content

Commit

Permalink
Merge pull request #708 from clrfund/fix/ipfs-url
Browse files Browse the repository at this point in the history
Make IPFS gateway url configurable from the environment file or as command line param
  • Loading branch information
yuetloo authored Aug 21, 2023
2 parents cfdd301 + 1fa7415 commit d41a50e
Show file tree
Hide file tree
Showing 13 changed files with 58 additions and 36 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=
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
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
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 d41a50e

Please sign in to comment.