ox
Version:
Ethereum Standard Library
142 lines • 4.61 kB
JavaScript
import * as Errors from '../core/Errors.js';
import * as eth from './internal/rpcSchemas/Eth.js';
import { from as fromItem } from './internal/rpcSchemas/from.js';
import * as wallet from './internal/rpcSchemas/Wallet.js';
import * as z from 'zod/mini';
// eslint-disable-next-line jsdoc-js/require-jsdoc
export function from(input) {
if (typeof input.method === 'string')
return fromItem(input);
return Object.fromEntries(Object.entries(input).map(([method, item]) => [
method,
fromItem({ method, params: item.params, returns: item.returns }),
]));
}
/** JSON-RPC method schemas for the `eth_` namespace. */
export const Eth = eth;
/** JSON-RPC method schemas for the `wallet_` namespace. */
export const Wallet = wallet;
/** JSON-RPC method schemas for the `eth_` and `wallet_` namespaces. */
export const Default = { ...eth, ...wallet };
const requestCache = new WeakMap();
// Builds (and caches) the discriminated-union request schema for a namespace.
function requestSchema(namespace) {
const cached = requestCache.get(namespace);
if (cached)
return cached;
const schema = z.discriminatedUnion('method', Object.values(namespace).map((item) => item.request));
requestCache.set(namespace, schema);
return schema;
}
/**
* Looks up the `RpcSchema.Item` for a method on a namespace. Resolve a method
* once and pass the item to the `decode*`/`encode*` codecs to encode params and
* decode returns without repeating the namespace and method name.
*
* @example
* ```ts twoslash
* import { z } from 'ox/zod'
*
* const item = z.RpcSchema.parseItem(
* z.RpcSchema.Eth,
* 'eth_getBlockTransactionCountByNumber'
* )
*
* const params = z.RpcSchema.encodeParams(item, [1n])
* const count = z.RpcSchema.decodeReturns(item, '0x1')
* ```
*
* @throws `RpcSchema.MethodNotFoundError` if the method does not exist.
*/
export function parseItem(namespace, method) {
const item = namespace[method];
if (!item)
throw new MethodNotFoundError({ method });
return item;
}
// Resolves a codec function's arguments into `[item, value]`, accepting either
// `(item, value)` or `(namespace, method, value)`.
function resolveItem(args) {
if (args.length === 2)
return [args[0], args[1]];
return [parseItem(args[0], args[1]), args[2]];
}
// eslint-disable-next-line jsdoc-js/require-jsdoc
export function decodeParams(...args) {
const [item, params] = resolveItem(args);
return z.decode(item.params, params);
}
// eslint-disable-next-line jsdoc-js/require-jsdoc
export function encodeParams(...args) {
const [item, params] = resolveItem(args);
return z.encode(item.params, params);
}
// eslint-disable-next-line jsdoc-js/require-jsdoc
export function decodeReturns(...args) {
const [item, returns] = resolveItem(args);
return z.decode(item.returns, returns);
}
// eslint-disable-next-line jsdoc-js/require-jsdoc
export function encodeReturns(...args) {
const [item, returns] = resolveItem(args);
return z.encode(item.returns, returns);
}
/**
* Decodes (wire → native) a full JSON-RPC request (`{ method, params }`)
* against a namespace, dispatching on `method`.
*
* @example
* ```ts twoslash
* import { z } from 'ox/zod'
*
* const request = z.RpcSchema.decodeRequest(z.RpcSchema.Eth, {
* method: 'eth_getBlockByNumber',
* params: ['0x1', true]
* })
* ```
*/
export function decodeRequest(namespace, request) {
return z.decode(requestSchema(namespace), request);
}
/**
* Encodes (native → wire) a full JSON-RPC request (`{ method, params }`)
* against a namespace, dispatching on `method`.
*
* @example
* ```ts twoslash
* import { z } from 'ox/zod'
*
* const request = z.RpcSchema.encodeRequest(z.RpcSchema.Eth, {
* method: 'eth_getBlockByNumber',
* params: [1n, true]
* })
* ```
*/
export function encodeRequest(namespace, request) {
return z.encode(requestSchema(namespace), request);
}
/**
* Alias for `RpcSchema.decodeRequest`.
*
* @example
* ```ts twoslash
* import { z } from 'ox/zod'
*
* const request = z.RpcSchema.parse(z.RpcSchema.Eth, {
* method: 'eth_getBalance',
* params: [
* '0x0000000000000000000000000000000000000000',
* 'latest'
* ]
* })
* ```
*/
export const parse = decodeRequest;
/** Thrown when a method does not exist on a namespace. */
export class MethodNotFoundError extends Errors.BaseError {
name = 'RpcSchema.MethodNotFoundError';
constructor({ method }) {
super(`Method \`${method}\` does not exist on the schema.`);
}
}
//# sourceMappingURL=RpcSchema.js.map