From 8ec9151949ff2ad9d236bfa42eb31fd84b48cca3 Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Wed, 30 Aug 2023 18:40:54 +0200
Subject: [PATCH] apply pr suggestions
---
src/agents/contracts.ts | 3 +-
src/conditions/base/index.ts | 9 +--
src/conditions/base/rpc.ts | 24 ++-----
src/conditions/base/shared.ts | 18 ++++++
src/conditions/compound-condition.ts | 6 +-
src/conditions/condition-expr.ts | 29 +--------
src/conditions/condition.ts | 64 +++++++++++--------
src/conditions/const.ts | 9 +++
src/conditions/index.ts | 5 +-
src/conditions/zod.ts | 31 +++++++++
src/types.ts | 7 --
src/web3.ts | 8 +++
test/unit/conditions/base/condition.test.ts | 34 +---------
test/unit/conditions/base/contract.test.ts | 43 +++++++++----
test/unit/conditions/base/rpc.test.ts | 8 ++-
test/unit/conditions/base/time.test.ts | 7 +-
.../conditions/compound-condition.test.ts | 26 +++++---
test/unit/conditions/condition-expr.test.ts | 58 +++++++++++++----
test/unit/testVariables.ts | 2 +-
19 files changed, 226 insertions(+), 165 deletions(-)
create mode 100644 src/conditions/base/shared.ts
create mode 100644 src/conditions/zod.ts
diff --git a/src/agents/contracts.ts b/src/agents/contracts.ts
index 0ed03352f..a25d89115 100644
--- a/src/agents/contracts.ts
+++ b/src/agents/contracts.ts
@@ -1,4 +1,5 @@
-import { ChainId, ChecksumAddress } from '../types';
+import { ChecksumAddress } from '../types';
+import { ChainId } from '../web3';
type Contracts = {
readonly SUBSCRIPTION_MANAGER: ChecksumAddress | undefined;
diff --git a/src/conditions/base/index.ts b/src/conditions/base/index.ts
index a6a0abe36..b17914f34 100644
--- a/src/conditions/base/index.ts
+++ b/src/conditions/base/index.ts
@@ -35,9 +35,6 @@ export class TimeCondition extends Condition {
}
}
-export {
- contractConditionSchema,
- type ContractConditionProps,
-} from './contract';
-export { rpcConditionSchema, type RpcConditionProps } from './rpc';
-export { timeConditionSchema, type TimeConditionProps } from './time';
+export { type ContractConditionProps } from './contract';
+export { type RpcConditionProps } from './rpc';
+export { type TimeConditionProps } from './time';
diff --git a/src/conditions/base/rpc.ts b/src/conditions/base/rpc.ts
index 2b16d7823..ea232d50f 100644
--- a/src/conditions/base/rpc.ts
+++ b/src/conditions/base/rpc.ts
@@ -1,29 +1,15 @@
import { z } from 'zod';
-import { ETH_ADDRESS_REGEXP, USER_ADDRESS_PARAM } from '../const';
+import { SUPPORTED_CHAIN_IDS } from '../const';
+import createUnionSchema from '../zod';
-export const returnValueTestSchema = z.object({
- index: z.number().optional(),
- comparator: z.enum(['==', '>', '<', '>=', '<=', '!=']),
- value: z.union([z.string(), z.number(), z.boolean()]),
-});
-
-export type ReturnValueTestProps = z.infer;
-
-const EthAddressOrUserAddressSchema = z.array(
- z.union([z.string().regex(ETH_ADDRESS_REGEXP), z.literal(USER_ADDRESS_PARAM)])
-);
+import { EthAddressOrUserAddressSchema, returnValueTestSchema } from './shared';
export const rpcConditionSchema = z.object({
conditionType: z.literal('rpc').default('rpc'),
- chain: z.union([
- z.literal(137),
- z.literal(80001),
- z.literal(5),
- z.literal(1),
- ]),
+ chain: createUnionSchema(SUPPORTED_CHAIN_IDS),
method: z.enum(['eth_getBalance', 'balanceOf']),
- parameters: EthAddressOrUserAddressSchema,
+ parameters: z.array(EthAddressOrUserAddressSchema),
returnValueTest: returnValueTestSchema,
});
diff --git a/src/conditions/base/shared.ts b/src/conditions/base/shared.ts
new file mode 100644
index 000000000..904329521
--- /dev/null
+++ b/src/conditions/base/shared.ts
@@ -0,0 +1,18 @@
+import { z } from 'zod';
+
+import { ETH_ADDRESS_REGEXP, USER_ADDRESS_PARAM } from '../const';
+
+export const returnValueTestSchema = z.object({
+ index: z.number().optional(),
+ comparator: z.enum(['==', '>', '<', '>=', '<=', '!=']),
+ value: z.unknown(),
+});
+
+export type ReturnValueTestProps = z.infer;
+
+const EthAddressSchema = z.string().regex(ETH_ADDRESS_REGEXP);
+const UserAddressSchema = z.literal(USER_ADDRESS_PARAM);
+export const EthAddressOrUserAddressSchema = z.union([
+ EthAddressSchema,
+ UserAddressSchema,
+]);
diff --git a/src/conditions/compound-condition.ts b/src/conditions/compound-condition.ts
index 33c137a99..2c88e0bfe 100644
--- a/src/conditions/compound-condition.ts
+++ b/src/conditions/compound-condition.ts
@@ -1,8 +1,8 @@
import { z } from 'zod';
-import { contractConditionSchema } from './base';
-import { rpcConditionSchema } from './base';
-import { timeConditionSchema } from './base';
+import { contractConditionSchema } from './base/contract';
+import { rpcConditionSchema } from './base/rpc';
+import { timeConditionSchema } from './base/time';
export const compoundConditionSchema: z.ZodSchema = z.object({
conditionType: z.literal('compound').default('compound'),
diff --git a/src/conditions/condition-expr.ts b/src/conditions/condition-expr.ts
index 99358f84c..697687088 100644
--- a/src/conditions/condition-expr.ts
+++ b/src/conditions/condition-expr.ts
@@ -4,17 +4,7 @@ import { SemVer } from 'semver';
import { toBytes, toJSON } from '../utils';
-import {
- CompoundCondition,
- ContractCondition,
- ContractConditionProps,
- RpcCondition,
- RpcConditionProps,
- TimeCondition,
- TimeConditionProps,
-} from './base';
-import { CompoundConditionProps } from './compound-condition';
-import { Condition, ConditionProps } from './condition';
+import { Condition } from './condition';
import { ConditionContext, CustomContextParam } from './context';
export type ConditionExpressionJSON = {
@@ -38,21 +28,6 @@ export class ConditionExpression {
};
}
- private static conditionFromObject(obj: ConditionProps): Condition {
- switch (obj.conditionType) {
- case 'rpc':
- return new RpcCondition(obj as RpcConditionProps);
- case 'time':
- return new TimeCondition(obj as TimeConditionProps);
- case 'contract':
- return new ContractCondition(obj as ContractConditionProps);
- case 'compound':
- return new CompoundCondition(obj as CompoundConditionProps);
- default:
- throw new Error(`Invalid conditionType: ${obj.conditionType}`);
- }
- }
-
public static fromObj(obj: ConditionExpressionJSON): ConditionExpression {
const receivedVersion = new SemVer(obj.version);
const currentVersion = new SemVer(ConditionExpression.VERSION);
@@ -70,7 +45,7 @@ export class ConditionExpression {
);
}
- const condition = this.conditionFromObject(obj.condition as ConditionProps);
+ const condition = Condition.fromObj(obj.condition);
return new ConditionExpression(condition, obj.version);
}
diff --git a/src/conditions/condition.ts b/src/conditions/condition.ts
index fe957bf32..b16444ef1 100644
--- a/src/conditions/condition.ts
+++ b/src/conditions/condition.ts
@@ -3,40 +3,40 @@ import { z } from 'zod';
import { objectEquals } from '../utils';
import {
+ CompoundCondition,
+ ContractCondition,
ContractConditionProps,
+ RpcCondition,
RpcConditionProps,
+ TimeCondition,
TimeConditionProps,
} from './base';
import { CompoundConditionProps } from './compound-condition';
import { USER_ADDRESS_PARAM } from './const';
-// Not using discriminated union because of inconsistent Zod types
-// Some conditions have ZodEffect types because of .refine() calls
-export type ConditionProps =
- | RpcConditionProps
- | TimeConditionProps
- | ContractConditionProps
- | CompoundConditionProps;
+type ConditionSchema = z.ZodSchema;
+export type ConditionProps = z.infer;
export class Condition {
constructor(
- public readonly schema: z.ZodSchema,
- public readonly value:
- | RpcConditionProps
- | TimeConditionProps
- | ContractConditionProps
- | CompoundConditionProps
- ) {}
+ public readonly schema: ConditionSchema,
+ public readonly value: ConditionProps
+ ) {
+ const { data, error } = Condition.validate(schema, value);
+ if (error) {
+ throw new Error(`Invalid condition: ${JSON.stringify(error.issues)}`);
+ }
+ this.value = data;
+ }
- public validate(override: Partial = {}): {
+ public static validate(
+ schema: ConditionSchema,
+ value: ConditionProps
+ ): {
data?: ConditionProps;
error?: z.ZodError;
} {
- const newValue = {
- ...this.value,
- ...override,
- };
- const result = this.schema.safeParse(newValue);
+ const result = schema.safeParse(value);
if (result.success) {
return { data: result.data };
}
@@ -48,18 +48,30 @@ export class Condition {
}
public toObj() {
- const { data, error } = this.validate(this.value);
+ const { data, error } = Condition.validate(this.schema, this.value);
if (error) {
throw new Error(`Invalid condition: ${JSON.stringify(error.issues)}`);
}
return data;
}
- public static fromObj(
- this: new (...args: unknown[]) => T,
- obj: Record
- ): T {
- return new this(obj);
+ private static conditionFromObject(obj: ConditionProps): Condition {
+ switch (obj.conditionType) {
+ case 'rpc':
+ return new RpcCondition(obj as RpcConditionProps);
+ case 'time':
+ return new TimeCondition(obj as TimeConditionProps);
+ case 'contract':
+ return new ContractCondition(obj as ContractConditionProps);
+ case 'compound':
+ return new CompoundCondition(obj as CompoundConditionProps);
+ default:
+ throw new Error(`Invalid conditionType: ${obj.conditionType}`);
+ }
+ }
+
+ public static fromObj(obj: ConditionProps): Condition {
+ return Condition.conditionFromObject(obj);
}
public equals(other: Condition) {
diff --git a/src/conditions/const.ts b/src/conditions/const.ts
index 3a8b941d2..9854c6a13 100644
--- a/src/conditions/const.ts
+++ b/src/conditions/const.ts
@@ -1,3 +1,12 @@
+import { ChainId } from '../web3';
+
export const USER_ADDRESS_PARAM = ':userAddress';
export const ETH_ADDRESS_REGEXP = new RegExp('^0x[a-fA-F0-9]{40}$');
+
+export const SUPPORTED_CHAIN_IDS = [
+ ChainId.POLYGON,
+ ChainId.MUMBAI,
+ ChainId.GOERLI,
+ ChainId.MAINNET,
+];
diff --git a/src/conditions/index.ts b/src/conditions/index.ts
index 365b87a63..ac71ad556 100644
--- a/src/conditions/index.ts
+++ b/src/conditions/index.ts
@@ -8,7 +8,4 @@ export {
} from './condition-expr';
export { ConditionContext, type CustomContextParam } from './context';
export { Condition, type ConditionProps } from './condition';
-export {
- compoundConditionSchema,
- type CompoundConditionProps,
-} from './compound-condition';
+export { type CompoundConditionProps } from './compound-condition';
diff --git a/src/conditions/zod.ts b/src/conditions/zod.ts
new file mode 100644
index 000000000..1829e1201
--- /dev/null
+++ b/src/conditions/zod.ts
@@ -0,0 +1,31 @@
+import { Primitive, z, ZodLiteral } from 'zod';
+
+// Source: https://github.com/colinhacks/zod/issues/831#issuecomment-1063481764
+const createUnion = <
+ T extends Readonly<[Primitive, Primitive, ...Primitive[]]>
+>(
+ values: T
+) => {
+ const zodLiterals = values.map((value) => z.literal(value)) as unknown as [
+ ZodLiteral,
+ ZodLiteral,
+ ...ZodLiteral[]
+ ];
+ return z.union(zodLiterals);
+};
+
+function createUnionSchema(values: T) {
+ if (values.length === 0) {
+ return z.never();
+ }
+
+ if (values.length === 1) {
+ return z.literal(values[0]);
+ }
+
+ return createUnion(
+ values as unknown as Readonly<[Primitive, Primitive, ...Primitive[]]>
+ );
+}
+
+export default createUnionSchema;
diff --git a/src/types.ts b/src/types.ts
index 2440dcc53..9befc497e 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -1,10 +1,3 @@
export type ChecksumAddress = string;
export type HexEncodedBytes = string;
export type Base64EncodedBytes = string;
-
-export enum ChainId {
- POLYGON = 137,
- MUMBAI = 80001,
- GOERLI = 5,
- MAINNET = 1,
-}
diff --git a/src/web3.ts b/src/web3.ts
index 1b5dcd11a..a55508f8f 100644
--- a/src/web3.ts
+++ b/src/web3.ts
@@ -1,4 +1,12 @@
import { fromHexString } from './utils';
+
+export enum ChainId {
+ POLYGON = 137,
+ MUMBAI = 80001,
+ GOERLI = 5,
+ MAINNET = 1,
+}
+
export const toCanonicalAddress = (address: string): Uint8Array => {
const ETH_ADDRESS_STRING_PREFIX = '0x';
const nonPrefixed = address.startsWith(ETH_ADDRESS_STRING_PREFIX)
diff --git a/test/unit/conditions/base/condition.test.ts b/test/unit/conditions/base/condition.test.ts
index baa0882a0..e91322af0 100644
--- a/test/unit/conditions/base/condition.test.ts
+++ b/test/unit/conditions/base/condition.test.ts
@@ -1,3 +1,4 @@
+import { Condition } from '../../../../src/conditions';
import { ContractCondition } from '../../../../src/conditions/base';
import {
ERC721Balance,
@@ -6,7 +7,6 @@ import {
import {
TEST_CHAIN_ID,
TEST_CONTRACT_ADDR,
- TEST_CONTRACT_ADDR_2,
testContractConditionObj,
} from '../../testVariables';
@@ -17,40 +17,10 @@ describe('validation', () => {
});
it('accepts a correct schema', async () => {
- const result = condition.validate();
+ const result = Condition.validate(condition.schema, condition.value);
expect(result.error).toBeUndefined();
expect(result.data.contractAddress).toEqual(TEST_CONTRACT_ADDR);
});
-
- it('accepts on a valid value override', async () => {
- const validOverride = {
- chain: TEST_CHAIN_ID,
- contractAddress: TEST_CONTRACT_ADDR_2,
- };
- const result = condition.validate(validOverride);
- expect(result.error).toBeUndefined();
- expect(result.data).toMatchObject(validOverride);
- });
-
- it('rejects on an invalid value override', async () => {
- const invalidOverride = {
- chain: -1,
- contractAddress: TEST_CONTRACT_ADDR,
- };
- const result = condition.validate(invalidOverride);
- expect(result.error).toBeDefined();
- expect(result.data).toBeUndefined();
- expect(result.error?.format()).toMatchObject({
- chain: {
- _errors: [
- 'Invalid literal value, expected 137',
- 'Invalid literal value, expected 80001',
- 'Invalid literal value, expected 5',
- 'Invalid literal value, expected 1',
- ],
- },
- });
- });
});
describe('serialization', () => {
diff --git a/test/unit/conditions/base/contract.test.ts b/test/unit/conditions/base/contract.test.ts
index 11ff45f29..002467210 100644
--- a/test/unit/conditions/base/contract.test.ts
+++ b/test/unit/conditions/base/contract.test.ts
@@ -6,14 +6,20 @@ import {
ContractCondition,
ContractConditionProps,
} from '../../../../src/conditions/base';
-import { FunctionAbiProps } from '../../../../src/conditions/base/contract';
+import {
+ contractConditionSchema,
+ FunctionAbiProps,
+} from '../../../../src/conditions/base/contract';
import { USER_ADDRESS_PARAM } from '../../../../src/conditions/const';
import { fakeProvider, fakeSigner } from '../../../utils';
import { testContractConditionObj, testFunctionAbi } from '../../testVariables';
describe('validation', () => {
it('accepts on a valid schema', () => {
- const result = new ContractCondition(testContractConditionObj).validate();
+ const result = ContractCondition.validate(
+ contractConditionSchema,
+ testContractConditionObj
+ );
expect(result.error).toBeUndefined();
expect(result.data).toEqual(testContractConditionObj);
@@ -25,7 +31,10 @@ describe('validation', () => {
// Intentionally removing `contractAddress`
contractAddress: undefined,
} as unknown as ContractConditionProps;
- const result = new ContractCondition(badContractCondition).validate();
+ const result = ContractCondition.validate(
+ contractConditionSchema,
+ badContractCondition
+ );
expect(result.error).toBeDefined();
expect(result.data).toBeUndefined();
@@ -65,7 +74,10 @@ describe('accepts either standardContractType or functionAbi but not both or non
standardContractType,
functionAbi: undefined,
} as typeof testContractConditionObj;
- const result = new ContractCondition(conditionObj).validate();
+ const result = ContractCondition.validate(
+ contractConditionSchema,
+ conditionObj
+ );
expect(result.error).toBeUndefined();
expect(result.data).toEqual(conditionObj);
@@ -77,7 +89,10 @@ describe('accepts either standardContractType or functionAbi but not both or non
functionAbi,
standardContractType: undefined,
} as typeof testContractConditionObj;
- const result = new ContractCondition(conditionObj).validate();
+ const result = ContractCondition.validate(
+ contractConditionSchema,
+ conditionObj
+ );
expect(result.error).toBeUndefined();
expect(result.data).toEqual(conditionObj);
@@ -89,7 +104,10 @@ describe('accepts either standardContractType or functionAbi but not both or non
standardContractType,
functionAbi,
} as typeof testContractConditionObj;
- const result = new ContractCondition(conditionObj).validate();
+ const result = ContractCondition.validate(
+ contractConditionSchema,
+ conditionObj
+ );
expect(result.error).toBeDefined();
expect(result.data).toBeUndefined();
@@ -106,7 +124,10 @@ describe('accepts either standardContractType or functionAbi but not both or non
standardContractType: undefined,
functionAbi: undefined,
} as typeof testContractConditionObj;
- const result = new ContractCondition(conditionObj).validate();
+ const result = ContractCondition.validate(
+ contractConditionSchema,
+ conditionObj
+ );
expect(result.error).toBeDefined();
expect(result.data).toBeUndefined();
@@ -176,12 +197,12 @@ describe('supports custom function abi', () => {
},
},
])('accepts well-formed functionAbi', ({ method, functionAbi }) => {
- const result = new ContractCondition({
+ const result = ContractCondition.validate(contractConditionSchema, {
...contractConditionObj,
parameters: functionAbi.inputs.map((input) => `fake_parameter_${input}`), //
functionAbi: functionAbi as FunctionAbiProps,
method,
- }).validate();
+ });
expect(result.error).toBeUndefined();
expect(result.data).toBeDefined();
@@ -258,11 +279,11 @@ describe('supports custom function abi', () => {
])(
'rejects malformed functionAbi',
({ method, badField, expectedErrors, functionAbi }) => {
- const result = new ContractCondition({
+ const result = ContractCondition.validate(contractConditionSchema, {
...contractConditionObj,
functionAbi: functionAbi as unknown as FunctionAbiProps,
method,
- }).validate();
+ });
expect(result.error).toBeDefined();
expect(result.data).toBeUndefined();
diff --git a/test/unit/conditions/base/rpc.test.ts b/test/unit/conditions/base/rpc.test.ts
index a830d0f50..c4f658092 100644
--- a/test/unit/conditions/base/rpc.test.ts
+++ b/test/unit/conditions/base/rpc.test.ts
@@ -1,9 +1,13 @@
import { RpcCondition } from '../../../../src/conditions/base';
+import { rpcConditionSchema } from '../../../../src/conditions/base/rpc';
import { testRpcConditionObj } from '../../testVariables';
describe('validation', () => {
it('accepts on a valid schema', () => {
- const result = new RpcCondition(testRpcConditionObj).validate();
+ const result = RpcCondition.validate(
+ rpcConditionSchema,
+ testRpcConditionObj
+ );
expect(result.error).toBeUndefined();
expect(result.data).toEqual(testRpcConditionObj);
@@ -16,7 +20,7 @@ describe('validation', () => {
method: 'fake_invalid_method',
} as unknown as typeof testRpcConditionObj;
- const result = new RpcCondition(badRpcObj).validate();
+ const result = RpcCondition.validate(rpcConditionSchema, badRpcObj);
expect(result.error).toBeDefined();
expect(result.data).toBeUndefined();
diff --git a/test/unit/conditions/base/time.test.ts b/test/unit/conditions/base/time.test.ts
index e2d30cbed..0ace6466f 100644
--- a/test/unit/conditions/base/time.test.ts
+++ b/test/unit/conditions/base/time.test.ts
@@ -2,7 +2,8 @@ import {
TimeCondition,
TimeConditionProps,
} from '../../../../src/conditions/base';
-import { ReturnValueTestProps } from '../../../../src/conditions/base/rpc';
+import { ReturnValueTestProps } from '../../../../src/conditions/base/shared';
+import { timeConditionSchema } from '../../../../src/conditions/base/time';
describe('validation', () => {
const returnValueTest: ReturnValueTestProps = {
@@ -18,7 +19,7 @@ describe('validation', () => {
method: 'blocktime',
chain: 1,
};
- const result = new TimeCondition(conditionObj).validate();
+ const result = TimeCondition.validate(timeConditionSchema, conditionObj);
expect(result.error).toBeUndefined();
expect(result.data).toEqual(conditionObj);
@@ -34,7 +35,7 @@ describe('validation', () => {
},
chain: 5,
} as unknown as TimeConditionProps;
- const result = new TimeCondition(badObj).validate();
+ const result = TimeCondition.validate(timeConditionSchema, badObj);
expect(result.error).toBeDefined();
expect(result.data).toBeUndefined();
diff --git a/test/unit/conditions/compound-condition.test.ts b/test/unit/conditions/compound-condition.test.ts
index f558fd8c9..2f81a8bc8 100644
--- a/test/unit/conditions/compound-condition.test.ts
+++ b/test/unit/conditions/compound-condition.test.ts
@@ -1,4 +1,6 @@
+import { Condition } from '../../../src/conditions';
import { CompoundCondition } from '../../../src/conditions/base';
+import { compoundConditionSchema } from '../../../src/conditions/compound-condition';
import {
testContractConditionObj,
testRpcConditionObj,
@@ -11,7 +13,7 @@ describe('validation', () => {
operator: 'or',
operands: [testContractConditionObj, testTimeConditionObj],
};
- const result = new CompoundCondition(conditionObj).validate();
+ const result = Condition.validate(compoundConditionSchema, conditionObj);
expect(result.error).toBeUndefined();
expect(result.data).toEqual({
@@ -25,7 +27,10 @@ describe('validation', () => {
operator: 'and',
operands: [testContractConditionObj, testTimeConditionObj],
};
- const result = new CompoundCondition(conditionObj).validate();
+ const result = CompoundCondition.validate(
+ compoundConditionSchema,
+ conditionObj
+ );
expect(result.error).toBeUndefined();
expect(result.data).toEqual({
@@ -35,10 +40,10 @@ describe('validation', () => {
});
it('rejects an invalid operator', () => {
- const result = new CompoundCondition({
+ const result = CompoundCondition.validate(compoundConditionSchema, {
operator: 'not-an-operator',
operands: [testRpcConditionObj, testTimeConditionObj],
- }).validate();
+ });
expect(result.error).toBeDefined();
expect(result.data).toBeUndefined();
@@ -52,10 +57,10 @@ describe('validation', () => {
});
it('rejects invalid number of operands = 0', () => {
- const result = new CompoundCondition({
+ const result = CompoundCondition.validate(compoundConditionSchema, {
operator: 'or',
operands: [],
- }).validate();
+ });
expect(result.error).toBeDefined();
expect(result.data).toBeUndefined();
@@ -67,10 +72,10 @@ describe('validation', () => {
});
it('rejects invalid number of operands = 1', () => {
- const result = new CompoundCondition({
+ const result = CompoundCondition.validate(compoundConditionSchema, {
operator: 'or',
operands: [testRpcConditionObj],
- }).validate();
+ });
expect(result.error).toBeDefined();
expect(result.data).toBeUndefined();
expect(result.error?.format()).toMatchObject({
@@ -93,7 +98,10 @@ describe('validation', () => {
},
],
};
- const result = new CompoundCondition(conditionObj).validate();
+ const result = CompoundCondition.validate(
+ compoundConditionSchema,
+ conditionObj
+ );
expect(result.error).toBeUndefined();
expect(result.data).toEqual({
conditionType: 'compound',
diff --git a/test/unit/conditions/condition-expr.test.ts b/test/unit/conditions/condition-expr.test.ts
index bcc78e7a7..ff53730e1 100644
--- a/test/unit/conditions/condition-expr.test.ts
+++ b/test/unit/conditions/condition-expr.test.ts
@@ -7,6 +7,7 @@ import {
ContractConditionProps,
RpcCondition,
TimeCondition,
+ TimeConditionProps,
} from '../../../src/conditions/base';
import { USER_ADDRESS_PARAM } from '../../../src/conditions/const';
import { ERC721Balance } from '../../../src/conditions/predefined';
@@ -66,7 +67,7 @@ describe('condition set', () => {
describe('equality', () => {
const conditionExprCurrentVersion = new ConditionExpression(rpcCondition);
- it('same version and condition', async () => {
+ it('same version and condition', () => {
const conditionExprSameCurrentVersion = new ConditionExpression(
rpcCondition,
ConditionExpression.VERSION
@@ -76,7 +77,7 @@ describe('condition set', () => {
).toBeTruthy();
});
- it('different minor/patch version but same condition', async () => {
+ it('different minor/patch version but same condition', () => {
const conditionExprOlderMinorVersion = new ConditionExpression(
rpcCondition,
'0.1.0'
@@ -96,7 +97,7 @@ describe('condition set', () => {
).not.toBeTruthy();
});
- it('minor/patch number greater than major; still older', async () => {
+ it('minor/patch number greater than major; still older', () => {
const conditionExprOlderMinorVersion = new ConditionExpression(
rpcCondition,
'0.9.0'
@@ -139,7 +140,7 @@ describe('condition set', () => {
contractConditionWithAbi,
timeCondition,
compoundCondition,
- ])('same version but different condition', async (condition) => {
+ ])('same version but different condition', (condition) => {
const conditionExprSameVersionDifferentCondition =
new ConditionExpression(condition);
expect(
@@ -149,7 +150,7 @@ describe('condition set', () => {
).not.toBeTruthy();
});
- it('same contract condition although using erc721 helper', async () => {
+ it('same contract condition although using erc721 helper', () => {
const erc721ConditionExpr = new ConditionExpression(
erc721BalanceCondition
);
@@ -172,7 +173,7 @@ describe('condition set', () => {
rpcCondition,
timeCondition,
compoundCondition,
- ])('serializes to and from json', async (condition) => {
+ ])('serializes to and from json', (condition) => {
const conditionExpr = new ConditionExpression(condition);
const conditionExprJson = conditionExpr.toJson();
expect(conditionExprJson).toBeDefined();
@@ -187,7 +188,7 @@ describe('condition set', () => {
expect(conditionExprFromJson.equals(conditionExprFromJson)).toBeTruthy();
});
- it('incompatible version', async () => {
+ it('incompatible version', () => {
const currentVersion = new SemVer(ConditionExpression.VERSION);
const invalidVersion = currentVersion.inc('major');
expect(() => {
@@ -202,7 +203,7 @@ describe('condition set', () => {
it.each(['version', 'x.y', 'x.y.z', '-1,0.0', '1.0.0.0.0.0.0'])(
'invalid versions',
- async (invalidVersion) => {
+ (invalidVersion) => {
expect(() => {
ConditionExpression.fromObj({
version: invalidVersion,
@@ -212,7 +213,36 @@ describe('condition set', () => {
}
);
- it('erc721 condition serialization', async () => {
+ it.each(['_invalid_condition_type_', undefined as unknown as string])(
+ 'rejects an invalid condition type',
+ (invalidConditionType) => {
+ const conditionObj = {
+ ...testTimeConditionObj,
+ conditionType: invalidConditionType,
+ } as unknown as TimeConditionProps;
+ expect(() => {
+ ConditionExpression.fromObj({
+ version: ConditionExpression.VERSION,
+ condition: conditionObj,
+ });
+ }).toThrow(`Invalid conditionType: ${invalidConditionType}`);
+ }
+ );
+
+ it('rejects a mismatched condition type', () => {
+ const conditionObj = {
+ ...testTimeConditionObj,
+ conditionType: 'rpc',
+ } as unknown as TimeConditionProps;
+ expect(() => {
+ ConditionExpression.fromObj({
+ version: ConditionExpression.VERSION,
+ condition: conditionObj,
+ });
+ }).toThrow(/^Invalid condition/);
+ });
+
+ it('erc721 condition serialization', () => {
const conditionExpr = new ConditionExpression(erc721BalanceCondition);
const erc721BalanceConditionObj = erc721BalanceCondition.toObj();
@@ -240,7 +270,7 @@ describe('condition set', () => {
expect(conditionExprFromJson.condition).toBeInstanceOf(ContractCondition);
});
- it('contract condition no abi serialization', async () => {
+ it('contract condition no abi serialization', () => {
const conditionExpr = new ConditionExpression(contractConditionNoAbi);
const conditionExprJson = conditionExpr.toJson();
@@ -272,7 +302,7 @@ describe('condition set', () => {
expect(conditionExprFromJson.condition).toBeInstanceOf(ContractCondition);
});
- it('contract condition with abi serialization', async () => {
+ it('contract condition with abi serialization', () => {
const conditionExpr = new ConditionExpression(contractConditionWithAbi);
const conditionExprJson = conditionExpr.toJson();
@@ -305,7 +335,7 @@ describe('condition set', () => {
expect(conditionExprFromJson.condition).toBeInstanceOf(ContractCondition);
});
- it('time condition serialization', async () => {
+ it('time condition serialization', () => {
const conditionExpr = new ConditionExpression(timeCondition);
const conditionExprJson = conditionExpr.toJson();
@@ -328,7 +358,7 @@ describe('condition set', () => {
expect(conditionExprFromJson.condition).toBeInstanceOf(TimeCondition);
});
- it('rpc condition serialization', async () => {
+ it('rpc condition serialization', () => {
const conditionExpr = new ConditionExpression(rpcCondition);
const conditionExprJson = conditionExpr.toJson();
@@ -352,7 +382,7 @@ describe('condition set', () => {
expect(conditionExprFromJson.condition).toBeInstanceOf(RpcCondition);
});
- it('compound condition serialization', async () => {
+ it('compound condition serialization', () => {
const conditionExpr = new ConditionExpression(compoundCondition);
const compoundConditionObj = compoundCondition.toObj();
diff --git a/test/unit/testVariables.ts b/test/unit/testVariables.ts
index c7f85dec8..1acfe86eb 100644
--- a/test/unit/testVariables.ts
+++ b/test/unit/testVariables.ts
@@ -4,7 +4,7 @@ import {
TimeConditionProps,
} from '../../src/conditions/base';
import { FunctionAbiProps } from '../../src/conditions/base/contract';
-import { ReturnValueTestProps } from '../../src/conditions/base/rpc';
+import { ReturnValueTestProps } from '../../src/conditions/base/shared';
export const aliceSecretKeyBytes = new Uint8Array([
55, 82, 190, 189, 203, 164, 60, 148, 36, 86, 46, 123, 63, 152, 215, 113, 174,