@mentaproject/client 0.1.22 → 0.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @module AccountTypes
3
+ */
4
+
5
+ import { Address } from "@mentaproject/core";
6
+
7
+ /**
8
+ * Defines the options for retrieving transactions associated with an account.
9
+ */
10
+ export type GetTransactionsParams = FetchTransactionParams & {
11
+ };
12
+
13
+ /**
14
+ * Parameters for retrieving transactions emitted by an account by exploring blocks.
15
+ * @interface IGetTransactionReceiptParams
16
+ */
17
+ export type FetchTransactionParams = {
18
+ /**
19
+ * The block number to start exploring from.
20
+ * @type {bigint}
21
+ */
22
+ fromBlock?: bigint;
23
+ /**
24
+ * The block number to stop exploring at.
25
+ * @type {bigint}
26
+ */
27
+ toBlock?: bigint;
28
+ /**
29
+ * The maximum number of items to retrieve.
30
+ * @type {number}
31
+ */
32
+ limit?: number;
33
+ };
34
+
35
+ export type AccountData = {
36
+ address: Address;
37
+ }
38
+
39
+ export type JSONAccount<depth extends number> = depth extends 0 ? AccountData : AccountData & {
40
+ isContract: boolean;
41
+ ETHBalance: string;
42
+ contractType: string;
43
+ transactionCount: number;
44
+ }
@@ -0,0 +1,14 @@
1
+ import { Address, Hash, Hex, Transaction as RawTransaction, Withdrawal } from "@mentaproject/core/types";
2
+ import { Block as RawBlock } from "@mentaproject/core";
3
+ import { JSONAccount } from "./Account"
4
+ import { WithBigintStringified } from "./Utils";
5
+ import { JSONTransaction } from "./Transaction";
6
+
7
+ export type JSONBlock<depth extends number> = depth extends 0
8
+ ? WithBigintStringified<Omit<RawBlock, "miner" | "transactions">> & {
9
+ transactions?: JSONTransaction<depth>[] | Hash[],
10
+ }
11
+ : WithBigintStringified<Omit<RawBlock, "miner" | "transactions">> & {
12
+ miner: JSONAccount<depth>,
13
+ transactions?: JSONTransaction<depth>[] | Hash[],
14
+ }
@@ -0,0 +1,55 @@
1
+ import { Methods } from "./JsonRPC";
2
+
3
+ /**
4
+ * @interface ICacheEntry
5
+ * Represents a single entry in the cache.
6
+ * @template T The type of the cached value.
7
+ */
8
+ export interface ICacheEntry<T> {
9
+ /** The cached value. */
10
+ value: T;
11
+ /** The block number at which this entry expires. */
12
+ expiry: bigint;
13
+ }
14
+
15
+ /**
16
+ * @interface ICacheConfig
17
+ * Defines the configuration options for a cache.
18
+ */
19
+ export interface ICacheConfig {
20
+ /** The maximum number of items the cache can hold. */
21
+ maxSize: number;
22
+ /** The default time-to-live (in blocks) for cache entries if no specific policy is defined. */
23
+ defaultTtl: number;
24
+ /** A map of RPC methods to their specific time-to-live policies (in blocks). */
25
+ ttlPolicies: Partial<Record<Methods, number>>;
26
+ }
27
+
28
+ /**
29
+ * @interface ICache
30
+ * Defines the interface for a cache implementation.
31
+ */
32
+ export interface ICache {
33
+ /** The configuration for the cache. */
34
+ config: ICacheConfig;
35
+ /**
36
+ * Sets the current block number for TTL calculations.
37
+ * @param {bigint} blockNumber The new current block number.
38
+ */
39
+ setBlockNumber(blockNumber: bigint): void;
40
+ /**
41
+ * Retrieves a value from the cache.
42
+ * @template T The type of the value.
43
+ * @param {string} key The key for the cache entry.
44
+ * @returns {T | undefined} The cached value, or undefined if not found or expired.
45
+ */
46
+ get<T>(key: string): T | undefined;
47
+ /**
48
+ * Sets a value in the cache.
49
+ * @template T The type of the value.
50
+ * @param {string} key The key for the cache entry.
51
+ * @param {T} value The value to store.
52
+ * @param {number} [ttl] The time-to-live (in blocks) for the entry. If not provided, `defaultTtl` from config is used.
53
+ */
54
+ set<T>(key: string, value: T, ttl?: number): void;
55
+ };
@@ -0,0 +1,126 @@
1
+ /**
2
+ * @module JsonRPC
3
+ */
4
+
5
+ /**
6
+ * Defines standard Ethereum JSON-RPC methods.
7
+ */
8
+ export type StandardMethods =
9
+ /** Returns a list of addresses owned by client. */
10
+ | "eth_accounts"
11
+ /** Returns the current blob base fee. */
12
+ | "eth_blobBaseFee"
13
+ /** Returns the number of most recent block. */
14
+ | "eth_blockNumber"
15
+ /** Executes a new message call immediately without creating a transaction on the blockchain. */
16
+ | "eth_call"
17
+ /** Returns the current chain ID. */
18
+ | "eth_chainId"
19
+ /** Creates an EIP-2930 type access list for a transaction. */
20
+ | "eth_createAccessList"
21
+ /** Generates and returns an estimate of how much gas is necessary to allow the transaction to complete. */
22
+ | "eth_estimateGas"
23
+ /** Returns a historical log of gas prices. */
24
+ | "eth_feeHistory"
25
+ /** Returns the current price per gas in wei. */
26
+ | "eth_gasPrice"
27
+ /** Returns the balance of the account of given address. */
28
+ | "eth_getBalance"
29
+ /** Returns information about a block by hash. */
30
+ | "eth_getBlockByHash"
31
+ /** Returns information about a block by block number. */
32
+ | "eth_getBlockByNumber"
33
+ /** Returns all transaction receipts for a given block. */
34
+ | "eth_getBlockReceipts"
35
+ /** Returns the number of transactions in a block from a block matching the given block hash. */
36
+ | "eth_getBlockTransactionCountByHash"
37
+ /** Returns the number of transactions in a block from a block matching the given block number. */
38
+ | "eth_getBlockTransactionCountByNumber"
39
+ /** Returns the code at a given address. */
40
+ | "eth_getCode"
41
+ /** Returns an array of all logs matching a given filter object. */
42
+ | "eth_getLogs"
43
+ /** Returns the account and storage proof for the specified address and storage points. */
44
+ | "eth_getProof"
45
+ /** Returns the value from a storage position at a given address. */
46
+ | "eth_getStorageAt"
47
+ /** Returns information about a transaction by block hash and transaction index position. */
48
+ | "eth_getTransactionByBlockHashAndIndex"
49
+ /** Returns information about a transaction by block number and transaction index position. */
50
+ | "eth_getTransactionByBlockNumberAndIndex"
51
+ /** Returns the information about a transaction requested by transaction hash. */
52
+ | "eth_getTransactionByHash"
53
+ /** Returns the number of transactions sent from an address. */
54
+ | "eth_getTransactionCount"
55
+ /** Returns the receipt of a transaction by transaction hash. */
56
+ | "eth_getTransactionReceipt"
57
+ /** Returns information about an uncle of a block by hash and uncle index position. */
58
+ | "eth_getUncleByBlockHashAndIndex"
59
+ /** Returns information about an uncle of a block by number and uncle index position. */
60
+ | "eth_getUncleByBlockNumberAndIndex"
61
+ /** Returns the number of uncles in a block from a block matching the given block hash. */
62
+ | "eth_getUncleCountByBlockHash"
63
+ /** Returns the number of uncles in a block from a block matching the given block number. */
64
+ | "eth_getUncleCountByBlockNumber"
65
+ /** Returns the hash of the current block, the seedHash, and the boundary condition to be met. */
66
+ | "eth_getWork"
67
+ /** Returns the number of hashes per second that the node is mining with. */
68
+ | "eth_hashrate"
69
+ /** Returns a fee per gas that a user is willing to pay for their transaction to be included in the current block. */
70
+ | "eth_maxPriorityFeePerGas"
71
+ /** Returns true if client is actively mining new blocks. */
72
+ | "eth_mining"
73
+ /** Returns the current Ethereum protocol version. */
74
+ | "eth_protocolVersion"
75
+ /** Submits a signed transaction for inclusion in the blockchain. */
76
+ | "eth_sendRawTransaction"
77
+ /** Simulates a transaction execution. */
78
+ | "eth_simulateV1"
79
+ /** Used for submitting a proof-of-work solution. */
80
+ | "eth_submitWork"
81
+ /** Returns an object with data about the sync status or false. */
82
+ | "eth_syncing";
83
+
84
+ /**
85
+ * Defines JSON-RPC methods related to filters.
86
+ */
87
+ export type filterMethods =
88
+ /** Polling method for a filter, which returns an array of logs or hashes. */
89
+ | "eth_getFilterChanges"
90
+ /** Returns an array of all logs matching a given filter id. */
91
+ | "eth_getFilterLogs"
92
+ /** Creates a filter in the node, to notify when a new block arrives. */
93
+ | "eth_newBlockFilter"
94
+ /** Creates a filter object, based on filter options, to notify when the state changes (logs). */
95
+ | "eth_newFilter"
96
+ /** Uninstalls a filter with given id. */
97
+ | "eth_uninstallFilter";
98
+
99
+ /**
100
+ * Defines JSON-RPC methods related to subscriptions.
101
+ */
102
+ export type subscriptionMethods =
103
+ /** Subscribes to events. */
104
+ | "eth_subscribe"
105
+ /** Unsubscribes from events. */
106
+ | "eth_unsubscribe";
107
+
108
+ /**
109
+ * Defines JSON-RPC methods related to tracing.
110
+ */
111
+ export type traceMethods =
112
+ /** Returns traces for a given block. */
113
+ | "trace_block"
114
+ /** Returns a trace of the given transaction. */
115
+ | "trace_call"
116
+ /** Returns traces for multiple transactions. */
117
+ | "trace_callMany"
118
+ /** Returns traces matching the given filter. */
119
+ | "trace_filter"
120
+ /** Returns a trace of the given transaction. */
121
+ | "trace_transaction";
122
+
123
+ /**
124
+ * Union type of all supported JSON-RPC methods.
125
+ */
126
+ export type Methods = StandardMethods | filterMethods | subscriptionMethods | traceMethods;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @module MentaClientTypes
3
+ */
4
+ import { CoreClientConfig } from "@mentaproject/core/types";
5
+ import { ICache } from "./Cache";
6
+ import { watchBlockNumber, watchBlocks } from "@mentaproject/core/actions";
7
+ import { IPersistenceAdapter } from "./PersistenceAdapter";
8
+
9
+ /**
10
+ * Configuration for the client's cache.
11
+ * @interface CacheConfig
12
+ */
13
+ export interface CacheConfig {
14
+ /**
15
+ * Time-to-live policies for different RPC methods.
16
+ * Keys are RPC method names (e.g., "eth_getBlockByNumber"), and values are
17
+ * the TTL in milliseconds for caching responses from those methods.
18
+ */
19
+ ttl_policies: Record<string, number>;
20
+ };
21
+
22
+ /**
23
+ * Configuration options for the MentaClient.
24
+ * Extends {@link CoreClientConfig} from `@mentaproject/core`.
25
+ * @interface MentaClientConfig
26
+ */
27
+ export interface MentaClientConfig extends CoreClientConfig {
28
+ /**
29
+ * Optional cache implementation for the client.
30
+ * If provided, the client will use this cache for RPC responses.
31
+ */
32
+ cache?: ICache;
33
+ /**
34
+ * Optional persistence adapter for local data storage.
35
+ * If provided, the client will use this adapter to persist and retrieve data.
36
+ */
37
+ persistenceAdapter?: IPersistenceAdapter;
38
+ };
39
+
40
+ /**
41
+ * Defines the available client events and their corresponding watch functions.
42
+ * These functions are used to subscribe to real-time updates from the client.
43
+ */
44
+ export const ClientEvents = {
45
+ /**
46
+ * Event for new blocks.
47
+ * Uses the {@link watchBlocks} function from `@mentaproject/core`.
48
+ */
49
+ block: watchBlocks,
50
+ /**
51
+ * Event for new block numbers.
52
+ * Uses the {@link watchBlockNumber} function from `@mentaproject/core`.
53
+ */
54
+ blockNumber: watchBlockNumber,
55
+ };
56
+
57
+ /**
58
+ * Utility type to extract the callback function type for a given event.
59
+ * This type dynamically determines the expected callback signature for a specific client event.
60
+ * @template TEvent The name of the event (e.g., 'block' or 'blockNumber') for which to get the listener callback type.
61
+ */
62
+ export type GetListenerCallback<TEvent extends keyof typeof ClientEvents> =
63
+ Parameters<typeof ClientEvents[TEvent]>[1] extends infer P
64
+ ? P extends { [K in `on${Capitalize<TEvent>}`]: infer TCallback }
65
+ ? TCallback
66
+ : never
67
+ : never;
@@ -0,0 +1,44 @@
1
+ import { Address } from '@mentaproject/core/types';
2
+
3
+ import { Transaction } from '../structures/Transaction';
4
+ import { GetTransactionsParams } from './Account';
5
+ import { JSONTransaction } from './Transaction';
6
+
7
+ /**
8
+ * @interface IPersistenceAdapter
9
+ * @description Defines the contract for persistence layers, ensuring consistent data storage and retrieval operations.
10
+ */
11
+ export interface IPersistenceAdapter {
12
+ /**
13
+ * @method upsertTransactions
14
+ * @description Inserts or updates a list of transactions. The operation must be atomic.
15
+ * @param {Transaction[]} transactions - An array of transaction data, including associated account addresses and timestamps.
16
+ * @returns {Promise<void>} A Promise that resolves when the transactions have been successfully inserted or updated.
17
+ */
18
+ upsertTransactions(transactions: Transaction[]): Promise<void>;
19
+
20
+ /**
21
+ * @method getTransactions
22
+ * @description Retrieves a paginated list of transactions for a specific account based on provided filters.
23
+ * @param {GetTransactionsFilters} filters - An object containing filters for retrieving transactions, such as account address, block range, pagination, and sort order.
24
+ * @returns {Promise<JSONTransaction[]>} A Promise that resolves with transactions objects.
25
+ */
26
+ getTransactions(address: Address, params: GetTransactionsParams): Promise<JSONTransaction<0>[]>;
27
+
28
+ /**
29
+ * @method getLastSyncedBlock
30
+ * @description Retrieves the last synced block number for a given account. This is used to track the synchronization progress of an account's transactions.
31
+ * @param {string} accountAddress - The address of the account for which to retrieve the last synced block number.
32
+ * @returns {Promise<number | null>} A Promise that resolves with the last synced block number, or `null` if no block has been synced for the account.
33
+ */
34
+ getLastSyncedBlock(accountAddress: string): Promise<bigint | null>;
35
+
36
+ /**
37
+ * @method setLastSyncedBlock
38
+ * @description Saves the last synced block number for a given account. This updates the synchronization progress for an account.
39
+ * @param {string} accountAddress - The address of the account for which to save the last synced block number.
40
+ * @param {bigint} blockNumber - The block number to save as the last synced block for the account.
41
+ * @returns {Promise<void>} A Promise that resolves when the last synced block number has been successfully saved.
42
+ */
43
+ setLastSyncedBlock(accountAddress: string, blockNumber: bigint): Promise<void>;
44
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @module TransactionTypes
3
+ */
4
+
5
+ import { Hex, TransactionReceipt, Transaction as RawTransaction } from "@mentaproject/core";
6
+ import { Account } from "../structures";
7
+ import { JSONBlock } from "./Block";
8
+ import { JSONAccount } from "./Account";
9
+ import { WithBigintStringified } from "./Utils";
10
+
11
+ /**
12
+ * Defines the direction of a transaction relative to an account.
13
+ * "in" for incoming transactions, "out" for outgoing transactions.
14
+ * Defines the direction of a transaction relative to an account.
15
+ * "in" for incoming transactions, "out" for outgoing transactions.
16
+ */
17
+ export type TransactionDirection = "in" | "out";
18
+
19
+ /**
20
+ /**
21
+ * Parameters for retrieving a transaction's block.
22
+ * @interface IGetTransactionBlockParams
23
+ */
24
+ export interface IGetTransactionBlockParams {
25
+ /**
26
+ * Whether to include full transaction objects in the block.
27
+ * @type {boolean}
28
+ */
29
+ includeTransactions?: boolean;
30
+ };
31
+
32
+ export type TransactionCall = {
33
+ from: Account;
34
+ to: Account;
35
+ value: bigint;
36
+ input: Hex;
37
+ gas: bigint;
38
+ callType: string;
39
+ };
40
+
41
+ export type JSONTransaction<depth extends number> = depth extends 0
42
+ ? WithBigintStringified<Omit<RawTransaction, 'from' | 'to'>> & {
43
+ from: JSONAccount<depth>;
44
+ to?: JSONAccount<depth>;
45
+ }
46
+ : WithBigintStringified<Omit<RawTransaction, 'from' | 'to'>> & {
47
+ from: JSONAccount<depth>;
48
+ to?: JSONAccount<depth>;
49
+ block: JSONBlock<depth>;
50
+ receipt: WithBigintStringified<TransactionReceipt>;
51
+ calls?: WithBigintStringified<TransactionCall>[];
52
+ };
@@ -0,0 +1,30 @@
1
+ export type BigintStringified = `${number}n`;
2
+
3
+ // -- TRANSFORMATION EN CHAÎNE (AVEC RÉCURSIVITÉ) --
4
+
5
+ export type WithBigintStringified<T> = T extends bigint
6
+ // Cas de base : c'est un bigint, on le transforme
7
+ ? BigintStringified
8
+ // Cas récursif pour les tableaux : on applique la transformation à chaque élément
9
+ : T extends (infer E)[]
10
+ ? Array<WithBigintStringified<E>>
11
+ // Cas récursif pour les objets : on parcourt les propriétés et on ré-applique le type
12
+ : T extends object
13
+ ? { [K in keyof T]: WithBigintStringified<T[K]> }
14
+ // Cas de base : ce n'est ni un bigint, ni un objet, ni un tableau, on ne touche à rien
15
+ : T;
16
+
17
+
18
+ // -- TRANSFORMATION EN BIGINT (AVEC RÉCURSIVITÉ) --
19
+
20
+ export type WithoutBigintStringified<T> = T extends BigintStringified
21
+ // Cas de base : c'est une chaîne bigint, on la transforme
22
+ ? bigint
23
+ // Cas récursif pour les tableaux
24
+ : T extends (infer E)[]
25
+ ? Array<WithoutBigintStringified<E>>
26
+ // Cas récursif pour les objets
27
+ : T extends object
28
+ ? { [K in keyof T]: WithoutBigintStringified<T[K]> }
29
+ // Cas de base : on ne touche à rien
30
+ : T;
@@ -0,0 +1,8 @@
1
+ export * from './Account';
2
+ export * from './Block';
3
+ export * from './Transaction';
4
+ export * from './Cache';
5
+ export * from './PersistenceAdapter';
6
+ export * from './Utils';
7
+
8
+ export * from "@mentaproject/core/types";
@@ -0,0 +1,59 @@
1
+ import { WithoutBigintStringified } from "../types/Utils";
2
+
3
+ export const bigIntMax = (...args: bigint[]) => args.reduce((m, e) => e > m ? e : m);
4
+ export const bigIntMin = (...args: bigint[]) => args.reduce((m, e) => e < m ? e : m);
5
+
6
+ export function bigIntReviver(key: string, value: any) {
7
+ if (typeof value === 'string') {
8
+ if (value.endsWith('n')) {
9
+ try {
10
+ return BigInt(value.slice(0, -1));
11
+ } catch (e) {
12
+ return value;
13
+ }
14
+ };
15
+ };
16
+
17
+ return value;
18
+ };
19
+
20
+ export function stringifyBingints(obj: any) {
21
+ if (typeof obj === 'bigint') {
22
+ return obj.toString() + "n";
23
+ }
24
+
25
+ if (typeof obj === 'object') {
26
+ for (const key in obj) {
27
+ obj[key] = stringifyBingints(obj[key]);
28
+ }
29
+ }
30
+
31
+ if (Array.isArray(obj)) {
32
+ for (let i = 0; i < obj.length; i++) {
33
+ obj[i] = stringifyBingints(obj[i]);
34
+ }
35
+ }
36
+
37
+ return obj;
38
+ };
39
+
40
+ export function parseBingints<T extends { [key: string]: any }>(obj: T): WithoutBigintStringified<T> {
41
+ if (typeof obj !== 'object' || obj === null) {
42
+ return obj;
43
+ }
44
+
45
+ if (Array.isArray(obj)) {
46
+ return obj.map((item, index) => bigIntReviver(index.toString(), parseBingints(item))) as WithoutBigintStringified<T>;
47
+ }
48
+
49
+ const newObj: { [key: string]: any } = {};
50
+ for (const key in obj) {
51
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
52
+ const value = obj[key];
53
+ const processedValue = parseBingints(value);
54
+ newObj[key] = bigIntReviver(key, processedValue);
55
+ }
56
+ };
57
+
58
+ return newObj as WithoutBigintStringified<T>;
59
+ };
@@ -0,0 +1,123 @@
1
+ /**
2
+ * @module toJSON
3
+ */
4
+
5
+ /**
6
+ * Interface for parameters passed to the toJSON function.
7
+ * @template T The type of the object to be converted to JSON.
8
+ */
9
+ export interface IToJSONParams<T extends { [key: string]: any } = { [key: string]: any }> {
10
+ /** The object to convert. */
11
+ obj: T;
12
+ /** The depth for recursive conversion. Defaults to 0. */
13
+ depth?: number;
14
+ }
15
+
16
+ /**
17
+ * Checks if an object is a class instance (not a native JavaScript object like Array, Date, etc.).
18
+ * @param {any} obj The object to check.
19
+ * @returns {boolean} True if the object is a class instance, false otherwise.
20
+ */
21
+ function isClassInstance(obj: any): boolean {
22
+ if (!obj) return false;
23
+
24
+ const constructor = obj.constructor;
25
+ const nativeConstructors = [Array, Date, RegExp, Map, Set, Promise, Function, Number, String, Boolean, Error, Object];
26
+
27
+ if (nativeConstructors.includes(constructor)) {
28
+ return false;
29
+ }
30
+
31
+ return true
32
+ };
33
+
34
+ /**
35
+ * Recursively converts BigInt values in an object to strings.
36
+ * @param {any} obj The object to convert.
37
+ * @returns {any} The object with BigInts converted to strings.
38
+ */
39
+ function convertBigintsToStrings(obj: any): any {
40
+ if (typeof obj === 'bigint') {
41
+ return obj.toString() + "n";
42
+ }
43
+
44
+ if (typeof obj === 'object') {
45
+ for (const key in obj) {
46
+ obj[key] = convertBigintsToStrings(obj[key]);
47
+ }
48
+ }
49
+
50
+ if (Array.isArray(obj)) {
51
+ for (let i = 0; i < obj.length; i++) {
52
+ obj[i] = convertBigintsToStrings(obj[i]);
53
+ }
54
+ }
55
+
56
+ return obj;
57
+ }
58
+
59
+ /**
60
+ * Converts an object, including its nested class instances and getter methods, into a plain JSON object.
61
+ * BigInt values are converted to strings.
62
+ *
63
+ * @param params - The parameters for conversion.
64
+ * @param params.obj - The object to convert.
65
+ * @param [params.depth=0] - The depth for recursive conversion. Defaults to 0.
66
+ * @returns A promise that resolves to the JSON representation of the object.
67
+ */
68
+ export async function toJSON({ obj, depth = 0 }: IToJSONParams) {
69
+ const data: any = {};
70
+ const promises: Promise<any>[] = [];
71
+
72
+ for (const key in obj) {
73
+ // skip class related properties
74
+ if (key === "toJSON" || key === "constructor" || key === "client" || key === "persistenceManager") continue;
75
+
76
+ const prop: any = obj[key];
77
+
78
+ if (typeof prop === "function") {
79
+ // do not fetch getters if depth is 0
80
+ if (depth === 0) continue;
81
+
82
+ const promise = async () => {
83
+ const value = await obj[key]();
84
+
85
+ // if the value is a class instance, convert it to JSON recursively
86
+ if (typeof value === "object" && isClassInstance(value)) return data[key] = await toJSON({ obj: value, depth: depth - 1 });
87
+
88
+ data[key] = value;
89
+ };
90
+
91
+ promises.push(promise());
92
+ };
93
+
94
+ if (typeof prop === "object" && isClassInstance(prop)) {
95
+ // If depth is 0, just flatten the object using recursion
96
+ if (depth === 0) {
97
+ const promise = async () => {
98
+ data[key] = await toJSON({
99
+ obj: prop,
100
+ depth: depth - 1
101
+ });
102
+ };
103
+ promises.push(promise());
104
+
105
+ continue;
106
+ };
107
+
108
+ // If depth is not 0, fetch the object
109
+ const promise = async () => {
110
+ data[key] = await prop.toJSON({ depth: depth - 1 });
111
+ };
112
+ promises.push(promise());
113
+
114
+ continue;
115
+ };
116
+
117
+ data[key] = prop;
118
+ };
119
+
120
+ await Promise.all(promises);
121
+
122
+ return convertBigintsToStrings(data);
123
+ };
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @module withCache
3
+ */
4
+ import { watchBlockNumber } from "@mentaproject/core/actions";
5
+ import { CoreClient } from "../types";
6
+ import { ICache } from "../types/Cache";
7
+ import { Methods } from "../types/JsonRPC";
8
+
9
+ /**
10
+ * A higher-order function that enhances a class method with caching capabilities.
11
+ * It intercepts RPC requests made through the client and caches their responses
12
+ * based on the provided cache implementation.
13
+ *
14
+ * @param client The CoreClient instance to enhance with caching.
15
+ * @param cache The cache implementation (ICache) to use for storing and retrieving responses.
16
+ * @returns The enhanced CoreClient instance with caching enabled.
17
+ */
18
+ export function withCache(client: CoreClient, cache: ICache) {
19
+ watchBlockNumber(client, {
20
+ onBlockNumber: (blockNumber) => {
21
+ cache.setBlockNumber(blockNumber);
22
+ },
23
+ pollingInterval: 1000,
24
+ });
25
+ // 2. We keep a reference to the original request method
26
+ const originalRequest = client.request;
27
+
28
+ // 3. We replace the client's `request` method
29
+ client.request = (async (args: { method: Methods, params: any }) => {
30
+ const { method, params } = args;
31
+
32
+ const cacheKey = `${client.chain!.id}:${method}:${JSON.stringify(params || [], (_, v) => typeof v === 'bigint' ? v.toString() : v)}`;
33
+
34
+ let result;
35
+ if (method !== "eth_blockNumber") result = cache.get(cacheKey);
36
+
37
+ if (!result) {
38
+ result = await originalRequest(args as any);
39
+ };
40
+
41
+ if (result !== null && result !== undefined && method !== "eth_blockNumber") {
42
+ const ttl = cache.config.ttlPolicies[method] || cache.config.defaultTtl;
43
+ await cache.set(cacheKey, result, ttl);
44
+ }
45
+
46
+ return result;
47
+ }) as any;
48
+
49
+ return client;
50
+ };