diff --git a/apps/main/src/entities/gauge/api/rewards-mutate.ts b/apps/main/src/entities/gauge/api/rewards-mutate.ts index eacdf9aaa..7411f7f9b 100644 --- a/apps/main/src/entities/gauge/api/rewards-mutate.ts +++ b/apps/main/src/entities/gauge/api/rewards-mutate.ts @@ -9,46 +9,23 @@ * business logic and data fetching. */ -import { type MutateFunction } from '@tanstack/react-query' -import { assertGaugeValidity } from '@/entities/gauge/lib' -import { GaugeQueryKeyType, type PoolMethodResult } from '@/entities/gauge/types' +import { AddRewardQuery, DepositRewardApproveQuery, DepositRewardQuery } from '@/entities/gauge/types' import useStore from '@/store/useStore' -export const mutateAddRewardToken: MutateFunction< - PoolMethodResult<'gauge.addReward'>, - Error, - GaugeQueryKeyType<'addRewardToken'> -> = async (queryKey) => { - const [, { chainId }, , { poolId }, , , rewardTokenId, distributorId] = queryKey - const _valid = assertGaugeValidity({ chainId, poolId, rewardTokenId, distributorId }) - - const curve = useStore.getState().curve - const pool = curve.getPool(_valid.poolId) - return pool.gauge.addReward(_valid.rewardTokenId, _valid.distributorId) +export const mutateAddRewardToken = async ({ poolId, rewardTokenId, distributorId }: AddRewardQuery) => { + const { curve } = useStore.getState() + const pool = curve.getPool(poolId) + return pool.gauge.addReward(rewardTokenId, distributorId) } -export const mutateDepositRewardApprove: MutateFunction< - PoolMethodResult<'gauge.depositRewardApprove'>, - Error, - GaugeQueryKeyType<'depositRewardApprove'> -> = async (queryKey) => { - const [, { chainId }, , { poolId }, , , rewardTokenId, amount] = queryKey - const _valid = assertGaugeValidity({ chainId, poolId, rewardTokenId, amount }) - +export const mutateDepositRewardApprove = async ({ poolId, rewardTokenId, amount }: DepositRewardApproveQuery) => { const curve = useStore.getState().curve - const pool = curve.getPool(_valid.poolId) - return pool.gauge.depositRewardApprove(_valid.rewardTokenId, _valid.amount) + const pool = curve.getPool(poolId) + return pool.gauge.depositRewardApprove(rewardTokenId, amount) } -export const mutateDepositReward: MutateFunction< - PoolMethodResult<'gauge.depositReward'>, - Error, - GaugeQueryKeyType<'depositReward'> -> = async (queryKey) => { - const [, { chainId }, , { poolId }, , , rewardTokenId, amount, epoch] = queryKey - const _valid = assertGaugeValidity({ chainId, poolId, rewardTokenId, amount, epoch }) - - const curve = useStore.getState().curve - const pool = curve.getPool(_valid.poolId) - return pool.gauge.depositReward(_valid.rewardTokenId, _valid.amount, _valid.epoch) +export const mutateDepositReward = async ({ poolId, rewardTokenId, amount, epoch }: DepositRewardQuery) => { + const { curve } = useStore.getState() + const pool = curve.getPool(poolId) + return pool.gauge.depositReward(rewardTokenId, amount, epoch) } diff --git a/apps/main/src/entities/gauge/lib/index.ts b/apps/main/src/entities/gauge/lib/index.ts index cd69be520..db830e31b 100644 --- a/apps/main/src/entities/gauge/lib/index.ts +++ b/apps/main/src/entities/gauge/lib/index.ts @@ -1,3 +1,2 @@ export * from './reward-actions' export * from './gauge-info' -export * from './validation' diff --git a/apps/main/src/entities/gauge/lib/reward-actions.ts b/apps/main/src/entities/gauge/lib/reward-actions.ts index b9354d3e2..5f5445c7c 100644 --- a/apps/main/src/entities/gauge/lib/reward-actions.ts +++ b/apps/main/src/entities/gauge/lib/reward-actions.ts @@ -40,8 +40,10 @@ export const useAddRewardToken = ({ notifyNotification(txDescription, 'success') } - queryClient.invalidateQueries({ queryKey: keys.distributors({ chainId, poolId }) }) - queryClient.invalidateQueries({ queryKey: keys.isDepositRewardAvailable({ chainId, poolId }) }) + return Promise.all([ + queryClient.invalidateQueries({ queryKey: keys.distributors({ chainId, poolId }) }), + queryClient.invalidateQueries({ queryKey: keys.isDepositRewardAvailable({ chainId, poolId }) }), + ]) }, onError: (error) => { console.error('Error adding reward:', error) @@ -83,7 +85,7 @@ export const useDepositRewardApprove = ({ const notifyMessage = t`Approve spending ${rewardTokenId ? tokensMapper[rewardTokenId]?.symbol : ''}` notifyNotification(notifyMessage, 'success', 15000) } - queryClient.invalidateQueries({ + return queryClient.invalidateQueries({ queryKey: keys.depositRewardIsApproved({ chainId, poolId, rewardTokenId, amount }), }) }, @@ -117,12 +119,12 @@ export const useDepositReward = ({ return useMutation({ ...models.getDepositRewardMutation({ chainId, poolId }), - onSuccess: (resp, { rewardTokenId, amount, epoch }) => { + onSuccess: (resp, { rewardTokenId }) => { if (resp) { const txDescription = t`Deposited reward token ${rewardTokenId ? tokensMapper[rewardTokenId]?.symbol : ''}` notifyNotification(txDescription, 'success', 15000) } - queryClient.invalidateQueries({ queryKey: keys.isDepositRewardAvailable({ chainId, poolId }) }) + return queryClient.invalidateQueries({ queryKey: keys.isDepositRewardAvailable({ chainId, poolId }) }) }, onError: (error) => { console.error('Error depositing reward:', error) diff --git a/apps/main/src/entities/gauge/lib/validation.ts b/apps/main/src/entities/gauge/lib/validation.ts deleted file mode 100644 index e374e579e..000000000 --- a/apps/main/src/entities/gauge/lib/validation.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { gaugeValidationSuite } from '@/entities/gauge/model' -import type { CombinedGaugeParams } from '@/entities/gauge/types' -import { ValidatedData, assertValidity, checkValidity } from '@/shared/lib/validation' - -export function checkGaugeValidity( - data: T, - fields?: Extract[] -): boolean { - return checkValidity(gaugeValidationSuite, data, fields) -} - -export function assertGaugeValidity( - data: T, - fields?: Extract[] -): ValidatedData { - return assertValidity(gaugeValidationSuite, data, fields) -} diff --git a/apps/main/src/entities/gauge/model/mutate-options.ts b/apps/main/src/entities/gauge/model/mutate-options.ts index a4bf0dd14..da53da37b 100644 --- a/apps/main/src/entities/gauge/model/mutate-options.ts +++ b/apps/main/src/entities/gauge/model/mutate-options.ts @@ -11,13 +11,13 @@ */ import * as api from '@/entities/gauge/api' -import { gaugeKeys as keys } from '@/entities/gauge/model' +import { gaugeKeys as keys, gaugeValidationSuite } from '@/entities/gauge/model' import type { AddRewardParams, DepositRewardApproveParams, DepositRewardParams } from '@/entities/gauge/types' +import { assertValidity } from '@/shared/lib/validation' import { GaugeParams } from '@/shared/model/query' export const getAddRewardTokenMutation = ({ chainId, poolId }: GaugeParams) => ({ - mutationFn: async ({ rewardTokenId, distributorId }: AddRewardParams) => - api.mutateAddRewardToken(keys.addRewardToken({ chainId, poolId, rewardTokenId, distributorId })), + mutationFn: async (params: AddRewardParams) => api.mutateAddRewardToken(assertValidity(gaugeValidationSuite, params)), mutationKey: keys.addRewardToken({ chainId, poolId }), meta: { queryKeyFn: ({ rewardTokenId, distributorId }: AddRewardParams) => @@ -31,8 +31,8 @@ export const getAddRewardTokenMutation = ({ chainId, poolId }: GaugeParams) => ( }) export const getDepositRewardApproveMutation = ({ chainId, poolId }: GaugeParams) => ({ - mutationFn: async ({ rewardTokenId, amount }: DepositRewardApproveParams) => - api.mutateDepositRewardApprove(keys.depositRewardApprove({ chainId, poolId, rewardTokenId, amount })), + mutationFn: async (params: DepositRewardApproveParams) => + api.mutateDepositRewardApprove(assertValidity(gaugeValidationSuite, params)), mutationKey: keys.depositRewardApprove({ chainId, poolId }), meta: { queryKeyFn: ({ rewardTokenId, amount }: DepositRewardApproveParams) => @@ -41,8 +41,8 @@ export const getDepositRewardApproveMutation = ({ chainId, poolId }: GaugeParams }) export const getDepositRewardMutation = ({ chainId, poolId }: GaugeParams) => ({ - mutationFn: async ({ rewardTokenId, amount, epoch }: DepositRewardParams) => - api.mutateDepositReward(keys.depositReward({ chainId, poolId, rewardTokenId, amount, epoch })), + mutationFn: async (params: DepositRewardParams) => + api.mutateDepositReward(assertValidity(gaugeValidationSuite, params)), mutationKey: keys.depositReward({ chainId, poolId }), meta: { queryKeyFn: ({ rewardTokenId, amount, epoch }: DepositRewardParams) => diff --git a/packages/curve-lib/src/shared/lib/validation/lib.ts b/packages/curve-lib/src/shared/lib/validation/lib.ts index b9bb61783..7a62b56fe 100644 --- a/packages/curve-lib/src/shared/lib/validation/lib.ts +++ b/packages/curve-lib/src/shared/lib/validation/lib.ts @@ -1,36 +1,26 @@ import { create, enforce, only, type Suite } from 'vest' import { extendEnforce } from './enforce-extension' -import { FieldName, ValidatedData } from './types' +import { FieldName, FieldsOf } from './types' extendEnforce(enforce) -const getFieldsList = [] = Extract[]>( - data: T, - fields?: F -): F => fields && fields.length > 0 ? fields : (Object.keys(data) as F) - -export function checkValidity>( +export const checkValidity = >( suite: S, - data: D, - fields?: Extract[] -): boolean { - const fieldsList = getFieldsList(data, fields) - const result = suite(data, fieldsList) - return fieldsList.every((field) => result.getErrors(field).length === 0) -} + data: FieldsOf, + fields?: FieldName[] +): boolean => Object.keys(suite(data, fields).getErrors()).length === 0 export function assertValidity>( suite: S, - data: D, - fields?: Extract[] -): ValidatedData { - const fieldsList = getFieldsList(data, fields) - const result = suite(data, fieldsList) - const errors = fieldsList.flatMap((field) => result.getErrors(field)) - if (errors.length > 0) { - throw new Error('Validation failed: ' + errors.join(', ')) + data: FieldsOf, + fields?: FieldName[] +): D { + const result = suite(data, fields) + const entries = Object.entries(result.getErrors()) + if (entries.length > 0) { + throw new Error(`Validation failed: ${entries.map(([field, error]) => `${field}: ${error}`).join(', ')}`) } - return data as ValidatedData + return data as D } export const createValidationSuite = < diff --git a/packages/curve-lib/src/shared/lib/validation/types.ts b/packages/curve-lib/src/shared/lib/validation/types.ts index 8b83e2351..f3aa9fca1 100644 --- a/packages/curve-lib/src/shared/lib/validation/types.ts +++ b/packages/curve-lib/src/shared/lib/validation/types.ts @@ -1,7 +1,3 @@ -export type ValidatedData = { - [K in keyof T]-?: NonNullable -} - export type FieldName = Extract export type FieldsOf = { diff --git a/packages/curve-lib/src/shared/model/query/factory.ts b/packages/curve-lib/src/shared/model/query/factory.ts index 53795071f..6ee819d29 100644 --- a/packages/curve-lib/src/shared/model/query/factory.ts +++ b/packages/curve-lib/src/shared/model/query/factory.ts @@ -7,15 +7,17 @@ import { assertValidity as sharedAssertValidity, checkValidity, FieldName, Field import { REFRESH_INTERVAL } from '@/shared/model/time' import { QueryFactoryInput, QueryFactoryOutput } from '../../types' -const extractQueryParams = (queryKey: readonly unknown[]) => - (Object.fromEntries(queryKey.flatMap(i => i && typeof i === 'object' ? Object.entries(i) : []))) +export function getParamsFromQueryKey(queryKey: TKey, assertValidity: (data: TParams, fields?: TField[]) => TQuery) { + const queryParams = (Object.fromEntries(queryKey.flatMap(i => i && typeof i === 'object' ? Object.entries(i) : []))) as TParams + return assertValidity(queryParams) +} export function queryFactory< TQuery extends object, TKey extends readonly unknown[], TData, TParams extends FieldsOf = FieldsOf, - TField extends FieldName = FieldName, + TField extends FieldName = FieldName, TGroup extends string = string, TCallback extends CB = CB >({ @@ -32,8 +34,7 @@ export function queryFactory< queryKey: queryKey(params), queryFn: ({ queryKey }: QueryFunctionContext) => { logQuery(queryKey) - const queryParams = extractQueryParams(queryKey) as TParams - const params = assertValidity(queryParams) + const params = getParamsFromQueryKey(queryKey, assertValidity) return queryFn(params) }, staleTime: staleTime ? REFRESH_INTERVAL[staleTime] : undefined, diff --git a/packages/curve-lib/src/shared/types/factory.ts b/packages/curve-lib/src/shared/types/factory.ts index d73ced68b..fabcafcaa 100644 --- a/packages/curve-lib/src/shared/types/factory.ts +++ b/packages/curve-lib/src/shared/types/factory.ts @@ -15,7 +15,7 @@ type IsLiteralOrSingleKeyObject = ? true : false -// Recursively checks each element in the array +// Recursively checks each element in the tuple type AreAllElementsLiteralOrSinglePropertyObject = T extends readonly [ infer First, ...infer Rest,