Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into cohort/clrfund
Browse files Browse the repository at this point in the history
  • Loading branch information
yuetloo committed Jul 28, 2023
2 parents 45f8e90 + 3500007 commit e748cf5
Show file tree
Hide file tree
Showing 23 changed files with 264 additions and 86 deletions.
17 changes: 15 additions & 2 deletions .github/workflows/finalize-round.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
name: Finalize a test round

on: workflow_dispatch
on:
workflow_dispatch:
inputs:
branch_name:
description: 'Clrfund branch name'
required: true
default: 'develop'
subgraph_name:
description: 'Clrfund subgraph name'
required: true
default: 'yuetloo/clrfund-dev'

env:
NODE_VERSION: 16.x
SUBGRPAH_URL: "https://api.thegraph.com/subgraphs/name/clrfund/clrfund-arbitrum-goerli"
NETWORK: "arbitrum-goerli"
COORDINATOR_ETH_PK: ${{ secrets.ARBITRUM_GOERLI_COORDINATOR_WALLET_PRIVATE_KEY }}
COORDINATOR_PK: ${{ secrets.ARBITRUM_GOERLI_COORDINATOR_MACI_PRIVATE_KEY }}
Expand Down Expand Up @@ -33,6 +42,8 @@ jobs:
cargo install zkutil --version 0.3.2
- name: Checkout source code
uses: actions/checkout@v3
with:
ref: ${{ github.event.inputs.branch_name }}
- name: Download batch 64 params
run: |
ls -la $GITHUB_WORKSPACE
Expand All @@ -42,6 +53,8 @@ jobs:
yarn && yarn build
- name: Run finalize scripts
run: |
export SUBGRPAH_URL="https://api.thegraph.com/subgraphs/name/${{ github.event.inputs.subgraph_name }}"
echo $SUBGRAPH_URL
export NODE_CONFIG=$(node -e "const snarkParamsPath=process.env.GITHUB_WORKSPACE + '/params'; console.log(JSON.stringify({ snarkParamsPath }));")
export ROUND=$(curl -X POST -d '{"query":"{fundingRoundFactories {id currentRound {id maci}}}"}' $SUBGRPAH_URL)
export FACTORY_ADDRESS=$(node -e 'console.log(JSON.parse(process.env.ROUND).data.fundingRoundFactories[0].id)')
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ In a future version, we plan to address this by routing ETH and token contributi
- [Deployment](docs/deployment.md)
- [Providing matching funds](docs/funding-source.md)
- [How to tally votes and verify results](docs/tally-verify.md)
- [How to donate to projects](docs/howto-use-app.md)
- [Running the subgraph](docs/subgraph.md)
- [Sitemap](docs/sitemap.md)
- [Website theme and customization](docs/theme.md)
Expand Down
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.3",
"version": "4.2.4",
"license": "GPL-3.0",
"scripts": {
"hardhat": "hardhat",
Expand Down
62 changes: 62 additions & 0 deletions docs/howto-use-app.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# How to use the CLR.fund app

## What you'll need
1. ETH

> For testing,
- Get Goerli ETH from [Unitap](https://unitap.app/gas-tap)
- Use the [bridge](https://bridge.arbitrum.io/?l2ChainId=421613) to convert to Arbitrum Goerli ETH

2. Contribution tokens

> For testing, mint the DAI tokens using the `mint()` function from the [etherscan contract page](https://goerli.arbiscan.io//address/0x65bc8dd04808d99cf8aa6749f128d55c2051edde#writeContract) with the follow inputs:
- usr (address): Your wallet address
- wad (uint256): How many DAI tokens to mint, e.g. 20000000000000000000 is 20 DAI

Note, all the links provided below are from our test site for testing and illustration purposes only. For production, please replace https://clrfund-testnet.netlify.app with https://clr.fund

## How to add your project as a fund recipient

- Goto https://clrfund-testnet.netlify.app/#/join to submit your project
- Once your project is approved, it will show up on the project page and start receiving donations
- To check your project status, goto https://clrfund-testnet.netlify.app/#/recipients

## How to contribute to projects
1. Register as a contributor
- Verify with [BrightID](https://www.brightid.org)
- Goto https://clrfund-testnet.netlify.app/#/verify to get registered




https://github.com/clrfund/monorepo/assets/18424940/c0a995f8-1835-4de3-b6ee-ccfbe32e52b4




2. Contribute to projects
- Goto https://clrfund-testnet.netlify.app/#/projects to contribute to projects



https://github.com/clrfund/monorepo/assets/18424940/9b50acbf-ca43-454f-be88-4c52058669ad




3. Reallocate contributions
- Goto https://clrfund-testnet.netlify.app/#/projects to change your contribution allocations



https://github.com/clrfund/monorepo/assets/18424940/43188b69-9ece-4c2e-9ecc-babc1cdc09a3



## Bug report
You can report any issues with one of the following ways:
1. Report any issues in the `support` channel of the [CLR.fund discord](https://discord.gg/ZnsYPV6dCv)
2. Open a github issue on https://github.com/clrfund/monorepo/issues


3 changes: 2 additions & 1 deletion docs/tally-verify.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,9 +243,10 @@ 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>
yarn hardhat fetch-round --output-dir ../vue-app/src/rounds --network xdai --round-address <round address> --operator <operator>

```
3) Build and deploy the app



Expand Down
Binary file added docs/videos/contribute.mp4
Binary file not shown.
Binary file added docs/videos/reallocate.mp4
Binary file not shown.
Binary file added docs/videos/register.mp4
Binary file not shown.
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.3",
"version": "4.2.4",
"repository": "https://github.com/clrfund/monorepo/subgraph",
"keywords": [
"clr.fund",
Expand Down
95 changes: 78 additions & 17 deletions subgraph/src/OptimisticRecipientRegistryMapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
RequestSubmitted,
} from '../generated/OptimisticRecipientRegistry/OptimisticRecipientRegistry'

import { Recipient } from '../generated/schema'
import { Recipient, RecipientRegistry } from '../generated/schema'

// It is also possible to access smart contracts from mappings. For
// example, the contract that has emitted the event can be connected to
Expand All @@ -31,20 +31,48 @@ export function handleOwnershipTransferred(event: OwnershipTransferred): void {
}

export function handleRequestResolved(event: RequestResolved): void {
log.info('handleRequestResolved', [])

let recipientRegistryId = event.address.toHexString()
let recipientRegistry = RecipientRegistry.load(recipientRegistryId)
if (!recipientRegistry) {
log.warning(
'handleRequestResolved - ignore unknown recipient registry {} hash {}',
[event.address.toHexString(), event.transaction.hash.toHex()]
)
return
}

log.info('handleRequestResolved', [])
let recipientId = event.params._recipientId.toHexString()
let recipient = new Recipient(recipientId)

recipient.requestType = BigInt.fromI32(event.params._type).toString()
recipient.requester = event.transaction.from.toHexString()
recipient.submissionTime = event.params._timestamp.toString()
recipient.rejected = event.params._rejected
recipient.verified = !event.params._rejected
recipient.recipientRegistry = recipientRegistryId
recipient.recipientIndex = event.params._recipientIndex
recipient.requestResolvedHash = event.transaction.hash
// verified means the request is resolved
recipient.verified = true

if (event.params._rejected) {
// this is a challengeRequest
if (event.params._type == 0) {
// reject add request
recipient.rejected = event.params._rejected
recipient.recipientIndex = event.params._recipientIndex
recipient.requester = event.transaction.from.toHexString()
recipient.submissionTime = event.params._timestamp.toString()
} else {
// reject delete request - revert request type back to 'Add'
// to clear the 'Pending removal' status
recipient.requestType = '0'
}
} else {
// this is a executeRequest
recipient.requestType = BigInt.fromI32(event.params._type).toString()
recipient.recipientIndex = event.params._recipientIndex
// reject the recipient if it was a 'delete recipient request'
recipient.rejected = event.params._rejected
recipient.requester = event.transaction.from.toHexString()
recipient.submissionTime = event.params._timestamp.toString()
}

recipient.save()
}
Expand All @@ -53,20 +81,53 @@ export function handleRequestSubmitted(event: RequestSubmitted): void {
log.info('handleRequestSubmitted', [])
let recipientRegistryId = event.address.toHexString()

//TODO: create RecipientRegistry entity here if it does not exist.
let recipientRegistery = RecipientRegistry.load(recipientRegistryId)
if (!recipientRegistery) {
log.warning(
'handleRequestSubmitted - ignore unknown recipient registry {} hash {}',
[event.address.toHexString(), event.transaction.hash.toHex()]
)
return
}

let recipientId = event.params._recipientId.toHexString()
let recipient = new Recipient(recipientId)

recipient.recipientRegistry = recipientRegistryId
recipient.recipientAddress = event.params._recipient
recipient.requestType = BigInt.fromI32(event.params._type).toString()
recipient.requester = event.transaction.from.toHexString()
recipient.submissionTime = event.params._timestamp.toString()
recipient.deposit = event.transaction.value
recipient.recipientMetadata = event.params._metadata
recipient.verified = false
recipient.requestSubmittedHash = event.transaction.hash
recipient.lastUpdatedAt = event.block.timestamp.toString()

if (event.params._type == 0) {
// add recipient request
recipient.requestType = BigInt.fromI32(event.params._type).toString()
recipient.recipientIndex = null
recipient.recipientAddress = event.params._recipient
recipient.requester = event.transaction.from.toHexString()
recipient.deposit = event.transaction.value
recipient.recipientMetadata = event.params._metadata
recipient.requestSubmittedHash = event.transaction.hash

// reset these fields in case the same recipient was added and removed
// in which case these fields could hold values for previous record
recipient.requestResolvedHash = null
recipient.verified = false
recipient.rejected = false
recipient.createdAt = event.block.timestamp.toString()
} else if (event.params._type == 1) {
// mark the record as pending delete
recipient.requestType = BigInt.fromI32(event.params._type).toString()
recipient.verified = false
log.info('handleRequestSubmitted - delete id {}', [recipientId])
} else {
// don't know how to process this request
recipient.requestType = BigInt.fromI32(event.params._type).toString()
log.warning(
'handleRequestSubmitted - ignore unknown type {} from txHash {}',
[
BigInt.fromI32(event.params._type).toString(),
event.transaction.hash.toString(),
]
)
}

recipient.save()
}
8 changes: 3 additions & 5 deletions vue-app/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,12 @@ VITE_RECIPIENT_REGISTRY_TYPE=optimistic

VITE_RECIPIENT_REGISTRY_POLICY=QmeygKjvrpidJeFHv6ywjUrj718nwtFQgCCPPR4r5nL87R

# Comma-separated list of IPFS hashes
VITE_EXTRA_ROUNDS=

# Operator of clr.fund instance
VITE_OPERATOR=

# Index of first round to consider
VITE_FIRST_ROUND=
# Comma-separated list of cancelled round address that should not display on the app
# VITE_VOIDED_ROUNDS=0x123,0x456
VITE_VOIDED_ROUNDS=

# Default Language
VITE_I18N_LOCALE=
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.3",
"version": "4.2.4",
"private": true,
"license": "GPL-3.0",
"scripts": {
Expand Down
5 changes: 5 additions & 0 deletions vue-app/src/api/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,8 @@ export const recipientJoinDeadlineConfig = deadline?.isValid ? deadline : null

// make sure walletconnect qrcode modal is not blocked by the Wallet Modal
export const walletConnectZIndex = import.meta.env.VITE_WALLET_CONNECT_Z_INDEX || '1500'

// use this to filter out rounds that should not be displayed on the app
export const voidedRounds = new Set(
(import.meta.env.VITE_VOIDED_ROUNDS || '').split(',').map(round => round.toLowerCase()),
)
35 changes: 18 additions & 17 deletions vue-app/src/api/projects.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { BigNumber, Contract, Signer } from 'ethers'
import type { TransactionResponse } from '@ethersproject/abstract-provider'
import { FundingRound } from './abi'
import { FundingRound, OptimisticRecipientRegistry } from './abi'
import { factory, provider, recipientRegistryType, ipfsGatewayUrl } from './core'

import SimpleRegistry from './recipient-registry-simple'
Expand All @@ -9,6 +9,7 @@ import KlerosRegistry from './recipient-registry-kleros'
import sdk from '@/graphql/sdk'
import { getLeaderboardData } from '@/api/leaderboard'
import type { RecipientApplicationData } from '@/api/types'
import { getEventArg } from '@/utils/contracts'

export interface LeaderboardProject {
id: string // Address or another ID depending on registry implementation
Expand Down Expand Up @@ -164,28 +165,28 @@ export async function getProjectByIndex(
}

/**
* Check if the recipient with the submission hash exists in the subgraph
* Return the recipientId for the given transaction hash
* @param transactionHash recipient submission hash
* @returns true if recipients with the submission hash was found
* @returns recipientId or null for not found
*/
export async function recipientExists(transactionHash: string): Promise<boolean> {
const data = await sdk.GetRecipientBySubmitHash({ transactionHash })
return data.recipients.length > 0
}

/**
* Return the recipient for the given submission hash
* @param transactionHash recipient submission hash
* @returns project or null for not found
*/
export async function getRecipientBySubmitHash(transactionHash: string): Promise<Project | null> {
export async function getRecipientIdByHash(transactionHash: string): Promise<string | null> {
try {
const data = await sdk.GetRecipientBySubmitHash({ transactionHash })
const exists = data.recipients.length > 0
return exists ? OptimisticRegistry.decodeProject(data.recipients[0]) : null
const receipt = await provider.getTransactionReceipt(transactionHash)

// should only have 1 event, just in case, return the first matching event
for (const log of receipt.logs) {
const registry = new Contract(log.address, OptimisticRecipientRegistry, provider)
try {
const recipientId = getEventArg(receipt, registry, 'RequestSubmitted', '_recipientId')
return recipientId
} catch {
// try next log
}
}
} catch {
return null
}
return null
}

export function toLeaderboardProject(project: any): LeaderboardProject {
Expand Down
Loading

0 comments on commit e748cf5

Please sign in to comment.