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

feat(ui): prefetch protocol constraints #15

Merged
merged 2 commits into from
Apr 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
15 changes: 9 additions & 6 deletions ui/src/components/StakingTable.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useQuery, useQueryClient } from '@tanstack/react-query'
import { useQueryClient } from '@tanstack/react-query'
import { useRouter } from '@tanstack/react-router'
import {
ColumnDef,
Expand All @@ -15,7 +15,6 @@ import { useWallet } from '@txnlab/use-wallet-react'
import dayjs from 'dayjs'
import { FlaskConical, MoreHorizontal } from 'lucide-react'
import * as React from 'react'
import { constraintsQueryOptions } from '@/api/queries'
import { AddStakeModal } from '@/components/AddStakeModal'
import { AlgoDisplayAmount } from '@/components/AlgoDisplayAmount'
import { DataTableColumnHeader } from '@/components/DataTableColumnHeader'
Expand All @@ -38,7 +37,7 @@ import {
} from '@/components/ui/table'
import { UnstakeModal } from '@/components/UnstakeModal'
import { StakerValidatorData } from '@/interfaces/staking'
import { Validator } from '@/interfaces/validator'
import { Constraints, Validator } from '@/interfaces/validator'
import { canManageValidator, isStakingDisabled, isUnstakingDisabled } from '@/utils/contracts'
import { simulateEpoch } from '@/utils/development'
import { cn } from '@/utils/ui'
Expand All @@ -47,9 +46,15 @@ interface StakingTableProps {
validators: Validator[]
stakesByValidator: StakerValidatorData[]
isLoading: boolean
constraints: Constraints
}

export function StakingTable({ validators, stakesByValidator, isLoading }: StakingTableProps) {
export function StakingTable({
validators,
stakesByValidator,
isLoading,
constraints,
}: StakingTableProps) {
const [sorting, setSorting] = React.useState<SortingState>([])
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])
const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})
Expand All @@ -60,8 +65,6 @@ export function StakingTable({ validators, stakesByValidator, isLoading }: Staki

const { transactionSigner, activeAddress } = useWallet()

const { data: constraints } = useQuery(constraintsQueryOptions)

const router = useRouter()
const queryClient = useQueryClient()

Expand Down
19 changes: 10 additions & 9 deletions ui/src/components/ValidatorTable.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { AlgoAmount } from '@algorandfoundation/algokit-utils/types/amount'
import { useQuery } from '@tanstack/react-query'
import { Link } from '@tanstack/react-router'
import {
ColumnDef,
Expand All @@ -15,7 +14,6 @@ import {
import { useWallet } from '@txnlab/use-wallet-react'
import { FlaskConical, MoreHorizontal } from 'lucide-react'
import * as React from 'react'
import { constraintsQueryOptions } from '@/api/queries'
import { AddPoolModal } from '@/components/AddPoolModal'
import { AddStakeModal } from '@/components/AddStakeModal'
import { AlgoDisplayAmount } from '@/components/AlgoDisplayAmount'
Expand All @@ -42,7 +40,7 @@ import {
} from '@/components/ui/table'
import { UnstakeModal } from '@/components/UnstakeModal'
import { StakerValidatorData } from '@/interfaces/staking'
import { Validator } from '@/interfaces/validator'
import { Constraints, Validator } from '@/interfaces/validator'
import {
calculateMaxStake,
calculateMaxStakers,
Expand All @@ -59,9 +57,14 @@ import { cn } from '@/utils/ui'
interface ValidatorTableProps {
validators: Validator[]
stakesByValidator: StakerValidatorData[]
constraints: Constraints
}

export function ValidatorTable({ validators, stakesByValidator }: ValidatorTableProps) {
export function ValidatorTable({
validators,
stakesByValidator,
constraints,
}: ValidatorTableProps) {
const [sorting, setSorting] = React.useState<SortingState>([])
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])
const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})
Expand All @@ -73,8 +76,6 @@ export function ValidatorTable({ validators, stakesByValidator }: ValidatorTable

const { transactionSigner, activeAddress } = useWallet()

const { data: constraints } = useQuery(constraintsQueryOptions)

const columns: ColumnDef<Validator>[] = [
{
accessorKey: 'id',
Expand Down Expand Up @@ -138,7 +139,7 @@ export function ValidatorTable({ validators, stakesByValidator }: ValidatorTable
if (validator.state.numPools == 0) return '--'

const totalStakers = validator.state.totalStakers
const maxStakers = calculateMaxStakers(validator)
const maxStakers = calculateMaxStakers(validator, constraints)

return (
<span className="whitespace-nowrap">
Expand Down Expand Up @@ -173,7 +174,7 @@ export function ValidatorTable({ validators, stakesByValidator }: ValidatorTable
const validator = row.original
const stakingDisabled = isStakingDisabled(activeAddress, validator, constraints)
const unstakingDisabled = isUnstakingDisabled(activeAddress, validator, stakesByValidator)
const addingPoolDisabled = isAddingPoolDisabled(activeAddress, validator)
const addingPoolDisabled = isAddingPoolDisabled(activeAddress, validator, constraints)
const canManage = canManageValidator(activeAddress, validator)

const isDevelopment = process.env.NODE_ENV === 'development'
Expand Down Expand Up @@ -313,7 +314,7 @@ export function ValidatorTable({ validators, stakesByValidator }: ValidatorTable
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
{table.getRowModel().rows.length ? (
table.getRowModel().rows.map((row) => (
<TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
{row.getVisibleCells().map((cell) => (
Expand Down
23 changes: 20 additions & 3 deletions ui/src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useQuery, useSuspenseQuery } from '@tanstack/react-query'
import { createFileRoute } from '@tanstack/react-router'
import { useWallet } from '@txnlab/use-wallet-react'
import { fetchStakerValidatorData } from '@/api/contracts'
import { validatorsQueryOptions } from '@/api/queries'
import { constraintsQueryOptions, validatorsQueryOptions } from '@/api/queries'
import { Meta } from '@/components/Meta'
import { PageHeader } from '@/components/PageHeader'
import { PageMain } from '@/components/PageMain'
Expand All @@ -11,7 +11,16 @@ import { ValidatorTable } from '@/components/ValidatorTable'
import { StakerValidatorData } from '@/interfaces/staking'

export const Route = createFileRoute('/')({
loader: ({ context: { queryClient } }) => queryClient.ensureQueryData(validatorsQueryOptions),
beforeLoad: () => {
return {
validatorsQueryOptions,
constraintsQueryOptions,
}
},
loader: async ({ context: { queryClient, validatorsQueryOptions, constraintsQueryOptions } }) => {
queryClient.ensureQueryData(validatorsQueryOptions)
queryClient.ensureQueryData(constraintsQueryOptions)
},
component: Dashboard,
pendingComponent: () => <div>Loading...</div>,
errorComponent: ({ error }) => {
Expand All @@ -26,6 +35,9 @@ function Dashboard() {
const validatorsQuery = useSuspenseQuery(validatorsQueryOptions)
const validators = validatorsQuery.data

const constraintsQuery = useSuspenseQuery(constraintsQueryOptions)
const constraints = constraintsQuery.data

const { activeAddress } = useWallet()

const stakesQuery = useQuery<StakerValidatorData[]>({
Expand All @@ -47,8 +59,13 @@ function Dashboard() {
validators={validators || []}
stakesByValidator={stakesByValidator}
isLoading={stakesQuery.isLoading}
constraints={constraints}
/>
<ValidatorTable
validators={validators || []}
stakesByValidator={stakesByValidator}
constraints={constraints}
/>
<ValidatorTable validators={validators || []} stakesByValidator={stakesByValidator} />
</div>
</PageMain>
</>
Expand Down
21 changes: 11 additions & 10 deletions ui/src/utils/contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,9 +405,8 @@ export function calculateMaxStake(
return maxStake
}

export function calculateMaxStakers(validator: Validator): number {
// @todo: fetch max stakers from contract
const maxStakersPerPool = 200
export function calculateMaxStakers(validator: Validator, constraints?: Constraints): number {
const maxStakersPerPool = constraints?.maxStakersPerPool || 0
const maxStakers = maxStakersPerPool * validator.state.numPools

return maxStakers
Expand All @@ -428,8 +427,7 @@ export function isStakingDisabled(
maxAlgoPerPool = constraints.maxAlgoPerPool
}

// @todo: fetch max stakers from contract
const maxStakersPerPool = 200
const maxStakersPerPool = constraints?.maxStakersPerPool || 0

const maxStakers = maxStakersPerPool * numPools
const maxStake = Number(maxAlgoPerPool) * numPools
Expand All @@ -455,16 +453,19 @@ export function isUnstakingDisabled(
return noPools || !validatorHasStake
}

export function isAddingPoolDisabled(activeAddress: string | null, validator: Validator): boolean {
if (!activeAddress) {
export function isAddingPoolDisabled(
activeAddress: string | null,
validator: Validator,
constraints?: Constraints,
): boolean {
if (!activeAddress || !constraints) {
return true
}
// @todo: define totalNodes as global constant or fetch from protocol constraints
const totalNodes = 4
const maxNodes = constraints.maxNodes
const { numPools } = validator.state
const { poolsPerNode } = validator.config

const hasAvailableSlots = numPools < poolsPerNode * totalNodes
const hasAvailableSlots = numPools < poolsPerNode * maxNodes

return !hasAvailableSlots
}
Expand Down
Loading