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

Implement Zod schemas for Filters in utils [BOOST-4470] #514

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
5 changes: 5 additions & 0 deletions .changeset/blue-pigs-visit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rabbitholegg/questdk-plugin-utils": minor
---

implement filter types as zod schemas
2 changes: 1 addition & 1 deletion apps/create-plugin/src/questions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export const mainQuestions: PromptObject[] = [
name: 'action',
message: 'How would you describe the action you want the user to take?',
initial: '',
choices: _actionArray,
choices: _actionArray as Choice[],
},
{
type: 'confirm',
Expand Down
78 changes: 54 additions & 24 deletions apps/questdk/src/filter/filters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import {
parseAbiParameters,
slice,
AbiParameter,
ByteArray,
Hex,
} from 'viem'
type OperatorKey = keyof typeof operators

Expand All @@ -29,7 +31,10 @@ type OperatorKey = keyof typeof operators
* @param filter - The set of filters to apply.
* @returns True if all filters pass, false otherwise.
*/
export const handleAnd = (context: any, filter: Filter[]): boolean => {
export const handleAnd = (
context: TransactionEIP1559 | Record<string, unknown>,
filter: Filter[],
): boolean => {
for (let i = 0; i < filter.length; i++) {
if (!apply(context, filter[i] as FilterObject)) {
return false
Expand All @@ -44,7 +49,10 @@ export const handleAnd = (context: any, filter: Filter[]): boolean => {
* @param filter - The set of filters to apply.
* @returns True if any filter passes, false otherwise.
*/
export const handleOr = (context: any, filter: Filter[]): boolean => {
export const handleOr = (
context: TransactionEIP1559 | Record<string, unknown>,
filter: Filter[],
): boolean => {
for (let i = 0; i < filter.length; i++) {
if (apply(context, filter[i] as FilterObject)) {
return true
Expand All @@ -60,7 +68,7 @@ export const handleOr = (context: any, filter: Filter[]): boolean => {
* @returns True if any filter passes, false otherwise.
*/
export const handleSome = (
context: any,
context: Array<TransactionEIP1559 | Record<string, unknown>>,
filter: TransactionFilter | FilterObject,
): boolean => {
for (let i = 0; i < context.length; i++) {
Expand All @@ -77,7 +85,7 @@ export const handleSome = (
* @returns True if context is less than filter, false otherwise.
*/
export const handleLessThan = (
context: any,
context: bigint | boolean | number | string,
filter: bigint | number | string,
): boolean => {
return BigInt(context) < BigInt(filter)
Expand All @@ -90,7 +98,7 @@ export const handleLessThan = (
* @returns True if context is less than or equal to filter, false otherwise.
*/
export const handleLessThanOrEqual = (
context: any,
context: bigint | boolean | number | string,
filter: bigint | number | string,
): boolean => {
return BigInt(context) <= BigInt(filter)
Expand All @@ -103,7 +111,7 @@ export const handleLessThanOrEqual = (
* @returns True if context is equal to filter, false otherwise.
*/
export const handleEqual = (
context: any,
context: bigint | boolean | number | string,
filter: bigint | number | string,
): boolean => {
return BigInt(context) === BigInt(filter)
Expand All @@ -116,7 +124,7 @@ export const handleEqual = (
* @returns True if context is greater than filter, false otherwise.
*/
export const handleGreaterThan = (
context: any,
context: bigint | boolean | number | string,
filter: bigint | number | string,
): boolean => {
return BigInt(context) > BigInt(filter)
Expand All @@ -129,7 +137,7 @@ export const handleGreaterThan = (
* @returns True if context is greater than or equal to filter, false otherwise.
*/
export const handleGreaterThanOrEqual = (
context: any,
context: bigint | boolean | number | string,
filter: bigint | number | string,
): boolean => {
return BigInt(context) >= BigInt(filter)
Expand All @@ -142,7 +150,7 @@ export const handleGreaterThanOrEqual = (
* @returns The result of applying the filter.
*/
export const handleFirst = (
context: any,
context: Array<TransactionEIP1559 | Record<string, unknown>>,
filter: TransactionFilter | FilterObject,
): boolean => {
return apply(context[0], filter)
Expand All @@ -155,7 +163,7 @@ export const handleFirst = (
* @returns The result of applying the filter.
*/
export const handleLast = (
context: any,
context: Array<TransactionEIP1559 | Record<string, unknown>>,
filter: TransactionFilter | FilterObject,
): boolean => {
return apply(context[context.length - 1], filter)
Expand All @@ -167,10 +175,13 @@ export const handleLast = (
* @param filter - An object containing the index and the condition to check.
* @returns True if the value at the nth index meets the condition, false otherwise.
*/
export const handleNth = (context: any, filter: NthFilter): boolean => {
export const handleNth = (
context: Array<TransactionEIP1559 | Record<string, unknown>>,
filter: NthFilter,
): boolean => {
const { index, value } = filter

if (Number(index) < 0 || index >= context.length) {
if (Number(index) < 0 || Number(index) >= context.length) {
return false // index out of bounds
}
return apply(context[Number(index)], value as FilterObject)
Expand All @@ -182,7 +193,7 @@ export const handleNth = (context: any, filter: NthFilter): boolean => {
* @param filter - The regular expression to match against.
* @returns True if the context matches the filter, false otherwise.
*/
export const handleRegex = (context: any, filter: string): boolean => {
export const handleRegex = (context: string, filter: string): boolean => {
const re = new RegExp(filter)
return re.test(context)
}
Expand All @@ -193,9 +204,13 @@ export const handleRegex = (context: any, filter: string): boolean => {
* @param filter - An object containing the bitmask and the value to compare against.
* @returns True if the masked context is equal to the value, false otherwise.
*/
export const handleBitmask = (context: any, filter: BitmaskFilter): boolean => {
export const handleBitmask = (
context: bigint | boolean | number | string,
filter: BitmaskFilter,
): boolean => {
const maskedContext = BigInt(context) & BigInt(filter.bitmask)
if (typeof filter.value === 'object') {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return apply(maskedContext as any, filter.value as FilterObject)
}
return maskedContext === BigInt(filter.value)
Expand All @@ -207,6 +222,7 @@ export const handleBitmask = (context: any, filter: BitmaskFilter): boolean => {
* @param filter - The filter containing the ABI.
* @returns The decoded ABI.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const handleAbiDecode = (context: any, filter: AbiFilter) => {
try {
const sighash = slice(context, 0, 4)
Expand All @@ -222,12 +238,14 @@ export const handleAbiDecode = (context: any, filter: AbiFilter) => {
}) as AbiFunction

const namedArgs = [...abiItem.inputs].reduce(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(acc: Record<string, any>, input, index) => {
acc[`${input.name || index}`] = args[index]
return acc
},
{},
)
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { $abi: _, ...newFilter } = filter
if (apply({ ...namedArgs, sighash, functionName }, newFilter)) {
return true
Expand All @@ -239,12 +257,14 @@ export const handleAbiDecode = (context: any, filter: AbiFilter) => {
}

export const handleAbstractAbiDecode = (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
context: any,
filter: AbstractAbiFilter,
) => {
const decodedReturn: Array<ReturnType<typeof handleAbiDecode>> = []
const elementCount = filter.$abiAbstract!.length
const $abiAbstract = filter.$abiAbstract
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { $abiAbstract: _, ...newFilter } = filter

const contextMap = new Map<string, number>()
Expand Down Expand Up @@ -284,18 +304,24 @@ export const handleAbstractAbiDecode = (
* @param filter - The filter containing the ABI parameters.
* @returns The decoded ABI parameters.
*/
export const handleAbiParamDecode = (context: any, filter: AbiParamFilter) => {
export const handleAbiParamDecode = (
context: ByteArray | Hex,
filter: AbiParamFilter,
) => {
try {
const params = parseAbiParameters(filter.$abiParams.join(', '))
const params = parseAbiParameters(
filter.$abiParams.join(', '),
) as AbiParameter[]
const args = decodeAbiParameters(params, context)
const namedArgs = params.reduce(
(acc: Record<string, any>, param: AbiParameter, index) => {
(acc: Record<string, unknown>, param: AbiParameter, index) => {
acc[`${param.name || index}`] = args[index]
return acc
},
{},
)
const { $abiParams: _, ...newFilter } = filter
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { $abiParams: _unused, ...newFilter } = filter
if (apply(namedArgs, newFilter)) {
return true
}
Expand Down Expand Up @@ -335,10 +361,10 @@ const operators = {
* @returns True if all filters pass, false otherwise.
*/
export function apply(
originalContext: TransactionEIP1559 | Record<string, any>,
originalContext: TransactionEIP1559 | Record<string, unknown>,
filters: TransactionFilter | FilterObject,
): boolean {
let context: TransactionEIP1559 | Record<string, any> = originalContext
let context: TransactionEIP1559 | Record<string, unknown> = originalContext
if (typeof filters === 'object') {
if ('$abi' in filters) {
const processedContext = handleAbiDecode(context, filters as AbiFilter)
Expand Down Expand Up @@ -367,7 +393,8 @@ export function apply(

if ('$abiParams' in filters) {
const processedContext = handleAbiParamDecode(
context,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
context as any,
filters as AbiParamFilter,
)
if (processedContext === true) {
Expand All @@ -394,7 +421,8 @@ export function apply(

if (
!operator(
context,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
context as any,
filter as Filter[] &
string &
TransactionFilter &
Expand All @@ -410,7 +438,8 @@ export function apply(
if (!(key in context)) {
return false
}
if (!apply(_context, filter as FilterObject | TransactionFilter)) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (!apply(_context as any, filter as FilterObject | TransactionFilter)) {
return false
}
} else if (isAddress(_context as string)) {
Expand All @@ -428,7 +457,8 @@ export function apply(
) {
if (
_context === undefined ||
BigInt(_context) !== BigInt(filter as bigint | number | string)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
BigInt(_context as any) !== BigInt(filter as bigint | number | string)
) {
return false
}
Expand Down
19 changes: 19 additions & 0 deletions apps/questdk/src/filter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,22 @@ export type {
Filter,
FilterObject,
} from '@rabbitholegg/questdk-plugin-utils'

export {
NumericSchema,
NumericOperatorSchema,
BitmaskFilterSchema,
StringOperatorSchema,
ArrayOperatorSchema,
LogicalOperatorSchema,
FilterOperatorSchema,
TransactionFilterSchema,
PrimitiveSchema,
FilterObjectSchema,
AbiFilterSchema,
AbstractAbiFilterSchema,
AbiParamFilterSchema,
FilterSchema,
FilterArraySchema,
NthFilterSchema,
} from '@rabbitholegg/questdk-plugin-utils'
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"react-intl": "6.6.2",
"ts-pattern": "5.0.1",
"viem": "2.15.1",
"zod": "3.21.4"
"zod": "3.23.8"
},
"pnpm": {
"overrides": {
Expand Down
5 changes: 4 additions & 1 deletion packages/balancer/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ export const buildAmountQuery = (
if (amountOut) {
let condition: FilterOperator | undefined
if (typeof amountOut === 'object') {
const [operator, value] = Object.entries(amountOut)[0]
const [operator, value] = Object.entries(amountOut)[0] as [
string,
bigint | boolean | number | string,
]
switch (operator) {
case '$gte':
condition = { $lte: BigInt(-value) }
Expand Down
3 changes: 2 additions & 1 deletion packages/llama/src/Llama.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ export const vote = async (voteParams: VoteActionParams) => {

const supportIsBoolean = support !== undefined && typeof support === 'boolean'

let abi = []
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let abi: any[] = []
if (supportIsBoolean) {
// if the support param is a boolean, we only want to use the abi that matches the boolean
if (support) {
Expand Down
5 changes: 4 additions & 1 deletion packages/orbit/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ export function getUnlockTime(
const now = Math.floor(new Date().getTime() / 1000)

if (typeof duration === 'object') {
const [operator, value] = Object.entries(duration)[0]
const [operator, value] = Object.entries(duration)[0] as [
string,
string | number | bigint | boolean,
]
return { [operator]: BigInt(value) + BigInt(now) }
}
return { $gte: BigInt(duration) + BigInt(now) }
Expand Down
3 changes: 3 additions & 0 deletions packages/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,8 @@
"test:cov": "vitest dev --coverage",
"test:ci": "CI=true vitest --coverage",
"test:ui": "vitest dev --ui"
},
"dependencies": {
"abitype": "^1.0.6"
}
}
17 changes: 17 additions & 0 deletions packages/utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,23 @@ export {
PremintValidationParamsSchema,
PremintActionDetailSchema,
PremintActionFormSchema,
// Filter Schemas
NumericSchema,
NumericOperatorSchema,
BitmaskFilterSchema,
StringOperatorSchema,
ArrayOperatorSchema,
LogicalOperatorSchema,
FilterOperatorSchema,
TransactionFilterSchema,
PrimitiveSchema,
FilterObjectSchema,
AbiFilterSchema,
AbstractAbiFilterSchema,
AbiParamFilterSchema,
FilterSchema,
FilterArraySchema,
NthFilterSchema,
} from './types'

export {
Expand Down
Loading