Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update UI for simple user registry and simple recipient registry #676

Merged
merged 2 commits into from
Jun 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions vue-app/src/api/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,6 @@ const leaderboardRounds = historicalRounds as LeaderboardRound[]
export { leaderboardRounds }

export const showComplianceRequirement = /^yes$/i.test(import.meta.env.VITE_SHOW_COMPLIANCE_REQUIREMENT)

export const isBrightIdRequired = userRegistryType === 'brightid'
export const isOptimisticRecipientRegistry = recipientRegistryType === 'optimistic'
27 changes: 27 additions & 0 deletions vue-app/src/api/projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import OptimisticRegistry from './recipient-registry-optimistic'
import KlerosRegistry from './recipient-registry-kleros'
import sdk from '@/graphql/sdk'
import { getLeaderboardData } from '@/api/leaderboard'
import type { RecipientApplicationData } from '@/api/types'

export interface LeaderboardProject {
id: string // Address or another ID depending on registry implementation
Expand Down Expand Up @@ -231,3 +232,29 @@ export async function getLeaderboardProject(
isLocked: true, // Visible, but contributions are not allowed
}
}

export function formToProjectInterface(data: RecipientApplicationData): Project {
const { project, fund, team, links, image } = data
return {
id: fund.resolvedAddress,
address: fund.resolvedAddress,
name: project.name,
tagline: project.tagline,
description: project.description,
category: project.category,
problemSpace: project.problemSpace,
plans: fund.plans,
teamName: team.name,
teamDescription: team.description,
githubUrl: links.github,
radicleUrl: links.radicle,
websiteUrl: links.website,
twitterUrl: links.twitter,
discordUrl: links.discord,
bannerImageUrl: `${ipfsGatewayUrl}/ipfs/${image.bannerHash}`,
thumbnailImageUrl: `${ipfsGatewayUrl}/ipfs/${image.thumbnailHash}`,
index: 0,
isHidden: false,
isLocked: true,
}
}
31 changes: 29 additions & 2 deletions vue-app/src/api/recipient-registry-kleros.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Contract, type Event, Signer } from 'ethers'
import { Contract, type Event, Signer, BigNumber } from 'ethers'
import type { TransactionResponse } from '@ethersproject/abstract-provider'
import { gtcrDecode } from '@kleros/gtcr-encoder'

import { KlerosGTCR, KlerosGTCRAdapter } from './abi'
import { provider, ipfsGatewayUrl } from './core'
import type { Project } from './projects'
import type { RegistryInfo } from './types'

const KLEROS_CURATE_URL = 'https://curate.kleros.io/tcr/0x2E3B10aBf091cdc53cC892A50daBDb432e220398'

Expand Down Expand Up @@ -179,4 +180,30 @@ export async function registerProject(
return transaction
}

export default { getProjects, getProject, registerProject }
async function getRegistryInfo(registryAddress: string): Promise<RegistryInfo> {
const registry = new Contract(registryAddress, KlerosGTCRAdapter, provider)

let recipientCount
try {
recipientCount = await registry.getRecipientCount()
} catch {
// older BaseRecipientRegistry contract did not have recipientCount
// set it to zero as this information is only
// used during current round for space calculation
recipientCount = BigNumber.from(0)
}

// Kleros registry does not have owner
const owner = ''

// deposit, depositToken and challengePeriodDuration are only relevant to the optimistic registry
return {
deposit: BigNumber.from(0),
depositToken: '',
challengePeriodDuration: 0,
recipientCount: recipientCount.toNumber(),
owner,
}
}

export default { getProjects, getProject, registerProject, getRegistryInfo }
123 changes: 6 additions & 117 deletions vue-app/src/api/recipient-registry-optimistic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,15 @@ import { getEventArg } from '@/utils/contracts'
import { chain } from '@/api/core'

import { OptimisticRecipientRegistry } from './abi'
import { provider, ipfsGatewayUrl, recipientRegistryPolicy } from './core'
import { provider, ipfsGatewayUrl } from './core'
import type { Project } from './projects'
import sdk from '@/graphql/sdk'
import type { Recipient } from '@/graphql/API'
import { hasDateElapsed } from '@/utils/dates'
import type { RegistryInfo, RecipientApplicationData } from './types'
import { formToRecipientData } from './recipient'

export interface RegistryInfo {
deposit: BigNumber
depositToken: string
challengePeriodDuration: number
listingPolicyUrl: string
recipientCount: number
owner: string
}

export async function getRegistryInfo(registryAddress: string): Promise<RegistryInfo> {
async function getRegistryInfo(registryAddress: string): Promise<RegistryInfo> {
const registry = new Contract(registryAddress, OptimisticRecipientRegistry, provider)
const deposit = await registry.baseDeposit()
const challengePeriodDuration = await registry.challengePeriodDuration()
Expand All @@ -39,7 +32,6 @@ export async function getRegistryInfo(registryAddress: string): Promise<Registry
deposit,
depositToken: chain.currency,
challengePeriodDuration: challengePeriodDuration.toNumber(),
listingPolicyUrl: `${ipfsGatewayUrl}/ipfs/${recipientRegistryPolicy}`,
recipientCount: recipientCount.toNumber(),
owner,
}
Expand All @@ -63,65 +55,6 @@ export enum RequestStatus {
Removed = 'Removed',
}

export interface RecipientApplicationData {
project: {
name: string
tagline: string
description: string
category: string
problemSpace: string
}
fund: {
addressName: string
resolvedAddress: string
plans: string
}
team: {
name: string
description: string
email: string
}
links: {
github: string
radicle: string
website: string
twitter: string
discord: string
}
image: {
bannerHash: string
thumbnailHash: string
}
furthestStep: number
hasEns: boolean
}

export function formToProjectInterface(data: RecipientApplicationData): Project {
const { project, fund, team, links, image } = data
return {
id: fund.resolvedAddress,
address: fund.resolvedAddress,
name: project.name,
tagline: project.tagline,
description: project.description,
category: project.category,
problemSpace: project.problemSpace,
plans: fund.plans,
teamName: team.name,
teamDescription: team.description,
githubUrl: links.github,
radicleUrl: links.radicle,
websiteUrl: links.website,
twitterUrl: links.twitter,
discordUrl: links.discord,
bannerImageUrl: `${ipfsGatewayUrl}/ipfs/${image.bannerHash}`,
thumbnailImageUrl: `${ipfsGatewayUrl}/ipfs/${image.thumbnailHash}`,
index: 0,
isHidden: false,
isLocked: true,
}
}

interface RecipientMetadata {
name: string
description: string
Expand Down Expand Up @@ -207,51 +140,7 @@ export async function getRequests(registryInfo: RegistryInfo, registryAddress: s
return Object.keys(requests).map(recipientId => requests[recipientId])
}

// TODO merge this with `Project` inteface
export interface RecipientData {
name: string
description: string
imageHash?: string // TODO remove - old flow
address: string
tagline?: string
category?: string
problemSpace?: string
plans?: string
teamName?: string
teamDescription?: string
githubUrl?: string
radicleUrl?: string
websiteUrl?: string
twitterUrl?: string
discordUrl?: string
// fields different vs. Project
bannerImageHash?: string
thumbnailImageHash?: string
}

export function formToRecipientData(data: RecipientApplicationData): RecipientData {
const { project, fund, team, links, image } = data
return {
address: fund.resolvedAddress,
name: project.name,
tagline: project.tagline,
description: project.description,
category: project.category,
problemSpace: project.problemSpace,
plans: fund.plans,
teamName: team.name,
teamDescription: team.description,
githubUrl: links.github,
radicleUrl: links.radicle,
websiteUrl: links.website,
twitterUrl: links.twitter,
discordUrl: links.discord,
bannerImageHash: image.bannerHash,
thumbnailImageHash: image.thumbnailHash,
}
}

export async function addRecipient(
async function addRecipient(
registryAddress: string,
recipientApplicationData: RecipientApplicationData,
deposit: BigNumber,
Expand Down Expand Up @@ -455,4 +344,4 @@ export async function removeProject(registryAddress: string, recipientId: string
return transaction
}

export default { getProjects, getProject, registerProject, decodeProject }
export default { getProjects, getProject, registerProject, decodeProject, getRegistryInfo, addRecipient }
58 changes: 55 additions & 3 deletions vue-app/src/api/recipient-registry-simple.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,36 @@
import { Contract } from 'ethers'
import { Contract, BigNumber, Signer } from 'ethers'
import type { Event } from 'ethers'
import { isHexString } from '@ethersproject/bytes'
import type { TransactionResponse } from '@ethersproject/abstract-provider'

import { SimpleRecipientRegistry } from './abi'
import { provider, ipfsGatewayUrl } from './core'
import type { Project } from './projects'
import type { RegistryInfo, RecipientApplicationData } from './types'
import { formToRecipientData } from './recipient'

function decodeRecipientAdded(event: Event): Project {
const args = event.args as any
const metadata = JSON.parse(args._metadata)
console.log('metata', metadata)
return {
id: args._recipientId,
address: args._recipient,
name: metadata.name,
description: metadata.description,
imageUrl: `${ipfsGatewayUrl}/ipfs/${metadata.imageHash}`,
tagline: metadata.tagline,
category: metadata.category,
problemSpace: metadata.problemSpace,
plans: metadata.plans,
teamName: metadata.teamName,
teamDescription: metadata.teamDescription,
githubUrl: metadata.githubUrl,
radicleUrl: metadata.radicleUrl,
websiteUrl: metadata.websiteUrl,
twitterUrl: metadata.twitterUrl,
discordUrl: metadata.discordUrl,
bannerImageUrl: `${ipfsGatewayUrl}/ipfs/${metadata.bannerImageHash}`,
thumbnailImageUrl: `${ipfsGatewayUrl}/ipfs/${metadata.thumbnailImageHash}`,
index: args._index.toNumber(),
isHidden: false,
isLocked: false,
Expand Down Expand Up @@ -90,4 +106,40 @@ export async function getProject(registryAddress: string, recipientId: string):
return project
}

export default { getProjects, getProject }
async function getRegistryInfo(registryAddress: string): Promise<RegistryInfo> {
const registry = new Contract(registryAddress, SimpleRecipientRegistry, provider)

let recipientCount
try {
recipientCount = await registry.getRecipientCount()
} catch {
// older BaseRecipientRegistry contract did not have recipientCount
// set it to zero as this information is only
// used during current round for space calculation
recipientCount = BigNumber.from(0)
}
const owner = await registry.owner()

// deposit, depositToken and challengePeriodDuration are only relevant to the optimistic registry
return {
deposit: BigNumber.from(0),
depositToken: '',
challengePeriodDuration: 0,
recipientCount: recipientCount.toNumber(),
owner,
}
}

async function addRecipient(
registryAddress: string,
recipientApplicationData: RecipientApplicationData,
signer: Signer,
): Promise<TransactionResponse> {
const registry = new Contract(registryAddress, SimpleRecipientRegistry, signer)
const recipientData = formToRecipientData(recipientApplicationData)
const { address, ...metadata } = recipientData
const transaction = await registry.addRecipient(address, JSON.stringify(metadata))
return transaction
}

export default { getProjects, getProject, getRegistryInfo, addRecipient }
36 changes: 36 additions & 0 deletions vue-app/src/api/recipient-registry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { RegistryInfo, RecipientApplicationData } from './types'
import { recipientRegistryType } from './core'
import SimpleRegistry from './recipient-registry-simple'
import OptimisticRegistry from './recipient-registry-optimistic'
import KlerosRegistry from './recipient-registry-kleros'
import type { BigNumber, Signer } from 'ethers'
import type { TransactionResponse } from '@ethersproject/abstract-provider'

export async function getRegistryInfo(registryAddress: string): Promise<RegistryInfo> {
if (recipientRegistryType === 'simple') {
return await SimpleRegistry.getRegistryInfo(registryAddress)
} else if (recipientRegistryType === 'optimistic') {
return await OptimisticRegistry.getRegistryInfo(registryAddress)
} else if (recipientRegistryType === 'kleros') {
return await KlerosRegistry.getRegistryInfo(registryAddress)
} else {
throw new Error('Invalid recipient registry type: ' + recipientRegistryType)
}
}

export async function addRecipient(
registryAddress: string,
recipientApplicationData: RecipientApplicationData,
deposit: BigNumber,
signer: Signer,
): Promise<TransactionResponse> {
if (recipientRegistryType === 'simple') {
return await SimpleRegistry.addRecipient(registryAddress, recipientApplicationData, signer)
} else if (recipientRegistryType === 'optimistic') {
return await OptimisticRegistry.addRecipient(registryAddress, recipientApplicationData, deposit, signer)
} else if (recipientRegistryType === 'kleros') {
throw new Error('Kleros recipient registry is not supported')
} else {
throw new Error('Invalid recipient registry type: ' + recipientRegistryType)
}
}
Loading