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

TOK-515: include halted builders #430

Merged
merged 4 commits into from
Dec 4, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,22 @@ import { Badge } from '@/components/Badge'
import { Jdenticon } from '@/components/Header/Jdenticon'
import { Paragraph, Typography } from '@/components/Typography'
import { FC } from 'react'
import { Builder, BuilderProposal, BuilderStateFlags } from '../../types'
import { Builder, BuilderProposal, BuilderStateFlags } from '@/app/collective-rewards/types'
import { getBuilderInactiveState } from '@/app/collective-rewards/utils'

export type BuilderAllocationHeaderProps = Pick<Builder, 'builderName' | 'address' | 'stateFlags' | 'gauge'> &
Pick<BuilderProposal, 'date'>

const isBuilderActive = ({ communityApproved, kycApproved, paused }: BuilderStateFlags) => {
return communityApproved && kycApproved && !paused
const isBuilderActive = ({ communityApproved, kycApproved, paused, revoked }: BuilderStateFlags) => {
return communityApproved && kycApproved && !paused && !revoked
}

const haltedClass = 'bg-[#932309] color-text-primary py-1 px-1 text-[12px]'
const haltedStateBadges = {
Paused: <Badge content="Paused" className="bg-[#F9E1FF] text-secondary py-1 px-1 text-[12px]" />,
Deactivated: <Badge content="Deactivated" className={haltedClass} />,
KYCRevoked: <Badge content="KYC Revoked" className={haltedClass} />,
Revoked: <Badge content="Revoked" className={haltedClass} />,
}

export const BuilderAllocationHeader: FC<BuilderAllocationHeaderProps> = ({
Expand All @@ -28,13 +37,11 @@ export const BuilderAllocationHeader: FC<BuilderAllocationHeaderProps> = ({
<Typography tagVariant="label" className="font-semibold line-clamp-1 text-wrap text-base leading-4">
<AddressOrAlias addressOrAlias={builderName || address} className="text-base font-bold leading-4" />
</Typography>
{gauge && !state.communityApproved && (
<Badge content="Deactivated" className="bg-[#932309] color-text-primary py-1 px-1 text-[12px]" />
)}
{state.paused && state.communityApproved && (
<Badge content="Paused" className="bg-[#F9E1FF] text-secondary py-1 px-1 text-[12px]" />
{gauge && isBuilderActive(state) ? (
<Paragraph className="text-sm font-light"> Joined {date}</Paragraph>
) : (
haltedStateBadges[getBuilderInactiveState(state)]
)}
{isBuilderActive(state) && <Paragraph className="text-sm font-light"> Joined {date}</Paragraph>}
</div>
</div>
)
Expand Down
4 changes: 2 additions & 2 deletions src/app/collective-rewards/metrics/Metrics.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useGetGaugesArray, withBuilderButton } from '@/app/collective-rewards/user'
import { useGetGaugesArrayByType, withBuilderButton } from '@/app/collective-rewards/user'
import { HeaderTitle } from '@/components/Typography'
import {
TotalAllocationsMetrics,
Expand All @@ -15,7 +15,7 @@ import { PricesContextProvider } from '@/shared/context/PricesContext'
const HeaderWithBuilderButton = withBuilderButton(HeaderTitle)

export const Metrics = () => {
const { data: activeGauges } = useGetGaugesArray('active')
const { data: activeGauges } = useGetGaugesArrayByType('active')
const gauges = activeGauges ?? []

const tokens = {
Expand Down
8 changes: 3 additions & 5 deletions src/app/collective-rewards/rewards/MyRewards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,17 @@ const SubText = () => {

export const Rewards: FC<{ builder: Address }> = ({ builder }) => {
const router = useRouter()
const { data: rewardGauges, error: rewardGaugesError } = useGetGaugesArray('active')
const { data: haltedGauges, error: haltedGaugesError } = useGetGaugesArray('halted')
const { data: gauges, error: gaugesError } = useGetGaugesArray()
const { data: gauge, error: gaugeError } = useGetBuilderToGauge(builder)
const gauges = [...(rewardGauges ?? []), ...(haltedGauges ?? [])]

const error = rewardGaugesError ?? haltedGaugesError ?? gaugeError
const error = gaugesError ?? gaugeError

useHandleErrors({ error, title: 'Error loading gauge(s)' })

// TODO: check where to store this information
const data: RewardDetails = {
builder,
gauges,
gauges: gauges || [],
tokens: {
rif: {
address: getAddress(tokenContracts.RIF),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ type RequiredBuilder = Required<Builder>

// from the builders list, filter out the builders that are not kycApproved or are revoked or have no allocation
const isBuilderShown = (
{ stateFlags: { kycApproved, revoked }, address }: RequiredBuilder,
{ stateFlags: { kycApproved, revoked, communityApproved }, address }: RequiredBuilder,
allocations: Allocations,
) => {
const allocation = allocations[address]
return (kycApproved && !revoked) || (allocation && allocation > 0n)
return (kycApproved && !revoked && communityApproved) || (allocation && allocation > 0n)
}

// FIXME: remove and use Builder and/or combination of existing types
Expand Down
17 changes: 11 additions & 6 deletions src/app/collective-rewards/shared/components/Table/TableCells.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { ProgressBar } from '@/components/ProgressBar'
import { Button } from '@/components/Button'
import { BuilderStateFlags } from '@/app/collective-rewards/types'
import { AllocationsContext } from '@/app/collective-rewards/allocations/context'
import { getBuilderInactiveState, isBuilderOperational } from '@/app/collective-rewards/utils'

export function getFormattedCurrency(value: number, symbol: string) {
const formattedCurrency = formatCurrency(value, symbol)
Expand Down Expand Up @@ -54,17 +55,21 @@ export const LazyRewardCell = memo(RewardCell, ({ rewards: prevReward }, { rewar
type BuilderStatusFlagProps = {
stateFlags: BuilderStateFlags
}

const getStatusColor = (isOperational: boolean, builderInactiveState: string) => {
if (isOperational) return 'transparent'
if (builderInactiveState === 'Paused') return '#F9E1FF'
return '#932309'
}
const BuilderStatusFlag: FC<BuilderStatusFlagProps> = ({ stateFlags }) => {
const isDeactivated = !stateFlags.kycApproved || !stateFlags.communityApproved
const isPaused = stateFlags.paused
const isOperational = isBuilderOperational(stateFlags)
const builderInactiveState = getBuilderInactiveState(stateFlags)

const color = isDeactivated ? '#932309' : isPaused ? '#F9E1FF' : 'transparent'
const content = isDeactivated ? 'Status: Deactivated' : isPaused ? 'Status: Paused' : ''
const color = getStatusColor(isOperational, builderInactiveState)
const content = builderInactiveState

return (
<Popover
disabled={!isDeactivated && !isPaused}
disabled={isOperational}
content={content}
className="font-normal text-sm flex items-center"
size="small"
Expand Down
2 changes: 1 addition & 1 deletion src/app/collective-rewards/user/hooks/useGetBuilders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const useGetBuilders: UseGetBuilders = () => {
* ignore the builder if paused or revoked (to be confirmed)
*/
// get the gauges
const { data: gauges, isLoading: gaugesLoading, error: gaugesError } = useGetGaugesArray('active')
const { data: gauges, isLoading: gaugesLoading, error: gaugesError } = useGetGaugesArray()

// get the builders for each gauge
const gaugeToBuilderCalls = gauges?.map(
Expand Down
70 changes: 52 additions & 18 deletions src/app/collective-rewards/user/hooks/useGetGaugesArray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,11 @@ const gaugeType: Record<GaugeType, FunctionName> = {
halted: 'getHaltedGaugeAt',
}

export const useGetGaugesArray = (type: GaugeType) => {
const {
data: gaugesLength,
isLoading: gaugesLengthLoading,
error: gaugesLengthError,
} = useGetGaugesLength(type)
export const useGetGaugesArray = () => {
const { data: activeCalls, isLoading: isLoadingActive, error: errorActive } = useGetContractCalls('active')
const { data: haltedCalls, isLoading: isLoadingHalted, error: errorHalted } = useGetContractCalls('halted')

const length = Number(gaugesLength) ?? 0

const contractCalls = Array.from({ length }, (_, index) => {
return {
address: BackersManagerAddress,
abi: BuilderRegistryAbi,
functionName: gaugeType[type],
args: [index],
} as const
})
const contractCalls = [...activeCalls, ...haltedCalls]

const {
data: gaugesAddress,
Expand All @@ -47,12 +35,58 @@ export const useGetGaugesArray = (type: GaugeType) => {
})

const gauges = useMemo(() => gaugesAddress?.map(gauge => gauge.result as Address), [gaugesAddress])
const isLoading = gaugesLengthLoading || gaugesAddressLoading
const error = gaugesLengthError ?? gaugesAddressError
const isLoading = isLoadingActive || isLoadingHalted || gaugesAddressLoading
const error = errorActive ?? errorHalted ?? gaugesAddressError

return {
data: gauges,
isLoading,
error,
}
}

export const useGetGaugesArrayByType = (type: GaugeType) => {
const {
data: calls,
isLoading: contractCallsLoading,
error: contractCallsError,
} = useGetContractCalls(type)

const {
data: gaugesAddress,
isLoading: gaugesAddressLoading,
error: gaugesAddressError,
} = useReadContracts<Address[]>({
contracts: calls,
query: {
refetchInterval: AVERAGE_BLOCKTIME,
},
})

const gauges = useMemo(() => gaugesAddress?.map(gauge => gauge.result as Address), [gaugesAddress])
const isLoading = contractCallsLoading || gaugesAddressLoading
const error = contractCallsError ?? gaugesAddressError

return {
data: gauges,
isLoading: isLoading || gaugesAddressLoading,
error: error ?? gaugesAddressError,
}
}

const useGetContractCalls = (type: GaugeType) => {
const { data: gaugesLength, isLoading, error } = useGetGaugesLength(type)

const length = Number(gaugesLength) ?? 0

const data = Array.from({ length }, (_, index) => {
return {
address: BackersManagerAddress,
abi: BuilderRegistryAbi,
functionName: gaugeType[type],
args: [index],
} as const
})

return { data, isLoading, error }
}
1 change: 1 addition & 0 deletions src/app/collective-rewards/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './getCoinbaseAddress'
export * from './getMostAdvancedProposal'
export * from './handleErrors'
export * from './removeBrackets'
export * from './isBuilderOperational'
7 changes: 0 additions & 7 deletions src/app/collective-rewards/utils/isBuilderActive.ts

This file was deleted.

14 changes: 14 additions & 0 deletions src/app/collective-rewards/utils/isBuilderOperational.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { BuilderStateFlags } from '../types'

export const isBuilderOperational = (stateFlags?: BuilderStateFlags) => {
return !!(stateFlags && stateFlags.communityApproved && stateFlags.kycApproved && !stateFlags.paused)
}

const inactiveStates = ['Deactivated', 'KYCRevoked', 'Revoked', 'Paused'] as const
type InactiveState = (typeof inactiveStates)[number]
export const getBuilderInactiveState = (state: BuilderStateFlags): InactiveState => {
if (!state.communityApproved) return 'Deactivated'
if (!state.kycApproved) return 'KYCRevoked'
if (state.revoked) return 'Revoked'
return 'Paused'
}
Loading