/*
This file is part of web3.js.
web3.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
web3.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see .
*/
import { isNullish } from '@theqrl/web3-validator';
import {
JsonRpcPayload,
JsonRpcResponse,
JsonRpcResponseWithResult,
JsonRpcResponseWithError,
JsonRpcOptionalRequest,
JsonRpcBatchRequest,
JsonRpcNotification,
JsonRpcRequest,
JsonRpcBatchResponse,
JsonRpcSubscriptionResult,
} from '@theqrl/web3-types';
import { rpcErrorsMap } from '@theqrl/web3-errors';
import { uuidV4 } from './uuid.js';
// check if code is a valid rpc server error code
export const isResponseRpcError = (rpcError: JsonRpcResponseWithError) => {
const errorCode = rpcError.error.code;
return rpcErrorsMap.has(errorCode) || (errorCode >= -32099 && errorCode <= -32000);
};
export const isResponseWithResult = (
response: JsonRpcResponse,
): response is JsonRpcResponseWithResult =>
!Array.isArray(response) &&
!!response &&
response.jsonrpc === '2.0' &&
// JSON RPC consider "null" as valid response
'result' in response &&
isNullish(response.error) &&
(typeof response.id === 'number' || typeof response.id === 'string');
// To avoid circular package dependency, copied to code here. If you update this please update same function in `response_errors.ts`
export const isResponseWithError = (
response: JsonRpcResponse,
): response is JsonRpcResponseWithError =>
!Array.isArray(response) &&
response.jsonrpc === '2.0' &&
!!response &&
isNullish(response.result) &&
// JSON RPC consider "null" as valid response
'error' in response &&
(typeof response.id === 'number' || typeof response.id === 'string');
export const isResponseWithNotification = (
response: JsonRpcNotification | JsonRpcSubscriptionResult,
): response is JsonRpcNotification =>
!Array.isArray(response) &&
!!response &&
response.jsonrpc === '2.0' &&
!isNullish(response.params) &&
!isNullish(response.method);
export const isSubscriptionResult = (
response: JsonRpcNotification | JsonRpcSubscriptionResult,
): response is JsonRpcSubscriptionResult =>
!Array.isArray(response) &&
!!response &&
response.jsonrpc === '2.0' &&
'id' in response &&
// JSON RPC consider "null" as valid response
'result' in response;
export const validateResponse = (
response: JsonRpcResponse,
): boolean => isResponseWithResult(response) || isResponseWithError(response);
export const isValidResponse = (
response: JsonRpcResponse,
): boolean =>
Array.isArray(response) ? response.every(validateResponse) : validateResponse(response);
export const isBatchResponse = (
response: JsonRpcResponse,
): response is JsonRpcBatchResponse =>
Array.isArray(response) && response.length > 0 && isValidResponse(response);
// internal optional variable to increment and use for the jsonrpc `id`
let requestIdSeed: number | undefined;
/**
* Optionally use to make the jsonrpc `id` start from a specific number.
* Without calling this function, the `id` will be filled with a Uuid.
* But after this being called with a number, the `id` will be a number staring from the provided `start` variable.
* However, if `undefined` was passed to this function, the `id` will be a Uuid again.
* @param start - a number to start incrementing from.
* Or `undefined` to use a new Uuid (this is the default behavior)
*/
export const setRequestIdStart = (start: number | undefined) => {
requestIdSeed = start;
};
export const toPayload = (
request: JsonRpcOptionalRequest,
): JsonRpcPayload => {
if (typeof requestIdSeed !== 'undefined') {
requestIdSeed += 1;
}
return {
jsonrpc: request.jsonrpc ?? '2.0',
id: request.id ?? requestIdSeed ?? uuidV4(),
method: request.method,
params: request.params ?? undefined,
};
};
export const toBatchPayload = (requests: JsonRpcOptionalRequest[]): JsonRpcBatchRequest =>
requests.map(request => toPayload(request)) as JsonRpcBatchRequest;
export const isBatchRequest = (
request: JsonRpcBatchRequest | JsonRpcRequest | JsonRpcOptionalRequest,
): request is JsonRpcBatchRequest => Array.isArray(request) && request.length > 0;