Skip to content

Commit

Permalink
Refactor cond #206 (#220)
Browse files Browse the repository at this point in the history
  • Loading branch information
piotr-roslaniec authored Jun 14, 2023
2 parents 989e6d5 + 96a92d5 commit aad7ebe
Show file tree
Hide file tree
Showing 12 changed files with 114 additions and 111 deletions.
24 changes: 24 additions & 0 deletions src/conditions/base/contract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Joi from 'joi';

import { ETH_ADDRESS_REGEXP } from '../const';

import { RpcCondition, rpcConditionSchema } from './rpc';

export const STANDARD_CONTRACT_TYPES = ['ERC20', 'ERC721'];

const contractMethodSchemas: Record<string, Joi.Schema> = {
...rpcConditionSchema,
contractAddress: Joi.string().pattern(ETH_ADDRESS_REGEXP).required(),
standardContractType: Joi.string()
.valid(...STANDARD_CONTRACT_TYPES)
.optional(),
method: Joi.string().required(),
functionAbi: Joi.object().optional(),
parameters: Joi.array().required(),
};

export class ContractCondition extends RpcCondition {
public readonly schema = Joi.object(contractMethodSchemas)
// At most one of these keys needs to be present
.xor('standardContractType', 'functionAbi');
}
26 changes: 0 additions & 26 deletions src/conditions/base/evm.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/conditions/base/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { Condition } from './condition';
export { EvmCondition } from './evm';
export { ContractCondition } from './contract';
export { RpcCondition } from './rpc';
export { TimeCondition } from './time';
22 changes: 12 additions & 10 deletions src/conditions/base/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@ const makeParameters = () =>
})),
});

export const rpcConditionSchema = {
chain: Joi.number()
.valid(...SUPPORTED_CHAINS)
.required(),
method: Joi.string()
.valid(...Object.keys(rpcMethodSchemas))
.required(),
parameters: makeParameters(),
returnValueTest: returnValueTestSchema.required(),
};

export class RpcCondition extends Condition {
public readonly schema = Joi.object({
chain: Joi.number()
.valid(...SUPPORTED_CHAINS)
.required(),
method: Joi.string()
.valid(...Object.keys(rpcMethodSchemas))
.required(),
parameters: makeParameters(),
returnValueTest: returnValueTestSchema.required(),
});
public readonly schema = Joi.object(rpcConditionSchema);
}
29 changes: 13 additions & 16 deletions src/conditions/base/time.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
import Joi from 'joi';

import { SUPPORTED_CHAINS } from '../const';
import { omit } from '../../utils';

import { Condition } from './condition';
import { returnValueTestSchema } from './schema';
import { RpcCondition, rpcConditionSchema } from './rpc';

export class TimeCondition extends Condition {
// TODO: This is the only condition that uses defaults, and also the only condition that uses `method` in order
// to determine the schema. I.e. the only method that used `METHOD = 'blocktime'` in `nucypher/nucypher`.
// TODO: Consider introducing a different field for this, e.g. `conditionType` or `type`. Use this field in a
// condition factory.
const BLOCKTIME_METHOD = 'blocktime';

const timeConditionSchema = {
// TimeCondition is an RpcCondition with the method set to 'blocktime' and no parameters
...omit(rpcConditionSchema, ['parameters']),
method: Joi.string().valid(BLOCKTIME_METHOD).required(),
};

export class TimeCondition extends RpcCondition {
public readonly defaults: Record<string, unknown> = {
method: 'blocktime',
method: BLOCKTIME_METHOD,
};

public readonly schema = Joi.object({
method: Joi.string().valid(this.defaults.method).required(),
returnValueTest: returnValueTestSchema.required(),
chain: Joi.number()
.valid(...SUPPORTED_CHAINS)
.required(),
});
public readonly schema = Joi.object(timeConditionSchema);
}
6 changes: 3 additions & 3 deletions src/conditions/predefined/erc721.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { EvmCondition } from '../base';
import { ContractCondition } from '../base';
import { USER_ADDRESS_PARAM } from '../const';

export class ERC721Ownership extends EvmCondition {
export class ERC721Ownership extends ContractCondition {
public readonly defaults = {
method: 'ownerOf',
parameters: [],
Expand All @@ -14,7 +14,7 @@ export class ERC721Ownership extends EvmCondition {
};
}

export class ERC721Balance extends EvmCondition {
export class ERC721Balance extends ContractCondition {
public readonly defaults = {
method: 'balanceOf',
parameters: [USER_ADDRESS_PARAM],
Expand Down
6 changes: 6 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,9 @@ export const bytesEquals = (first: Uint8Array, second: Uint8Array): boolean =>

export const objectEquals = (a: unknown, b: unknown, strict = true): boolean =>
deepEqual(a, b, { strict });

export const omit = (obj: Record<string, unknown>, keys: string[]) => {
const copy = { ...obj };
keys.forEach((key) => delete copy[key]);
return copy;
};
4 changes: 2 additions & 2 deletions test/docs/cbd.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {

const {
predefined: { ERC721Ownership },
base: { EvmCondition },
base: { ContractCondition },
ConditionSet,
} = conditions;

Expand Down Expand Up @@ -100,7 +100,7 @@ describe('Get Started (CBD PoC)', () => {
value: 3,
},
};
const NFTBalance = new EvmCondition(NFTBalanceConfig);
const NFTBalance = new ContractCondition(NFTBalanceConfig);

const encrypter = newDeployed.encrypter;

Expand Down
20 changes: 10 additions & 10 deletions test/unit/conditions/base/condition.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { EvmCondition } from '../../../../src/conditions/base';
import { ContractCondition } from '../../../../src/conditions/base';
import {
ERC721Balance,
ERC721Ownership,
Expand All @@ -7,7 +7,7 @@ import {
TEST_CHAIN_ID,
TEST_CONTRACT_ADDR,
TEST_CONTRACT_ADDR_2,
testEvmConditionObj,
testContractConditionObj,
} from '../../testVariables';

describe('validation', () => {
Expand Down Expand Up @@ -47,18 +47,18 @@ describe('validation', () => {

describe('serialization', () => {
it('serializes to a plain object', () => {
const evm = new EvmCondition(testEvmConditionObj);
expect(evm.toObj()).toEqual({
...testEvmConditionObj,
_class: 'EvmCondition',
const contract = new ContractCondition(testContractConditionObj);
expect(contract.toObj()).toEqual({
...testContractConditionObj,
_class: 'ContractCondition',
});
});

it('serializes predefined conditions', () => {
const evm = new ERC721Ownership(testEvmConditionObj);
expect(evm.toObj()).toEqual({
...evm.defaults,
...testEvmConditionObj,
const contract = new ERC721Ownership(testContractConditionObj);
expect(contract.toObj()).toEqual({
...contract.defaults,
...testContractConditionObj,
_class: 'ERC721Ownership',
});
});
Expand Down
56 changes: 28 additions & 28 deletions test/unit/conditions/base/evm.test.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
import { EvmCondition } from '../../../../src/conditions/base';
import { testEvmConditionObj } from '../../testVariables';
import { ContractCondition } from '../../../../src/conditions/base';
import { testContractConditionObj } from '../../testVariables';

describe('validation', () => {
it('accepts on a valid schema', () => {
const evm = new EvmCondition(testEvmConditionObj);
expect(evm.toObj()).toEqual({
...testEvmConditionObj,
_class: 'EvmCondition',
const contract = new ContractCondition(testContractConditionObj);
expect(contract.toObj()).toEqual({
...testContractConditionObj,
_class: 'ContractCondition',
});
});

it('rejects an invalid schema', () => {
const badEvmCondition = {
...testEvmConditionObj,
const badContractCondition = {
...testContractConditionObj,
// Intentionally removing `contractAddress`
contractAddress: undefined,
};
const badEvm = new EvmCondition(badEvmCondition);
const badEvm = new ContractCondition(badContractCondition);
expect(() => badEvm.toObj()).toThrow(
'Invalid condition: "contractAddress" is required'
);

const { error } = badEvm.validate(badEvmCondition);
const { error } = badEvm.validate(badContractCondition);
expect(error?.message).toEqual('"contractAddress" is required');
});
});
Expand All @@ -32,50 +32,50 @@ describe('accepts either standardContractType or functionAbi but not both or non

it('accepts standardContractType', () => {
const conditionObj = {
...testEvmConditionObj,
...testContractConditionObj,
standardContractType,
functionAbi: undefined,
};
const evmCondition = new EvmCondition(conditionObj);
expect(evmCondition.toObj()).toEqual({
const contractCondition = new ContractCondition(conditionObj);
expect(contractCondition.toObj()).toEqual({
...conditionObj,
_class: 'EvmCondition',
_class: 'ContractCondition',
});
});

it('accepts functionAbi', () => {
const conditionObj = {
...testEvmConditionObj,
...testContractConditionObj,
functionAbi,
standardContractType: undefined,
};
const evmCondition = new EvmCondition(conditionObj);
expect(evmCondition.toObj()).toEqual({
const contractCondition = new ContractCondition(conditionObj);
expect(contractCondition.toObj()).toEqual({
...conditionObj,
_class: 'EvmCondition',
_class: 'ContractCondition',
});
});

it('rejects both', () => {
const conditionObj = {
...testEvmConditionObj,
...testContractConditionObj,
standardContractType,
functionAbi,
};
const evmCondition = new EvmCondition(conditionObj);
expect(() => evmCondition.toObj()).toThrow(
const contractCondition = new ContractCondition(conditionObj);
expect(() => contractCondition.toObj()).toThrow(
'"value" contains a conflict between exclusive peers [standardContractType, functionAbi]'
);
});

it('rejects none', () => {
const conditionObj = {
...testEvmConditionObj,
...testContractConditionObj,
standardContractType: undefined,
functionAbi: undefined,
};
const evmCondition = new EvmCondition(conditionObj);
expect(() => evmCondition.toObj()).toThrow(
const contractCondition = new ContractCondition(conditionObj);
expect(() => contractCondition.toObj()).toThrow(
'"value" must contain at least one of [standardContractType, functionAbi]'
);
});
Expand Down Expand Up @@ -108,8 +108,8 @@ describe('accepts either standardContractType or functionAbi but not both or non
// },
// ],
// };
// const evmConditionObj = {
// ...testEvmConditionObj,
// const contractConditionObj = {
// ...testContractConditionObj,
// functionAbi: fakeFunctionAbi,
// method: 'myFunction',
// parameters: [USER_ADDRESS_PARAM, ':customParam'],
Expand All @@ -119,9 +119,9 @@ describe('accepts either standardContractType or functionAbi but not both or non
// value: USER_ADDRESS_PARAM,
// },
// };
// const evmCondition = new EvmCondition(evmConditionObj);
// const contractCondition = new ContractCondition(contractConditionObj);
// const web3Provider = fakeWeb3Provider(SecretKey.random().toBEBytes());
// const conditionSet = new ConditionSet([evmCondition]);
// const conditionSet = new ConditionSet([contractCondition]);
// const conditionContext = new ConditionContext(
// conditionSet.toWASMConditions(),
// web3Provider
Expand Down
Loading

1 comment on commit aad7ebe

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bundled size for the package is listed below:

build/module/types/ethers-contracts/factories: 82.03 KB
build/module/types/ethers-contracts: 156.25 KB
build/module/types: 160.16 KB
build/module/src/agents: 31.25 KB
build/module/src/policies: 19.53 KB
build/module/src/conditions/base: 50.78 KB
build/module/src/conditions/predefined: 19.53 KB
build/module/src/conditions/context: 39.06 KB
build/module/src/conditions: 148.44 KB
build/module/src/sdk/strategy: 42.97 KB
build/module/src/sdk: 58.59 KB
build/module/src/characters: 89.84 KB
build/module/src/kits: 19.53 KB
build/module/src: 433.59 KB
build/module: 644.53 KB
build/main/types/ethers-contracts/factories: 82.03 KB
build/main/types/ethers-contracts: 156.25 KB
build/main/types: 160.16 KB
build/main/src/agents: 31.25 KB
build/main/src/policies: 19.53 KB
build/main/src/conditions/base: 50.78 KB
build/main/src/conditions/predefined: 19.53 KB
build/main/src/conditions/context: 39.06 KB
build/main/src/conditions: 148.44 KB
build/main/src/sdk/strategy: 42.97 KB
build/main/src/sdk: 58.59 KB
build/main/src/characters: 89.84 KB
build/main/src/kits: 19.53 KB
build/main/src: 437.50 KB
build/main: 648.44 KB
build: 1.27 MB

Please sign in to comment.