Skip to content

Commit 11d9335

Browse files
committed
More readable code
1 parent d417f5e commit 11d9335

File tree

4 files changed

+339
-215
lines changed

4 files changed

+339
-215
lines changed

packages/nextjs/app/page.tsx

Lines changed: 32 additions & 215 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,10 @@
22

33
import { useState } from "react";
44
import type { NextPage } from "next";
5-
import { concat, createPublicClient, hexToString, http, isAddress, keccak256, pad, toHex } from "viem";
6-
import { RocketLaunchIcon } from "@heroicons/react/24/outline";
75
import { Interpretations, NetworkSelector } from "~~/components/storagoor";
6+
import { StorageForm } from "~~/components/storagoor/StorageForm";
87
import { useTargetNetwork } from "~~/hooks/scaffold-eth";
9-
10-
interface StorageValueFormats {
11-
hex: string;
12-
decimal: string;
13-
string: string;
14-
address: string;
15-
}
8+
import { useStorageSlot } from "~~/hooks/storagoor/useStorageSlot";
169

1710
const Home: NextPage = () => {
1811
const [contractAddress, setContractAddress] = useState("");
@@ -21,102 +14,19 @@ const Home: NextPage = () => {
2114
const [isDoubleMapping, setIsDoubleMapping] = useState(false);
2215
const [mappingKey, setMappingKey] = useState("");
2316
const [secondMappingKey, setSecondMappingKey] = useState("");
24-
const [storageValue, setStorageValue] = useState<StorageValueFormats | null>(null);
25-
const [isLoading, setIsLoading] = useState(false);
26-
const { targetNetwork } = useTargetNetwork();
27-
28-
const formatStorageValue = (value: `0x${string}`): StorageValueFormats => {
29-
// Convert to BigInt for decimal representation
30-
const bigIntValue = BigInt(value);
31-
32-
// Try to interpret as string (skip if not valid UTF-8)
33-
let stringValue = "";
34-
try {
35-
stringValue = hexToString(value, { size: 32 });
36-
// Filter out non-printable characters
37-
stringValue = stringValue.replace(/[^\x20-\x7E]/g, "");
38-
if (!stringValue.length) stringValue = "Not a valid UTF-8 string";
39-
} catch {
40-
stringValue = "Not a valid UTF-8 string";
41-
}
42-
43-
return {
44-
hex: value,
45-
decimal: bigIntValue.toString(),
46-
string: stringValue,
47-
address: isAddress(value.slice(0, 42)) ? value.slice(0, 42) : "Not a valid address",
48-
};
49-
};
50-
51-
const fetchStorageSlot = async () => {
52-
try {
53-
setIsLoading(true);
54-
if (!contractAddress || !slot || !isAddress(contractAddress)) return;
55-
if (isMapping && !mappingKey) return;
56-
57-
const publicClient = createPublicClient({
58-
chain: targetNetwork,
59-
transport: http(targetNetwork.rpcUrls.default.http[0]),
60-
});
61-
62-
let finalSlot: `0x${string}`;
63-
if (isMapping) {
64-
const mappingSlot = pad(toHex(BigInt(slot)), { size: 32 });
65-
let paddedKey: `0x${string}`;
66-
let paddedSecondKey: `0x${string}`;
67-
68-
// Handle first key
69-
if (isAddress(mappingKey)) {
70-
paddedKey = pad(mappingKey as `0x${string}`, { size: 32 });
71-
} else {
72-
try {
73-
const keyBigInt = BigInt(mappingKey);
74-
paddedKey = pad(toHex(keyBigInt), { size: 32 });
75-
} catch {
76-
paddedKey = pad(mappingKey as `0x${string}`, { size: 32 });
77-
}
78-
}
7917

80-
if (isDoubleMapping && secondMappingKey) {
81-
// Handle second key
82-
if (isAddress(secondMappingKey)) {
83-
paddedSecondKey = pad(secondMappingKey as `0x${string}`, { size: 32 });
84-
} else {
85-
try {
86-
const keyBigInt = BigInt(secondMappingKey);
87-
paddedSecondKey = pad(toHex(keyBigInt), { size: 32 });
88-
} catch {
89-
paddedSecondKey = pad(secondMappingKey as `0x${string}`, { size: 32 });
90-
}
91-
}
92-
// For double mapping: keccak256(key2 + keccak256(key1 + slot))
93-
const firstHash = keccak256(concat([paddedKey, mappingSlot]));
94-
finalSlot = keccak256(concat([paddedSecondKey, firstHash]));
95-
} else {
96-
// Single mapping: keccak256(key + slot)
97-
finalSlot = keccak256(concat([paddedKey, mappingSlot]));
98-
}
99-
} else {
100-
finalSlot = toHex(BigInt(slot), { size: 32 });
101-
}
102-
103-
const value = await publicClient.getStorageAt({
104-
address: contractAddress as `0x${string}`,
105-
slot: finalSlot,
106-
});
107-
108-
if (!value) {
109-
setStorageValue(null);
110-
return;
111-
}
112-
113-
setStorageValue(formatStorageValue(value));
114-
} catch (error) {
115-
console.error("Error fetching storage slot:", error);
116-
setStorageValue(null);
117-
} finally {
118-
setIsLoading(false);
119-
}
18+
const { targetNetwork } = useTargetNetwork();
19+
const { readStorageSlot, storageValue, isLoading, error } = useStorageSlot(targetNetwork);
20+
21+
const handleSubmit = () => {
22+
readStorageSlot({
23+
contractAddress,
24+
slot,
25+
isMapping,
26+
isDoubleMapping,
27+
mappingKey,
28+
secondMappingKey,
29+
});
12030
};
12131

12232
return (
@@ -131,120 +41,27 @@ const Home: NextPage = () => {
13141

13242
{/* Main Card */}
13343
<div className="bg-base-100 rounded-2xl shadow-xl border border-base-300">
134-
{/* Network Selector */}
13544
<NetworkSelector />
136-
{/* Input Form */}
137-
<div className="p-6 space-y-6">
138-
<div>
139-
<label className="label">
140-
<span className="label-text font-semibold">Contract Address</span>
141-
</label>
142-
<input
143-
type="text"
144-
placeholder="0x..."
145-
className="input input-bordered w-full font-mono"
146-
value={contractAddress}
147-
onChange={e => setContractAddress(e.target.value)}
148-
/>
149-
</div>
150-
151-
<div>
152-
<label className="label">
153-
<span className="label-text font-semibold">Storage Slot</span>
154-
</label>
155-
<input
156-
type="text"
157-
placeholder="0x0"
158-
className="input input-bordered w-full font-mono"
159-
value={slot}
160-
onChange={e => setSlot(e.target.value)}
161-
/>
162-
</div>
163-
164-
<div className="flex items-center justify-between p-2 rounded-lg bg-base-200">
165-
<span className="font-semibold px-2">Mapping Mode</span>
166-
<input
167-
type="checkbox"
168-
className="toggle toggle-primary"
169-
checked={isMapping}
170-
onChange={e => {
171-
setIsMapping(e.target.checked);
172-
if (!e.target.checked) {
173-
setIsDoubleMapping(false);
174-
}
175-
}}
176-
/>
177-
</div>
178-
179-
{isMapping && (
180-
<>
181-
<div className="flex items-center justify-between p-2 rounded-lg bg-base-200">
182-
<span className="font-semibold px-2">Double Mapping</span>
183-
<input
184-
type="checkbox"
185-
className="toggle toggle-primary"
186-
checked={isDoubleMapping}
187-
onChange={e => setIsDoubleMapping(e.target.checked)}
188-
/>
189-
</div>
190-
191-
<div className="animate-fadeIn">
192-
<label className="label">
193-
<span className="label-text font-semibold">First Mapping Key</span>
194-
<span className="label-text-alt">address, number, or string</span>
195-
</label>
196-
<input
197-
type="text"
198-
placeholder="Key value..."
199-
className="input input-bordered w-full font-mono"
200-
value={mappingKey}
201-
onChange={e => setMappingKey(e.target.value)}
202-
/>
203-
</div>
204-
205-
{isDoubleMapping && (
206-
<div className="animate-fadeIn">
207-
<label className="label">
208-
<span className="label-text font-semibold">Second Mapping Key</span>
209-
<span className="label-text-alt">address, number, or string</span>
210-
</label>
211-
<input
212-
type="text"
213-
placeholder="Second key value..."
214-
className="input input-bordered w-full font-mono"
215-
value={secondMappingKey}
216-
onChange={e => setSecondMappingKey(e.target.value)}
217-
/>
218-
</div>
219-
)}
220-
</>
221-
)}
22245

223-
<button
224-
className="btn btn-primary w-full"
225-
onClick={fetchStorageSlot}
226-
disabled={
227-
!isAddress(contractAddress) ||
228-
(isMapping && !mappingKey) ||
229-
(isDoubleMapping && !secondMappingKey) ||
230-
isLoading
231-
}
232-
>
233-
{isLoading ? (
234-
<>
235-
<span className="loading loading-spinner"></span>
236-
Reading Storage...
237-
</>
238-
) : (
239-
<>
240-
<RocketLaunchIcon className="h-5 w-5" />
241-
Read Storage Slot
242-
</>
243-
)}
244-
</button>
245-
</div>
46+
<StorageForm
47+
contractAddress={contractAddress}
48+
setContractAddress={setContractAddress}
49+
slot={slot}
50+
setSlot={setSlot}
51+
isMapping={isMapping}
52+
setIsMapping={setIsMapping}
53+
isDoubleMapping={isDoubleMapping}
54+
setIsDoubleMapping={setIsDoubleMapping}
55+
mappingKey={mappingKey}
56+
setMappingKey={setMappingKey}
57+
secondMappingKey={secondMappingKey}
58+
setSecondMappingKey={setSecondMappingKey}
59+
onSubmit={handleSubmit}
60+
isLoading={isLoading}
61+
/>
62+
63+
{error && <div className="p-4 mx-6 mb-6 text-error bg-error/10 rounded-lg">{error}</div>}
24664

247-
{/* Results Section */}
24865
{storageValue && <Interpretations storageValue={storageValue} />}
24966
</div>
25067
</div>

0 commit comments

Comments
 (0)