@dappql/react 1.0.1
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.
- package/dist/react/src/Context.d.ts +35 -0
- package/dist/react/src/Context.d.ts.map +1 -0
- package/dist/react/src/Context.js +42 -0
- package/dist/react/src/ContextQuery.d.ts +66 -0
- package/dist/react/src/ContextQuery.d.ts.map +1 -0
- package/dist/react/src/ContextQuery.js +94 -0
- package/dist/react/src/ContextQueryManager.d.ts +71 -0
- package/dist/react/src/ContextQueryManager.d.ts.map +1 -0
- package/dist/react/src/ContextQueryManager.js +135 -0
- package/dist/react/src/Mutation.d.ts +79 -0
- package/dist/react/src/Mutation.d.ts.map +1 -0
- package/dist/react/src/Mutation.js +147 -0
- package/dist/react/src/Provider.d.ts +34 -0
- package/dist/react/src/Provider.d.ts.map +1 -0
- package/dist/react/src/Provider.js +39 -0
- package/dist/react/src/Query.d.ts +52 -0
- package/dist/react/src/Query.d.ts.map +1 -0
- package/dist/react/src/Query.js +92 -0
- package/dist/react/src/blocksHandler.d.ts +10 -0
- package/dist/react/src/blocksHandler.d.ts.map +1 -0
- package/dist/react/src/blocksHandler.js +32 -0
- package/dist/react/src/buildIteratorQuery.d.ts +5 -0
- package/dist/react/src/buildIteratorQuery.d.ts.map +1 -0
- package/dist/react/src/buildIteratorQuery.js +9 -0
- package/dist/react/src/index.d.ts +7 -0
- package/dist/react/src/index.d.ts.map +1 -0
- package/dist/react/src/index.js +7 -0
- package/dist/react/src/queryHooks.d.ts +31 -0
- package/dist/react/src/queryHooks.d.ts.map +1 -0
- package/dist/react/src/queryHooks.js +49 -0
- package/dist/react/src/useTransactionUpdates.d.ts +3 -0
- package/dist/react/src/useTransactionUpdates.d.ts.map +1 -0
- package/dist/react/src/useTransactionUpdates.js +112 -0
- package/dist/shared/types.d.ts +105 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +2 -0
- package/package.json +74 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { MutationCallbacks, AddressResolverFunction } from '../../shared/types.js';
|
|
2
|
+
import { BlockSubscriptionManager } from './blocksHandler.js';
|
|
3
|
+
/**
|
|
4
|
+
* Context for DappQL
|
|
5
|
+
* @param children - React children
|
|
6
|
+
* @returns DappQL context
|
|
7
|
+
*/
|
|
8
|
+
export declare const DappQLContext: import("react").Context<{
|
|
9
|
+
blocksRefetchInterval: number;
|
|
10
|
+
defaultBatchSize: number;
|
|
11
|
+
addressResolver?: AddressResolverFunction;
|
|
12
|
+
onBlockChange: BlockSubscriptionManager["subscribe"];
|
|
13
|
+
watchBlocks?: boolean;
|
|
14
|
+
simulateMutations?: boolean;
|
|
15
|
+
} & MutationCallbacks>;
|
|
16
|
+
/**
|
|
17
|
+
* Hook to access DappQL context
|
|
18
|
+
* @returns Context containing current block number, address resolver, and mutation callbacks
|
|
19
|
+
*/
|
|
20
|
+
export declare function useDappQL(): {
|
|
21
|
+
blocksRefetchInterval: number;
|
|
22
|
+
defaultBatchSize: number;
|
|
23
|
+
addressResolver?: AddressResolverFunction;
|
|
24
|
+
onBlockChange: BlockSubscriptionManager["subscribe"];
|
|
25
|
+
watchBlocks?: boolean;
|
|
26
|
+
simulateMutations?: boolean;
|
|
27
|
+
} & MutationCallbacks;
|
|
28
|
+
/**
|
|
29
|
+
* Hook to refetch on block change
|
|
30
|
+
* @param refetchFn - Function to refetch
|
|
31
|
+
* @param watchBlocks - Whether to watch blocks
|
|
32
|
+
* @param blocksRefetchInterval - Blocks refetch interval
|
|
33
|
+
*/
|
|
34
|
+
export declare function useRefetchOnBlockChange(refetchFn: () => any, watchBlocks?: boolean, blocksRefetchInterval?: number): void;
|
|
35
|
+
//# sourceMappingURL=Context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Context.d.ts","sourceRoot":"","sources":["../../../src/Context.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AAClF,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAA;AAE7D;;;;GAIG;AACH,eAAO,MAAM,aAAa;2BAEC,MAAM;sBACX,MAAM;sBACN,uBAAuB;mBAC1B,wBAAwB,CAAC,WAAW,CAAC;kBACtC,OAAO;wBACD,OAAO;sBAE0D,CAAA;AAEzF;;;GAGG;AACH,wBAAgB,SAAS;2BAbE,MAAM;sBACX,MAAM;sBACN,uBAAuB;mBAC1B,wBAAwB,CAAC,WAAW,CAAC;kBACtC,OAAO;wBACD,OAAO;sBAU9B;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,EAAE,WAAW,UAAQ,EAAE,qBAAqB,SAAI,QAmB3G"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { useContext, useEffect } from 'react';
|
|
2
|
+
import { createContext } from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* Context for DappQL
|
|
5
|
+
* @param children - React children
|
|
6
|
+
* @returns DappQL context
|
|
7
|
+
*/
|
|
8
|
+
export const DappQLContext = createContext({ onBlockChange: () => () => false, blocksRefetchInterval: 1, defaultBatchSize: 1024 });
|
|
9
|
+
/**
|
|
10
|
+
* Hook to access DappQL context
|
|
11
|
+
* @returns Context containing current block number, address resolver, and mutation callbacks
|
|
12
|
+
*/
|
|
13
|
+
export function useDappQL() {
|
|
14
|
+
return useContext(DappQLContext);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Hook to refetch on block change
|
|
18
|
+
* @param refetchFn - Function to refetch
|
|
19
|
+
* @param watchBlocks - Whether to watch blocks
|
|
20
|
+
* @param blocksRefetchInterval - Blocks refetch interval
|
|
21
|
+
*/
|
|
22
|
+
export function useRefetchOnBlockChange(refetchFn, watchBlocks = false, blocksRefetchInterval = 1) {
|
|
23
|
+
const { onBlockChange } = useDappQL();
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!watchBlocks)
|
|
26
|
+
return;
|
|
27
|
+
let lastBlockFetched = 0n;
|
|
28
|
+
const unsubscribe = onBlockChange((blockNumber) => {
|
|
29
|
+
if (lastBlockFetched === 0n && blockNumber > 0n) {
|
|
30
|
+
lastBlockFetched = blockNumber - 1n;
|
|
31
|
+
}
|
|
32
|
+
const shouldRefetch = blockNumber > 0n && blockNumber >= lastBlockFetched + BigInt(blocksRefetchInterval);
|
|
33
|
+
if (shouldRefetch) {
|
|
34
|
+
refetchFn();
|
|
35
|
+
lastBlockFetched = blockNumber;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
return () => {
|
|
39
|
+
unsubscribe();
|
|
40
|
+
};
|
|
41
|
+
}, [watchBlocks, blocksRefetchInterval]);
|
|
42
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { RequestCollection, ReadContractsResult, Request, GetItemCallFunction } from '../../shared/types.js';
|
|
2
|
+
import { IteratorQueryResult } from './queryHooks.js';
|
|
3
|
+
/**
|
|
4
|
+
* Hook to execute contract queries through the global query manager
|
|
5
|
+
*
|
|
6
|
+
* All queries across your application using this hook will be automatically
|
|
7
|
+
* aggregated into a single multicall query. This optimization significantly
|
|
8
|
+
* reduces RPC calls by batching multiple contract reads together.
|
|
9
|
+
*
|
|
10
|
+
* For example, if you have:
|
|
11
|
+
* - Component A reading balanceOf(user1)
|
|
12
|
+
* - Component B reading balanceOf(user2)
|
|
13
|
+
* - Component C reading totalSupply()
|
|
14
|
+
*
|
|
15
|
+
* These will be combined into a single multicall instead of 3 separate RPC calls.
|
|
16
|
+
*
|
|
17
|
+
* @param requests - Collection of contract requests to execute
|
|
18
|
+
* @returns Object containing:
|
|
19
|
+
* - isLoading: Whether the query is in progress
|
|
20
|
+
* - isError: Whether an error occurred
|
|
21
|
+
* - data: The query results
|
|
22
|
+
* - error: Any error that occurred
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* const { isLoading, isError, data, error } = useContextQuery({
|
|
27
|
+
* balanceOf: { deployAddress: '0x...', method: 'balanceOf', args: [user1] },
|
|
28
|
+
* balanceOf2: { deployAddress: '0x...', method: 'balanceOf', args: [user2] },
|
|
29
|
+
* })
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare function useContextQuery<T extends RequestCollection>(requests: T): Omit<ReadContractsResult, 'data'> & {
|
|
33
|
+
data: {
|
|
34
|
+
[K in keyof T]: NonNullable<T[K]['defaultValue']>;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* React hook for querying a single contract request through the global query manager
|
|
39
|
+
* @param request - The contract request to query
|
|
40
|
+
* @returns Object containing:
|
|
41
|
+
* - isLoading: Whether the query is in progress
|
|
42
|
+
* - isError: Whether an error occurred
|
|
43
|
+
* - data: The query result
|
|
44
|
+
* - error: Any error that occurred
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```tsx
|
|
48
|
+
* const { isLoading, isError, data, error } = useSingleContextQuery({ deployAddress: '0x...', method: 'balanceOf', args: [user1] })
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare function useSingleContextQuery<T extends Request>(request: T): Omit<ReturnType<typeof useContextQuery>, 'data'> & {
|
|
52
|
+
data: NonNullable<T['defaultValue']>;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* React hook for querying iterable data structures (like arrays) from smart contracts through the global query manager
|
|
56
|
+
* @param total Total number of items to query
|
|
57
|
+
* @param getItem Function that generates the query for a specific index
|
|
58
|
+
* @param options Query configuration options including optional starting index
|
|
59
|
+
* @returns Object containing array of query results and status
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* const { data, isLoading } = useIteratorQuery(10, (i) => contracts.myContract.getValue(i))
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare function useIteratorContextQuery<T>(total: bigint, getItem: GetItemCallFunction<T>, firstIndex?: bigint): IteratorQueryResult<T>;
|
|
66
|
+
//# sourceMappingURL=ContextQuery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContextQuery.d.ts","sourceRoot":"","sources":["../../../src/ContextQuery.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAC5G,OAAO,EACL,mBAAmB,EAMpB,MAAM,iBAAiB,CAAA;AAGxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,iBAAiB,EACzD,QAAQ,EAAE,CAAC,GACV,IAAI,CAAC,mBAAmB,EAAE,MAAM,CAAC,GAAG;IACrC,IAAI,EAAE;SAAG,CAAC,IAAI,MAAM,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;KAAE,CAAA;CAC5D,CA2BA;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,OAAO,EACrD,OAAO,EAAE,CAAC,GACT,IAAI,CAAC,UAAU,CAAC,OAAO,eAAe,CAAC,EAAE,MAAM,CAAC,GAAG;IAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAA;CAAE,CAM7F;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EACvC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC,EAC/B,UAAU,GAAE,MAAW,GACtB,mBAAmB,CAAC,CAAC,CAAC,CAIxB"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { useCallKeys, useDefaultData, useIteratorQueryData, useRequestString, useResultData, } from './queryHooks.js';
|
|
3
|
+
import { useQueryContextProvider } from './ContextQueryManager.js';
|
|
4
|
+
import { buildIteratorQuery } from './buildIteratorQuery.js';
|
|
5
|
+
/**
|
|
6
|
+
* Hook to execute contract queries through the global query manager
|
|
7
|
+
*
|
|
8
|
+
* All queries across your application using this hook will be automatically
|
|
9
|
+
* aggregated into a single multicall query. This optimization significantly
|
|
10
|
+
* reduces RPC calls by batching multiple contract reads together.
|
|
11
|
+
*
|
|
12
|
+
* For example, if you have:
|
|
13
|
+
* - Component A reading balanceOf(user1)
|
|
14
|
+
* - Component B reading balanceOf(user2)
|
|
15
|
+
* - Component C reading totalSupply()
|
|
16
|
+
*
|
|
17
|
+
* These will be combined into a single multicall instead of 3 separate RPC calls.
|
|
18
|
+
*
|
|
19
|
+
* @param requests - Collection of contract requests to execute
|
|
20
|
+
* @returns Object containing:
|
|
21
|
+
* - isLoading: Whether the query is in progress
|
|
22
|
+
* - isError: Whether an error occurred
|
|
23
|
+
* - data: The query results
|
|
24
|
+
* - error: Any error that occurred
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```tsx
|
|
28
|
+
* const { isLoading, isError, data, error } = useContextQuery({
|
|
29
|
+
* balanceOf: { deployAddress: '0x...', method: 'balanceOf', args: [user1] },
|
|
30
|
+
* balanceOf2: { deployAddress: '0x...', method: 'balanceOf', args: [user2] },
|
|
31
|
+
* })
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export function useContextQuery(requests) {
|
|
35
|
+
const requestString = useRequestString(requests);
|
|
36
|
+
const queryManager = useQueryContextProvider();
|
|
37
|
+
const [result, setResult] = useState({
|
|
38
|
+
isLoading: true,
|
|
39
|
+
isError: false,
|
|
40
|
+
data: undefined,
|
|
41
|
+
error: null,
|
|
42
|
+
});
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
const queryId = queryManager.addQuery({
|
|
45
|
+
collection: requests,
|
|
46
|
+
callBack: setResult,
|
|
47
|
+
});
|
|
48
|
+
return () => {
|
|
49
|
+
queryManager.removeQuery(queryId);
|
|
50
|
+
};
|
|
51
|
+
}, [requestString]);
|
|
52
|
+
const callKeys = useCallKeys(requests, requestString);
|
|
53
|
+
const defaultData = useDefaultData(requests, callKeys);
|
|
54
|
+
const data = useResultData(requests, callKeys, result, defaultData);
|
|
55
|
+
return useMemo(() => {
|
|
56
|
+
return { isLoading: result.isLoading, isError: result.isError, data, error: result.error };
|
|
57
|
+
}, [result.error, result.isLoading, data]);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* React hook for querying a single contract request through the global query manager
|
|
61
|
+
* @param request - The contract request to query
|
|
62
|
+
* @returns Object containing:
|
|
63
|
+
* - isLoading: Whether the query is in progress
|
|
64
|
+
* - isError: Whether an error occurred
|
|
65
|
+
* - data: The query result
|
|
66
|
+
* - error: Any error that occurred
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```tsx
|
|
70
|
+
* const { isLoading, isError, data, error } = useSingleContextQuery({ deployAddress: '0x...', method: 'balanceOf', args: [user1] })
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export function useSingleContextQuery(request) {
|
|
74
|
+
const result = useContextQuery({ value: request });
|
|
75
|
+
return useMemo(() => {
|
|
76
|
+
return { ...result, data: result.data.value };
|
|
77
|
+
}, [result]);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* React hook for querying iterable data structures (like arrays) from smart contracts through the global query manager
|
|
81
|
+
* @param total Total number of items to query
|
|
82
|
+
* @param getItem Function that generates the query for a specific index
|
|
83
|
+
* @param options Query configuration options including optional starting index
|
|
84
|
+
* @returns Object containing array of query results and status
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* const { data, isLoading } = useIteratorQuery(10, (i) => contracts.myContract.getValue(i))
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export function useIteratorContextQuery(total, getItem, firstIndex = 0n) {
|
|
91
|
+
const query = useMemo(() => buildIteratorQuery(total, firstIndex, getItem), [total, firstIndex, getItem]);
|
|
92
|
+
const result = useContextQuery(query);
|
|
93
|
+
return useIteratorQueryData(total, result);
|
|
94
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContextQuery Module
|
|
3
|
+
*
|
|
4
|
+
* Manages the aggregation and distribution of multiple contract queries into a single global query.
|
|
5
|
+
* This optimization reduces the number of RPC calls by batching multiple contract reads together.
|
|
6
|
+
*
|
|
7
|
+
* Key features:
|
|
8
|
+
* - Query Aggregation: Combines multiple individual queries into a single batch
|
|
9
|
+
* - Version Control: Manages race conditions in async responses
|
|
10
|
+
* - Result Distribution: Routes results back to individual query callbacks
|
|
11
|
+
* - Address Resolution: Flexible contract address resolution
|
|
12
|
+
*/
|
|
13
|
+
import { Abi, Address } from 'viem';
|
|
14
|
+
import { RequestCollection, AddressResolverFunction, ReadContractsResult, QueryContextProps } from '../../shared/types.js';
|
|
15
|
+
type Query = {
|
|
16
|
+
collection: RequestCollection;
|
|
17
|
+
callBack: (result: ReadContractsResult) => void;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Represents a single contract call within the global query
|
|
21
|
+
*/
|
|
22
|
+
type Call = {
|
|
23
|
+
queryId: number;
|
|
24
|
+
abi: Abi;
|
|
25
|
+
functionName: string;
|
|
26
|
+
args: readonly any[];
|
|
27
|
+
address: Address;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Represents the state of all aggregated queries
|
|
31
|
+
*/
|
|
32
|
+
type ContextQuery = {
|
|
33
|
+
version: number;
|
|
34
|
+
count: Record<number, number>;
|
|
35
|
+
calls: Call[];
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Manages the aggregation and distribution of contract queries
|
|
39
|
+
*/
|
|
40
|
+
export declare class ContextQueryManager {
|
|
41
|
+
private queries;
|
|
42
|
+
private activeQueries;
|
|
43
|
+
private currGlobal;
|
|
44
|
+
private version;
|
|
45
|
+
private queryId;
|
|
46
|
+
private addressResolver?;
|
|
47
|
+
private onUpdate;
|
|
48
|
+
/**
|
|
49
|
+
* Creates a new QueryManager instance
|
|
50
|
+
* @param onUpdate - Callback triggered when the global query changes
|
|
51
|
+
* @param addressResolver - Optional function to resolve contract addresses
|
|
52
|
+
*/
|
|
53
|
+
constructor(onUpdate: (ContextQuery: ContextQuery) => any, addressResolver?: AddressResolverFunction);
|
|
54
|
+
getContextQuery(): ContextQuery;
|
|
55
|
+
getVersion(): number;
|
|
56
|
+
addQuery(query: Query): number;
|
|
57
|
+
removeQuery(id: number): void;
|
|
58
|
+
private aggregateQueries;
|
|
59
|
+
setAddressResolver(resolver?: AddressResolverFunction): void;
|
|
60
|
+
onResult(result: ReadContractsResult, version: number): void;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* React Context provider for scoped query management
|
|
64
|
+
* Handles the lifecycle of queries and their results
|
|
65
|
+
*/
|
|
66
|
+
export declare function ContextQueryProvider({ children, defaultBatchSize, watchBlocks, blocksRefetchInterval, }: {
|
|
67
|
+
children: any;
|
|
68
|
+
} & QueryContextProps): import("react/jsx-runtime").JSX.Element;
|
|
69
|
+
export declare function useQueryContextProvider(): ContextQueryManager;
|
|
70
|
+
export {};
|
|
71
|
+
//# sourceMappingURL=ContextQueryManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContextQueryManager.d.ts","sourceRoot":"","sources":["../../../src/ContextQueryManager.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,GAAG,EAAa,OAAO,EAAE,MAAM,MAAM,CAAA;AAE9C,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EAEvB,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,uBAAuB,CAAA;AAG9B,KAAK,KAAK,GAAG;IAAE,UAAU,EAAE,iBAAiB,CAAC;IAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAA;CAAE,CAAA;AAC/F;;GAEG;AACH,KAAK,IAAI,GAAG;IACV,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,GAAG,CAAA;IACR,YAAY,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,SAAS,GAAG,EAAE,CAAA;IACpB,OAAO,EAAE,OAAO,CAAA;CACjB,CAAA;AAED;;GAEG;AACH,KAAK,YAAY,GAAG;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,KAAK,EAAE,IAAI,EAAE,CAAA;CACd,CAAA;AAED;;GAEG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,aAAa,CAAyB;IAC9C,OAAO,CAAC,UAAU,CAAqD;IACvE,OAAO,CAAC,OAAO,CAAI;IACnB,OAAO,CAAC,OAAO,CAAY;IAC3B,OAAO,CAAC,eAAe,CAAC,CAAyB;IACjD,OAAO,CAAC,QAAQ,CAAsC;IAEtD;;;;OAIG;gBACS,QAAQ,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,GAAG,EAAE,eAAe,CAAC,EAAE,uBAAuB;IAKpG,eAAe,IAAI,YAAY;IAI/B,UAAU,IAAI,MAAM;IAIpB,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM;IAQ9B,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAM7B,OAAO,CAAC,gBAAgB;IAsCxB,kBAAkB,CAAC,QAAQ,CAAC,EAAE,uBAAuB;IAKrD,QAAQ,CAAC,MAAM,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM;CAuBtD;AAID;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,QAAQ,EACR,gBAAgB,EAChB,WAAW,EACX,qBAAqB,GACtB,EAAE;IAAE,QAAQ,EAAE,GAAG,CAAA;CAAE,GAAG,iBAAiB,2CAwBvC;AAED,wBAAgB,uBAAuB,wBAEtC"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* ContextQuery Module
|
|
4
|
+
*
|
|
5
|
+
* Manages the aggregation and distribution of multiple contract queries into a single global query.
|
|
6
|
+
* This optimization reduces the number of RPC calls by batching multiple contract reads together.
|
|
7
|
+
*
|
|
8
|
+
* Key features:
|
|
9
|
+
* - Query Aggregation: Combines multiple individual queries into a single batch
|
|
10
|
+
* - Version Control: Manages race conditions in async responses
|
|
11
|
+
* - Result Distribution: Routes results back to individual query callbacks
|
|
12
|
+
* - Address Resolution: Flexible contract address resolution
|
|
13
|
+
*/
|
|
14
|
+
import { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
|
15
|
+
import { stringify } from 'viem';
|
|
16
|
+
import { useReadContracts } from 'wagmi';
|
|
17
|
+
import { useDappQL, useRefetchOnBlockChange } from './Context.js';
|
|
18
|
+
/**
|
|
19
|
+
* Manages the aggregation and distribution of contract queries
|
|
20
|
+
*/
|
|
21
|
+
export class ContextQueryManager {
|
|
22
|
+
/**
|
|
23
|
+
* Creates a new QueryManager instance
|
|
24
|
+
* @param onUpdate - Callback triggered when the global query changes
|
|
25
|
+
* @param addressResolver - Optional function to resolve contract addresses
|
|
26
|
+
*/
|
|
27
|
+
constructor(onUpdate, addressResolver) {
|
|
28
|
+
this.queries = {};
|
|
29
|
+
this.activeQueries = new Set();
|
|
30
|
+
this.currGlobal = { version: 0, count: {}, calls: [] };
|
|
31
|
+
this.version = 0;
|
|
32
|
+
this.queryId = 0;
|
|
33
|
+
this.addressResolver = addressResolver;
|
|
34
|
+
this.onUpdate = onUpdate;
|
|
35
|
+
}
|
|
36
|
+
getContextQuery() {
|
|
37
|
+
return this.currGlobal;
|
|
38
|
+
}
|
|
39
|
+
getVersion() {
|
|
40
|
+
return this.version;
|
|
41
|
+
}
|
|
42
|
+
addQuery(query) {
|
|
43
|
+
const id = this.queryId++;
|
|
44
|
+
this.queries[id] = query;
|
|
45
|
+
this.activeQueries.add(id);
|
|
46
|
+
this.aggregateQueries();
|
|
47
|
+
return id;
|
|
48
|
+
}
|
|
49
|
+
removeQuery(id) {
|
|
50
|
+
delete this.queries[id];
|
|
51
|
+
this.activeQueries.delete(id);
|
|
52
|
+
this.aggregateQueries();
|
|
53
|
+
}
|
|
54
|
+
aggregateQueries() {
|
|
55
|
+
const queryVersion = ++this.version;
|
|
56
|
+
const newContextQuery = Object.keys(this.queries)
|
|
57
|
+
.map((id) => {
|
|
58
|
+
const queryId = Number(id);
|
|
59
|
+
const query = this.queries[queryId];
|
|
60
|
+
return Object.values(query.collection).map((request) => ({
|
|
61
|
+
queryId,
|
|
62
|
+
abi: request.getAbi(),
|
|
63
|
+
functionName: request.method,
|
|
64
|
+
args: request.args,
|
|
65
|
+
address: request.address || this.addressResolver?.(request.contractName) || request.deployAddress,
|
|
66
|
+
}));
|
|
67
|
+
})
|
|
68
|
+
.reduce((acc, queries) => {
|
|
69
|
+
if (queries.length) {
|
|
70
|
+
acc.calls.push(...queries);
|
|
71
|
+
acc.count[queries[0].queryId] = queries.length;
|
|
72
|
+
}
|
|
73
|
+
return acc;
|
|
74
|
+
}, { version: queryVersion, count: {}, calls: [] });
|
|
75
|
+
if (stringify(newContextQuery) !== stringify(this.currGlobal)) {
|
|
76
|
+
this.currGlobal = newContextQuery;
|
|
77
|
+
if (this.version === queryVersion) {
|
|
78
|
+
this.onUpdate(newContextQuery);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
setAddressResolver(resolver) {
|
|
83
|
+
this.addressResolver = resolver;
|
|
84
|
+
this.aggregateQueries();
|
|
85
|
+
}
|
|
86
|
+
onResult(result, version) {
|
|
87
|
+
const shouldUpdate = !result.isLoading &&
|
|
88
|
+
result.data &&
|
|
89
|
+
result.data.length === this.currGlobal.calls.length &&
|
|
90
|
+
version === this.currGlobal.version;
|
|
91
|
+
if (shouldUpdate) {
|
|
92
|
+
let index = 0;
|
|
93
|
+
this.activeQueries.forEach((id) => {
|
|
94
|
+
const queryId = Number(id);
|
|
95
|
+
const query = this.queries[queryId];
|
|
96
|
+
const count = this.currGlobal.count[queryId];
|
|
97
|
+
if (!count)
|
|
98
|
+
return; //query has been removed
|
|
99
|
+
const chunk = result.data?.slice(index, index + count);
|
|
100
|
+
index += this.currGlobal.count[queryId];
|
|
101
|
+
if (chunk) {
|
|
102
|
+
query.callBack({ isLoading: false, isError: result.isError, data: chunk, error: result.error });
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const QueryContext = createContext(new ContextQueryManager(() => { }));
|
|
109
|
+
/**
|
|
110
|
+
* React Context provider for scoped query management
|
|
111
|
+
* Handles the lifecycle of queries and their results
|
|
112
|
+
*/
|
|
113
|
+
export function ContextQueryProvider({ children, defaultBatchSize, watchBlocks, blocksRefetchInterval, }) {
|
|
114
|
+
const { addressResolver } = useDappQL();
|
|
115
|
+
const [query, setQuery] = useState({ version: 0, count: {}, calls: [] });
|
|
116
|
+
const queryManager = useMemo(() => new ContextQueryManager(setQuery, addressResolver), []);
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
queryManager.setAddressResolver(addressResolver);
|
|
119
|
+
}, [addressResolver]);
|
|
120
|
+
const result = useReadContracts({
|
|
121
|
+
contracts: query.calls,
|
|
122
|
+
query: {
|
|
123
|
+
notifyOnChangeProps: ['data', 'error'],
|
|
124
|
+
},
|
|
125
|
+
batchSize: defaultBatchSize,
|
|
126
|
+
});
|
|
127
|
+
useRefetchOnBlockChange(result.refetch, watchBlocks && !!query.calls.length, blocksRefetchInterval);
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
queryManager.onResult(result, query.version);
|
|
130
|
+
}, [result]);
|
|
131
|
+
return _jsx(QueryContext.Provider, { value: queryManager, children: children });
|
|
132
|
+
}
|
|
133
|
+
export function useQueryContextProvider() {
|
|
134
|
+
return useContext(QueryContext);
|
|
135
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Chain, type Address, PublicClient } from 'viem';
|
|
2
|
+
import { type MutationConfig } from '../../shared/types.js';
|
|
3
|
+
import { WriteContractErrorType } from 'wagmi/actions';
|
|
4
|
+
declare function useSimulate<M extends string, Args extends readonly any[]>(config: MutationConfig<M, Args>, address: Address, account: Address | undefined, chain: Chain | undefined, client: PublicClient | undefined): (...args: Args) => Promise<import("viem").SimulateContractReturnType<import("viem").Abi, M, Args, Chain | undefined, import("viem").Account | undefined, Chain | undefined, `0x${string}`>>;
|
|
5
|
+
declare function useEstimate<M extends string, Args extends readonly any[]>(config: MutationConfig<M, Args>, address: Address, account: Address | undefined, chain: Chain | undefined, client: PublicClient | undefined): (...args: Args) => Promise<bigint>;
|
|
6
|
+
declare function useMutationConfirmation(hash: `0x${string}` | undefined): import("wagmi").UseWaitForTransactionReceiptReturnType<import("wagmi").Config, number, {
|
|
7
|
+
blobGasPrice?: bigint | undefined;
|
|
8
|
+
blobGasUsed?: bigint | undefined;
|
|
9
|
+
blockHash: import("viem").Hash;
|
|
10
|
+
blockNumber: bigint;
|
|
11
|
+
contractAddress: Address | null | undefined;
|
|
12
|
+
cumulativeGasUsed: bigint;
|
|
13
|
+
effectiveGasPrice: bigint;
|
|
14
|
+
from: Address;
|
|
15
|
+
gasUsed: bigint;
|
|
16
|
+
logs: import("viem").Log<bigint, number, false>[];
|
|
17
|
+
logsBloom: import("viem").Hex;
|
|
18
|
+
root?: `0x${string}` | undefined;
|
|
19
|
+
status: "success" | "reverted";
|
|
20
|
+
to: Address | null;
|
|
21
|
+
transactionHash: import("viem").Hash;
|
|
22
|
+
transactionIndex: number;
|
|
23
|
+
type: import("viem").TransactionType;
|
|
24
|
+
chainId: number;
|
|
25
|
+
}>;
|
|
26
|
+
/**
|
|
27
|
+
* Configuration options for mutations
|
|
28
|
+
* Can be either a string (transaction name) or an object with additional options
|
|
29
|
+
*/
|
|
30
|
+
export type MutationOptions = {
|
|
31
|
+
/** Human-readable name for the transaction */
|
|
32
|
+
transactionName?: string;
|
|
33
|
+
/** Override the contract address */
|
|
34
|
+
address?: Address;
|
|
35
|
+
/** Whether to simulate the transaction before sending */
|
|
36
|
+
simulate?: boolean;
|
|
37
|
+
} | string;
|
|
38
|
+
/**
|
|
39
|
+
* Hook for executing contract write operations (mutations)
|
|
40
|
+
* @param config Configuration object containing contract details and ABI
|
|
41
|
+
* @param optionsOrTransactionName Optional configuration or transaction name
|
|
42
|
+
* @returns Object containing mutation state and send function
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* const mutation = useMutation({
|
|
46
|
+
* contractName: 'MyContract',
|
|
47
|
+
* functionName: 'setValue',
|
|
48
|
+
* getAbi: () => CONTRACT_ABI,
|
|
49
|
+
* deployAddress: '0x...'
|
|
50
|
+
* }, 'Set Value')
|
|
51
|
+
*
|
|
52
|
+
* // Execute the mutation
|
|
53
|
+
* mutation.send(newValue)
|
|
54
|
+
*/
|
|
55
|
+
export declare function useMutation<M extends string, Args extends readonly any[]>(config: MutationConfig<M, Args>, optionsOrTransactionName?: MutationOptions): {
|
|
56
|
+
status: 'pending' | 'success' | 'error' | 'idle';
|
|
57
|
+
data: Address | undefined;
|
|
58
|
+
error: WriteContractErrorType | null;
|
|
59
|
+
isPending: boolean;
|
|
60
|
+
isSuccess: boolean;
|
|
61
|
+
isError: boolean;
|
|
62
|
+
isLoading: boolean;
|
|
63
|
+
failureCount: number;
|
|
64
|
+
failureReason: WriteContractErrorType | null;
|
|
65
|
+
isIdle: boolean;
|
|
66
|
+
submittedAt: number;
|
|
67
|
+
confirmation: ReturnType<typeof useMutationConfirmation>;
|
|
68
|
+
reset: () => void;
|
|
69
|
+
send: (...args: Args) => void;
|
|
70
|
+
simulate: ReturnType<typeof useSimulate<M, Args>>;
|
|
71
|
+
estimate: ReturnType<typeof useEstimate<M, Args>>;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Return type of the useMutation hook
|
|
75
|
+
* Includes transaction state, confirmation status, and send function
|
|
76
|
+
*/
|
|
77
|
+
export type Mutation<M extends string, Args extends readonly any[]> = ReturnType<typeof useMutation<M, Args>>;
|
|
78
|
+
export {};
|
|
79
|
+
//# sourceMappingURL=Mutation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Mutation.d.ts","sourceRoot":"","sources":["../../../src/Mutation.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAE,KAAK,OAAO,EAAE,YAAY,EAAE,MAAM,MAAM,CAAA;AAGxD,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAEzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAA;AAEtD,iBAAS,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,SAAS,SAAS,GAAG,EAAE,EAChE,MAAM,EAAE,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC,EAC/B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,GAAG,SAAS,EAC5B,KAAK,EAAE,KAAK,GAAG,SAAS,EACxB,MAAM,EAAE,YAAY,GAAG,SAAS,aAGd,IAAI,8KAYvB;AAED,iBAAS,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,SAAS,SAAS,GAAG,EAAE,EAChE,MAAM,EAAE,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC,EAC/B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,GAAG,SAAS,EAC5B,KAAK,EAAE,KAAK,GAAG,SAAS,EACxB,MAAM,EAAE,YAAY,GAAG,SAAS,aAGd,IAAI,qBAYvB;AAED,iBAAS,uBAAuB,CAAC,IAAI,EAAE,KAAK,MAAM,EAAE,GAAG,SAAS;;;;;;;;;;;;;;;;;;;GAE/D;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GACvB;IACE,8CAA8C;IAC9C,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,oCAAoC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,GACD,MAAM,CAAA;AAEV;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,SAAS,SAAS,GAAG,EAAE,EACvE,MAAM,EAAE,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC,EAC/B,wBAAwB,CAAC,EAAE,eAAe,GACzC;IACD,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAA;IAChD,IAAI,EAAE,OAAO,GAAG,SAAS,CAAA;IACzB,KAAK,EAAE,sBAAsB,GAAG,IAAI,CAAA;IACpC,SAAS,EAAE,OAAO,CAAA;IAClB,SAAS,EAAE,OAAO,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,OAAO,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,sBAAsB,GAAG,IAAI,CAAA;IAC5C,MAAM,EAAE,OAAO,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAA;IACxD,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;IAC7B,QAAQ,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAA;IACjD,QAAQ,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAA;CAClD,CA6HA;AAED;;;GAGG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,SAAS,SAAS,GAAG,EAAE,IAAI,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAA"}
|