Skip to content

Commit

Permalink
feat(utils): implement filters schemas
Browse files Browse the repository at this point in the history
fix(utils): better zod lazy usage to fix type issues

chore(utils): ignore esoteric arrayoperator type error

chore(questdk): re-export zod schemas

chore(types): address build issues for unknown / any types

fix(utils): update zod to utilize abitype readonly

chore: fix formatting
  • Loading branch information
sammccord committed Aug 16, 2024
1 parent 482c89e commit 49f27ac
Show file tree
Hide file tree
Showing 16 changed files with 299 additions and 179 deletions.
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
61 changes: 37 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,7 @@ 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 +46,7 @@ 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 +62,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 +79,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 +92,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 +105,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 +118,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 +131,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 +144,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 +157,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 +169,10 @@ 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 +184,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 +195,10 @@ 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 +210,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 +226,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 +245,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 +292,19 @@ 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 +344,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 +376,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 +404,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 +421,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 +440,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
2 changes: 1 addition & 1 deletion packages/balancer/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ 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
2 changes: 1 addition & 1 deletion packages/orbit/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ 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

0 comments on commit 49f27ac

Please sign in to comment.