Skip to content

Commit a2c6169

Browse files
committed
feat: start using zod for schema validation and type definitions
1 parent b4f1658 commit a2c6169

File tree

10 files changed

+1081
-1125
lines changed

10 files changed

+1081
-1125
lines changed

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@
4242
"@dotenvx/dotenvx": "^1.6.4",
4343
"@ethersproject/abi": "^5.7.0",
4444
"@ethersproject/providers": "^5.7.2",
45-
"@lit-protocol/contracts": "^0.0.63",
4645
"@lit-protocol/accs-schemas": "^0.0.12",
46+
"@lit-protocol/contracts": "^0.0.63",
4747
"@metamask/eth-sig-util": "5.0.2",
4848
"@mysten/sui.js": "^0.37.1",
4949
"@openagenda/verror": "^3.1.4",
@@ -72,7 +72,9 @@
7272
"tslib": "^2.7.0",
7373
"tweetnacl": "^1.0.3",
7474
"tweetnacl-util": "^0.15.1",
75-
"uint8arrays": "^4.0.3"
75+
"uint8arrays": "^4.0.3",
76+
"zod": "^3.23.8",
77+
"zod-validation-error": "^3.4.0"
7678
},
7779
"devDependencies": {
7880
"@nrwl/devkit": "19.6.3",
@@ -98,11 +100,11 @@
98100
"buffer": "^6.0.3",
99101
"chalk": "^5.3.0",
100102
"cypress": "11.0.1",
101-
"esbuild-node-externals": "^1.14.0",
102103
"cypress-metamask": "^1.0.5-development",
103104
"cypress-metamask-v2": "^1.7.2",
104105
"esbuild": "^0.17.3",
105106
"esbuild-node-builtins": "^0.1.0",
107+
"esbuild-node-externals": "^1.14.0",
106108
"esbuild-plugin-tsc": "^0.4.0",
107109
"eslint": "8.48.0",
108110
"eslint-config-next": "12.2.3",

packages/contracts-sdk/src/lib/contracts-sdk.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ import {
66
EpochInfo,
77
GasLimitParam,
88
LIT_NETWORKS_KEYS,
9+
LitNetworkKeysSchema,
910
LitContractContext,
11+
LitContractContextSchema,
1012
LitContractResolverContext,
13+
LitContractResolverContextSchema,
1114
MintCapacityCreditsContext,
1215
MintCapacityCreditsRes,
1316
MintNextAndAddAuthMethods,
@@ -638,9 +641,11 @@ export class LitContracts {
638641
context?: LitContractContext | LitContractResolverContext,
639642
rpcUrl?: string
640643
) {
644+
const _network = LitNetworkKeysSchema.parse(network);
645+
641646
let provider: ethers.providers.StaticJsonRpcProvider;
642647

643-
const _rpcUrl = rpcUrl || RPC_URL_BY_NETWORK[network];
648+
const _rpcUrl = rpcUrl || RPC_URL_BY_NETWORK[_network];
644649

645650
if (context && 'provider' in context!) {
646651
provider = context.provider;
@@ -653,7 +658,7 @@ export class LitContracts {
653658

654659
if (!context) {
655660
const contractData = await LitContracts._resolveContractContext(
656-
network
661+
_network
657662
//context
658663
);
659664

@@ -669,7 +674,7 @@ export class LitContracts {
669674
info: {
670675
address,
671676
abi,
672-
network,
677+
_network,
673678
},
674679
},
675680
'❌ Required contract data is missing'
@@ -718,7 +723,7 @@ export class LitContracts {
718723
}
719724
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
720725
//@ts-ignore data is callable as an array type
721-
const stakingABI = NETWORK_CONTEXT_BY_NETWORK[network].data.find(
726+
const stakingABI = NETWORK_CONTEXT_BY_NETWORK[_network].data.find(
722727
(data: any) => {
723728
return data.name === 'Staking';
724729
}
@@ -737,9 +742,10 @@ export class LitContracts {
737742
provider: ethers.providers.StaticJsonRpcProvider,
738743
contractNames?: ContractName[]
739744
): Promise<LitContractContext> {
745+
const _context = LitContractResolverContextSchema.parse(context);
740746
const resolverContract = new ethers.Contract(
741-
context.resolverAddress,
742-
context.abi,
747+
_context.resolverAddress,
748+
_context.abi,
743749
provider
744750
);
745751

@@ -847,10 +853,13 @@ export class LitContracts {
847853
// if there is a resolver address we use the resolver contract to query the rest of the contracts
848854
// here we override context to be what is returned from the resolver which is of type LitContractContext
849855
if (context?.resolverAddress) {
856+
const _context = LitContractResolverContextSchema.parse(context);
850857
context = await LitContracts._getContractsFromResolver(
851-
context as LitContractResolverContext,
858+
_context,
852859
provider
853860
);
861+
} else {
862+
context = LitContractContextSchema.parse(context);
854863
}
855864

856865
const flatten = [];

packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ export class LitNodeClientNodeJs
154154

155155
super(args);
156156

157-
if (args !== undefined && args !== null && 'defaultAuthCallback' in args) {
157+
if ('defaultAuthCallback' in args) {
158158
this.defaultAuthCallback = args.defaultAuthCallback;
159159
}
160160
}

packages/misc/src/lib/helper/session-sigs-validator.spec.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ describe('validateSessionSigs', () => {
1010
capabilities: [
1111
{
1212
sig: 'valid-capability-sig',
13+
derivedVia: 'some-method',
1314
signedMessage: `Capability Signed Message
1415
Expiration Time: 2099-12-31T23:59:59Z`,
1516
address: '0xValidAddress',
@@ -43,7 +44,7 @@ Expiration Time: 2099-12-31T23:59:59Z`,
4344

4445
expect(validationResult.isValid).toBe(false);
4546
expect(validationResult.errors).toContain(
46-
"Session Sig 'session1': Main signedMessage is not valid JSON."
47+
"Session Sig 'session1': Main signedMessage is not valid."
4748
);
4849
});
4950

@@ -65,7 +66,7 @@ Expiration Time: 2099-12-31T23:59:59Z`,
6566

6667
expect(validationResult.isValid).toBe(false);
6768
expect(validationResult.errors).toContain(
68-
"Session Sig 'session1': Capabilities not found in main signedMessage."
69+
`Session Sig 'session1': Validation error: Required at "capabilities"`
6970
);
7071
});
7172

@@ -87,7 +88,9 @@ Expiration Time: 2099-12-31T23:59:59Z`,
8788

8889
expect(validationResult.isValid).toBe(false);
8990
expect(validationResult.errors).toContainEqual(
90-
expect.stringContaining('No capabilities found in main signedMessage.')
91+
expect.stringContaining(
92+
`Session Sig 'session1': Validation error: Array must contain at least 1 element(s) at "capabilities"`
93+
)
9194
);
9295
});
9396

@@ -199,6 +202,7 @@ Expiration Time: invalid-date-format`; // Invalid expiration date in capability
199202
capabilities: [
200203
{
201204
sig: 'valid-capability-sig',
205+
derivedVia: 'some-method',
202206
signedMessage: `Capability Signed Message
203207
Expiration Time: invalid-date-format`, // Invalid date format
204208
address: '0xValidAddress',
@@ -218,7 +222,7 @@ Expiration Time: invalid-date-format`, // Invalid date format
218222

219223
expect(validationResult.isValid).toBe(false);
220224
expect(validationResult.errors).toContain(
221-
"Session Sig 'session2': Main signedMessage is not valid JSON."
225+
"Session Sig 'session2': Main signedMessage is not valid."
222226
);
223227
expect(validationResult.errors).toContainEqual(
224228
expect.stringContaining(

packages/misc/src/lib/helper/session-sigs-validator.ts

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import { fromError, isZodErrorLike } from 'zod-validation-error';
12
import {
23
AuthSig,
34
Capability,
45
ParsedSessionMessage,
56
ParsedSignedMessage,
7+
ParsedSessionMessageSchema,
68
SessionSigsMap,
79
} from '@lit-protocol/types';
810

@@ -135,32 +137,41 @@ function parseCapabilities(capabilities: Capability[]): ValidationResult {
135137
export function validateSessionSig(sessionSig: AuthSig): ValidationResult {
136138
const errors: string[] = [];
137139

138-
// Parse the main signedMessage
139-
let parsedSignedMessage: ParsedSessionMessage;
140+
// JSON Parse the main signedMessage
141+
let signedMessage: any;
140142
try {
141-
parsedSignedMessage = JSON.parse(sessionSig.signedMessage);
143+
signedMessage = JSON.parse(sessionSig.signedMessage);
142144
} catch (error) {
143-
errors.push('Main signedMessage is not valid JSON.');
145+
errors.push('Main signedMessage is not valid.');
146+
if (isZodErrorLike(error)) {
147+
const validationError = fromError(error);
148+
errors.push(validationError.toString());
149+
}
144150
return { isValid: false, errors };
145151
}
146152

147-
// Validate capabilities
148-
const capabilities: Capability[] = parsedSignedMessage.capabilities;
153+
// Validate signedMessage schema
154+
let parsedSessionMessage: ParsedSessionMessage;
155+
try {
156+
parsedSessionMessage = ParsedSessionMessageSchema.parse(signedMessage);
157+
} catch (error) {
158+
if (isZodErrorLike(error)) {
159+
const validationError = fromError(error);
160+
errors.push(validationError.toString());
161+
}
162+
return { isValid: false, errors };
163+
}
149164

150-
if (!capabilities) {
151-
errors.push('Capabilities not found in main signedMessage.');
152-
} else if (capabilities.length === 0) {
153-
errors.push('No capabilities found in main signedMessage.');
154-
} else {
155-
const capabilitiesValidationResult = parseCapabilities(capabilities);
165+
// Validate capabilities
166+
const capabilities: Capability[] = parsedSessionMessage.capabilities;
167+
const capabilitiesValidationResult = parseCapabilities(capabilities);
156168

157-
if (!capabilitiesValidationResult.isValid) {
158-
errors.push(...capabilitiesValidationResult.errors);
159-
}
169+
if (!capabilitiesValidationResult.isValid) {
170+
errors.push(...capabilitiesValidationResult.errors);
160171
}
161172

162173
// Validate outer expiration
163-
const outerExpirationTimeStr = parsedSignedMessage['expiration'];
174+
const outerExpirationTimeStr = parsedSessionMessage['expiration'];
164175

165176
if (outerExpirationTimeStr) {
166177
const validationResult = validateExpiration(

0 commit comments

Comments
 (0)