@0xslots/sdk 0.9.2 → 0.10.0

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,100 @@
1
+ import { cw as SlotsChain, cx as SlotsClient, C as CreateSlotParams, o as CreateSlotsParams, n as BuyParams } from './client-BtZNzXuf.js';
2
+ import { Hash, Address } from 'viem';
3
+ import 'graphql-request';
4
+ import 'graphql';
5
+
6
+ /**
7
+ * React hook that creates a memoized {@link SlotsClient} from wagmi's public/wallet clients.
8
+ *
9
+ * @param chainId - Optional chain ID override. Defaults to the connected chain.
10
+ * @returns A configured SlotsClient instance.
11
+ * @throws If no public client is available or the chain has no factory address.
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * function MyComponent() {
16
+ * const client = useSlotsClient(SlotsChain.ARBITRUM);
17
+ * // use client.getSlots(), client.buy(), etc.
18
+ * }
19
+ * ```
20
+ */
21
+ declare function useSlotsClient(chainId?: SlotsChain, subgraphApiKey?: string): SlotsClient;
22
+
23
+ interface SlotActionCallbacks {
24
+ onSuccess?: (label: string, hash: Hash) => void;
25
+ onError?: (label: string, error: string) => void;
26
+ }
27
+ declare function useSlotAction(opts?: SlotActionCallbacks): {
28
+ createSlot: (params: CreateSlotParams) => Promise<void>;
29
+ createSlots: (params: CreateSlotsParams) => Promise<void>;
30
+ buy: (params: BuyParams) => Promise<void>;
31
+ selfAssess: (slot: Address, newPrice: bigint) => Promise<void>;
32
+ topUp: (slot: Address, amount: bigint) => Promise<void>;
33
+ withdraw: (slot: Address, amount: bigint) => Promise<void>;
34
+ release: (slot: Address) => Promise<void>;
35
+ collect: (slot: Address) => Promise<void>;
36
+ payTax: (slot: Address) => Promise<void>;
37
+ liquidate: (slot: Address) => Promise<void>;
38
+ proposeTaxUpdate: (slot: Address, newPct: bigint) => Promise<void>;
39
+ proposeModuleUpdate: (slot: Address, newModule: Address) => Promise<void>;
40
+ cancelPendingUpdates: (slot: Address) => Promise<void>;
41
+ setLiquidationBounty: (slot: Address, newBps: bigint) => Promise<void>;
42
+ updateMetadata: (moduleAddress: Address, slot: Address, uri: string) => Promise<void>;
43
+ exec: (label: string, fn: () => Promise<Hash>) => Promise<void>;
44
+ busy: boolean;
45
+ isPending: boolean;
46
+ isConfirming: boolean;
47
+ isSuccess: boolean;
48
+ activeAction: string | null;
49
+ };
50
+
51
+ type SlotOnChain = {
52
+ id: string;
53
+ recipient: string;
54
+ currency: string;
55
+ manager: string;
56
+ mutableTax: boolean;
57
+ mutableModule: boolean;
58
+ occupant: string | null;
59
+ price: bigint;
60
+ taxPercentage: bigint;
61
+ module: string;
62
+ liquidationBountyBps: bigint;
63
+ minDepositSeconds: bigint;
64
+ deposit: bigint;
65
+ collectedTax: bigint;
66
+ taxOwed: bigint;
67
+ secondsUntilLiquidation: bigint;
68
+ insolvent: boolean;
69
+ hasPendingTax: boolean;
70
+ pendingTaxPercentage: bigint;
71
+ hasPendingModule: boolean;
72
+ pendingModule: string;
73
+ currencyName?: string;
74
+ currencySymbol?: string;
75
+ currencyDecimals?: number;
76
+ };
77
+ /**
78
+ * Fetch a single slot's complete state from on-chain via getSlotInfo() + currency metadata.
79
+ *
80
+ * @param slotAddress - The slot contract address
81
+ * @param chainId - The chain ID to read from
82
+ */
83
+ declare function useSlotOnChain(slotAddress: string, chainId: number): {
84
+ data: SlotOnChain | null;
85
+ isLoading: boolean;
86
+ refetch: () => void;
87
+ };
88
+ /**
89
+ * Fetch multiple slots' state via multicall getSlotInfo().
90
+ *
91
+ * @param slotAddresses - Array of slot contract addresses
92
+ * @param chainId - The chain ID to read from
93
+ */
94
+ declare function useSlotsOnChain(slotAddresses: string[], chainId: number): {
95
+ data: SlotOnChain[];
96
+ isLoading: boolean;
97
+ refetch: () => void;
98
+ };
99
+
100
+ export { type SlotActionCallbacks, type SlotOnChain, useSlotAction, useSlotOnChain, useSlotsClient, useSlotsOnChain };
package/dist/react.js ADDED
@@ -0,0 +1,320 @@
1
+ import { SlotsClient } from './chunk-KRJINGNH.js';
2
+ import { slotFactoryAddress, slotAbi } from '@0xslots/contracts';
3
+ import { useMemo, useState, useRef, useEffect, useCallback } from 'react';
4
+ import { usePublicClient, useWalletClient, useWaitForTransactionReceipt, useReadContract, useReadContracts, useBlockNumber } from 'wagmi';
5
+ import { erc20Abi } from 'viem';
6
+ import { useQueryClient } from '@tanstack/react-query';
7
+
8
+ function useSlotsClient(chainId, subgraphApiKey) {
9
+ const publicClient = usePublicClient({ chainId });
10
+ const { data: walletClient } = useWalletClient({ chainId });
11
+ return useMemo(() => {
12
+ if (!publicClient) throw new Error("No publicClient available");
13
+ const resolvedChainId = chainId ?? publicClient.chain.id;
14
+ const factoryAddress = slotFactoryAddress[resolvedChainId];
15
+ if (!factoryAddress)
16
+ throw new Error(`No factory address for chain ${resolvedChainId}`);
17
+ return new SlotsClient({
18
+ chainId: resolvedChainId,
19
+ factoryAddress,
20
+ publicClient,
21
+ walletClient: walletClient ?? void 0,
22
+ subgraphApiKey
23
+ });
24
+ }, [chainId, publicClient, walletClient, subgraphApiKey]);
25
+ }
26
+ function extractErrorMessage(error) {
27
+ const message = error instanceof Error ? error.message : "";
28
+ return message.includes("User rejected") || message.includes("User denied") ? "Transaction rejected" : message.split("\n")[0] || "Transaction failed";
29
+ }
30
+ function useSlotAction(opts) {
31
+ const client = useSlotsClient();
32
+ const [hash, setHash] = useState();
33
+ const [activeAction, setActiveAction] = useState(null);
34
+ const [isPending, setIsPending] = useState(false);
35
+ const labelRef = useRef("");
36
+ const {
37
+ isLoading: isConfirming,
38
+ isSuccess,
39
+ isError
40
+ } = useWaitForTransactionReceipt({ hash });
41
+ const busy = isPending || isConfirming;
42
+ useEffect(() => {
43
+ if (isSuccess && labelRef.current) {
44
+ opts?.onSuccess?.(labelRef.current, hash);
45
+ setActiveAction(null);
46
+ labelRef.current = "";
47
+ }
48
+ }, [isSuccess]);
49
+ useEffect(() => {
50
+ if (isError && labelRef.current) {
51
+ opts?.onError?.(labelRef.current, `${labelRef.current} failed on-chain`);
52
+ setActiveAction(null);
53
+ labelRef.current = "";
54
+ }
55
+ }, [isError]);
56
+ useEffect(() => {
57
+ if (!isPending && !isConfirming && !isSuccess && !isError) {
58
+ setActiveAction(null);
59
+ }
60
+ }, [isPending, isConfirming, isSuccess, isError]);
61
+ const exec = useCallback(
62
+ async (label, fn) => {
63
+ labelRef.current = label;
64
+ setActiveAction(label);
65
+ setIsPending(true);
66
+ setHash(void 0);
67
+ try {
68
+ const txHash = await fn();
69
+ setHash(txHash);
70
+ } catch (error) {
71
+ setActiveAction(null);
72
+ labelRef.current = "";
73
+ opts?.onError?.(label, extractErrorMessage(error));
74
+ } finally {
75
+ setIsPending(false);
76
+ }
77
+ },
78
+ [opts?.onError]
79
+ );
80
+ const createSlot = useCallback(
81
+ (params) => exec("Create slot", () => client.createSlot(params)),
82
+ [exec, client]
83
+ );
84
+ const createSlots = useCallback(
85
+ (params) => exec("Create slots", () => client.createSlots(params)),
86
+ [exec, client]
87
+ );
88
+ const buy = useCallback(
89
+ (params) => exec("Buy slot", () => client.buy(params)),
90
+ [exec, client]
91
+ );
92
+ const selfAssess = useCallback(
93
+ (slot, newPrice) => exec("Set price", () => client.selfAssess(slot, newPrice)),
94
+ [exec, client]
95
+ );
96
+ const topUp = useCallback(
97
+ (slot, amount) => exec("Top up", () => client.topUp(slot, amount)),
98
+ [exec, client]
99
+ );
100
+ const withdraw = useCallback(
101
+ (slot, amount) => exec("Withdraw", () => client.withdraw(slot, amount)),
102
+ [exec, client]
103
+ );
104
+ const release = useCallback(
105
+ (slot) => exec("Release slot", () => client.release(slot)),
106
+ [exec, client]
107
+ );
108
+ const collect = useCallback(
109
+ (slot) => exec("Collect tax", () => client.collect(slot)),
110
+ [exec, client]
111
+ );
112
+ const payTax = useCallback(
113
+ (slot) => exec("Pay tax", () => client.collect(slot)),
114
+ [exec, client]
115
+ );
116
+ const liquidate = useCallback(
117
+ (slot) => exec("Liquidate", () => client.liquidate(slot)),
118
+ [exec, client]
119
+ );
120
+ const proposeTaxUpdate = useCallback(
121
+ (slot, newPct) => exec("Propose tax", () => client.proposeTaxUpdate(slot, newPct)),
122
+ [exec, client]
123
+ );
124
+ const proposeModuleUpdate = useCallback(
125
+ (slot, newModule) => exec(
126
+ "Propose module",
127
+ () => client.proposeModuleUpdate(slot, newModule)
128
+ ),
129
+ [exec, client]
130
+ );
131
+ const cancelPendingUpdates = useCallback(
132
+ (slot) => exec("Cancel updates", () => client.cancelPendingUpdates(slot)),
133
+ [exec, client]
134
+ );
135
+ const setLiquidationBounty = useCallback(
136
+ (slot, newBps) => exec("Set bounty", () => client.setLiquidationBounty(slot, newBps)),
137
+ [exec, client]
138
+ );
139
+ const updateMetadata = useCallback(
140
+ (moduleAddress, slot, uri) => exec(
141
+ "Update metadata",
142
+ () => client.modules.metadata.updateMetadata(moduleAddress, slot, uri)
143
+ ),
144
+ [exec, client]
145
+ );
146
+ return {
147
+ // Actions
148
+ createSlot,
149
+ createSlots,
150
+ buy,
151
+ selfAssess,
152
+ topUp,
153
+ withdraw,
154
+ release,
155
+ collect,
156
+ payTax,
157
+ liquidate,
158
+ proposeTaxUpdate,
159
+ proposeModuleUpdate,
160
+ cancelPendingUpdates,
161
+ setLiquidationBounty,
162
+ updateMetadata,
163
+ // Executor
164
+ exec,
165
+ // State
166
+ busy,
167
+ isPending,
168
+ isConfirming,
169
+ isSuccess,
170
+ activeAction
171
+ };
172
+ }
173
+ var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
174
+ function parseSlotInfo(slotAddress, info, currencyMeta) {
175
+ return {
176
+ id: slotAddress.toLowerCase(),
177
+ recipient: info.recipient.toLowerCase(),
178
+ currency: info.currency.toLowerCase(),
179
+ manager: info.manager.toLowerCase(),
180
+ mutableTax: info.mutableTax,
181
+ mutableModule: info.mutableModule,
182
+ occupant: info.occupant === ZERO_ADDRESS ? null : info.occupant.toLowerCase(),
183
+ price: info.price,
184
+ taxPercentage: info.taxPercentage,
185
+ module: info.module.toLowerCase(),
186
+ liquidationBountyBps: info.liquidationBountyBps,
187
+ minDepositSeconds: info.minDepositSeconds,
188
+ deposit: info.deposit,
189
+ collectedTax: info.collectedTax,
190
+ taxOwed: info.taxOwed,
191
+ secondsUntilLiquidation: info.secondsUntilLiquidation,
192
+ insolvent: info.insolvent,
193
+ hasPendingTax: info.hasPendingTax,
194
+ pendingTaxPercentage: info.pendingTaxPercentage,
195
+ hasPendingModule: info.hasPendingModule,
196
+ pendingModule: info.pendingModule.toLowerCase(),
197
+ currencyName: currencyMeta?.name,
198
+ currencySymbol: currencyMeta?.symbol,
199
+ currencyDecimals: currencyMeta?.decimals
200
+ };
201
+ }
202
+ function useInvalidateOnBlock(chainId) {
203
+ const queryClient = useQueryClient();
204
+ const { data: blockNumber } = useBlockNumber({ watch: true, chainId });
205
+ useEffect(() => {
206
+ if (blockNumber) {
207
+ queryClient.invalidateQueries({ queryKey: ["readContract"] });
208
+ queryClient.invalidateQueries({ queryKey: ["readContracts"] });
209
+ }
210
+ }, [blockNumber, queryClient]);
211
+ }
212
+ function useSlotOnChain(slotAddress, chainId) {
213
+ useInvalidateOnBlock(chainId);
214
+ const addr = slotAddress;
215
+ const {
216
+ data: info,
217
+ isLoading: infoLoading,
218
+ refetch
219
+ } = useReadContract({
220
+ address: addr,
221
+ abi: slotAbi,
222
+ functionName: "getSlotInfo",
223
+ chainId,
224
+ query: { gcTime: 0, staleTime: 0, refetchOnMount: "always" }
225
+ });
226
+ const currencyAddr = info ? info.currency : void 0;
227
+ const { data: currencyMeta, isLoading: metaLoading } = useReadContracts({
228
+ contracts: currencyAddr ? [
229
+ { address: currencyAddr, abi: erc20Abi, functionName: "name", chainId },
230
+ { address: currencyAddr, abi: erc20Abi, functionName: "symbol", chainId },
231
+ { address: currencyAddr, abi: erc20Abi, functionName: "decimals", chainId }
232
+ ] : [],
233
+ query: { enabled: !!currencyAddr, staleTime: Infinity }
234
+ });
235
+ const isLoading = infoLoading || metaLoading;
236
+ const slot = info ? parseSlotInfo(
237
+ slotAddress,
238
+ info,
239
+ currencyMeta ? {
240
+ name: currencyMeta[0]?.result,
241
+ symbol: currencyMeta[1]?.result,
242
+ decimals: currencyMeta[2]?.result
243
+ } : void 0
244
+ ) : null;
245
+ return { data: slot, isLoading, refetch };
246
+ }
247
+ function useSlotsOnChain(slotAddresses, chainId) {
248
+ useInvalidateOnBlock(chainId);
249
+ const contracts = slotAddresses.map((addr) => ({
250
+ address: addr,
251
+ abi: slotAbi,
252
+ functionName: "getSlotInfo",
253
+ chainId
254
+ }));
255
+ const {
256
+ data: infos,
257
+ isLoading: infosLoading,
258
+ refetch
259
+ } = useReadContracts({
260
+ contracts,
261
+ query: {
262
+ enabled: slotAddresses.length > 0,
263
+ gcTime: 0,
264
+ staleTime: 0,
265
+ refetchOnMount: "always"
266
+ }
267
+ });
268
+ const currencies = /* @__PURE__ */ new Set();
269
+ if (infos) {
270
+ for (const r of infos) {
271
+ if (r.result)
272
+ currencies.add(
273
+ r.result.currency.toLowerCase()
274
+ );
275
+ }
276
+ }
277
+ const currencyList = Array.from(currencies);
278
+ const { data: metaResults, isLoading: metaLoading } = useReadContracts({
279
+ contracts: currencyList.flatMap((c) => [
280
+ { address: c, abi: erc20Abi, functionName: "name", chainId },
281
+ { address: c, abi: erc20Abi, functionName: "symbol", chainId },
282
+ {
283
+ address: c,
284
+ abi: erc20Abi,
285
+ functionName: "decimals",
286
+ chainId
287
+ }
288
+ ]),
289
+ query: { enabled: currencyList.length > 0 }
290
+ });
291
+ const currencyMeta = {};
292
+ if (metaResults) {
293
+ currencyList.forEach((c, i) => {
294
+ currencyMeta[c] = {
295
+ name: metaResults[i * 3]?.result,
296
+ symbol: metaResults[i * 3 + 1]?.result,
297
+ decimals: metaResults[i * 3 + 2]?.result
298
+ };
299
+ });
300
+ }
301
+ const isLoading = infosLoading || metaLoading;
302
+ const slots = [];
303
+ if (infos) {
304
+ for (let i = 0; i < infos.length; i++) {
305
+ const r = infos[i];
306
+ if (r.result) {
307
+ const result = r.result;
308
+ const currency = result.currency.toLowerCase();
309
+ slots.push(
310
+ parseSlotInfo(slotAddresses[i], result, currencyMeta[currency])
311
+ );
312
+ }
313
+ }
314
+ }
315
+ return { data: slots, isLoading, refetch };
316
+ }
317
+
318
+ export { useSlotAction, useSlotOnChain, useSlotsClient, useSlotsOnChain };
319
+ //# sourceMappingURL=react.js.map
320
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/useSlotsClient.ts","../src/hooks/useSlotAction.ts","../src/hooks/useSlotOnChain.ts"],"names":["useEffect"],"mappings":"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","file":"react.js","sourcesContent":["\"use client\";\n\nimport { type SupportedChainId, slotFactoryAddress } from \"@0xslots/contracts\";\nimport { useMemo } from \"react\";\nimport { usePublicClient, useWalletClient } from \"wagmi\";\nimport { type SlotsChain, SlotsClient } from \"../client\";\n\n/**\n * React hook that creates a memoized {@link SlotsClient} from wagmi's public/wallet clients.\n *\n * @param chainId - Optional chain ID override. Defaults to the connected chain.\n * @returns A configured SlotsClient instance.\n * @throws If no public client is available or the chain has no factory address.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const client = useSlotsClient(SlotsChain.ARBITRUM);\n * // use client.getSlots(), client.buy(), etc.\n * }\n * ```\n */\nexport function useSlotsClient(chainId?: SlotsChain, subgraphApiKey?: string): SlotsClient {\n const publicClient = usePublicClient({ chainId });\n const { data: walletClient } = useWalletClient({ chainId });\n\n return useMemo(() => {\n if (!publicClient) throw new Error(\"No publicClient available\");\n const resolvedChainId = (chainId ?? publicClient.chain.id) as SlotsChain;\n const factoryAddress =\n slotFactoryAddress[resolvedChainId as SupportedChainId];\n if (!factoryAddress)\n throw new Error(`No factory address for chain ${resolvedChainId}`);\n\n return new SlotsClient({\n chainId: resolvedChainId,\n factoryAddress,\n publicClient,\n walletClient: walletClient ?? undefined,\n subgraphApiKey,\n });\n }, [chainId, publicClient, walletClient, subgraphApiKey]);\n}\n","\"use client\";\n\nimport type {\n BuyParams,\n CreateSlotParams,\n CreateSlotsParams,\n} from \"../client\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { Address, Hash } from \"viem\";\nimport { useWaitForTransactionReceipt } from \"wagmi\";\nimport { useSlotsClient } from \"./useSlotsClient\";\n\nfunction extractErrorMessage(error: unknown): string {\n const message = error instanceof Error ? error.message : \"\";\n return message.includes(\"User rejected\") || message.includes(\"User denied\")\n ? \"Transaction rejected\"\n : message.split(\"\\n\")[0] || \"Transaction failed\";\n}\n\nexport interface SlotActionCallbacks {\n onSuccess?: (label: string, hash: Hash) => void;\n onError?: (label: string, error: string) => void;\n}\n\nexport function useSlotAction(opts?: SlotActionCallbacks) {\n const client = useSlotsClient();\n\n // --- state ---\n const [hash, setHash] = useState<Hash | undefined>();\n const [activeAction, setActiveAction] = useState<string | null>(null);\n const [isPending, setIsPending] = useState(false);\n const labelRef = useRef<string>(\"\");\n\n // --- receipt tracking ---\n const {\n isLoading: isConfirming,\n isSuccess,\n isError,\n } = useWaitForTransactionReceipt({ hash });\n\n const busy = isPending || isConfirming;\n\n // --- callback on success ---\n useEffect(() => {\n if (isSuccess && labelRef.current) {\n opts?.onSuccess?.(labelRef.current, hash!);\n setActiveAction(null);\n labelRef.current = \"\";\n }\n }, [isSuccess]);\n\n // --- callback on on-chain error ---\n useEffect(() => {\n if (isError && labelRef.current) {\n opts?.onError?.(labelRef.current, `${labelRef.current} failed on-chain`);\n setActiveAction(null);\n labelRef.current = \"\";\n }\n }, [isError]);\n\n // --- reset if everything settles with no result ---\n useEffect(() => {\n if (!isPending && !isConfirming && !isSuccess && !isError) {\n setActiveAction(null);\n }\n }, [isPending, isConfirming, isSuccess, isError]);\n\n /**\n * Execute an SDK method with shared pending/receipt tracking.\n */\n const exec = useCallback(\n async (label: string, fn: () => Promise<Hash>) => {\n labelRef.current = label;\n setActiveAction(label);\n setIsPending(true);\n setHash(undefined);\n try {\n const txHash = await fn();\n setHash(txHash);\n } catch (error) {\n setActiveAction(null);\n labelRef.current = \"\";\n opts?.onError?.(label, extractErrorMessage(error));\n } finally {\n setIsPending(false);\n }\n },\n [opts?.onError],\n );\n\n // ═══════════════════════════════════════════════════════════════════════════\n // Named actions — each calls one SDK method\n // ═══════════════════════════════════════════════════════════════════════════\n\n // Factory\n const createSlot = useCallback(\n (params: CreateSlotParams) =>\n exec(\"Create slot\", () => client.createSlot(params)),\n [exec, client],\n );\n const createSlots = useCallback(\n (params: CreateSlotsParams) =>\n exec(\"Create slots\", () => client.createSlots(params)),\n [exec, client],\n );\n\n // Slot interactions\n const buy = useCallback(\n (params: BuyParams) => exec(\"Buy slot\", () => client.buy(params)),\n [exec, client],\n );\n const selfAssess = useCallback(\n (slot: Address, newPrice: bigint) =>\n exec(\"Set price\", () => client.selfAssess(slot, newPrice)),\n [exec, client],\n );\n const topUp = useCallback(\n (slot: Address, amount: bigint) =>\n exec(\"Top up\", () => client.topUp(slot, amount)),\n [exec, client],\n );\n const withdraw = useCallback(\n (slot: Address, amount: bigint) =>\n exec(\"Withdraw\", () => client.withdraw(slot, amount)),\n [exec, client],\n );\n const release = useCallback(\n (slot: Address) => exec(\"Release slot\", () => client.release(slot)),\n [exec, client],\n );\n const collect = useCallback(\n (slot: Address) => exec(\"Collect tax\", () => client.collect(slot)),\n [exec, client],\n );\n const payTax = useCallback(\n (slot: Address) => exec(\"Pay tax\", () => client.collect(slot)),\n [exec, client],\n );\n const liquidate = useCallback(\n (slot: Address) => exec(\"Liquidate\", () => client.liquidate(slot)),\n [exec, client],\n );\n\n // Manager\n const proposeTaxUpdate = useCallback(\n (slot: Address, newPct: bigint) =>\n exec(\"Propose tax\", () => client.proposeTaxUpdate(slot, newPct)),\n [exec, client],\n );\n const proposeModuleUpdate = useCallback(\n (slot: Address, newModule: Address) =>\n exec(\"Propose module\", () =>\n client.proposeModuleUpdate(slot, newModule),\n ),\n [exec, client],\n );\n const cancelPendingUpdates = useCallback(\n (slot: Address) =>\n exec(\"Cancel updates\", () => client.cancelPendingUpdates(slot)),\n [exec, client],\n );\n const setLiquidationBounty = useCallback(\n (slot: Address, newBps: bigint) =>\n exec(\"Set bounty\", () => client.setLiquidationBounty(slot, newBps)),\n [exec, client],\n );\n\n // Metadata module\n const updateMetadata = useCallback(\n (moduleAddress: Address, slot: Address, uri: string) =>\n exec(\"Update metadata\", () =>\n client.modules.metadata.updateMetadata(moduleAddress, slot, uri),\n ),\n [exec, client],\n );\n\n return {\n // Actions\n createSlot,\n createSlots,\n buy,\n selfAssess,\n topUp,\n withdraw,\n release,\n collect,\n payTax,\n liquidate,\n proposeTaxUpdate,\n proposeModuleUpdate,\n cancelPendingUpdates,\n setLiquidationBounty,\n updateMetadata,\n // Executor\n exec,\n // State\n busy,\n isPending,\n isConfirming,\n isSuccess,\n activeAction,\n };\n}\n","\"use client\";\n\nimport { slotAbi } from \"@0xslots/contracts\";\nimport { type Address, erc20Abi } from \"viem\";\nimport { useReadContract, useReadContracts, useBlockNumber } from \"wagmi\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { useEffect } from \"react\";\n\nexport type SlotOnChain = {\n // Identity\n id: string;\n recipient: string;\n currency: string;\n manager: string;\n mutableTax: boolean;\n mutableModule: boolean;\n // State\n occupant: string | null;\n price: bigint;\n taxPercentage: bigint;\n module: string;\n liquidationBountyBps: bigint;\n minDepositSeconds: bigint;\n // Financials\n deposit: bigint;\n collectedTax: bigint;\n taxOwed: bigint;\n secondsUntilLiquidation: bigint;\n insolvent: boolean;\n // Pending\n hasPendingTax: boolean;\n pendingTaxPercentage: bigint;\n hasPendingModule: boolean;\n pendingModule: string;\n // Currency metadata\n currencyName?: string;\n currencySymbol?: string;\n currencyDecimals?: number;\n};\n\nconst ZERO_ADDRESS = \"0x0000000000000000000000000000000000000000\";\n\ntype SlotInfoResult = {\n recipient: string;\n currency: string;\n manager: string;\n mutableTax: boolean;\n mutableModule: boolean;\n occupant: string;\n price: bigint;\n taxPercentage: bigint;\n module: string;\n liquidationBountyBps: bigint;\n minDepositSeconds: bigint;\n deposit: bigint;\n collectedTax: bigint;\n taxOwed: bigint;\n secondsUntilLiquidation: bigint;\n insolvent: boolean;\n hasPendingTax: boolean;\n pendingTaxPercentage: bigint;\n hasPendingModule: boolean;\n pendingModule: string;\n};\n\nfunction parseSlotInfo(\n slotAddress: string,\n info: SlotInfoResult,\n currencyMeta?: { name?: string; symbol?: string; decimals?: number },\n): SlotOnChain {\n return {\n id: slotAddress.toLowerCase(),\n recipient: info.recipient.toLowerCase(),\n currency: info.currency.toLowerCase(),\n manager: info.manager.toLowerCase(),\n mutableTax: info.mutableTax,\n mutableModule: info.mutableModule,\n occupant:\n info.occupant === ZERO_ADDRESS ? null : info.occupant.toLowerCase(),\n price: info.price,\n taxPercentage: info.taxPercentage,\n module: info.module.toLowerCase(),\n liquidationBountyBps: info.liquidationBountyBps,\n minDepositSeconds: info.minDepositSeconds,\n deposit: info.deposit,\n collectedTax: info.collectedTax,\n taxOwed: info.taxOwed,\n secondsUntilLiquidation: info.secondsUntilLiquidation,\n insolvent: info.insolvent,\n hasPendingTax: info.hasPendingTax,\n pendingTaxPercentage: info.pendingTaxPercentage,\n hasPendingModule: info.hasPendingModule,\n pendingModule: info.pendingModule.toLowerCase(),\n currencyName: currencyMeta?.name,\n currencySymbol: currencyMeta?.symbol,\n currencyDecimals: currencyMeta?.decimals,\n };\n}\n\n/**\n * Invalidate all contract reads on every new block — ensures fresh data after txs\n */\nfunction useInvalidateOnBlock(chainId: number) {\n const queryClient = useQueryClient();\n const { data: blockNumber } = useBlockNumber({ watch: true, chainId });\n useEffect(() => {\n if (blockNumber) {\n queryClient.invalidateQueries({ queryKey: [\"readContract\"] });\n queryClient.invalidateQueries({ queryKey: [\"readContracts\"] });\n }\n }, [blockNumber, queryClient]);\n}\n\n/**\n * Fetch a single slot's complete state from on-chain via getSlotInfo() + currency metadata.\n *\n * @param slotAddress - The slot contract address\n * @param chainId - The chain ID to read from\n */\nexport function useSlotOnChain(slotAddress: string, chainId: number): {\n data: SlotOnChain | null;\n isLoading: boolean;\n refetch: () => void;\n} {\n useInvalidateOnBlock(chainId);\n const addr = slotAddress as Address;\n\n const {\n data: info,\n isLoading: infoLoading,\n refetch,\n } = useReadContract({\n address: addr,\n abi: slotAbi,\n functionName: \"getSlotInfo\",\n chainId,\n query: { gcTime: 0, staleTime: 0, refetchOnMount: \"always\" },\n });\n\n // Currency metadata — only fetch when we have info (static, can cache)\n const currencyAddr = info\n ? ((info as SlotInfoResult).currency as Address)\n : undefined;\n const { data: currencyMeta, isLoading: metaLoading } = useReadContracts({\n contracts: currencyAddr\n ? [\n { address: currencyAddr, abi: erc20Abi, functionName: \"name\", chainId },\n { address: currencyAddr, abi: erc20Abi, functionName: \"symbol\", chainId },\n { address: currencyAddr, abi: erc20Abi, functionName: \"decimals\", chainId },\n ]\n : [],\n query: { enabled: !!currencyAddr, staleTime: Infinity },\n });\n\n const isLoading = infoLoading || metaLoading;\n\n const slot = info\n ? parseSlotInfo(\n slotAddress,\n info as SlotInfoResult,\n currencyMeta\n ? {\n name: currencyMeta[0]?.result as string | undefined,\n symbol: currencyMeta[1]?.result as string | undefined,\n decimals: currencyMeta[2]?.result as number | undefined,\n }\n : undefined,\n )\n : null;\n\n return { data: slot, isLoading, refetch };\n}\n\n/**\n * Fetch multiple slots' state via multicall getSlotInfo().\n *\n * @param slotAddresses - Array of slot contract addresses\n * @param chainId - The chain ID to read from\n */\nexport function useSlotsOnChain(slotAddresses: string[], chainId: number): {\n data: SlotOnChain[];\n isLoading: boolean;\n refetch: () => void;\n} {\n useInvalidateOnBlock(chainId);\n const contracts = slotAddresses.map((addr) => ({\n address: addr as Address,\n abi: slotAbi,\n functionName: \"getSlotInfo\" as const,\n chainId,\n }));\n\n const {\n data: infos,\n isLoading: infosLoading,\n refetch,\n } = useReadContracts({\n contracts,\n query: {\n enabled: slotAddresses.length > 0,\n gcTime: 0,\n staleTime: 0,\n refetchOnMount: \"always\",\n },\n });\n\n // Get unique currencies to fetch metadata\n const currencies = new Set<string>();\n if (infos) {\n for (const r of infos) {\n if (r.result)\n currencies.add(\n (r.result as SlotInfoResult).currency.toLowerCase(),\n );\n }\n }\n const currencyList = Array.from(currencies);\n\n const { data: metaResults, isLoading: metaLoading } = useReadContracts({\n contracts: currencyList.flatMap((c) => [\n { address: c as Address, abi: erc20Abi, functionName: \"name\" as const, chainId },\n { address: c as Address, abi: erc20Abi, functionName: \"symbol\" as const, chainId },\n {\n address: c as Address,\n abi: erc20Abi,\n functionName: \"decimals\" as const,\n chainId,\n },\n ]),\n query: { enabled: currencyList.length > 0 },\n });\n\n // Build currency metadata map\n const currencyMeta: Record<\n string,\n { name?: string; symbol?: string; decimals?: number }\n > = {};\n if (metaResults) {\n currencyList.forEach((c, i) => {\n currencyMeta[c] = {\n name: metaResults[i * 3]?.result as string | undefined,\n symbol: metaResults[i * 3 + 1]?.result as string | undefined,\n decimals: metaResults[i * 3 + 2]?.result as number | undefined,\n };\n });\n }\n\n const isLoading = infosLoading || metaLoading;\n\n const slots: SlotOnChain[] = [];\n if (infos) {\n for (let i = 0; i < infos.length; i++) {\n const r = infos[i];\n if (r.result) {\n const result = r.result as SlotInfoResult;\n const currency = result.currency.toLowerCase();\n slots.push(\n parseSlotInfo(slotAddresses[i], result, currencyMeta[currency]),\n );\n }\n }\n }\n\n return { data: slots, isLoading, refetch };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xslots/sdk",
3
- "version": "0.9.2",
3
+ "version": "0.10.0",
4
4
  "description": "Type-safe SDK for the 0xSlots protocol — reads (subgraph) + writes (viem)",
5
5
  "author": "Nezz",
6
6
  "license": "MIT",
@@ -14,6 +14,10 @@
14
14
  ".": {
15
15
  "types": "./dist/index.d.ts",
16
16
  "import": "./dist/index.js"
17
+ },
18
+ "./react": {
19
+ "types": "./dist/react.d.ts",
20
+ "import": "./dist/react.js"
17
21
  }
18
22
  },
19
23
  "publishConfig": {
@@ -23,23 +27,41 @@
23
27
  "graphql": "^16.9.0",
24
28
  "graphql-request": "^7.2.2",
25
29
  "graphql-tag": "^2.12.6",
26
- "@0xslots/contracts": "0.6.1"
30
+ "@0xslots/contracts": "0.7.0"
27
31
  },
28
32
  "devDependencies": {
29
33
  "@graphql-codegen/cli": "^5.0.4",
30
34
  "@graphql-codegen/typescript": "^4.1.3",
31
35
  "@graphql-codegen/typescript-graphql-request": "^6.3.0",
32
36
  "@graphql-codegen/typescript-operations": "^4.4.2",
37
+ "@tanstack/react-query": "^5.90.21",
33
38
  "@types/node": "^20.10.8",
39
+ "@types/react": "^19",
40
+ "react": "^19.0.0",
34
41
  "tsup": "^8.0.0",
35
- "typescript": "^5.4.4"
42
+ "typescript": "^5.4.4",
43
+ "wagmi": "^3.5.0"
36
44
  },
37
45
  "peerDependencies": {
38
- "viem": "2.47.4"
46
+ "@tanstack/react-query": ">=5",
47
+ "react": ">=18",
48
+ "viem": ">=2",
49
+ "wagmi": ">=2"
50
+ },
51
+ "peerDependenciesMeta": {
52
+ "react": {
53
+ "optional": true
54
+ },
55
+ "wagmi": {
56
+ "optional": true
57
+ },
58
+ "@tanstack/react-query": {
59
+ "optional": true
60
+ }
39
61
  },
40
62
  "scripts": {
41
63
  "codegen": "graphql-codegen --config codegen.yml",
42
- "build": "pnpm codegen && tsup",
64
+ "build": "tsup",
43
65
  "clean": "rm -rf dist generated",
44
66
  "dev": "tsup --watch",
45
67
  "typecheck": "tsc --noEmit"