-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathuseFetchBlocks.ts
More file actions
119 lines (102 loc) · 4.04 KB
/
useFetchBlocks.ts
File metadata and controls
119 lines (102 loc) · 4.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import { useCallback, useEffect, useState } from "react";
import { Block, Transaction, TransactionReceipt } from "viem";
import { usePublicClient } from "wagmi";
import { hardhat } from "wagmi/chains";
import { decodeTransactionData } from "~~/utils/scaffold-eth";
const BLOCKS_PER_PAGE = 20;
export const useFetchBlocks = () => {
const client = usePublicClient({ chainId: hardhat.id });
const [blocks, setBlocks] = useState<Block[]>([]);
const [transactionReceipts, setTransactionReceipts] = useState<{
[key: string]: TransactionReceipt;
}>({});
const [currentPage, setCurrentPage] = useState(0);
const [totalBlocks, setTotalBlocks] = useState(0n);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<Error | null>(null);
const fetchBlocks = useCallback(async () => {
setIsLoading(true);
setError(null);
try {
const blockNumber = await client.getBlockNumber();
setTotalBlocks(blockNumber);
const startingBlock = blockNumber - BigInt(currentPage * BLOCKS_PER_PAGE);
const blockNumbersToFetch = Array.from(
{ length: Number(BLOCKS_PER_PAGE < startingBlock + 1n ? BLOCKS_PER_PAGE : startingBlock + 1n) },
(_, i) => startingBlock - BigInt(i),
);
const blocksWithTransactions = blockNumbersToFetch.map(async blockNumber => {
try {
return client.getBlock({ blockNumber, includeTransactions: true });
} catch (err) {
setError(err instanceof Error ? err : new Error("An error occurred."));
throw err;
}
});
const fetchedBlocks = await Promise.all(blocksWithTransactions);
fetchedBlocks.forEach(block => {
block.transactions.forEach(tx => decodeTransactionData(tx as Transaction));
});
const txReceipts = await Promise.all(
fetchedBlocks.flatMap(block =>
block.transactions.map(async tx => {
try {
const receipt = await client.getTransactionReceipt({ hash: (tx as Transaction).hash });
return { [(tx as Transaction).hash]: receipt };
} catch (err) {
setError(err instanceof Error ? err : new Error("An error occurred."));
throw err;
}
}),
),
);
setBlocks(fetchedBlocks);
setTransactionReceipts(prevReceipts => ({ ...prevReceipts, ...Object.assign({}, ...txReceipts) }));
} catch (err) {
setError(err instanceof Error ? err : new Error("An error occurred."));
}
setIsLoading(false);
}, [client, currentPage]);
useEffect(() => {
fetchBlocks();
}, [fetchBlocks]);
useEffect(() => {
const handleNewBlock = async (newBlock: Block) => {
try {
if (!blocks.some(block => block.number === newBlock.number)) {
if (currentPage === 0) {
setBlocks(prevBlocks => [newBlock, ...prevBlocks.slice(0, BLOCKS_PER_PAGE - 1)]);
newBlock.transactions.forEach(tx => decodeTransactionData(tx as Transaction));
const receipts = await Promise.all(
newBlock.transactions.map(async tx => {
try {
const receipt = await client.getTransactionReceipt({ hash: (tx as Transaction).hash });
return { [(tx as Transaction).hash]: receipt };
} catch (err) {
setError(err instanceof Error ? err : new Error("An error occurred."));
throw err;
}
}),
);
setTransactionReceipts(prevReceipts => ({ ...prevReceipts, ...Object.assign({}, ...receipts) }));
}
if (newBlock.number) {
setTotalBlocks(newBlock.number);
}
}
} catch (err) {
setError(err instanceof Error ? err : new Error("An error occurred."));
}
};
return client.watchBlocks({ onBlock: handleNewBlock, includeTransactions: true });
}, [blocks, client, currentPage]);
return {
blocks,
transactionReceipts,
currentPage,
totalBlocks,
setCurrentPage,
isLoading,
error,
};
};