Skip to content
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
4 changes: 0 additions & 4 deletions app/src/components/admin/ComplianceSection.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ describe("ComplianceSection", () => {
verifier: "CVERIFIERADDRESS",
target: TARGET,
destination: undefined,
active: true,
})
const overview = screen.getByRole("region", { name: "Target" })
expect(within(overview).getByText("Allowlisted")).toBeTruthy()
Expand Down Expand Up @@ -300,8 +299,5 @@ describe("ComplianceSection", () => {
/>,
)
expect(screen.queryAllByRole("dialog", { hidden: true })).toHaveLength(0)
expect(useComplianceStateMock).toHaveBeenLastCalledWith(
expect.objectContaining({ active: false }),
)
})
})
1 change: 0 additions & 1 deletion app/src/components/admin/ComplianceSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ const ComplianceSection: React.FC<{
verifier,
target,
destination: destinationOf(inputs),
active,
})
const flows = useComplianceFlows()

Expand Down
18 changes: 0 additions & 18 deletions app/src/components/admin/ConfigurationSection.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,22 +196,4 @@ describe("ConfigurationSection", () => {
)
expect(screen.queryAllByRole("dialog", { hidden: true })).toHaveLength(0)
})

it("reads the parameters with polling only while active", () => {
const { rerender } = render(
<ConfigurationSection
grants={[governance]}
wallet={WALLET}
active={false}
/>,
)
expect(useConfigurationStateMock).toHaveBeenLastCalledWith({
active: false,
})

rerender(
<ConfigurationSection grants={[governance]} wallet={WALLET} active />,
)
expect(useConfigurationStateMock).toHaveBeenLastCalledWith({ active: true })
})
})
2 changes: 1 addition & 1 deletion app/src/components/admin/ConfigurationSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const ConfigurationSection: React.FC<{
contracts?: React.ReactNode
active?: boolean
}> = ({ grants, wallet, contracts, active = true }) => {
const { configuration } = useConfigurationState({ active })
const { configuration } = useConfigurationState()
const depositCap = usePendingTransaction(useSetDepositCap())
const custodian = usePendingTransaction(useSetCustodian())
const notice = usePendingTransaction(useSetNotice())
Expand Down
10 changes: 0 additions & 10 deletions app/src/components/admin/CycleSection.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -363,16 +363,6 @@ describe("CycleSection", () => {
expect(screen.getAllByRole("dialog", { hidden: true })).toHaveLength(1)
})

it("pauses the cycle polling while the surface is inactive", () => {
const { rerender } = render(
<CycleSection grants={[treasury]} wallet={WALLET} active={false} />,
)
expect(useCycleStateMock).toHaveBeenLastCalledWith({ active: false })

rerender(<CycleSection grants={[treasury]} wallet={WALLET} active />)
expect(useCycleStateMock).toHaveBeenLastCalledWith({ active: true })
})

it("labels the deployment modal with the exact amount that is signed", () => {
const { rerender } = render(
<CycleSection grants={[treasury]} wallet={WALLET} />,
Expand Down
2 changes: 1 addition & 1 deletion app/src/components/admin/CycleSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const CycleSection: React.FC<{
contracts?: React.ReactNode
active?: boolean
}> = ({ grants, wallet, contracts, active = true }) => {
const { cycle } = useCycleState({ active })
const { cycle } = useCycleState()
const { history } = useEpochHistory()
const { cycleEvents } = useCycleEvents()
const { balance } = useDepositBalance()
Expand Down
9 changes: 2 additions & 7 deletions app/src/components/admin/EmergencySection.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -221,15 +221,10 @@ describe("EmergencySection", () => {
expect(pauseVaultMock.reset).not.toHaveBeenCalled()
})

it("polls the state only while the surface is active", () => {
const { rerender } = render(
it("polls the vault pause state", () => {
render(
<EmergencySection grants={[guardian]} wallet={WALLET} active={false} />,
)
expect(useVaultPausedMock).toHaveBeenLastCalledWith({ poll: false })
expect(useTokenPausedMock).toHaveBeenLastCalledWith({ poll: false })
expect(useOracleStateMock).toHaveBeenLastCalledWith({ poll: false })

rerender(<EmergencySection grants={[guardian]} wallet={WALLET} active />)
expect(useVaultPausedMock).toHaveBeenLastCalledWith({ poll: true })
})
})
6 changes: 3 additions & 3 deletions app/src/components/admin/EmergencySection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ const EmergencySection: React.FC<{
contracts?: React.ReactNode
active?: boolean
}> = ({ grants, wallet, contracts, active = true }) => {
const { pause: vault } = useVaultPaused({ poll: active })
const { pause: token } = useTokenPaused({ poll: active })
const { oracle } = useOracleState({ poll: active })
const { pause: vault } = useVaultPaused({ poll: true })
const { pause: token } = useTokenPaused()
const { oracle } = useOracleState()
const pauseVault = usePendingTransaction(usePauseVault())
const unpauseVault = usePendingTransaction(useUnpauseVault())
const raiseRipcord = usePendingTransaction(useRaiseRipcord())
Expand Down
1 change: 0 additions & 1 deletion app/src/components/admin/GovernanceSection.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,6 @@ describe("GovernanceSection", () => {
)
expect(useGovernanceStateMock).toHaveBeenCalledWith({
contracts: { vault: VAULT, oracle: "CORACLE", token: "CTOKEN" },
active: true,
})
})

Expand Down
1 change: 0 additions & 1 deletion app/src/components/admin/GovernanceSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,6 @@ const GovernanceSection: React.FC<{
oracle: addresses.oracle,
token: addresses.shareToken,
},
active,
})
const flows = useGovernanceFlows()
const { inputs, setInputs, onInput } = useRailInputs()
Expand Down
4 changes: 1 addition & 3 deletions app/src/hooks/useComplianceState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,10 @@ export function useComplianceState({
verifier,
target,
destination,
active = true,
}: {
verifier: string | null
target: string | undefined
destination: string | undefined
active?: boolean
}): { target: TargetState; destination: Allowance } {
const { data } = useQuery({
queryKey: [...complianceReadsKey, verifier, target],
Expand All @@ -68,7 +66,7 @@ export function useComplianceState({
? skipToken
: () => fetchTargetReads(verifier, target),
staleTime: 30_000,
refetchInterval: active ? REFRESH_MS : false,
refetchInterval: REFRESH_MS,
})
const { data: destinationAllowance } = useQuery(
allowanceQuery(verifier, destination),
Expand Down
6 changes: 0 additions & 6 deletions app/src/hooks/useConfigurationState.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,4 @@ describe("useConfigurationState", () => {
}),
)
})

it("polls only while active", () => {
renderWithWallet(() => useConfigurationState({ active: false }))

expect(useCycleReadsMock).toHaveBeenCalledWith(false)
})
})
10 changes: 5 additions & 5 deletions app/src/hooks/useConfigurationState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,16 @@ async function fetchConfigurationReads() {
}
}

export function useConfigurationState({
active = true,
}: { active?: boolean } = {}): { configuration: ConfigurationState } {
const cycle = useCycleReads(active)
export function useConfigurationState(): {
configuration: ConfigurationState
} {
const cycle = useCycleReads()
const { authorities, isPending } = useVaultAuthorities()
const { data: reads } = useQuery({
queryKey: configurationReadsKey,
queryFn: fetchConfigurationReads,
staleTime: STALE_MS,
refetchInterval: active ? REFRESH_MS : false,
refetchInterval: REFRESH_MS,
})

if (cycle === undefined || reads === undefined || isPending)
Expand Down
22 changes: 0 additions & 22 deletions app/src/hooks/useCycleState.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,28 +363,6 @@ describe("useCycleState", () => {
}
})

it("stops refetching the cycle reads while inactive and resumes when active again", async () => {
vi.useFakeTimers({ shouldAdvanceTime: true })
try {
let active = false
const { result, rerender } = renderWithWallet(() =>
useCycleState({ active }),
)
await waitFor(() => expect(result.current.cycle.status).toBe("ready"))
const before = oracleMock.state.mock.calls.length

await vi.advanceTimersByTimeAsync(31_000)
expect(oracleMock.state.mock.calls).toHaveLength(before)

active = true
rerender()
await vi.advanceTimersByTimeAsync(16_000)
expect(oracleMock.state.mock.calls.length).toBeGreaterThan(before)
} finally {
vi.useRealTimers()
}
})

it("reads no balance when no custodian is set", async () => {
vaultMock.custodian.mockResolvedValue({ result: null })

Expand Down
8 changes: 4 additions & 4 deletions app/src/hooks/useCycleState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,24 +262,24 @@ async function fetchCustodianBalance(
return toAmount(balance)
}

export function useCycleReads(active: boolean): CycleReads | undefined {
export function useCycleReads(): CycleReads | undefined {
const { data } = useQuery({
queryKey: cycleReadsKey,
queryFn: fetchCycleReads,
staleTime: STALE_MS,
refetchInterval: active ? REFRESH_MS : false,
refetchInterval: REFRESH_MS,
})
return data
}

export function useCycleState({ active = true }: { active?: boolean } = {}): {
export function useCycleState(): {
cycle: CycleState
} {
const { history } = useEpochHistory()
const { figures, isPending: figuresPending } = useVaultFigures()
const { pause } = useVaultPaused()
const { authorities, isPending: authoritiesPending } = useVaultAuthorities()
const reads = useCycleReads(active)
const reads = useCycleReads()
const custodian = authorities?.custodian ?? { kind: "unreadable" }
const custodianAddress = custodian.kind === "set" ? custodian.address : null
const { data: custodianBalance, isPending: balancePending } = useQuery({
Expand Down
16 changes: 7 additions & 9 deletions app/src/hooks/useGovernanceState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,15 @@ async function fetchUpgradeProposal(): Promise<ProposalRead> {
}
}

function useUpgrades(active: boolean): Upgrades {
const cycle = useCycleReads(active)
const { configuration } = useConfigurationState({ active })
const { pause } = useVaultPaused({ poll: active })
function useUpgrades(): Upgrades {
const cycle = useCycleReads()
const { configuration } = useConfigurationState()
const { pause } = useVaultPaused({ poll: true })
const { data } = useQuery({
queryKey: upgradeProposalKey,
queryFn: fetchUpgradeProposal,
staleTime: STALE_MS,
refetchInterval: active ? REFRESH_MS : false,
refetchInterval: REFRESH_MS,
})
if (
cycle === undefined ||
Expand Down Expand Up @@ -104,16 +104,14 @@ function toHandovers(

export function useGovernanceState({
contracts,
active = true,
}: {
contracts: Record<GovernedContract, string> | undefined
active?: boolean
}): { handovers: Handovers; upgrades: Upgrades } {
const { data, isError } = useQuery({
...pendingAdminsQuery(contracts),
refetchInterval: active ? REFRESH_MS : false,
refetchInterval: REFRESH_MS,
})
const upgrades = useUpgrades(active)
const upgrades = useUpgrades()
let handovers: Handovers = { status: "checking" }
if (data !== undefined && contracts !== undefined)
handovers = toHandovers(data, contracts)
Expand Down
4 changes: 2 additions & 2 deletions app/src/hooks/useOracleState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ async function fetchOracleState(): Promise<OracleStatus> {
return classifyOracle(read)
}

export function useOracleState({ poll = false }: { poll?: boolean } = {}): {
export function useOracleState(): {
oracle: OracleStatus
} {
const { data } = useQuery({
queryKey: oracleStateKey,
queryFn: fetchOracleState,
staleTime: 30_000,
refetchInterval: poll ? PAUSE_REFRESH_MS : false,
refetchInterval: PAUSE_REFRESH_MS,
})

return { oracle: data ?? "checking" }
Expand Down
4 changes: 2 additions & 2 deletions app/src/hooks/useTokenPaused.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ async function fetchTokenPause(): Promise<PauseState> {
return classifyPause(read)
}

export function useTokenPaused({ poll = false }: { poll?: boolean } = {}): {
export function useTokenPaused(): {
pause: PauseState
} {
const { data } = useQuery({
queryKey: tokenPausedKey,
queryFn: fetchTokenPause,
staleTime: 30_000,
refetchInterval: poll ? PAUSE_REFRESH_MS : false,
refetchInterval: PAUSE_REFRESH_MS,
})

return { pause: data ?? "checking" }
Expand Down
55 changes: 50 additions & 5 deletions app/src/hooks/useVaultPaused.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
import { type ContractRead } from "@stellar-scaffold/app-lib"
import { describe, expect, it, vi } from "vitest"
import { classifyPause } from "./useVaultPaused"
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import { act, renderHook, waitFor } from "@testing-library/react"
import { createElement, type ReactNode } from "react"
import { afterEach, describe, expect, it, vi } from "vitest"
import {
classifyPause,
PAUSE_REFRESH_MS,
useVaultPaused,
} from "./useVaultPaused"

const { pausedMock } = vi.hoisted(() => ({
pausedMock: vi.fn(async () => ({ result: false })),
}))

vi.mock("../config/clients", () => ({
asyncVault: async () => ({
paused: async () => ({}),
}),
asyncVault: async () => ({ paused: pausedMock }),
}))

const setPageVisibility = (state: DocumentVisibilityState) => {
Object.defineProperty(document, "visibilityState", {
configurable: true,
get: () => state,
})
document.dispatchEvent(new Event("visibilitychange"))
}

const paused: ContractRead<boolean> = { kind: "value", value: true }
const open: ContractRead<boolean> = { kind: "value", value: false }
const contractError: ContractRead<boolean> = {
Expand All @@ -26,3 +43,31 @@ describe("classifyPause", () => {
expect(classifyPause(read)).toBe(expected)
})
})

describe("useVaultPaused", () => {
afterEach(() => {
setPageVisibility("visible")
vi.useRealTimers()
})

it("stops polling while the browser tab is hidden and resumes once shown", async () => {
vi.useFakeTimers({ shouldAdvanceTime: true })
const client = new QueryClient({
defaultOptions: {
queries: { refetchOnWindowFocus: false, retry: false },
},
})
const wrapper = ({ children }: { children: ReactNode }) =>
createElement(QueryClientProvider, { client }, children)
renderHook(() => useVaultPaused({ poll: true }), { wrapper })
await waitFor(() => expect(pausedMock).toHaveBeenCalledTimes(1))

act(() => setPageVisibility("hidden"))
await act(() => vi.advanceTimersByTimeAsync(PAUSE_REFRESH_MS * 3))
expect(pausedMock).toHaveBeenCalledTimes(1)

act(() => setPageVisibility("visible"))
await act(() => vi.advanceTimersByTimeAsync(PAUSE_REFRESH_MS))
expect(pausedMock).toHaveBeenCalledTimes(2)
})
})
Loading
Loading