@trustless-work/blocks 0.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.
Files changed (74) hide show
  1. package/README.md +96 -0
  2. package/bin/index.js +1123 -0
  3. package/package.json +44 -0
  4. package/templates/deps.json +29 -0
  5. package/templates/escrows/details/Actions.tsx +149 -0
  6. package/templates/escrows/details/Entities.tsx +48 -0
  7. package/templates/escrows/details/EntityCard.tsx +98 -0
  8. package/templates/escrows/details/EscrowDetailDialog.tsx +154 -0
  9. package/templates/escrows/details/GeneralInformation.tsx +329 -0
  10. package/templates/escrows/details/MilestoneCard.tsx +254 -0
  11. package/templates/escrows/details/MilestoneDetailDialog.tsx +276 -0
  12. package/templates/escrows/details/Milestones.tsx +87 -0
  13. package/templates/escrows/details/ProgressEscrow.tsx +191 -0
  14. package/templates/escrows/details/StatisticsCard.tsx +79 -0
  15. package/templates/escrows/details/SuccessReleaseDialog.tsx +101 -0
  16. package/templates/escrows/details/useDetailsEscrow.ts +126 -0
  17. package/templates/escrows/escrow-context/EscrowAmountProvider.tsx +86 -0
  18. package/templates/escrows/escrow-context/EscrowDialogsProvider.tsx +108 -0
  19. package/templates/escrows/escrow-context/EscrowProvider.tsx +124 -0
  20. package/templates/escrows/escrows-by-role/cards/EscrowsCards.tsx +503 -0
  21. package/templates/escrows/escrows-by-role/cards/Filters.tsx +421 -0
  22. package/templates/escrows/escrows-by-role/table/EscrowsTable.tsx +427 -0
  23. package/templates/escrows/escrows-by-role/table/Filters.tsx +421 -0
  24. package/templates/escrows/escrows-by-role/useEscrowsByRole.shared.ts +336 -0
  25. package/templates/escrows/escrows-by-signer/cards/EscrowsCards.tsx +502 -0
  26. package/templates/escrows/escrows-by-signer/cards/Filters.tsx +389 -0
  27. package/templates/escrows/escrows-by-signer/table/EscrowsTable.tsx +422 -0
  28. package/templates/escrows/escrows-by-signer/table/Filters.tsx +389 -0
  29. package/templates/escrows/escrows-by-signer/useEscrowsBySigner.shared.ts +320 -0
  30. package/templates/escrows/single-release/approve-milestone/button/ApproveMilestone.tsx +78 -0
  31. package/templates/escrows/single-release/approve-milestone/dialog/ApproveMilestone.tsx +102 -0
  32. package/templates/escrows/single-release/approve-milestone/form/ApproveMilestone.tsx +80 -0
  33. package/templates/escrows/single-release/approve-milestone/shared/schema.ts +9 -0
  34. package/templates/escrows/single-release/approve-milestone/shared/useApproveMilestone.ts +67 -0
  35. package/templates/escrows/single-release/change-milestone-status/button/ChangeMilestoneStatus.tsx +78 -0
  36. package/templates/escrows/single-release/change-milestone-status/dialog/ChangeMilestoneStatus.tsx +167 -0
  37. package/templates/escrows/single-release/change-milestone-status/form/ChangeMilestoneStatus.tsx +114 -0
  38. package/templates/escrows/single-release/change-milestone-status/shared/schema.ts +15 -0
  39. package/templates/escrows/single-release/change-milestone-status/shared/useChangeMilestoneStatus.ts +77 -0
  40. package/templates/escrows/single-release/dispute-escrow/button/DisputeEscrow.tsx +68 -0
  41. package/templates/escrows/single-release/fund-escrow/button/FundEscrow.tsx +84 -0
  42. package/templates/escrows/single-release/fund-escrow/dialog/FundEscrow.tsx +77 -0
  43. package/templates/escrows/single-release/fund-escrow/form/FundEscrow.tsx +54 -0
  44. package/templates/escrows/single-release/fund-escrow/shared/schema.ts +10 -0
  45. package/templates/escrows/single-release/fund-escrow/shared/useFundEscrow.ts +66 -0
  46. package/templates/escrows/single-release/initialize-escrow/dialog/InitializeEscrow.tsx +526 -0
  47. package/templates/escrows/single-release/initialize-escrow/form/InitializeEscrow.tsx +504 -0
  48. package/templates/escrows/single-release/initialize-escrow/shared/schema.ts +232 -0
  49. package/templates/escrows/single-release/initialize-escrow/shared/useInitializeEscrow.ts +115 -0
  50. package/templates/escrows/single-release/release-escrow/button/ReleaseEscrow.tsx +80 -0
  51. package/templates/escrows/single-release/resolve-dispute/button/ResolveDispute.tsx +94 -0
  52. package/templates/escrows/single-release/resolve-dispute/dialog/ResolveDispute.tsx +123 -0
  53. package/templates/escrows/single-release/resolve-dispute/form/ResolveDispute.tsx +82 -0
  54. package/templates/escrows/single-release/resolve-dispute/shared/schema.ts +82 -0
  55. package/templates/escrows/single-release/resolve-dispute/shared/useResolveDispute.ts +58 -0
  56. package/templates/escrows/single-release/update-escrow/dialog/UpdateEscrow.tsx +485 -0
  57. package/templates/escrows/single-release/update-escrow/form/UpdateEscrow.tsx +463 -0
  58. package/templates/escrows/single-release/update-escrow/shared/schema.ts +139 -0
  59. package/templates/escrows/single-release/update-escrow/shared/useUpdateEscrow.ts +211 -0
  60. package/templates/handle-errors/errors.enum.ts +6 -0
  61. package/templates/handle-errors/handle.ts +47 -0
  62. package/templates/helpers/format.helper.ts +27 -0
  63. package/templates/helpers/useCopy.ts +13 -0
  64. package/templates/providers/ReactQueryClientProvider.tsx +28 -0
  65. package/templates/providers/TrustlessWork.tsx +30 -0
  66. package/templates/tanstak/useEscrowsByRoleQuery.ts +87 -0
  67. package/templates/tanstak/useEscrowsBySignerQuery.ts +78 -0
  68. package/templates/tanstak/useEscrowsMutations.ts +411 -0
  69. package/templates/wallet-kit/WalletButtons.tsx +116 -0
  70. package/templates/wallet-kit/WalletProvider.tsx +94 -0
  71. package/templates/wallet-kit/trustlines.ts +40 -0
  72. package/templates/wallet-kit/useWallet.ts +77 -0
  73. package/templates/wallet-kit/validators.ts +12 -0
  74. package/templates/wallet-kit/wallet-kit.ts +30 -0
@@ -0,0 +1,211 @@
1
+ import * as React from "react";
2
+ import { useForm } from "react-hook-form";
3
+ import { zodResolver } from "@hookform/resolvers/zod";
4
+ import { useUpdateEscrowSchema } from "./schema";
5
+ import { z } from "zod";
6
+ import {
7
+ UpdateSingleReleaseEscrowPayload,
8
+ UpdateSingleReleaseEscrowResponse,
9
+ } from "@trustless-work/escrow/types";
10
+ import { toast } from "sonner";
11
+ import { useEscrowContext } from "../../../escrow-context/EscrowProvider";
12
+ import { useWalletContext } from "@/components/tw-blocks/wallet-kit/WalletProvider";
13
+ import { useEscrowsMutations } from "@/components/tw-blocks/tanstak/useEscrowsMutations";
14
+ import {
15
+ ErrorResponse,
16
+ handleError,
17
+ } from "@/components/tw-blocks/handle-errors/handle";
18
+ import { GetEscrowsFromIndexerResponse } from "@trustless-work/escrow/types";
19
+
20
+ export function useUpdateEscrow() {
21
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
22
+
23
+ const { getSingleReleaseFormSchema } = useUpdateEscrowSchema();
24
+ const formSchema = getSingleReleaseFormSchema();
25
+
26
+ const { walletAddress } = useWalletContext();
27
+ const { selectedEscrow, setSelectedEscrow } = useEscrowContext();
28
+ const { updateEscrow } = useEscrowsMutations();
29
+
30
+ const form = useForm<z.infer<typeof formSchema>>({
31
+ resolver: zodResolver(formSchema),
32
+ defaultValues: {
33
+ engagementId: selectedEscrow?.engagementId || "",
34
+ title: selectedEscrow?.title || "",
35
+ description: selectedEscrow?.description || "",
36
+ platformFee: selectedEscrow?.platformFee as unknown as
37
+ | number
38
+ | string
39
+ | undefined,
40
+ amount: selectedEscrow?.amount as unknown as number | string | undefined,
41
+ receiverMemo: selectedEscrow?.receiverMemo
42
+ ? String(selectedEscrow.receiverMemo)
43
+ : "",
44
+ trustline: {
45
+ address: selectedEscrow?.trustline?.address || "",
46
+ decimals: 10000000,
47
+ },
48
+ roles: {
49
+ approver: selectedEscrow?.roles?.approver || "",
50
+ serviceProvider: selectedEscrow?.roles?.serviceProvider || "",
51
+ platformAddress: selectedEscrow?.roles?.platformAddress || "",
52
+ receiver: selectedEscrow?.roles?.receiver || "",
53
+ releaseSigner: selectedEscrow?.roles?.releaseSigner || "",
54
+ disputeResolver: selectedEscrow?.roles?.disputeResolver || "",
55
+ },
56
+ milestones: (selectedEscrow?.milestones || []).map((m: any) => ({
57
+ description: m?.description || "",
58
+ })),
59
+ },
60
+ mode: "onChange",
61
+ });
62
+
63
+ React.useEffect(() => {
64
+ if (!selectedEscrow) return;
65
+ form.reset({
66
+ engagementId: selectedEscrow?.engagementId || "",
67
+ title: selectedEscrow?.title || "",
68
+ description: selectedEscrow?.description || "",
69
+ platformFee:
70
+ (selectedEscrow?.platformFee as unknown as
71
+ | number
72
+ | string
73
+ | undefined) || "",
74
+ amount:
75
+ (selectedEscrow?.amount as unknown as number | string | undefined) ||
76
+ "",
77
+ receiverMemo: selectedEscrow?.receiverMemo
78
+ ? String(selectedEscrow.receiverMemo)
79
+ : "",
80
+ trustline: {
81
+ address: selectedEscrow?.trustline?.address || "",
82
+ decimals: 10000000,
83
+ },
84
+ roles: {
85
+ approver: selectedEscrow?.roles?.approver || "",
86
+ serviceProvider: selectedEscrow?.roles?.serviceProvider || "",
87
+ platformAddress: selectedEscrow?.roles?.platformAddress || "",
88
+ receiver: selectedEscrow?.roles?.receiver || "",
89
+ releaseSigner: selectedEscrow?.roles?.releaseSigner || "",
90
+ disputeResolver: selectedEscrow?.roles?.disputeResolver || "",
91
+ },
92
+ milestones: (selectedEscrow?.milestones || []).map((m: any) => ({
93
+ description: m?.description || "",
94
+ })),
95
+ });
96
+ }, [selectedEscrow, form]);
97
+
98
+ const milestones = form.watch("milestones");
99
+ const isAnyMilestoneEmpty = milestones.some((m) => m.description === "");
100
+
101
+ const handleAddMilestone = () => {
102
+ const current = form.getValues("milestones");
103
+ const updated = [...current, { description: "" }];
104
+ form.setValue("milestones", updated);
105
+ };
106
+
107
+ const handleRemoveMilestone = (index: number) => {
108
+ const current = form.getValues("milestones");
109
+ const updated = current.filter((_, i) => i !== index);
110
+ form.setValue("milestones", updated);
111
+ };
112
+
113
+ const handleAmountChange = (e: React.ChangeEvent<HTMLInputElement>) => {
114
+ let rawValue = e.target.value;
115
+ rawValue = rawValue.replace(/[^0-9.]/g, "");
116
+ if (rawValue.split(".").length > 2) rawValue = rawValue.slice(0, -1);
117
+ if (rawValue.includes(".")) {
118
+ const parts = rawValue.split(".");
119
+ if (parts[1] && parts[1].length > 2) {
120
+ rawValue = parts[0] + "." + parts[1].slice(0, 2);
121
+ }
122
+ }
123
+ form.setValue("amount", rawValue);
124
+ };
125
+
126
+ const handlePlatformFeeChange = (e: React.ChangeEvent<HTMLInputElement>) => {
127
+ let rawValue = e.target.value;
128
+ rawValue = rawValue.replace(/[^0-9.]/g, "");
129
+ if (rawValue.split(".").length > 2) rawValue = rawValue.slice(0, -1);
130
+ if (rawValue.includes(".")) {
131
+ const parts = rawValue.split(".");
132
+ if (parts[1] && parts[1].length > 2) {
133
+ rawValue = parts[0] + "." + parts[1].slice(0, 2);
134
+ }
135
+ }
136
+ form.setValue("platformFee", rawValue);
137
+ };
138
+
139
+ const handleSubmit = form.handleSubmit(async (payload) => {
140
+ try {
141
+ setIsSubmitting(true);
142
+
143
+ const finalPayload: UpdateSingleReleaseEscrowPayload = {
144
+ contractId: selectedEscrow?.contractId || "",
145
+ signer: walletAddress || "",
146
+ escrow: {
147
+ engagementId: payload.engagementId,
148
+ title: payload.title,
149
+ description: payload.description,
150
+ platformFee:
151
+ typeof payload.platformFee === "string"
152
+ ? Number(payload.platformFee)
153
+ : payload.platformFee,
154
+ amount:
155
+ typeof payload.amount === "string"
156
+ ? Number(payload.amount)
157
+ : payload.amount,
158
+ receiverMemo: payload.receiverMemo
159
+ ? Number(payload.receiverMemo)
160
+ : undefined,
161
+ trustline: {
162
+ address: payload.trustline.address,
163
+ decimals: 10000000,
164
+ },
165
+ roles: payload.roles as any,
166
+ milestones: payload.milestones,
167
+ },
168
+ };
169
+
170
+ (await updateEscrow.mutateAsync({
171
+ payload: finalPayload,
172
+ type: "single-release",
173
+ address: walletAddress || "",
174
+ })) as UpdateSingleReleaseEscrowResponse;
175
+
176
+ if (!selectedEscrow) return;
177
+
178
+ const nextSelectedEscrow: GetEscrowsFromIndexerResponse = {
179
+ ...selectedEscrow,
180
+ ...finalPayload.escrow,
181
+ trustline: {
182
+ name:
183
+ selectedEscrow.trustline?.name ||
184
+ (selectedEscrow.trustline?.address as string) ||
185
+ "",
186
+ address: finalPayload.escrow.trustline.address,
187
+ decimals: finalPayload.escrow.trustline.decimals,
188
+ },
189
+ };
190
+
191
+ setSelectedEscrow(nextSelectedEscrow);
192
+ toast.success("Escrow updated successfully");
193
+ } catch (error) {
194
+ toast.error(handleError(error as ErrorResponse).message);
195
+ } finally {
196
+ setIsSubmitting(false);
197
+ }
198
+ });
199
+
200
+ return {
201
+ form,
202
+ isSubmitting,
203
+ milestones,
204
+ isAnyMilestoneEmpty,
205
+ handleSubmit,
206
+ handleAddMilestone,
207
+ handleRemoveMilestone,
208
+ handleAmountChange,
209
+ handlePlatformFeeChange,
210
+ };
211
+ }
@@ -0,0 +1,6 @@
1
+ export enum ApiErrorTypes {
2
+ NOT_FOUND = "NOT_FOUND",
3
+ UNAUTHORIZED = "UNAUTHORIZED",
4
+ UNKNOWN_ERROR = "UNKNOWN_ERROR",
5
+ WALLET_ERROR = "WALLET_ERROR",
6
+ }
@@ -0,0 +1,47 @@
1
+ import axios from "axios";
2
+ import { AxiosError } from "axios";
3
+ import { ApiErrorTypes } from "./errors.enum";
4
+
5
+ export type ErrorResponse = {
6
+ message: string;
7
+ code: number;
8
+ type: ApiErrorTypes;
9
+ };
10
+
11
+ export type WalletError = Pick<ErrorResponse, "message" | "code">;
12
+
13
+ export const handleError = (error: AxiosError | WalletError): ErrorResponse => {
14
+ if (axios.isAxiosError(error)) {
15
+ const axiosError = error as AxiosError<ErrorResponse>;
16
+ const code = axiosError.response?.status || 500;
17
+ const message = axiosError.response?.data?.message || error.message;
18
+ return {
19
+ message,
20
+ code,
21
+ type: mapStatusCodeToErrorType(code),
22
+ };
23
+ } else if (error.code === -4) {
24
+ return {
25
+ message: "Wallet was closed before transaction was sent",
26
+ code: -4,
27
+ type: ApiErrorTypes.WALLET_ERROR,
28
+ };
29
+ } else {
30
+ return {
31
+ message: error.message,
32
+ code: 500,
33
+ type: ApiErrorTypes.UNKNOWN_ERROR,
34
+ };
35
+ }
36
+ };
37
+
38
+ const mapStatusCodeToErrorType = (code: number): ApiErrorTypes => {
39
+ switch (code) {
40
+ case 404:
41
+ return ApiErrorTypes.NOT_FOUND;
42
+ case 401:
43
+ return ApiErrorTypes.UNAUTHORIZED;
44
+ default:
45
+ return ApiErrorTypes.UNKNOWN_ERROR;
46
+ }
47
+ };
@@ -0,0 +1,27 @@
1
+ export const formatCurrency = (value: number, currency: string) => {
2
+ return `${currency} ${value.toFixed(2)}`;
3
+ };
4
+
5
+ export function formatTimestamp(ts?: {
6
+ _seconds: number;
7
+ _nanoseconds: number;
8
+ }) {
9
+ if (!ts) return "-";
10
+ const d = new Date(ts._seconds * 1000);
11
+ return d.toLocaleString();
12
+ }
13
+
14
+ export function formatAddress(address: string) {
15
+ return `${address.slice(0, 10)}...${address.slice(-4)}`;
16
+ }
17
+
18
+ export function formatRole(role: string) {
19
+ return role
20
+ .replace(/([A-Z])/g, " $1")
21
+ .replace(/^./, (str) => str.toUpperCase())
22
+ .trim();
23
+ }
24
+
25
+ export function formatText(text: string) {
26
+ return text.charAt(0).toUpperCase() + text.slice(1);
27
+ }
@@ -0,0 +1,13 @@
1
+ import { useState } from "react";
2
+
3
+ export const useCopy = () => {
4
+ const [copiedKeyId, setCopiedKeyId] = useState(false);
5
+
6
+ const copyToClipboard = async (text: string) => {
7
+ await navigator.clipboard.writeText(text);
8
+ setCopiedKeyId(true);
9
+ setTimeout(() => setCopiedKeyId(false), 1500);
10
+ };
11
+
12
+ return { copiedKeyId, copyToClipboard };
13
+ };
@@ -0,0 +1,28 @@
1
+ "use client";
2
+
3
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
4
+ import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
5
+
6
+ const queryClient = new QueryClient({
7
+ defaultOptions: {
8
+ queries: {
9
+ staleTime: 1000 * 60 * 5, // 5 minutes
10
+ gcTime: 1000 * 60 * 30, // 30 minutes
11
+ retry: 1,
12
+ refetchOnWindowFocus: false,
13
+ },
14
+ },
15
+ });
16
+
17
+ export function ReactQueryClientProvider({
18
+ children,
19
+ }: {
20
+ children: React.ReactNode;
21
+ }) {
22
+ return (
23
+ <QueryClientProvider client={queryClient}>
24
+ {children}
25
+ <ReactQueryDevtools initialIsOpen={false} />
26
+ </QueryClientProvider>
27
+ );
28
+ }
@@ -0,0 +1,30 @@
1
+ "use client"; // make sure this is a client component
2
+
3
+ import React from "react";
4
+ import {
5
+ // development environment = "https://dev.api.trustlesswork.com"
6
+ development,
7
+
8
+ // mainnet environment = "https://api.trustlesswork.com"
9
+ mainNet,
10
+ TrustlessWorkConfig,
11
+ } from "@trustless-work/escrow";
12
+
13
+ interface TrustlessWorkProviderProps {
14
+ children: React.ReactNode;
15
+ }
16
+
17
+ export function TrustlessWorkProvider({
18
+ children,
19
+ }: TrustlessWorkProviderProps) {
20
+ /**
21
+ * Get the API key from the environment variables
22
+ */
23
+ const apiKey = process.env.NEXT_PUBLIC_API_KEY || "";
24
+
25
+ return (
26
+ <TrustlessWorkConfig baseURL={development} apiKey={apiKey}>
27
+ {children}
28
+ </TrustlessWorkConfig>
29
+ );
30
+ }
@@ -0,0 +1,87 @@
1
+ import { useQuery } from "@tanstack/react-query";
2
+ import {
3
+ GetEscrowsFromIndexerByRoleParams,
4
+ useGetEscrowsFromIndexerByRole,
5
+ } from "@trustless-work/escrow";
6
+ import { GetEscrowsFromIndexerResponse as Escrow } from "@trustless-work/escrow/types";
7
+
8
+ type UseEscrowsByRoleQueryParams = Omit<
9
+ GetEscrowsFromIndexerByRoleParams,
10
+ "role"
11
+ > & {
12
+ role?: GetEscrowsFromIndexerByRoleParams["role"];
13
+ enabled?: boolean;
14
+ validateOnChain?: boolean;
15
+ };
16
+
17
+ export const useEscrowsByRoleQuery = ({
18
+ role,
19
+ roleAddress,
20
+ isActive = true,
21
+ page,
22
+ orderDirection,
23
+ orderBy,
24
+ startDate,
25
+ endDate,
26
+ maxAmount,
27
+ minAmount,
28
+ title,
29
+ engagementId,
30
+ status,
31
+ type,
32
+ enabled = true,
33
+ validateOnChain = true,
34
+ }: UseEscrowsByRoleQueryParams) => {
35
+ const { getEscrowsByRole } = useGetEscrowsFromIndexerByRole();
36
+
37
+ return useQuery({
38
+ queryKey: [
39
+ "escrows",
40
+ roleAddress,
41
+ role,
42
+ isActive,
43
+ page,
44
+ orderDirection,
45
+ orderBy,
46
+ startDate,
47
+ endDate,
48
+ maxAmount,
49
+ minAmount,
50
+ title,
51
+ engagementId,
52
+ status,
53
+ type,
54
+ validateOnChain,
55
+ ],
56
+ queryFn: async (): Promise<Escrow[]> => {
57
+ if (!role) {
58
+ throw new Error("Role is required to fetch escrows by role");
59
+ }
60
+ const escrows = await getEscrowsByRole({
61
+ role,
62
+ roleAddress,
63
+ isActive,
64
+ page,
65
+ orderDirection,
66
+ orderBy,
67
+ startDate,
68
+ endDate,
69
+ maxAmount,
70
+ minAmount,
71
+ title,
72
+ engagementId,
73
+ status,
74
+ type,
75
+ validateOnChain,
76
+ });
77
+
78
+ if (!escrows) {
79
+ throw new Error("Failed to fetch escrows");
80
+ }
81
+
82
+ return escrows;
83
+ },
84
+ enabled: enabled && !!roleAddress && !!role,
85
+ staleTime: 1000 * 60 * 5,
86
+ });
87
+ };
@@ -0,0 +1,78 @@
1
+ import { useQuery } from "@tanstack/react-query";
2
+ import {
3
+ GetEscrowsFromIndexerBySignerParams,
4
+ useGetEscrowsFromIndexerBySigner,
5
+ } from "@trustless-work/escrow";
6
+ import { GetEscrowsFromIndexerResponse as Escrow } from "@trustless-work/escrow/types";
7
+
8
+ interface UseEscrowsBySignerQueryParams
9
+ extends GetEscrowsFromIndexerBySignerParams {
10
+ enabled?: boolean;
11
+ validateOnChain?: boolean;
12
+ }
13
+
14
+ export const useEscrowsBySignerQuery = ({
15
+ signer,
16
+ isActive,
17
+ page,
18
+ orderDirection,
19
+ orderBy,
20
+ startDate,
21
+ endDate,
22
+ maxAmount,
23
+ minAmount,
24
+ title,
25
+ engagementId,
26
+ status,
27
+ type,
28
+ enabled = true,
29
+ validateOnChain = true,
30
+ }: UseEscrowsBySignerQueryParams) => {
31
+ const { getEscrowsBySigner } = useGetEscrowsFromIndexerBySigner();
32
+
33
+ return useQuery({
34
+ queryKey: [
35
+ "escrows",
36
+ signer,
37
+ isActive,
38
+ page,
39
+ orderDirection,
40
+ orderBy,
41
+ startDate,
42
+ endDate,
43
+ maxAmount,
44
+ minAmount,
45
+ title,
46
+ engagementId,
47
+ status,
48
+ type,
49
+ validateOnChain,
50
+ ],
51
+ queryFn: async (): Promise<Escrow[]> => {
52
+ const escrows = await getEscrowsBySigner({
53
+ signer,
54
+ isActive,
55
+ page,
56
+ orderDirection,
57
+ orderBy,
58
+ startDate,
59
+ endDate,
60
+ maxAmount,
61
+ minAmount,
62
+ title,
63
+ engagementId,
64
+ status,
65
+ type,
66
+ validateOnChain,
67
+ });
68
+
69
+ if (!escrows) {
70
+ throw new Error("Failed to fetch escrows");
71
+ }
72
+
73
+ return escrows;
74
+ },
75
+ enabled: enabled && !!signer,
76
+ staleTime: 1000 * 60 * 5, // 5 min
77
+ });
78
+ };