@provex/react 1.2.5 → 1.3.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.
- package/dist/ProvexProvider-DWxHsaR8.d.cts +1013 -0
- package/dist/ProvexProvider-DWxHsaR8.d.ts +1013 -0
- package/dist/chunk-7BVFQVKS.js +2165 -0
- package/dist/chunk-7BVFQVKS.js.map +1 -0
- package/dist/index.cjs +174 -107
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -1030
- package/dist/index.d.ts +35 -1030
- package/dist/index.js +79 -2174
- package/dist/index.js.map +1 -1
- package/dist/wagmi.cjs +2142 -0
- package/dist/wagmi.cjs.map +1 -0
- package/dist/wagmi.d.cts +82 -0
- package/dist/wagmi.d.ts +82 -0
- package/dist/wagmi.js +72 -0
- package/dist/wagmi.js.map +1 -0
- package/package.json +16 -5
package/dist/index.js
CHANGED
|
@@ -1,2123 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import { providerConfigs, providerKeyToContractId, computePayeeDetailsHash, tiers, verifiablePaymentMethods, getPlatformRisk, verifierGetsKey, isSubProviderKey, getParentProviderKey, getPaymentMethodName } from '@provex/utils/payment';
|
|
5
|
-
import { SUPPORTED_CURRENCIES, tickerToContractId } from '@provex/utils/currencies';
|
|
6
|
-
import { getDefaultToken, publicClient } from '@provex/utils/tokens';
|
|
7
|
-
import { parseUnits, formatUnits } from '@provex/utils/units';
|
|
8
|
-
import { convertCurrencyToTokenOutput } from '@provex/utils/conversionRates';
|
|
9
|
-
import { DEFAULT_REPUTATION, getTierFromVolume, TIER_ORDER, TAKER_TIERS, getVolumeRangeDisplay, getCooldownHours, getEffectiveCap } from '@provex/utils/reputation';
|
|
10
|
-
import { getLatestContract, reclaimSigners, getEscrowVersion } from '@provex/utils/contracts';
|
|
11
|
-
import { encodeAbiParameters, parseAbiParameters, zeroAddress, encodeFunctionData, decodeEventLog, createPublicClient, http, maxUint256, erc20Abi } from 'viem';
|
|
12
|
-
import { normalizeFeePrecision } from '@provex/utils/fees';
|
|
1
|
+
import { useOptionalProvexPublicClient, useContractRead, useOptionalProvexWallet, getTransactionGasInputs, useOptionalProvex, createProveXClient, checkTransactionIndexed, ProveXError, isUserRejectionError, getUserFriendlyErrorMessage, checkMutation, useProvex, ProveXClient } from './chunk-7BVFQVKS.js';
|
|
2
|
+
export { BrowsePhase, CommittedPhase, CompletePhase, ProveXClient, ProveXError, ProvexBuy, ProvexBuyProvider, ProvexProvider, ProvingPhase, createApiClient, createProveXClient, getRate, getTierDisplayInfo, intentStatuses, useDeposits, useOptionalProvexPublicClient, useOptionalProvexWallet, usePayeeDetails, useProtocolFeePercentage, useProtocolFees, useProvex, useProvexBuy, useProvexBuyContext, useProvexPublicClient, useProvexWallet, useReputation, useReputationLimits, useSignalIntent } from './chunk-7BVFQVKS.js';
|
|
3
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
13
4
|
import { V3EscrowAbi, OrchestratorAbi, PaymentVerifierRegistryAbi, UnifiedPaymentVerifierAbi, NullifierRegistryAbi, V2EscrowAbi } from '@provex/abis';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { useReadContract, useReadContracts, useAccount, useWalletClient, usePublicClient, useConnection, useSwitchChain, useWriteContract } from 'wagmi';
|
|
5
|
+
import { maxUint256, erc20Abi, encodeFunctionData } from 'viem';
|
|
6
|
+
import { getEscrowVersion, getLatestContract } from '@provex/utils/contracts';
|
|
17
7
|
import { orderId } from '@provex/utils/ids';
|
|
18
8
|
|
|
19
|
-
// src/ProvexProvider.tsx
|
|
20
|
-
|
|
21
|
-
// src/lib/api.ts
|
|
22
|
-
function createApiClient(apiUrl) {
|
|
23
|
-
async function request(path, options) {
|
|
24
|
-
const url = `${apiUrl}${path}`;
|
|
25
|
-
const response = await fetch(url, {
|
|
26
|
-
...options,
|
|
27
|
-
headers: {
|
|
28
|
-
"Content-Type": "application/json",
|
|
29
|
-
...options.headers
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
if (!response.ok) {
|
|
33
|
-
throw new Error(`API request failed: ${response.status} ${response.statusText} (${url})`);
|
|
34
|
-
}
|
|
35
|
-
return response.json();
|
|
36
|
-
}
|
|
37
|
-
return {
|
|
38
|
-
get: (path, options) => request(path, { ...options, method: "GET" }),
|
|
39
|
-
post: (path, body, options) => request(path, {
|
|
40
|
-
...options,
|
|
41
|
-
method: "POST",
|
|
42
|
-
body: JSON.stringify(body)
|
|
43
|
-
})
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
var ProvexContext = createContext(null);
|
|
47
|
-
var defaultQueryClient = new QueryClient({
|
|
48
|
-
defaultOptions: {
|
|
49
|
-
queries: {
|
|
50
|
-
staleTime: 3e4,
|
|
51
|
-
refetchOnWindowFocus: false
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
function ProvexProvider({
|
|
56
|
-
config,
|
|
57
|
-
indexer,
|
|
58
|
-
queryClient,
|
|
59
|
-
children
|
|
60
|
-
}) {
|
|
61
|
-
const resolvedQueryClient = queryClient ?? defaultQueryClient;
|
|
62
|
-
const contextValue = useMemo(() => {
|
|
63
|
-
const apiClient = createApiClient(config.apiUrl);
|
|
64
|
-
return { config, indexer, apiClient };
|
|
65
|
-
}, [config.apiUrl, config.chain, indexer]);
|
|
66
|
-
return /* @__PURE__ */ jsx(ProvexContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(QueryClientProvider, { client: resolvedQueryClient, children }) });
|
|
67
|
-
}
|
|
68
|
-
function useProvex() {
|
|
69
|
-
const context = useContext(ProvexContext);
|
|
70
|
-
if (!context) {
|
|
71
|
-
throw new Error("useProvex must be used within a <ProvexProvider>");
|
|
72
|
-
}
|
|
73
|
-
return context;
|
|
74
|
-
}
|
|
75
|
-
function useOptionalProvex() {
|
|
76
|
-
return useContext(ProvexContext);
|
|
77
|
-
}
|
|
78
|
-
var DEFAULT_REFETCH_INTERVAL_MS = 5e3;
|
|
79
|
-
function getRate({
|
|
80
|
-
deposit,
|
|
81
|
-
paymentMethod,
|
|
82
|
-
currency
|
|
83
|
-
}) {
|
|
84
|
-
if (!deposit) return 0n;
|
|
85
|
-
const paymentConfig = providerConfigs(deposit.chainId)[paymentMethod];
|
|
86
|
-
const candidateKeys = [
|
|
87
|
-
paymentMethod,
|
|
88
|
-
...Array.from(paymentConfig?.subProviders ?? []).map((sp) => sp.key)
|
|
89
|
-
];
|
|
90
|
-
let minRate = null;
|
|
91
|
-
for (const key of candidateKeys) {
|
|
92
|
-
const contractId = providerKeyToContractId(key).toLowerCase();
|
|
93
|
-
const value = deposit.conversionRates.get(contractId)?.get(currency.contractId.toLowerCase());
|
|
94
|
-
if (value) {
|
|
95
|
-
if (minRate === null || value < minRate) {
|
|
96
|
-
minRate = value;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return minRate ?? 0n;
|
|
101
|
-
}
|
|
102
|
-
function toDepositInfo(deposit) {
|
|
103
|
-
return {
|
|
104
|
-
escrow: deposit.escrow,
|
|
105
|
-
localId: deposit.localId,
|
|
106
|
-
chainId: deposit.chainId,
|
|
107
|
-
participantAddress: deposit.participantAddress,
|
|
108
|
-
token: deposit.token,
|
|
109
|
-
remaining: deposit.remaining,
|
|
110
|
-
deposited: deposit.deposited,
|
|
111
|
-
minAmount: deposit.minAmount,
|
|
112
|
-
maxAmount: deposit.maxAmount,
|
|
113
|
-
status: deposit.status,
|
|
114
|
-
acceptingIntents: deposit.acceptingIntents,
|
|
115
|
-
availableFunds: deposit.availableFunds,
|
|
116
|
-
conversionRates: deposit.conversionRates,
|
|
117
|
-
verifierPaymentMethodIds: deposit.paymentMethodIds
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
function useDeposits(options) {
|
|
121
|
-
const {
|
|
122
|
-
token,
|
|
123
|
-
currency = SUPPORTED_CURRENCIES.USD,
|
|
124
|
-
paymentMethod,
|
|
125
|
-
refetchIntervalMs = DEFAULT_REFETCH_INTERVAL_MS
|
|
126
|
-
} = options;
|
|
127
|
-
const { indexer } = useProvex();
|
|
128
|
-
const queryClient = useQueryClient();
|
|
129
|
-
const paymentMethodIds = useMemo(() => {
|
|
130
|
-
const paymentConfig = providerConfigs(token.chainId)[paymentMethod];
|
|
131
|
-
return /* @__PURE__ */ new Set([
|
|
132
|
-
providerKeyToContractId(paymentMethod).toLowerCase(),
|
|
133
|
-
...paymentConfig.v2Verifiers.map((v) => v.toLowerCase()),
|
|
134
|
-
...Array.from(paymentConfig.subProviders).flatMap((subProvider) => [
|
|
135
|
-
providerKeyToContractId(subProvider.key).toLowerCase(),
|
|
136
|
-
...subProvider.v2Verifiers(token.chainId).map((v) => v.toLowerCase())
|
|
137
|
-
])
|
|
138
|
-
]);
|
|
139
|
-
}, [token.chainId, paymentMethod]);
|
|
140
|
-
const depositsQuery = useQuery({
|
|
141
|
-
queryKey: ["provex", "deposits", token.address, token.chainId, currency.contractId, paymentMethod],
|
|
142
|
-
queryFn: async () => {
|
|
143
|
-
const result = await indexer.getMatchableDeposits({
|
|
144
|
-
chainId: token.chainId,
|
|
145
|
-
token: token.address,
|
|
146
|
-
currencyId: currency.contractId
|
|
147
|
-
});
|
|
148
|
-
return result.items.filter((d) => {
|
|
149
|
-
for (const id of d.paymentMethodIds) {
|
|
150
|
-
if (paymentMethodIds.has(id)) return true;
|
|
151
|
-
}
|
|
152
|
-
return false;
|
|
153
|
-
}).map(toDepositInfo);
|
|
154
|
-
},
|
|
155
|
-
staleTime: refetchIntervalMs,
|
|
156
|
-
refetchInterval: refetchIntervalMs
|
|
157
|
-
});
|
|
158
|
-
const deposits = useMemo(() => depositsQuery.data ?? [], [depositsQuery.data]);
|
|
159
|
-
const canAcceptAmount = useCallback((deposit, amount) => {
|
|
160
|
-
return amount <= deposit.availableFunds && amount >= deposit.minAmount && amount <= deposit.maxAmount;
|
|
161
|
-
}, []);
|
|
162
|
-
const filterDepositsByAmount = useCallback((amountInInt) => {
|
|
163
|
-
if (!amountInInt || !currency) return [];
|
|
164
|
-
const matchable = [];
|
|
165
|
-
for (const deposit of deposits) {
|
|
166
|
-
const rate = getRate({ deposit, paymentMethod, currency });
|
|
167
|
-
if (rate === 0n) continue;
|
|
168
|
-
const amountToken = convertCurrencyToTokenOutput({
|
|
169
|
-
token,
|
|
170
|
-
currency,
|
|
171
|
-
currencyAmountInt: amountInInt,
|
|
172
|
-
rate
|
|
173
|
-
});
|
|
174
|
-
if (canAcceptAmount(deposit, amountToken)) {
|
|
175
|
-
matchable.push({ deposit, rate });
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
return matchable.sort((a, b) => {
|
|
179
|
-
if (a.rate < b.rate) return -1;
|
|
180
|
-
if (a.rate > b.rate) return 1;
|
|
181
|
-
if (a.deposit.localId < b.deposit.localId) return -1;
|
|
182
|
-
if (a.deposit.localId > b.deposit.localId) return 1;
|
|
183
|
-
return 0;
|
|
184
|
-
}).map((m) => m.deposit);
|
|
185
|
-
}, [deposits, currency, paymentMethod, token, canAcceptAmount]);
|
|
186
|
-
const refetch = useCallback(() => {
|
|
187
|
-
queryClient.invalidateQueries({
|
|
188
|
-
queryKey: ["provex", "deposits", token.address, token.chainId, currency.contractId, paymentMethod]
|
|
189
|
-
});
|
|
190
|
-
}, [queryClient, token.address, token.chainId, currency.contractId, paymentMethod]);
|
|
191
|
-
return {
|
|
192
|
-
deposits,
|
|
193
|
-
isLoading: depositsQuery.isLoading,
|
|
194
|
-
isUpdating: depositsQuery.isFetching && !depositsQuery.isLoading,
|
|
195
|
-
error: depositsQuery.error,
|
|
196
|
-
refetch,
|
|
197
|
-
filterDepositsByAmount,
|
|
198
|
-
getMatchableDeposits: (amountInInt) => {
|
|
199
|
-
if (typeof amountInInt === "string") {
|
|
200
|
-
amountInInt = parseUnits(amountInInt, { decimals: currency?.decimals || 2 });
|
|
201
|
-
}
|
|
202
|
-
if (!amountInInt) return [];
|
|
203
|
-
return filterDepositsByAmount(amountInInt);
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
var getTransactionGasInputs = async (chainId) => {
|
|
208
|
-
const chain = chainIdToChain.get(chainId);
|
|
209
|
-
if (!chain) {
|
|
210
|
-
throw new Error(`Unsupported chainId: ${chainId}`);
|
|
211
|
-
}
|
|
212
|
-
const block = await publicClient(chain).getBlock({
|
|
213
|
-
blockTag: "latest"
|
|
214
|
-
});
|
|
215
|
-
if (!block.baseFeePerGas) {
|
|
216
|
-
throw new Error(`No baseFeePerGas available for chainId: ${chainId}`);
|
|
217
|
-
}
|
|
218
|
-
return {
|
|
219
|
-
maxFeePerGas: block.baseFeePerGas * 2n,
|
|
220
|
-
maxPriorityFeePerGas: block.baseFeePerGas / 5n
|
|
221
|
-
};
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
// src/lib/updates.ts
|
|
225
|
-
var POLL_INTERVAL_MS = 1e3;
|
|
226
|
-
var SLOW_SYNC_THRESHOLD_MS = 15e3;
|
|
227
|
-
var checkMutation = async ({
|
|
228
|
-
queryDeposit,
|
|
229
|
-
depositIdHex,
|
|
230
|
-
status,
|
|
231
|
-
onSuccess,
|
|
232
|
-
onSlowSync,
|
|
233
|
-
slowSyncThresholdMs = SLOW_SYNC_THRESHOLD_MS
|
|
234
|
-
}) => {
|
|
235
|
-
const startTime = Date.now();
|
|
236
|
-
let slowSyncFired = false;
|
|
237
|
-
while (true) {
|
|
238
|
-
const result = await queryDeposit(depositIdHex);
|
|
239
|
-
if (result?.status === status) {
|
|
240
|
-
break;
|
|
241
|
-
}
|
|
242
|
-
if (!slowSyncFired && onSlowSync && Date.now() - startTime > slowSyncThresholdMs) {
|
|
243
|
-
slowSyncFired = true;
|
|
244
|
-
onSlowSync();
|
|
245
|
-
}
|
|
246
|
-
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
247
|
-
}
|
|
248
|
-
setTimeout(() => {
|
|
249
|
-
onSuccess?.();
|
|
250
|
-
}, POLL_INTERVAL_MS);
|
|
251
|
-
};
|
|
252
|
-
var checkTransactionIndexed = async ({
|
|
253
|
-
queryTransaction,
|
|
254
|
-
hash,
|
|
255
|
-
onSuccess,
|
|
256
|
-
onSlowSync,
|
|
257
|
-
slowSyncThresholdMs = SLOW_SYNC_THRESHOLD_MS
|
|
258
|
-
}) => {
|
|
259
|
-
const startTime = Date.now();
|
|
260
|
-
let slowSyncFired = false;
|
|
261
|
-
while (true) {
|
|
262
|
-
const result = await queryTransaction(hash);
|
|
263
|
-
if (result) {
|
|
264
|
-
break;
|
|
265
|
-
}
|
|
266
|
-
if (!slowSyncFired && onSlowSync && Date.now() - startTime > slowSyncThresholdMs) {
|
|
267
|
-
slowSyncFired = true;
|
|
268
|
-
onSlowSync();
|
|
269
|
-
}
|
|
270
|
-
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
271
|
-
}
|
|
272
|
-
onSuccess?.();
|
|
273
|
-
};
|
|
274
|
-
|
|
275
|
-
// src/lib/errors.ts
|
|
276
|
-
var ERROR_PATTERNS = [
|
|
277
|
-
// Wallet / signer rejections
|
|
278
|
-
{ pattern: /user rejected|user denied|rejected the request|user cancelled|user canceled/i, message: "Transaction was cancelled." },
|
|
279
|
-
// On-chain reverts — specific errors first (first match wins)
|
|
280
|
-
{ pattern: /InsufficientDepositLiquidity|0xc3df48f3/i, message: "This deposit no longer has enough available liquidity. Please try a smaller amount or a different deposit." },
|
|
281
|
-
{ pattern: /execution reverted/i, message: "Transaction failed on-chain. The order may no longer be available." },
|
|
282
|
-
// Gas / balance issues
|
|
283
|
-
{ pattern: /insufficient funds/i, message: "Insufficient funds for gas fees." },
|
|
284
|
-
{ pattern: /gas required exceeds/i, message: "Transaction requires more gas than allowed." },
|
|
285
|
-
// Transaction replacement / nonce issues
|
|
286
|
-
{ pattern: /could not replace existing tx|replacement transaction underpriced|nonce too low/i, message: "A previous transaction is still pending. Please wait for it to confirm or speed it up in your wallet." },
|
|
287
|
-
// Deposit state errors
|
|
288
|
-
{ pattern: /DepositNotAcceptingIntents|0x67688c1a/i, message: "This deposit is currently paused. Please try a different deposit." },
|
|
289
|
-
// Network / RPC errors
|
|
290
|
-
{ pattern: /could not detect network|network changed/i, message: "Network connection issue. Please check your wallet network." },
|
|
291
|
-
{ pattern: /disconnected|not connected/i, message: "Wallet disconnected. Please reconnect and try again." },
|
|
292
|
-
{ pattern: /timeout|etimedout/i, message: "Request timed out. Please try again." },
|
|
293
|
-
{ pattern: /fetch failed|econnrefused|enotfound/i, message: "Unable to reach the server. Please check your connection." },
|
|
294
|
-
// Rate limiting / service unavailable
|
|
295
|
-
{ pattern: /429|too many requests/i, message: "Too many requests. Please wait a moment and try again." },
|
|
296
|
-
{ pattern: /503|service unavailable/i, message: "Service temporarily unavailable. Please try again shortly." },
|
|
297
|
-
// Nullifier / double-spend (keep the original — it's already user-friendly)
|
|
298
|
-
{ pattern: /nullifier has already been used/i, message: "This payment has already been verified and cannot be used again." },
|
|
299
|
-
{ pattern: /already been verified/i, message: "This payment has already been verified and cannot be used again." }
|
|
300
|
-
];
|
|
301
|
-
function getUserFriendlyErrorMessage(error) {
|
|
302
|
-
const raw = extractErrorString(error);
|
|
303
|
-
for (const { pattern, message } of ERROR_PATTERNS) {
|
|
304
|
-
if (pattern.test(raw)) {
|
|
305
|
-
return message;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
return "Something went wrong. Please try again.";
|
|
309
|
-
}
|
|
310
|
-
function isUserRejectionError(error) {
|
|
311
|
-
const raw = extractErrorString(error);
|
|
312
|
-
return /user rejected|user denied|rejected the request|user cancelled|user canceled/i.test(raw);
|
|
313
|
-
}
|
|
314
|
-
function extractErrorString(error) {
|
|
315
|
-
if (error instanceof Error) return error.message;
|
|
316
|
-
if (typeof error === "string") return error;
|
|
317
|
-
try {
|
|
318
|
-
return JSON.stringify(error);
|
|
319
|
-
} catch {
|
|
320
|
-
return String(error);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// src/client/types.ts
|
|
325
|
-
var PROVEX_DEFAULTS = {
|
|
326
|
-
8453: { apiUrl: "https://app.provex.com", indexerUrl: "https://indexer.provex.com" },
|
|
327
|
-
369: { apiUrl: "https://app.provex.com", indexerUrl: "https://indexer.provex.com" }
|
|
328
|
-
};
|
|
329
|
-
var ProveXError = class extends Error {
|
|
330
|
-
code;
|
|
331
|
-
cause;
|
|
332
|
-
constructor(code, message, cause) {
|
|
333
|
-
super(message);
|
|
334
|
-
this.name = "ProveXError";
|
|
335
|
-
this.code = code;
|
|
336
|
-
this.cause = cause;
|
|
337
|
-
}
|
|
338
|
-
/** Check if this error was caused by the user rejecting in their wallet. */
|
|
339
|
-
get isRejection() {
|
|
340
|
-
return this.code === "WALLET_REJECTED";
|
|
341
|
-
}
|
|
342
|
-
};
|
|
343
|
-
|
|
344
|
-
// src/client/ProveXClient.ts
|
|
345
|
-
var ProveXClient = class {
|
|
346
|
-
/** The viem Chain object — carries RPC URLs, chain ID, and metadata. */
|
|
347
|
-
chain;
|
|
348
|
-
/** Numeric chain ID (derived from chain.id). */
|
|
349
|
-
chainId;
|
|
350
|
-
wallet;
|
|
351
|
-
indexer;
|
|
352
|
-
escrowOverride;
|
|
353
|
-
onTransactionHash;
|
|
354
|
-
apiUrl;
|
|
355
|
-
onSlowSync;
|
|
356
|
-
/** Lazily-created public client for RPC calls. */
|
|
357
|
-
_publicClient = null;
|
|
358
|
-
/** Cached orchestrator address (lazy-loaded). */
|
|
359
|
-
cachedOrchestratorAddress = null;
|
|
360
|
-
constructor(config) {
|
|
361
|
-
this.chain = config.chain;
|
|
362
|
-
this.chainId = config.chain.id;
|
|
363
|
-
const defaults = PROVEX_DEFAULTS[this.chainId];
|
|
364
|
-
this.wallet = config.wallet;
|
|
365
|
-
this.indexer = config.indexer;
|
|
366
|
-
this.escrowOverride = config.escrowAddress;
|
|
367
|
-
this.onTransactionHash = config.onTransactionHash;
|
|
368
|
-
this.onSlowSync = config.onSlowSync;
|
|
369
|
-
this.apiUrl = config.apiUrl ?? defaults?.apiUrl ?? "https://app.provex.com";
|
|
370
|
-
this.createDepositRaw = this.buildWritableMethod({
|
|
371
|
-
abi: V3EscrowAbi,
|
|
372
|
-
contractResolver: () => this.getEscrowAddress(),
|
|
373
|
-
functionName: "createDeposit",
|
|
374
|
-
argsMapper: (params) => [params]
|
|
375
|
-
});
|
|
376
|
-
this.addFunds = this.buildWritableMethod({
|
|
377
|
-
abi: V3EscrowAbi,
|
|
378
|
-
contractResolver: () => this.getEscrowAddress(),
|
|
379
|
-
functionName: "addFunds",
|
|
380
|
-
argsMapper: (params) => [params.depositId, params.amount]
|
|
381
|
-
});
|
|
382
|
-
this.removeFunds = this.buildWritableMethod({
|
|
383
|
-
abi: V3EscrowAbi,
|
|
384
|
-
contractResolver: () => this.getEscrowAddress(),
|
|
385
|
-
functionName: "removeFunds",
|
|
386
|
-
argsMapper: (params) => [params.depositId, params.amount]
|
|
387
|
-
});
|
|
388
|
-
this.withdrawDeposit = this.buildWritableMethod({
|
|
389
|
-
abi: V3EscrowAbi,
|
|
390
|
-
contractResolver: () => this.getEscrowAddress(),
|
|
391
|
-
functionName: "withdrawDeposit",
|
|
392
|
-
argsMapper: (params) => [params.depositId]
|
|
393
|
-
});
|
|
394
|
-
this.pruneExpiredIntents = this.buildWritableMethod({
|
|
395
|
-
abi: V3EscrowAbi,
|
|
396
|
-
contractResolver: () => this.getEscrowAddress(),
|
|
397
|
-
functionName: "pruneExpiredIntents",
|
|
398
|
-
argsMapper: (params) => [params.depositId]
|
|
399
|
-
});
|
|
400
|
-
this.setAcceptingIntents = this.buildWritableMethod({
|
|
401
|
-
abi: V3EscrowAbi,
|
|
402
|
-
contractResolver: () => this.getEscrowAddress(),
|
|
403
|
-
functionName: "setAcceptingIntents",
|
|
404
|
-
argsMapper: (params) => [params.depositId, params.accepting]
|
|
405
|
-
});
|
|
406
|
-
this.setRetainOnEmpty = this.buildWritableMethod({
|
|
407
|
-
abi: V3EscrowAbi,
|
|
408
|
-
contractResolver: () => this.getEscrowAddress(),
|
|
409
|
-
functionName: "setRetainOnEmpty",
|
|
410
|
-
argsMapper: (params) => [params.depositId, params.retain]
|
|
411
|
-
});
|
|
412
|
-
this.setIntentRange = this.buildWritableMethod({
|
|
413
|
-
abi: V3EscrowAbi,
|
|
414
|
-
contractResolver: () => this.getEscrowAddress(),
|
|
415
|
-
functionName: "setIntentRange",
|
|
416
|
-
argsMapper: (params) => [params.depositId, { min: params.min, max: params.max }]
|
|
417
|
-
});
|
|
418
|
-
this.setPaymentMethodActive = this.buildWritableMethod({
|
|
419
|
-
abi: V3EscrowAbi,
|
|
420
|
-
contractResolver: () => this.getEscrowAddress(),
|
|
421
|
-
functionName: "setPaymentMethodActive",
|
|
422
|
-
argsMapper: (params) => [params.depositId, params.paymentMethod, params.active]
|
|
423
|
-
});
|
|
424
|
-
this.setCurrencyMinRate = this.buildWritableMethod({
|
|
425
|
-
abi: V3EscrowAbi,
|
|
426
|
-
contractResolver: () => this.getEscrowAddress(),
|
|
427
|
-
functionName: "setCurrencyMinRate",
|
|
428
|
-
argsMapper: (params) => [params.depositId, params.paymentMethod, params.currency, params.rate]
|
|
429
|
-
});
|
|
430
|
-
this.addCurrencies = this.buildWritableMethod({
|
|
431
|
-
abi: V3EscrowAbi,
|
|
432
|
-
contractResolver: () => this.getEscrowAddress(),
|
|
433
|
-
functionName: "addCurrencies",
|
|
434
|
-
argsMapper: (params) => [params.depositId, params.paymentMethod, params.currencies]
|
|
435
|
-
});
|
|
436
|
-
this.deactivateCurrency = this.buildWritableMethod({
|
|
437
|
-
abi: V3EscrowAbi,
|
|
438
|
-
contractResolver: () => this.getEscrowAddress(),
|
|
439
|
-
functionName: "deactivateCurrency",
|
|
440
|
-
argsMapper: (params) => [params.depositId, params.paymentMethod, params.currencyCode]
|
|
441
|
-
});
|
|
442
|
-
this.addPaymentMethods = this.buildWritableMethod({
|
|
443
|
-
abi: V3EscrowAbi,
|
|
444
|
-
contractResolver: () => this.getEscrowAddress(),
|
|
445
|
-
functionName: "addPaymentMethods",
|
|
446
|
-
argsMapper: (params) => [params.depositId, params.paymentMethods, params.paymentMethodData, params.currencies]
|
|
447
|
-
});
|
|
448
|
-
this.cancelIntent = this.buildWritableMethod({
|
|
449
|
-
abi: OrchestratorAbi,
|
|
450
|
-
contractResolver: () => this.getOrchestratorAddress(),
|
|
451
|
-
functionName: "cancelIntent",
|
|
452
|
-
argsMapper: (params) => [params.intentHash]
|
|
453
|
-
});
|
|
454
|
-
this.releaseFundsToPayer = this.buildWritableMethod({
|
|
455
|
-
abi: OrchestratorAbi,
|
|
456
|
-
contractResolver: () => this.getOrchestratorAddress(),
|
|
457
|
-
functionName: "releaseFundsToPayer",
|
|
458
|
-
argsMapper: (params) => [params.intentHash]
|
|
459
|
-
});
|
|
460
|
-
this.approve = this.buildWritableMethod({
|
|
461
|
-
abi: [{ name: "approve", type: "function", stateMutability: "nonpayable", inputs: [{ name: "spender", type: "address" }, { name: "amount", type: "uint256" }], outputs: [{ name: "", type: "bool" }] }],
|
|
462
|
-
contractResolver: (_params) => _params.token,
|
|
463
|
-
functionName: "approve",
|
|
464
|
-
argsMapper: (params) => [params.spender, params.amount ?? BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")]
|
|
465
|
-
});
|
|
466
|
-
}
|
|
467
|
-
// ─── Address Resolution ──────────────────────────────────────────────────
|
|
468
|
-
/** Get the V3 escrow address for this client's chain. */
|
|
469
|
-
getEscrowAddress() {
|
|
470
|
-
if (this.escrowOverride) return this.escrowOverride;
|
|
471
|
-
const addr = getLatestContract(this.chainId, "escrow", "v3");
|
|
472
|
-
if (!addr) throw new ProveXError("VALIDATION_ERROR", `No V3 escrow found for chain ${this.chainId}`);
|
|
473
|
-
return addr;
|
|
474
|
-
}
|
|
475
|
-
/** Get the orchestrator address (cached after first read). */
|
|
476
|
-
async getOrchestratorAddress() {
|
|
477
|
-
if (this.cachedOrchestratorAddress) return this.cachedOrchestratorAddress;
|
|
478
|
-
const escrow = this.getEscrowAddress();
|
|
479
|
-
const result = await this.readContract({
|
|
480
|
-
address: escrow,
|
|
481
|
-
abi: V3EscrowAbi,
|
|
482
|
-
functionName: "orchestrator"
|
|
483
|
-
});
|
|
484
|
-
this.cachedOrchestratorAddress = result;
|
|
485
|
-
return this.cachedOrchestratorAddress;
|
|
486
|
-
}
|
|
487
|
-
// ─── Indexer Reads ───────────────────────────────────────────────────────
|
|
488
|
-
requireIndexer() {
|
|
489
|
-
if (!this.indexer) throw new ProveXError("INDEXER_NOT_CONFIGURED", "No IndexerAdapter provided. Pass `indexer` to createProveXClient().");
|
|
490
|
-
return this.indexer;
|
|
491
|
-
}
|
|
492
|
-
async getMatchableDeposits(params) {
|
|
493
|
-
return this.requireIndexer().getMatchableDeposits({ ...params, chainId: this.chainId });
|
|
494
|
-
}
|
|
495
|
-
async getDepositWithVerifiers(params) {
|
|
496
|
-
return this.requireIndexer().getDepositWithVerifiers({ ...params, chainId: this.chainId });
|
|
497
|
-
}
|
|
498
|
-
async getIntent(intentHash) {
|
|
499
|
-
return this.requireIndexer().getIntent({ intentHash, chainId: this.chainId });
|
|
500
|
-
}
|
|
501
|
-
async getPayeeDetailsHash(params) {
|
|
502
|
-
return this.requireIndexer().getPayeeDetailsHash({ ...params, chainId: this.chainId });
|
|
503
|
-
}
|
|
504
|
-
async getUserReputation(address) {
|
|
505
|
-
return this.requireIndexer().getUserReputation({ address, chainId: this.chainId });
|
|
506
|
-
}
|
|
507
|
-
// ─── On-Chain Reads ──────────────────────────────────────────────────────
|
|
508
|
-
async getProtocolFees() {
|
|
509
|
-
const orchestrator = await this.getOrchestratorAddress();
|
|
510
|
-
const [feeRaw, feeRecipient] = await Promise.all([
|
|
511
|
-
this.readContract({ address: orchestrator, abi: OrchestratorAbi, functionName: "protocolFee" }),
|
|
512
|
-
this.readContract({ address: orchestrator, abi: OrchestratorAbi, functionName: "protocolFeeRecipient" })
|
|
513
|
-
]);
|
|
514
|
-
return {
|
|
515
|
-
feeRaw,
|
|
516
|
-
feeInfo: normalizeFeePrecision(feeRaw),
|
|
517
|
-
feeRecipient
|
|
518
|
-
};
|
|
519
|
-
}
|
|
520
|
-
async getDeposit(depositId) {
|
|
521
|
-
return this.readContract({
|
|
522
|
-
address: this.getEscrowAddress(),
|
|
523
|
-
abi: V3EscrowAbi,
|
|
524
|
-
functionName: "getDeposit",
|
|
525
|
-
args: [depositId]
|
|
526
|
-
});
|
|
527
|
-
}
|
|
528
|
-
async getAccountDeposits(account) {
|
|
529
|
-
return this.readContract({
|
|
530
|
-
address: this.getEscrowAddress(),
|
|
531
|
-
abi: V3EscrowAbi,
|
|
532
|
-
functionName: "getAccountDeposits",
|
|
533
|
-
args: [account]
|
|
534
|
-
});
|
|
535
|
-
}
|
|
536
|
-
async getDepositCounter() {
|
|
537
|
-
return this.readContract({
|
|
538
|
-
address: this.getEscrowAddress(),
|
|
539
|
-
abi: V3EscrowAbi,
|
|
540
|
-
functionName: "depositCounter"
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
|
-
async getAllowance(params) {
|
|
544
|
-
return this.readContract({
|
|
545
|
-
address: params.token,
|
|
546
|
-
abi: [{ name: "allowance", type: "function", stateMutability: "view", inputs: [{ name: "owner", type: "address" }, { name: "spender", type: "address" }], outputs: [{ name: "", type: "uint256" }] }],
|
|
547
|
-
functionName: "allowance",
|
|
548
|
-
args: [params.owner, params.spender]
|
|
549
|
-
});
|
|
550
|
-
}
|
|
551
|
-
async checkNullifierUsed(params) {
|
|
552
|
-
try {
|
|
553
|
-
const orchestrator = await this.getOrchestratorAddress();
|
|
554
|
-
const verifierRegistry = await this.readContract({ address: orchestrator, abi: OrchestratorAbi, functionName: "paymentVerifierRegistry" });
|
|
555
|
-
const verifier = await this.readContract({ address: verifierRegistry, abi: PaymentVerifierRegistryAbi, functionName: "getVerifier", args: [params.paymentMethodId] });
|
|
556
|
-
const nullifierRegistry = await this.readContract({ address: verifier, abi: UnifiedPaymentVerifierAbi, functionName: "nullifierRegistry" });
|
|
557
|
-
return await this.readContract({ address: nullifierRegistry, abi: NullifierRegistryAbi, functionName: "isNullified", args: [params.nullifier] });
|
|
558
|
-
} catch {
|
|
559
|
-
return null;
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
// ─── Escrow Writes ───────────────────────────────────────────────────────
|
|
563
|
-
/** Low-level deposit creation — pass pre-hashed contract params directly. */
|
|
564
|
-
createDepositRaw;
|
|
565
|
-
addFunds;
|
|
566
|
-
removeFunds;
|
|
567
|
-
withdrawDeposit;
|
|
568
|
-
pruneExpiredIntents;
|
|
569
|
-
setAcceptingIntents;
|
|
570
|
-
setRetainOnEmpty;
|
|
571
|
-
setIntentRange;
|
|
572
|
-
setPaymentMethodActive;
|
|
573
|
-
setCurrencyMinRate;
|
|
574
|
-
addCurrencies;
|
|
575
|
-
deactivateCurrency;
|
|
576
|
-
addPaymentMethods;
|
|
577
|
-
/**
|
|
578
|
-
* Create a deposit with human-readable params.
|
|
579
|
-
*
|
|
580
|
-
* Handles all encoding internally:
|
|
581
|
-
* 1. Registers payee details with the API (so buyers can discover them)
|
|
582
|
-
* 2. Hashes provider keys and currency codes to bytes32
|
|
583
|
-
* 3. Expands sub-providers (e.g., 'zelle' → zelle-chase, zelle-bofa, zelle-citi)
|
|
584
|
-
* 4. Encodes gating service witness signers
|
|
585
|
-
* 5. Submits the on-chain transaction
|
|
586
|
-
*
|
|
587
|
-
* @example
|
|
588
|
-
* ```ts
|
|
589
|
-
* await client.createDeposit({
|
|
590
|
-
* token: USDC_ADDRESS,
|
|
591
|
-
* amount: 1000_000000n,
|
|
592
|
-
* intentRange: { min: 10_000000n, max: 500_000000n },
|
|
593
|
-
* paymentMethods: [
|
|
594
|
-
* { provider: 'venmo', payeeId: '@myvenmo', currencies: [{ code: 'USD', minRate: 0n }] },
|
|
595
|
-
* ],
|
|
596
|
-
* retainOnEmpty: true,
|
|
597
|
-
* })
|
|
598
|
-
* ```
|
|
599
|
-
*/
|
|
600
|
-
async createDeposit(params) {
|
|
601
|
-
await Promise.all(
|
|
602
|
-
params.paymentMethods.map(
|
|
603
|
-
(pm) => this.registerMaker({
|
|
604
|
-
providerKey: pm.provider,
|
|
605
|
-
providerId: pm.payeeId,
|
|
606
|
-
telegramHandle: params.telegramHandle
|
|
607
|
-
}).catch((err) => {
|
|
608
|
-
console.warn(`[ProveXClient] Failed to register maker for ${pm.provider}:`, err);
|
|
609
|
-
})
|
|
610
|
-
)
|
|
611
|
-
);
|
|
612
|
-
const rawParams = this.buildCreateDepositRawParams(params);
|
|
613
|
-
return this.createDepositRaw(rawParams);
|
|
614
|
-
}
|
|
615
|
-
/**
|
|
616
|
-
* Prepare an unsigned createDeposit transaction (no API call, no wallet).
|
|
617
|
-
*
|
|
618
|
-
* Use this for smart accounts, multisig, gasless relayers, or offline signing.
|
|
619
|
-
* Maker registration is NOT performed — call `registerMaker()` separately
|
|
620
|
-
* if you need buyers to discover the payee.
|
|
621
|
-
*/
|
|
622
|
-
async prepareCreateDeposit(params) {
|
|
623
|
-
return this.createDepositRaw.prepare(this.buildCreateDepositRawParams(params));
|
|
624
|
-
}
|
|
625
|
-
/**
|
|
626
|
-
* Convert human-readable deposit params to raw contract params.
|
|
627
|
-
* Handles provider expansion, hashing, gating service encoding, and defaults.
|
|
628
|
-
*/
|
|
629
|
-
buildCreateDepositRawParams(params) {
|
|
630
|
-
const expanded = [];
|
|
631
|
-
const configs = providerConfigs(this.chainId);
|
|
632
|
-
for (const pm of params.paymentMethods) {
|
|
633
|
-
const hash = computePayeeDetailsHash(pm.payeeId);
|
|
634
|
-
const config = configs[pm.provider];
|
|
635
|
-
if (config?.subProviders && config.subProviders.size > 0) {
|
|
636
|
-
for (const sub of config.subProviders) {
|
|
637
|
-
expanded.push({
|
|
638
|
-
providerKey: sub.key,
|
|
639
|
-
payeeDetailsHash: hash,
|
|
640
|
-
currencies: pm.currencies,
|
|
641
|
-
intentGatingService: pm.intentGatingService,
|
|
642
|
-
data: pm.data
|
|
643
|
-
});
|
|
644
|
-
}
|
|
645
|
-
} else {
|
|
646
|
-
expanded.push({
|
|
647
|
-
providerKey: pm.provider,
|
|
648
|
-
payeeDetailsHash: hash,
|
|
649
|
-
currencies: pm.currencies,
|
|
650
|
-
intentGatingService: pm.intentGatingService,
|
|
651
|
-
data: pm.data
|
|
652
|
-
});
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
const defaultGatingData = encodeAbiParameters(
|
|
656
|
-
parseAbiParameters(["address[]"]),
|
|
657
|
-
[[reclaimSigners.peerWitnessSigner, reclaimSigners.reclaimWitnessSigner]]
|
|
658
|
-
);
|
|
659
|
-
const defaultGatingService = getLatestContract(this.chainId, "gatingService", "v3") ?? zeroAddress;
|
|
660
|
-
return {
|
|
661
|
-
token: params.token,
|
|
662
|
-
amount: params.amount,
|
|
663
|
-
intentAmountRange: {
|
|
664
|
-
min: params.intentRange?.min ?? 1000000n,
|
|
665
|
-
max: params.intentRange?.max ?? params.amount
|
|
666
|
-
},
|
|
667
|
-
paymentMethods: expanded.map((p) => providerKeyToContractId(p.providerKey)),
|
|
668
|
-
paymentMethodData: expanded.map((p) => ({
|
|
669
|
-
intentGatingService: p.intentGatingService ?? defaultGatingService,
|
|
670
|
-
payeeDetails: p.payeeDetailsHash,
|
|
671
|
-
data: p.data ?? defaultGatingData
|
|
672
|
-
})),
|
|
673
|
-
currencies: expanded.map(
|
|
674
|
-
(p) => p.currencies.map((c) => ({
|
|
675
|
-
code: tickerToContractId(c.code),
|
|
676
|
-
minConversionRate: c.minRate
|
|
677
|
-
}))
|
|
678
|
-
),
|
|
679
|
-
delegate: params.delegate ?? zeroAddress,
|
|
680
|
-
intentGuardian: params.intentGuardian ?? zeroAddress,
|
|
681
|
-
retainOnEmpty: params.retainOnEmpty ?? false
|
|
682
|
-
};
|
|
683
|
-
}
|
|
684
|
-
// ─── Orchestrator Writes ─────────────────────────────────────────────────
|
|
685
|
-
cancelIntent;
|
|
686
|
-
releaseFundsToPayer;
|
|
687
|
-
/**
|
|
688
|
-
* Signal an intent to buy tokens from a deposit (buyer side).
|
|
689
|
-
*
|
|
690
|
-
* Handles the full multi-step flow:
|
|
691
|
-
* 1. Fetches payee details hash from the indexer
|
|
692
|
-
* 2. Requests a gating service signature from the API
|
|
693
|
-
* 3. Simulates the transaction
|
|
694
|
-
* 4. Submits to Orchestrator.signalIntent()
|
|
695
|
-
* 5. Parses the IntentSignaled event to extract the intent hash
|
|
696
|
-
*
|
|
697
|
-
* @returns Transaction result with the on-chain intent hash.
|
|
698
|
-
* @throws {ProveXError} VALIDATION_ERROR if payee details or gating signature missing.
|
|
699
|
-
* @throws {ProveXError} API_ERROR if gating service rejects the intent.
|
|
700
|
-
* @throws {ProveXError} WALLET_REJECTED if user cancels in wallet.
|
|
701
|
-
*
|
|
702
|
-
* @example
|
|
703
|
-
* ```ts
|
|
704
|
-
* const { hash, intentHash } = await client.signalIntent({
|
|
705
|
-
* deposit: { escrow: '0x...', localId: 1n },
|
|
706
|
-
* paymentMethod: providerKeyToContractId('venmo'),
|
|
707
|
-
* tokenAmount: 100_000000n,
|
|
708
|
-
* toAddress: wallet.address,
|
|
709
|
-
* fiatCurrencyCode: tickerToContractId('USD'),
|
|
710
|
-
* conversionRate: 1_000000000000000000n,
|
|
711
|
-
* })
|
|
712
|
-
* ```
|
|
713
|
-
*/
|
|
714
|
-
async signalIntent(params) {
|
|
715
|
-
const wallet = this.requireWallet();
|
|
716
|
-
const orchestrator = await this.getOrchestratorAddress();
|
|
717
|
-
const indexer = this.requireIndexer();
|
|
718
|
-
const payeeDetailsHash = await indexer.getPayeeDetailsHash({
|
|
719
|
-
escrow: params.deposit.escrow,
|
|
720
|
-
localId: params.deposit.localId,
|
|
721
|
-
chainId: this.chainId,
|
|
722
|
-
paymentMethodId: params.paymentMethod
|
|
723
|
-
});
|
|
724
|
-
if (!payeeDetailsHash) {
|
|
725
|
-
throw new ProveXError("VALIDATION_ERROR", "No payee details found for this deposit and payment method.");
|
|
726
|
-
}
|
|
727
|
-
const gatingResponse = await this.requestGatingSignature({
|
|
728
|
-
processorName: params.subProvider ?? "",
|
|
729
|
-
depositId: params.deposit.localId.toString(),
|
|
730
|
-
amount: params.tokenAmount.toString(),
|
|
731
|
-
payeeDetails: payeeDetailsHash,
|
|
732
|
-
toAddress: params.toAddress,
|
|
733
|
-
paymentMethod: params.paymentMethod,
|
|
734
|
-
fiatCurrency: params.fiatCurrencyCode,
|
|
735
|
-
conversionRate: params.conversionRate.toString(),
|
|
736
|
-
chainId: this.chainId.toString(),
|
|
737
|
-
orchestratorAddress: orchestrator,
|
|
738
|
-
escrowAddress: params.deposit.escrow
|
|
739
|
-
});
|
|
740
|
-
const rawParams = {
|
|
741
|
-
escrow: params.deposit.escrow,
|
|
742
|
-
depositId: params.deposit.localId,
|
|
743
|
-
amount: params.tokenAmount,
|
|
744
|
-
to: params.toAddress,
|
|
745
|
-
paymentMethod: params.paymentMethod,
|
|
746
|
-
fiatCurrency: params.fiatCurrencyCode,
|
|
747
|
-
conversionRate: params.conversionRate,
|
|
748
|
-
referrer: zeroAddress,
|
|
749
|
-
referrerFee: 0n,
|
|
750
|
-
gatingServiceSignature: gatingResponse.signature,
|
|
751
|
-
signatureExpiration: gatingResponse.expiration,
|
|
752
|
-
postIntentHook: zeroAddress,
|
|
753
|
-
data: "0x"
|
|
754
|
-
};
|
|
755
|
-
const publicClient2 = this.getPublicClient();
|
|
756
|
-
try {
|
|
757
|
-
await publicClient2.simulateContract({
|
|
758
|
-
address: orchestrator,
|
|
759
|
-
abi: OrchestratorAbi,
|
|
760
|
-
functionName: "signalIntent",
|
|
761
|
-
args: [rawParams],
|
|
762
|
-
account: params.toAddress
|
|
763
|
-
});
|
|
764
|
-
} catch (simError) {
|
|
765
|
-
throw new ProveXError("CONTRACT_ERROR", simError.message ?? "Signal intent simulation failed", simError);
|
|
766
|
-
}
|
|
767
|
-
const gasInputs = await getTransactionGasInputs(this.chainId);
|
|
768
|
-
const txData = encodeFunctionData({
|
|
769
|
-
abi: OrchestratorAbi,
|
|
770
|
-
functionName: "signalIntent",
|
|
771
|
-
args: [rawParams]
|
|
772
|
-
});
|
|
773
|
-
let txHash;
|
|
774
|
-
try {
|
|
775
|
-
txHash = await wallet.sendTransaction({
|
|
776
|
-
to: orchestrator,
|
|
777
|
-
data: txData,
|
|
778
|
-
chainId: this.chainId,
|
|
779
|
-
...gasInputs
|
|
780
|
-
});
|
|
781
|
-
} catch (err) {
|
|
782
|
-
if (isUserRejectionError(err)) {
|
|
783
|
-
throw new ProveXError("WALLET_REJECTED", "Transaction was rejected in wallet.", err);
|
|
784
|
-
}
|
|
785
|
-
throw new ProveXError("CONTRACT_ERROR", err.message ?? "Transaction failed", err);
|
|
786
|
-
}
|
|
787
|
-
this.onTransactionHash?.(txHash);
|
|
788
|
-
const receipt = await publicClient2.waitForTransactionReceipt({ hash: txHash });
|
|
789
|
-
let intentHash = null;
|
|
790
|
-
for (const log of receipt.logs) {
|
|
791
|
-
try {
|
|
792
|
-
const decoded = decodeEventLog({
|
|
793
|
-
abi: OrchestratorAbi,
|
|
794
|
-
data: log.data,
|
|
795
|
-
topics: log.topics
|
|
796
|
-
});
|
|
797
|
-
if (decoded.eventName === "IntentSignaled") {
|
|
798
|
-
intentHash = decoded.args.intentHash;
|
|
799
|
-
break;
|
|
800
|
-
}
|
|
801
|
-
} catch {
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
if (!intentHash) {
|
|
805
|
-
throw new ProveXError("CONTRACT_ERROR", "Transaction succeeded but IntentSignaled event not found in receipt.");
|
|
806
|
-
}
|
|
807
|
-
if (this.indexer) {
|
|
808
|
-
await checkTransactionIndexed({
|
|
809
|
-
queryTransaction: this.indexer.getTransactionByHash,
|
|
810
|
-
hash: txHash,
|
|
811
|
-
onSlowSync: this.onSlowSync
|
|
812
|
-
});
|
|
813
|
-
}
|
|
814
|
-
return { hash: txHash, receipt, intentHash };
|
|
815
|
-
}
|
|
816
|
-
/**
|
|
817
|
-
* Request a gating service signature for intent signaling.
|
|
818
|
-
* The gating service validates the intent and returns a signature
|
|
819
|
-
* the Orchestrator contract verifies on-chain.
|
|
820
|
-
*/
|
|
821
|
-
async requestGatingSignature(params) {
|
|
822
|
-
const res = await this.apiPost("/api/v0/attestation/verify/intent", params);
|
|
823
|
-
if (!res.success) {
|
|
824
|
-
throw new ProveXError("API_ERROR", res.message ?? "Gating service rejected the intent.");
|
|
825
|
-
}
|
|
826
|
-
const signature = res.responseObject.intentData?.gatingServiceSignature ?? res.responseObject.signedIntent;
|
|
827
|
-
if (!signature) {
|
|
828
|
-
throw new ProveXError("API_ERROR", "No signature received from gating service.");
|
|
829
|
-
}
|
|
830
|
-
const expiration = res.responseObject.signatureExpiration ? BigInt(res.responseObject.signatureExpiration) : BigInt(Math.floor(Date.now() / 1e3) + 3600);
|
|
831
|
-
return { signature, expiration };
|
|
832
|
-
}
|
|
833
|
-
// ─── ERC20 ───────────────────────────────────────────────────────────────
|
|
834
|
-
approve;
|
|
835
|
-
// ─── API Methods (Maker Registration, Attestation) ──────────────────────
|
|
836
|
-
/** Get payee details for a provider and user ID. */
|
|
837
|
-
async getPayeeInfo(params) {
|
|
838
|
-
try {
|
|
839
|
-
const res = await fetch(`${this.apiUrl}/api/v0/makers/${params.provider}/${params.userId}`);
|
|
840
|
-
if (!res.ok) return null;
|
|
841
|
-
const json = await res.json();
|
|
842
|
-
return json.responseObject ?? null;
|
|
843
|
-
} catch {
|
|
844
|
-
return null;
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
/** Validate a maker's payment identity before registration. */
|
|
848
|
-
async validateMaker(params) {
|
|
849
|
-
const res = await this.apiPost("/api/v0/makers/validate", {
|
|
850
|
-
processorName: params.providerKey,
|
|
851
|
-
depositData: {
|
|
852
|
-
[params.providerKey]: params.providerId,
|
|
853
|
-
telegramUsername: params.telegramHandle ?? ""
|
|
854
|
-
}
|
|
855
|
-
});
|
|
856
|
-
return res.responseObject ?? false;
|
|
857
|
-
}
|
|
858
|
-
/** Register a maker's payment identity (e.g., Venmo username). Required before creating deposits. */
|
|
859
|
-
async registerMaker(params) {
|
|
860
|
-
const res = await this.apiPost("/api/v0/makers/create", {
|
|
861
|
-
processorName: params.providerKey,
|
|
862
|
-
depositData: {
|
|
863
|
-
[params.providerKey]: params.providerId,
|
|
864
|
-
telegramUsername: params.telegramHandle ?? ""
|
|
865
|
-
}
|
|
866
|
-
});
|
|
867
|
-
return res.responseObject ?? null;
|
|
868
|
-
}
|
|
869
|
-
/**
|
|
870
|
-
* Submit zkTLS proofs and get a signed attestation for fulfillIntent.
|
|
871
|
-
* This is the proof verification step — after the buyer makes payment and
|
|
872
|
-
* generates proofs via the browser extension.
|
|
873
|
-
*/
|
|
874
|
-
async getAttestation(params) {
|
|
875
|
-
const endpoint = `/api/v0/attestation/verify/${params.platform}/${params.actionType}`;
|
|
876
|
-
const proof = params.proofs.length === 1 ? params.proofs[0] : params.proofs;
|
|
877
|
-
const res = await fetch(`${this.apiUrl}${endpoint}`, {
|
|
878
|
-
method: "POST",
|
|
879
|
-
headers: { "Content-Type": "application/json" },
|
|
880
|
-
body: JSON.stringify({
|
|
881
|
-
proofType: "reclaim",
|
|
882
|
-
proof: JSON.stringify(proof),
|
|
883
|
-
chainId: params.chainId,
|
|
884
|
-
verifyingContract: params.verifyingContract,
|
|
885
|
-
intent: params.intent
|
|
886
|
-
})
|
|
887
|
-
});
|
|
888
|
-
if (!res.ok) {
|
|
889
|
-
let errorMessage = `Attestation error: ${res.status}`;
|
|
890
|
-
try {
|
|
891
|
-
const errorJson = await res.json();
|
|
892
|
-
if (errorJson.message) errorMessage = errorJson.message;
|
|
893
|
-
} catch {
|
|
894
|
-
}
|
|
895
|
-
return {
|
|
896
|
-
success: false,
|
|
897
|
-
message: errorMessage,
|
|
898
|
-
statusCode: res.status,
|
|
899
|
-
responseObject: {}
|
|
900
|
-
};
|
|
901
|
-
}
|
|
902
|
-
return await res.json();
|
|
903
|
-
}
|
|
904
|
-
/** Make a POST request to the API. */
|
|
905
|
-
async apiPost(path, body) {
|
|
906
|
-
const res = await fetch(`${this.apiUrl}${path}`, {
|
|
907
|
-
method: "POST",
|
|
908
|
-
headers: { "Content-Type": "application/json" },
|
|
909
|
-
body: JSON.stringify(body)
|
|
910
|
-
});
|
|
911
|
-
if (!res.ok) {
|
|
912
|
-
throw new ProveXError("API_ERROR", `API request failed: ${res.status}`);
|
|
913
|
-
}
|
|
914
|
-
return await res.json();
|
|
915
|
-
}
|
|
916
|
-
// ─── Indexer Sync ────────────────────────────────────────────────────────
|
|
917
|
-
async waitForTransactionIndexed(hash) {
|
|
918
|
-
const indexer = this.requireIndexer();
|
|
919
|
-
await checkTransactionIndexed({
|
|
920
|
-
queryTransaction: indexer.getTransactionByHash,
|
|
921
|
-
hash,
|
|
922
|
-
onSlowSync: this.onSlowSync
|
|
923
|
-
});
|
|
924
|
-
}
|
|
925
|
-
// ─── Internal Helpers ────────────────────────────────────────────────────
|
|
926
|
-
/** Get or create a viem PublicClient for this chain. Cached after first use. */
|
|
927
|
-
getPublicClient() {
|
|
928
|
-
if (!this._publicClient) {
|
|
929
|
-
this._publicClient = createPublicClient({ chain: this.chain, transport: http() });
|
|
930
|
-
}
|
|
931
|
-
return this._publicClient;
|
|
932
|
-
}
|
|
933
|
-
/** Read from a contract using wallet adapter or public RPC. */
|
|
934
|
-
async readContract(params) {
|
|
935
|
-
if (this.wallet?.readContract) {
|
|
936
|
-
return this.wallet.readContract({ ...params, chainId: this.chainId });
|
|
937
|
-
}
|
|
938
|
-
return this.getPublicClient().readContract(params);
|
|
939
|
-
}
|
|
940
|
-
/** Require a connected wallet, or throw. */
|
|
941
|
-
requireWallet() {
|
|
942
|
-
if (!this.wallet) throw new ProveXError("WALLET_NOT_CONNECTED", "No wallet adapter provided. Pass `wallet` to createProveXClient().");
|
|
943
|
-
if (!this.wallet.address) throw new ProveXError("WALLET_NOT_CONNECTED", "Wallet is not connected.");
|
|
944
|
-
return this.wallet;
|
|
945
|
-
}
|
|
946
|
-
/**
|
|
947
|
-
* Build a WritableMethod from an ABI definition.
|
|
948
|
-
* The returned function supports both execute (full lifecycle) and .prepare() (unsigned tx).
|
|
949
|
-
*/
|
|
950
|
-
buildWritableMethod({
|
|
951
|
-
abi,
|
|
952
|
-
contractResolver,
|
|
953
|
-
functionName,
|
|
954
|
-
argsMapper
|
|
955
|
-
}) {
|
|
956
|
-
const prepare = async (params) => {
|
|
957
|
-
const to = await contractResolver(params);
|
|
958
|
-
const args = argsMapper(params);
|
|
959
|
-
const data = encodeFunctionData({
|
|
960
|
-
abi,
|
|
961
|
-
functionName,
|
|
962
|
-
args
|
|
963
|
-
});
|
|
964
|
-
return { to, data, value: 0n, chainId: this.chainId };
|
|
965
|
-
};
|
|
966
|
-
const execute = async (params) => {
|
|
967
|
-
const wallet = this.requireWallet();
|
|
968
|
-
const prepared = await prepare(params);
|
|
969
|
-
const gasInputs = await getTransactionGasInputs(this.chainId);
|
|
970
|
-
let hash;
|
|
971
|
-
try {
|
|
972
|
-
hash = await wallet.sendTransaction({ ...prepared, ...gasInputs });
|
|
973
|
-
} catch (err) {
|
|
974
|
-
if (isUserRejectionError(err)) {
|
|
975
|
-
throw new ProveXError("WALLET_REJECTED", "Transaction was rejected in wallet.", err);
|
|
976
|
-
}
|
|
977
|
-
throw new ProveXError("CONTRACT_ERROR", err.message ?? "Transaction failed", err);
|
|
978
|
-
}
|
|
979
|
-
this.onTransactionHash?.(hash);
|
|
980
|
-
const receipt = await this.getPublicClient().waitForTransactionReceipt({ hash });
|
|
981
|
-
if (this.indexer) {
|
|
982
|
-
await checkTransactionIndexed({
|
|
983
|
-
queryTransaction: this.indexer.getTransactionByHash,
|
|
984
|
-
hash,
|
|
985
|
-
onSlowSync: this.onSlowSync
|
|
986
|
-
});
|
|
987
|
-
}
|
|
988
|
-
return { hash, receipt };
|
|
989
|
-
};
|
|
990
|
-
execute.prepare = prepare;
|
|
991
|
-
return execute;
|
|
992
|
-
}
|
|
993
|
-
};
|
|
994
|
-
function createProveXClient(config) {
|
|
995
|
-
return new ProveXClient(config);
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
// src/hooks/useSignalIntent.ts
|
|
999
|
-
var ERROR_PATTERNS2 = [
|
|
1000
|
-
{ pattern: /user rejected|user denied|rejected the request|user cancelled|user canceled/i, message: "Transaction was cancelled." },
|
|
1001
|
-
{ pattern: /InsufficientDepositLiquidity|0xc3df48f3/i, message: "This deposit no longer has enough available liquidity. Please try a smaller amount or a different deposit." },
|
|
1002
|
-
{ pattern: /execution reverted/i, message: "Transaction failed on-chain. The order may no longer be available." },
|
|
1003
|
-
{ pattern: /insufficient funds/i, message: "Insufficient funds for gas fees." },
|
|
1004
|
-
{ pattern: /timeout|etimedout/i, message: "Request timed out. Please try again." }
|
|
1005
|
-
];
|
|
1006
|
-
function getUserFriendlyErrorMessage2(error) {
|
|
1007
|
-
const raw = error instanceof Error ? error.message : String(error);
|
|
1008
|
-
for (const { pattern, message } of ERROR_PATTERNS2) {
|
|
1009
|
-
if (pattern.test(raw)) return message;
|
|
1010
|
-
}
|
|
1011
|
-
return "Something went wrong. Please try again.";
|
|
1012
|
-
}
|
|
1013
|
-
function useSignalIntent({
|
|
1014
|
-
wallet,
|
|
1015
|
-
onSuccess,
|
|
1016
|
-
onFailure,
|
|
1017
|
-
deposit,
|
|
1018
|
-
refetchDeposits
|
|
1019
|
-
}) {
|
|
1020
|
-
const provex = useOptionalProvex();
|
|
1021
|
-
const [status, setStatus] = useState("input");
|
|
1022
|
-
const [message, setMessage] = useState(null);
|
|
1023
|
-
const client = useMemo(() => {
|
|
1024
|
-
if (!provex) return null;
|
|
1025
|
-
return createProveXClient({
|
|
1026
|
-
chain: provex.config.chain,
|
|
1027
|
-
apiUrl: provex.config.apiUrl,
|
|
1028
|
-
wallet,
|
|
1029
|
-
indexer: provex.indexer
|
|
1030
|
-
});
|
|
1031
|
-
}, [provex, wallet]);
|
|
1032
|
-
const isLoading = useMemo(() => {
|
|
1033
|
-
return status === "loading_payee" || status === "loading_intent" || status === "prompt_wallet_confirm" || status === "writing_intent";
|
|
1034
|
-
}, [status]);
|
|
1035
|
-
const startOrder = useCallback(async ({
|
|
1036
|
-
paymentMethod,
|
|
1037
|
-
depositId,
|
|
1038
|
-
tokenAmount,
|
|
1039
|
-
toAddress,
|
|
1040
|
-
fiatCurrencyCode,
|
|
1041
|
-
conversionRate,
|
|
1042
|
-
subProvider
|
|
1043
|
-
}) => {
|
|
1044
|
-
if (!client || !deposit) {
|
|
1045
|
-
setStatus("error");
|
|
1046
|
-
setMessage("Client or deposit not available");
|
|
1047
|
-
return;
|
|
1048
|
-
}
|
|
1049
|
-
const escrow = deposit.escrow;
|
|
1050
|
-
if (!escrow) {
|
|
1051
|
-
setStatus("error");
|
|
1052
|
-
setMessage("No escrow address found");
|
|
1053
|
-
return;
|
|
1054
|
-
}
|
|
1055
|
-
setStatus("loading_intent");
|
|
1056
|
-
try {
|
|
1057
|
-
const result = await client.signalIntent({
|
|
1058
|
-
deposit: { escrow, localId: deposit.localId ?? depositId },
|
|
1059
|
-
paymentMethod,
|
|
1060
|
-
tokenAmount,
|
|
1061
|
-
toAddress,
|
|
1062
|
-
fiatCurrencyCode,
|
|
1063
|
-
conversionRate,
|
|
1064
|
-
subProvider
|
|
1065
|
-
});
|
|
1066
|
-
setStatus("success");
|
|
1067
|
-
setMessage("Intent signaled successfully");
|
|
1068
|
-
onSuccess(result.intentHash);
|
|
1069
|
-
} catch (error) {
|
|
1070
|
-
if (error instanceof ProveXError && error.isRejection) {
|
|
1071
|
-
setStatus("input");
|
|
1072
|
-
setMessage(null);
|
|
1073
|
-
return;
|
|
1074
|
-
}
|
|
1075
|
-
console.error("Failed to signal intent", error);
|
|
1076
|
-
setStatus("error");
|
|
1077
|
-
setMessage(getUserFriendlyErrorMessage2(error));
|
|
1078
|
-
refetchDeposits?.();
|
|
1079
|
-
onFailure?.();
|
|
1080
|
-
}
|
|
1081
|
-
}, [client, deposit, onSuccess, onFailure, refetchDeposits]);
|
|
1082
|
-
return {
|
|
1083
|
-
startOrder,
|
|
1084
|
-
status,
|
|
1085
|
-
message,
|
|
1086
|
-
isLoading
|
|
1087
|
-
};
|
|
1088
|
-
}
|
|
1089
|
-
function useReputation({
|
|
1090
|
-
address,
|
|
1091
|
-
chainId
|
|
1092
|
-
}) {
|
|
1093
|
-
const { indexer } = useProvex();
|
|
1094
|
-
const queryClient = useQueryClient();
|
|
1095
|
-
const isBase = chainId === base.id;
|
|
1096
|
-
const reputationQuery = useQuery({
|
|
1097
|
-
queryKey: ["provex", "reputation", address, isBase ? base.id : "all"],
|
|
1098
|
-
queryFn: async () => {
|
|
1099
|
-
if (!address) return null;
|
|
1100
|
-
return indexer.getUserReputation({
|
|
1101
|
-
address,
|
|
1102
|
-
chainId: isBase ? base.id : void 0
|
|
1103
|
-
});
|
|
1104
|
-
},
|
|
1105
|
-
enabled: !!address,
|
|
1106
|
-
staleTime: 6e4,
|
|
1107
|
-
refetchInterval: 12e4
|
|
1108
|
-
});
|
|
1109
|
-
const reputation = useMemo(() => {
|
|
1110
|
-
const data = reputationQuery.data;
|
|
1111
|
-
if (!data) return DEFAULT_REPUTATION;
|
|
1112
|
-
let tier = getTierFromVolume(data.fulfilledVolumeUsdc);
|
|
1113
|
-
const lockScore = data.lateCancellations * 50;
|
|
1114
|
-
const dilutedLockScore = data.fulfilledCount > 0 ? lockScore / (1 + data.fulfilledCount * 0.1) : lockScore;
|
|
1115
|
-
let tierPenalty = 0;
|
|
1116
|
-
if (dilutedLockScore >= 1e3) tierPenalty = 4;
|
|
1117
|
-
else if (dilutedLockScore >= 500) tierPenalty = 3;
|
|
1118
|
-
else if (dilutedLockScore >= 200) tierPenalty = 2;
|
|
1119
|
-
else if (dilutedLockScore >= 50) tierPenalty = 1;
|
|
1120
|
-
if (tierPenalty > 0) {
|
|
1121
|
-
const currentTierIndex = TIER_ORDER.indexOf(tier);
|
|
1122
|
-
const newTierIndex = Math.max(0, currentTierIndex - tierPenalty);
|
|
1123
|
-
tier = TIER_ORDER[newTierIndex] ?? "peasant";
|
|
1124
|
-
}
|
|
1125
|
-
const cooldownHours = TAKER_TIERS[tier].cooldownHours;
|
|
1126
|
-
let cooldownEndsAt = null;
|
|
1127
|
-
let isOnCooldown = false;
|
|
1128
|
-
const baseTimestamp = data.lastSignaledAt[base.id] ?? null;
|
|
1129
|
-
const pulseTimestamp = data.lastSignaledAt[369] ?? null;
|
|
1130
|
-
const candidateTimestamps = isBase ? [baseTimestamp] : [baseTimestamp, pulseTimestamp];
|
|
1131
|
-
const lastSignaledTimestamp = candidateTimestamps.filter((ts) => ts !== null).sort((a, b) => Number(b) - Number(a))[0] ?? null;
|
|
1132
|
-
if (cooldownHours > 0 && lastSignaledTimestamp) {
|
|
1133
|
-
const lastSignaledTime = Number(lastSignaledTimestamp) * 1e3;
|
|
1134
|
-
const cooldownMs = cooldownHours * 60 * 60 * 1e3;
|
|
1135
|
-
cooldownEndsAt = new Date(lastSignaledTime + cooldownMs);
|
|
1136
|
-
isOnCooldown = cooldownEndsAt > /* @__PURE__ */ new Date();
|
|
1137
|
-
}
|
|
1138
|
-
return {
|
|
1139
|
-
tier,
|
|
1140
|
-
fulfilledVolumeUsdc: data.fulfilledVolumeUsdc,
|
|
1141
|
-
lockScore: dilutedLockScore,
|
|
1142
|
-
cooldownEndsAt,
|
|
1143
|
-
isOnCooldown
|
|
1144
|
-
};
|
|
1145
|
-
}, [reputationQuery.data, isBase]);
|
|
1146
|
-
const hasLoadedData = reputationQuery.data !== void 0;
|
|
1147
|
-
const isLoading = reputationQuery.isLoading && !hasLoadedData;
|
|
1148
|
-
const refetch = useCallback(() => {
|
|
1149
|
-
queryClient.invalidateQueries({
|
|
1150
|
-
queryKey: ["provex", "reputation", address]
|
|
1151
|
-
});
|
|
1152
|
-
}, [queryClient, address]);
|
|
1153
|
-
return {
|
|
1154
|
-
reputation,
|
|
1155
|
-
isLoading,
|
|
1156
|
-
error: reputationQuery.error,
|
|
1157
|
-
refetch
|
|
1158
|
-
};
|
|
1159
|
-
}
|
|
1160
|
-
function getTierDisplayInfo(tier) {
|
|
1161
|
-
const config = TAKER_TIERS[tier];
|
|
1162
|
-
const colors = {
|
|
1163
|
-
[tiers.PEASANT]: "gray",
|
|
1164
|
-
[tiers.NEUTRAL]: "blue",
|
|
1165
|
-
[tiers.PLUS]: "green",
|
|
1166
|
-
[tiers.PRO]: "purple",
|
|
1167
|
-
[tiers.PLATINUM]: "yellow",
|
|
1168
|
-
[tiers.PRESIDENT]: "cyan"
|
|
1169
|
-
};
|
|
1170
|
-
return {
|
|
1171
|
-
name: config.name,
|
|
1172
|
-
baseCap: config.baseCap,
|
|
1173
|
-
cooldownHours: config.cooldownHours,
|
|
1174
|
-
color: colors[tier],
|
|
1175
|
-
volumeRangeDisplay: getVolumeRangeDisplay(tier)
|
|
1176
|
-
};
|
|
1177
|
-
}
|
|
1178
|
-
function useReputationLimits({
|
|
1179
|
-
chainId,
|
|
1180
|
-
selectedPaymentMethod,
|
|
1181
|
-
tier,
|
|
1182
|
-
amountInInt,
|
|
1183
|
-
cooldownEndsAt
|
|
1184
|
-
}) {
|
|
1185
|
-
const hasLimits = true;
|
|
1186
|
-
const { cooldownRemaining, isOnCooldown } = useMemo(() => {
|
|
1187
|
-
const providerCooldownHours = getCooldownHours({ tier, providerKey: selectedPaymentMethod }) ;
|
|
1188
|
-
const providerHasCooldown = providerCooldownHours > 0;
|
|
1189
|
-
if (!cooldownEndsAt || !providerHasCooldown) {
|
|
1190
|
-
return { cooldownRemaining: null, isOnCooldown: false };
|
|
1191
|
-
}
|
|
1192
|
-
const remainingMs = cooldownEndsAt.getTime() - Date.now();
|
|
1193
|
-
if (remainingMs <= 0) {
|
|
1194
|
-
return { cooldownRemaining: null, isOnCooldown: false };
|
|
1195
|
-
}
|
|
1196
|
-
const hours = Math.floor(remainingMs / (1e3 * 60 * 60));
|
|
1197
|
-
const minutes = Math.floor(remainingMs % (1e3 * 60 * 60) / (1e3 * 60));
|
|
1198
|
-
const formatted = hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
|
|
1199
|
-
return { cooldownRemaining: formatted, isOnCooldown: true };
|
|
1200
|
-
}, [cooldownEndsAt, hasLimits, tier, selectedPaymentMethod]);
|
|
1201
|
-
const noCooldownProviders = useMemo(() => {
|
|
1202
|
-
const available = verifiablePaymentMethods(chainId);
|
|
1203
|
-
return available.filter((key) => {
|
|
1204
|
-
if (key === selectedPaymentMethod) return false;
|
|
1205
|
-
const platformRisk = getPlatformRisk(chainId, key);
|
|
1206
|
-
if (!platformRisk.hasCooldown) return false;
|
|
1207
|
-
return getCooldownHours({ tier, providerKey: key }) === 0;
|
|
1208
|
-
});
|
|
1209
|
-
}, [hasLimits, chainId, selectedPaymentMethod, tier]);
|
|
1210
|
-
const selectedProviderCooldownHours = useMemo(() => {
|
|
1211
|
-
return getCooldownHours({ tier, providerKey: selectedPaymentMethod });
|
|
1212
|
-
}, [hasLimits, tier, selectedPaymentMethod]);
|
|
1213
|
-
const effectiveCap = useMemo(() => {
|
|
1214
|
-
return getEffectiveCap({ tier, providerKey: selectedPaymentMethod });
|
|
1215
|
-
}, [hasLimits, tier, selectedPaymentMethod]);
|
|
1216
|
-
const amountExceedsCap = useMemo(() => {
|
|
1217
|
-
if (effectiveCap === null) return false;
|
|
1218
|
-
if (!amountInInt) return false;
|
|
1219
|
-
const amountUsd = Number(amountInInt) / 1e6;
|
|
1220
|
-
return amountUsd > effectiveCap;
|
|
1221
|
-
}, [effectiveCap, amountInInt]);
|
|
1222
|
-
const capExceededMessage = useMemo(() => {
|
|
1223
|
-
if (!amountExceedsCap || effectiveCap === null) return null;
|
|
1224
|
-
const providerName = providerConfigs(chainId)[selectedPaymentMethod]?.name ?? selectedPaymentMethod;
|
|
1225
|
-
return `Amount exceeds your $${effectiveCap.toLocaleString()} limit for ${providerName}`;
|
|
1226
|
-
}, [amountExceedsCap, effectiveCap, chainId, selectedPaymentMethod]);
|
|
1227
|
-
return {
|
|
1228
|
-
hasLimits,
|
|
1229
|
-
noCooldownProviders,
|
|
1230
|
-
selectedProviderCooldownHours,
|
|
1231
|
-
cooldownRemaining,
|
|
1232
|
-
isOnCooldown,
|
|
1233
|
-
effectiveCap,
|
|
1234
|
-
amountExceedsCap,
|
|
1235
|
-
capExceededMessage
|
|
1236
|
-
};
|
|
1237
|
-
}
|
|
1238
|
-
var intentStatuses = {
|
|
1239
|
-
pending: "pending",
|
|
1240
|
-
signalled: "signalled",
|
|
1241
|
-
fulfilled: "fulfilled",
|
|
1242
|
-
pruned: "pruned"
|
|
1243
|
-
};
|
|
1244
|
-
function usePayeeDetails({
|
|
1245
|
-
intentHash,
|
|
1246
|
-
chainId
|
|
1247
|
-
}) {
|
|
1248
|
-
const { indexer, apiClient } = useProvex();
|
|
1249
|
-
const queryClient = useQueryClient();
|
|
1250
|
-
const intentQuery = useQuery({
|
|
1251
|
-
queryKey: ["provex", "intent", intentHash, chainId],
|
|
1252
|
-
queryFn: () => indexer.getIntent({ intentHash, chainId }),
|
|
1253
|
-
enabled: !!intentHash,
|
|
1254
|
-
staleTime: Infinity,
|
|
1255
|
-
refetchInterval: false
|
|
1256
|
-
});
|
|
1257
|
-
const indexedIntent = intentQuery.data ?? null;
|
|
1258
|
-
const intentStatus = useMemo(() => {
|
|
1259
|
-
if (!indexedIntent) return null;
|
|
1260
|
-
return indexedIntent.status;
|
|
1261
|
-
}, [indexedIntent]);
|
|
1262
|
-
const intent = useMemo(() => {
|
|
1263
|
-
if (!indexedIntent) return null;
|
|
1264
|
-
return {
|
|
1265
|
-
owner: indexedIntent.ownerAddress,
|
|
1266
|
-
to: indexedIntent.toAddress,
|
|
1267
|
-
escrow: indexedIntent.escrow,
|
|
1268
|
-
depositId: indexedIntent.depositLocalId,
|
|
1269
|
-
amount: indexedIntent.amount,
|
|
1270
|
-
timestamp: indexedIntent.timestamp,
|
|
1271
|
-
paymentMethod: indexedIntent.paymentMethodId,
|
|
1272
|
-
fiatCurrency: indexedIntent.fiatCurrency,
|
|
1273
|
-
conversionRate: indexedIntent.conversionRate
|
|
1274
|
-
};
|
|
1275
|
-
}, [indexedIntent]);
|
|
1276
|
-
const expiryTime = indexedIntent?.expiryTime ?? null;
|
|
1277
|
-
const depositQuery = useQuery({
|
|
1278
|
-
queryKey: ["provex", "deposit", indexedIntent?.escrow, indexedIntent?.depositLocalId, chainId],
|
|
1279
|
-
queryFn: () => indexer.getDepositWithVerifiers({
|
|
1280
|
-
escrow: indexedIntent.escrow,
|
|
1281
|
-
localId: indexedIntent.depositLocalId,
|
|
1282
|
-
chainId
|
|
1283
|
-
}),
|
|
1284
|
-
enabled: !!indexedIntent,
|
|
1285
|
-
staleTime: Infinity
|
|
1286
|
-
});
|
|
1287
|
-
const deposit = depositQuery.data ?? null;
|
|
1288
|
-
const providerKey = useMemo(() => {
|
|
1289
|
-
if (!deposit || !indexedIntent) return null;
|
|
1290
|
-
return verifierGetsKey(deposit.chainId, indexedIntent.paymentMethodId);
|
|
1291
|
-
}, [deposit, indexedIntent]);
|
|
1292
|
-
const userId = useMemo(() => {
|
|
1293
|
-
if (!deposit || !providerKey) return null;
|
|
1294
|
-
const verifier = deposit.verifiers.find(
|
|
1295
|
-
(v) => verifierGetsKey(deposit.chainId, v.paymentMethodId) === providerKey
|
|
1296
|
-
);
|
|
1297
|
-
return verifier?.payeeDetailsHash ?? null;
|
|
1298
|
-
}, [deposit, providerKey]);
|
|
1299
|
-
const apiProviderKey = useMemo(() => {
|
|
1300
|
-
if (!providerKey) return null;
|
|
1301
|
-
if (isSubProviderKey(providerKey)) {
|
|
1302
|
-
return getParentProviderKey(providerKey);
|
|
1303
|
-
}
|
|
1304
|
-
return providerKey;
|
|
1305
|
-
}, [providerKey]);
|
|
1306
|
-
const payeeDetailsQuery = useQuery({
|
|
1307
|
-
queryKey: ["provex", "payeeDetails", apiProviderKey, userId],
|
|
1308
|
-
queryFn: async () => {
|
|
1309
|
-
if (!userId || !apiProviderKey) return null;
|
|
1310
|
-
try {
|
|
1311
|
-
const response = await apiClient.get(
|
|
1312
|
-
`/api/v1/makers/${apiProviderKey}/${userId}`
|
|
1313
|
-
);
|
|
1314
|
-
return response.responseObject ?? null;
|
|
1315
|
-
} catch {
|
|
1316
|
-
return null;
|
|
1317
|
-
}
|
|
1318
|
-
},
|
|
1319
|
-
enabled: !!userId && !!apiProviderKey,
|
|
1320
|
-
staleTime: Infinity,
|
|
1321
|
-
retry: false
|
|
1322
|
-
});
|
|
1323
|
-
const payeeDetails = payeeDetailsQuery.data ?? null;
|
|
1324
|
-
const isFetching = intentQuery.isFetching || depositQuery.isFetching;
|
|
1325
|
-
const refetch = useCallback(() => {
|
|
1326
|
-
queryClient.invalidateQueries({ queryKey: ["provex", "intent", intentHash] });
|
|
1327
|
-
}, [queryClient, intentHash]);
|
|
1328
|
-
const refetchAll = useCallback(async () => {
|
|
1329
|
-
const [intentResult] = await Promise.all([
|
|
1330
|
-
intentQuery.refetch(),
|
|
1331
|
-
depositQuery.refetch(),
|
|
1332
|
-
payeeDetailsQuery.refetch()
|
|
1333
|
-
]);
|
|
1334
|
-
const updated = intentResult.data;
|
|
1335
|
-
if (!updated) return null;
|
|
1336
|
-
return updated.status;
|
|
1337
|
-
}, [intentQuery, depositQuery, payeeDetailsQuery]);
|
|
1338
|
-
return useMemo(() => ({
|
|
1339
|
-
intentStatus,
|
|
1340
|
-
isFetching,
|
|
1341
|
-
isValid: !!intent,
|
|
1342
|
-
intent,
|
|
1343
|
-
providerKey,
|
|
1344
|
-
userId,
|
|
1345
|
-
payeeDetails,
|
|
1346
|
-
deposit,
|
|
1347
|
-
expiryTime,
|
|
1348
|
-
isV2Intent: false,
|
|
1349
|
-
// Adapter only returns V3 intents
|
|
1350
|
-
isPruned: indexedIntent?.status === "pruned",
|
|
1351
|
-
prunedAt: indexedIntent?.prunedAt ?? null,
|
|
1352
|
-
isFulfilled: indexedIntent?.status === "fulfilled",
|
|
1353
|
-
refetch,
|
|
1354
|
-
refetchAll
|
|
1355
|
-
}), [
|
|
1356
|
-
intentStatus,
|
|
1357
|
-
isFetching,
|
|
1358
|
-
intent,
|
|
1359
|
-
providerKey,
|
|
1360
|
-
userId,
|
|
1361
|
-
payeeDetails,
|
|
1362
|
-
deposit,
|
|
1363
|
-
expiryTime,
|
|
1364
|
-
indexedIntent,
|
|
1365
|
-
refetch,
|
|
1366
|
-
refetchAll
|
|
1367
|
-
]);
|
|
1368
|
-
}
|
|
1369
|
-
var FEE_CACHE_STALE_TIME = 60 * 60 * 1e3;
|
|
1370
|
-
function useProtocolFees({
|
|
1371
|
-
chainId,
|
|
1372
|
-
escrowAddress,
|
|
1373
|
-
enabled = true
|
|
1374
|
-
}) {
|
|
1375
|
-
const {
|
|
1376
|
-
data: orchestratorAddress,
|
|
1377
|
-
isLoading: isLoadingOrchestrator,
|
|
1378
|
-
isError: isErrorOrchestrator,
|
|
1379
|
-
error: errorOrchestrator,
|
|
1380
|
-
refetch: refetchOrchestrator
|
|
1381
|
-
} = useReadContract({
|
|
1382
|
-
address: escrowAddress,
|
|
1383
|
-
abi: V3EscrowAbi,
|
|
1384
|
-
functionName: "orchestrator",
|
|
1385
|
-
chainId,
|
|
1386
|
-
query: {
|
|
1387
|
-
enabled,
|
|
1388
|
-
staleTime: FEE_CACHE_STALE_TIME,
|
|
1389
|
-
gcTime: FEE_CACHE_STALE_TIME
|
|
1390
|
-
}
|
|
1391
|
-
});
|
|
1392
|
-
const {
|
|
1393
|
-
data: feeData,
|
|
1394
|
-
isLoading: isLoadingFees,
|
|
1395
|
-
isError: isErrorFees,
|
|
1396
|
-
error: errorFees,
|
|
1397
|
-
refetch: refetchFees
|
|
1398
|
-
} = useReadContracts({
|
|
1399
|
-
contracts: [
|
|
1400
|
-
{
|
|
1401
|
-
address: orchestratorAddress,
|
|
1402
|
-
abi: OrchestratorAbi,
|
|
1403
|
-
functionName: "protocolFee",
|
|
1404
|
-
chainId
|
|
1405
|
-
},
|
|
1406
|
-
{
|
|
1407
|
-
address: orchestratorAddress,
|
|
1408
|
-
abi: OrchestratorAbi,
|
|
1409
|
-
functionName: "protocolFeeRecipient",
|
|
1410
|
-
chainId
|
|
1411
|
-
}
|
|
1412
|
-
],
|
|
1413
|
-
query: {
|
|
1414
|
-
enabled: enabled && !!orchestratorAddress,
|
|
1415
|
-
staleTime: FEE_CACHE_STALE_TIME,
|
|
1416
|
-
gcTime: FEE_CACHE_STALE_TIME
|
|
1417
|
-
}
|
|
1418
|
-
});
|
|
1419
|
-
const protocolFeeRaw = feeData?.[0]?.result;
|
|
1420
|
-
const protocolFeeRecipient = feeData?.[1]?.result;
|
|
1421
|
-
const feeInfo = useMemo(() => {
|
|
1422
|
-
if (protocolFeeRaw === void 0) return void 0;
|
|
1423
|
-
return normalizeFeePrecision(protocolFeeRaw);
|
|
1424
|
-
}, [protocolFeeRaw]);
|
|
1425
|
-
const isFeeQueryPending = !!orchestratorAddress && protocolFeeRaw === void 0 && !isErrorFees;
|
|
1426
|
-
const isLoading = isLoadingOrchestrator || isLoadingFees || isFeeQueryPending;
|
|
1427
|
-
const isError = isErrorOrchestrator || isErrorFees;
|
|
1428
|
-
const error = errorOrchestrator || errorFees || null;
|
|
1429
|
-
const refetch = () => {
|
|
1430
|
-
refetchOrchestrator();
|
|
1431
|
-
refetchFees();
|
|
1432
|
-
};
|
|
1433
|
-
return {
|
|
1434
|
-
protocolFeeRaw,
|
|
1435
|
-
feeInfo,
|
|
1436
|
-
protocolFeeRecipient,
|
|
1437
|
-
orchestratorAddress,
|
|
1438
|
-
isLoading,
|
|
1439
|
-
isError,
|
|
1440
|
-
error,
|
|
1441
|
-
refetch
|
|
1442
|
-
};
|
|
1443
|
-
}
|
|
1444
|
-
function useProtocolFeePercentage(params) {
|
|
1445
|
-
const { feeInfo } = useProtocolFees(params);
|
|
1446
|
-
return feeInfo?.percentage;
|
|
1447
|
-
}
|
|
1448
|
-
|
|
1449
|
-
// src/useProvexBuy.ts
|
|
1450
|
-
function parseAmountSafe(value, decimals) {
|
|
1451
|
-
if (!value || value === "." || value === "0.") return null;
|
|
1452
|
-
try {
|
|
1453
|
-
const parsed = parseUnits(value, { decimals });
|
|
1454
|
-
return parsed > 0n ? parsed : null;
|
|
1455
|
-
} catch {
|
|
1456
|
-
return null;
|
|
1457
|
-
}
|
|
1458
|
-
}
|
|
1459
|
-
function useProvexBuy({
|
|
1460
|
-
wallet,
|
|
1461
|
-
onIntentSignaled,
|
|
1462
|
-
onComplete,
|
|
1463
|
-
paymentMethods: allowedPaymentMethods
|
|
1464
|
-
}) {
|
|
1465
|
-
const { config } = useProvex();
|
|
1466
|
-
const [phase, setPhase] = useState("browse");
|
|
1467
|
-
const [amount, setAmountRaw] = useState("");
|
|
1468
|
-
const [selectedPaymentMethod, setSelectedPaymentMethod] = useState("");
|
|
1469
|
-
const [selectedDeposit, setSelectedDeposit] = useState(null);
|
|
1470
|
-
const [intentHash, setIntentHash] = useState(null);
|
|
1471
|
-
const [errorMessage, setErrorMessage] = useState(null);
|
|
1472
|
-
const chainId = config.chain?.id ?? config.chainId;
|
|
1473
|
-
const token = useMemo(() => getDefaultToken(chainId), [chainId]);
|
|
1474
|
-
const currency = SUPPORTED_CURRENCIES.USD;
|
|
1475
|
-
const availablePaymentMethods = useMemo(() => {
|
|
1476
|
-
const all = verifiablePaymentMethods(chainId);
|
|
1477
|
-
if (!allowedPaymentMethods || allowedPaymentMethods.length === 0) return all;
|
|
1478
|
-
return all.filter((pm) => allowedPaymentMethods.includes(pm));
|
|
1479
|
-
}, [chainId, allowedPaymentMethods]);
|
|
1480
|
-
const activePaymentMethod = useMemo(() => {
|
|
1481
|
-
if (selectedPaymentMethod) return selectedPaymentMethod;
|
|
1482
|
-
return availablePaymentMethods[0] ?? null;
|
|
1483
|
-
}, [selectedPaymentMethod, availablePaymentMethods]);
|
|
1484
|
-
const depositsResult = useDeposits({
|
|
1485
|
-
token,
|
|
1486
|
-
paymentMethod: activePaymentMethod,
|
|
1487
|
-
currency
|
|
1488
|
-
});
|
|
1489
|
-
const { reputation } = useReputation({
|
|
1490
|
-
address: wallet.address,
|
|
1491
|
-
chainId
|
|
1492
|
-
});
|
|
1493
|
-
const amountBigInt = useMemo(
|
|
1494
|
-
() => parseAmountSafe(amount, currency.decimals),
|
|
1495
|
-
[amount, currency.decimals]
|
|
1496
|
-
);
|
|
1497
|
-
const limits = useReputationLimits({
|
|
1498
|
-
chainId,
|
|
1499
|
-
selectedPaymentMethod: activePaymentMethod,
|
|
1500
|
-
tier: reputation.tier,
|
|
1501
|
-
amountInInt: amountBigInt,
|
|
1502
|
-
cooldownEndsAt: reputation.cooldownEndsAt
|
|
1503
|
-
});
|
|
1504
|
-
const signalIntent = useSignalIntent({
|
|
1505
|
-
wallet,
|
|
1506
|
-
chainId,
|
|
1507
|
-
deposit: selectedDeposit,
|
|
1508
|
-
onSuccess: (hash) => {
|
|
1509
|
-
setIntentHash(hash);
|
|
1510
|
-
setPhase("committed");
|
|
1511
|
-
onIntentSignaled?.(hash, chainId);
|
|
1512
|
-
},
|
|
1513
|
-
onFailure: () => {
|
|
1514
|
-
setErrorMessage("Order failed. Please try again.");
|
|
1515
|
-
},
|
|
1516
|
-
refetchDeposits: depositsResult.refetch
|
|
1517
|
-
});
|
|
1518
|
-
const escrowAddress = useMemo(
|
|
1519
|
-
() => getLatestContract(chainId, "escrow"),
|
|
1520
|
-
[chainId]
|
|
1521
|
-
);
|
|
1522
|
-
const { feeInfo } = useProtocolFees({
|
|
1523
|
-
chainId,
|
|
1524
|
-
escrowAddress: escrowAddress ?? "0x",
|
|
1525
|
-
enabled: !!escrowAddress
|
|
1526
|
-
});
|
|
1527
|
-
const payeeResult = usePayeeDetails({
|
|
1528
|
-
intentHash,
|
|
1529
|
-
chainId
|
|
1530
|
-
});
|
|
1531
|
-
const refetchAllRef = useRef(payeeResult.refetchAll);
|
|
1532
|
-
refetchAllRef.current = payeeResult.refetchAll;
|
|
1533
|
-
useEffect(() => {
|
|
1534
|
-
if (phase !== "committed" && phase !== "proving") return;
|
|
1535
|
-
if (!intentHash) return;
|
|
1536
|
-
const interval = setInterval(() => {
|
|
1537
|
-
refetchAllRef.current();
|
|
1538
|
-
}, 5e3);
|
|
1539
|
-
return () => clearInterval(interval);
|
|
1540
|
-
}, [phase, intentHash]);
|
|
1541
|
-
useEffect(() => {
|
|
1542
|
-
if (!payeeResult.isFulfilled) return;
|
|
1543
|
-
if (phase === "complete") return;
|
|
1544
|
-
setPhase("complete");
|
|
1545
|
-
if (intentHash) onComplete?.(intentHash, chainId);
|
|
1546
|
-
}, [payeeResult.isFulfilled, phase, intentHash, chainId, onComplete]);
|
|
1547
|
-
useEffect(() => {
|
|
1548
|
-
if (!payeeResult.isPruned) return;
|
|
1549
|
-
if (phase === "browse") return;
|
|
1550
|
-
setErrorMessage("Order expired. Please try again.");
|
|
1551
|
-
setPhase("browse");
|
|
1552
|
-
}, [payeeResult.isPruned, phase]);
|
|
1553
|
-
const intentExpiryTime = useMemo(() => {
|
|
1554
|
-
if (!payeeResult.expiryTime) return null;
|
|
1555
|
-
return new Date(Number(payeeResult.expiryTime) * 1e3);
|
|
1556
|
-
}, [payeeResult.expiryTime]);
|
|
1557
|
-
const matchableDeposits = useMemo(() => {
|
|
1558
|
-
if (!amountBigInt) return [];
|
|
1559
|
-
return depositsResult.getMatchableDeposits(amountBigInt);
|
|
1560
|
-
}, [amountBigInt, depositsResult]);
|
|
1561
|
-
const bestDeposit = matchableDeposits[0] ?? null;
|
|
1562
|
-
const bestRate = useMemo(() => {
|
|
1563
|
-
if (!bestDeposit || !activePaymentMethod) return null;
|
|
1564
|
-
const r = getRate({ deposit: bestDeposit, paymentMethod: activePaymentMethod, currency });
|
|
1565
|
-
return r === 0n ? null : r;
|
|
1566
|
-
}, [bestDeposit, activePaymentMethod, currency]);
|
|
1567
|
-
const tokenAmount = useMemo(() => {
|
|
1568
|
-
if (!amountBigInt || !bestRate || !token) return null;
|
|
1569
|
-
return convertCurrencyToTokenOutput({
|
|
1570
|
-
token,
|
|
1571
|
-
currency,
|
|
1572
|
-
currencyAmountInt: amountBigInt,
|
|
1573
|
-
rate: bestRate
|
|
1574
|
-
});
|
|
1575
|
-
}, [amountBigInt, bestRate, token, currency]);
|
|
1576
|
-
const rateDisplay = useMemo(() => {
|
|
1577
|
-
if (!bestRate || !token) return null;
|
|
1578
|
-
const rateFloat = Number(bestRate) / 1e18;
|
|
1579
|
-
return `1 ${token.symbol} = ${currency.symbol}${rateFloat.toFixed(currency.decimals)}`;
|
|
1580
|
-
}, [bestRate, token, currency]);
|
|
1581
|
-
const tokenAmountDisplay = useMemo(() => {
|
|
1582
|
-
if (!tokenAmount || !token) return null;
|
|
1583
|
-
return formatUnits(tokenAmount, { decimals: token.decimals });
|
|
1584
|
-
}, [tokenAmount, token]);
|
|
1585
|
-
const canSubmit = useMemo(() => {
|
|
1586
|
-
if (!wallet.address) return false;
|
|
1587
|
-
if (!activePaymentMethod) return false;
|
|
1588
|
-
if (!amountBigInt || amountBigInt <= 0n) return false;
|
|
1589
|
-
if (!bestDeposit) return false;
|
|
1590
|
-
if (limits.isOnCooldown) return false;
|
|
1591
|
-
if (limits.amountExceedsCap) return false;
|
|
1592
|
-
if (signalIntent.isLoading) return false;
|
|
1593
|
-
return true;
|
|
1594
|
-
}, [wallet.address, activePaymentMethod, amountBigInt, bestDeposit, limits, signalIntent.isLoading]);
|
|
1595
|
-
const validationMessage = useMemo(() => {
|
|
1596
|
-
if (!wallet.address) return "Connect your wallet to continue";
|
|
1597
|
-
if (!activePaymentMethod) return "Select a payment method";
|
|
1598
|
-
if (!amount) return null;
|
|
1599
|
-
if (!amountBigInt || amountBigInt <= 0n) return "Enter a valid amount";
|
|
1600
|
-
if (limits.isOnCooldown && limits.cooldownRemaining) {
|
|
1601
|
-
return `Cooldown active: ${limits.cooldownRemaining} remaining`;
|
|
1602
|
-
}
|
|
1603
|
-
if (limits.capExceededMessage) return limits.capExceededMessage;
|
|
1604
|
-
if (depositsResult.isLoading) return "Loading available orders...";
|
|
1605
|
-
if (!bestDeposit && amount) return "No orders available for this amount";
|
|
1606
|
-
return null;
|
|
1607
|
-
}, [wallet.address, activePaymentMethod, amount, amountBigInt, limits, depositsResult.isLoading, bestDeposit]);
|
|
1608
|
-
const setAmount = useCallback((value) => {
|
|
1609
|
-
if (value === "" || /^\d*\.?\d*$/.test(value)) {
|
|
1610
|
-
setAmountRaw(value);
|
|
1611
|
-
setErrorMessage(null);
|
|
1612
|
-
}
|
|
1613
|
-
}, []);
|
|
1614
|
-
const selectDeposit = useCallback((deposit) => {
|
|
1615
|
-
setSelectedDeposit(deposit);
|
|
1616
|
-
}, []);
|
|
1617
|
-
const submitOrder = useCallback(async () => {
|
|
1618
|
-
if (!canSubmit || !bestDeposit || !tokenAmount || !activePaymentMethod || !wallet.address) return;
|
|
1619
|
-
setSelectedDeposit(bestDeposit);
|
|
1620
|
-
setErrorMessage(null);
|
|
1621
|
-
const paymentMethodContractId = providerKeyToContractId(activePaymentMethod);
|
|
1622
|
-
await signalIntent.startOrder({
|
|
1623
|
-
paymentMethod: paymentMethodContractId,
|
|
1624
|
-
depositId: bestDeposit.localId,
|
|
1625
|
-
tokenAmount,
|
|
1626
|
-
toAddress: wallet.address,
|
|
1627
|
-
fiatCurrencyCode: currency.contractId,
|
|
1628
|
-
conversionRate: bestRate
|
|
1629
|
-
});
|
|
1630
|
-
}, [canSubmit, bestDeposit, tokenAmount, activePaymentMethod, wallet.address, signalIntent, currency.contractId, bestRate]);
|
|
1631
|
-
const confirmPayment = useCallback(() => {
|
|
1632
|
-
setPhase("proving");
|
|
1633
|
-
}, []);
|
|
1634
|
-
const reset = useCallback(() => {
|
|
1635
|
-
setPhase("browse");
|
|
1636
|
-
setAmountRaw("");
|
|
1637
|
-
setSelectedPaymentMethod("");
|
|
1638
|
-
setSelectedDeposit(null);
|
|
1639
|
-
setIntentHash(null);
|
|
1640
|
-
setErrorMessage(null);
|
|
1641
|
-
}, []);
|
|
1642
|
-
return {
|
|
1643
|
-
phase,
|
|
1644
|
-
amount,
|
|
1645
|
-
setAmount,
|
|
1646
|
-
selectedPaymentMethod,
|
|
1647
|
-
setSelectedPaymentMethod,
|
|
1648
|
-
availablePaymentMethods,
|
|
1649
|
-
deposits: depositsResult.deposits,
|
|
1650
|
-
selectedDeposit,
|
|
1651
|
-
selectDeposit,
|
|
1652
|
-
isLoadingDeposits: depositsResult.isLoading,
|
|
1653
|
-
rate: bestRate,
|
|
1654
|
-
rateDisplay,
|
|
1655
|
-
tokenAmount,
|
|
1656
|
-
tokenAmountDisplay,
|
|
1657
|
-
token,
|
|
1658
|
-
currency,
|
|
1659
|
-
reputation: reputation ?? DEFAULT_REPUTATION,
|
|
1660
|
-
limits,
|
|
1661
|
-
feePercentage: feeInfo?.percentage ?? null,
|
|
1662
|
-
payeeDetails: payeeResult.payeeDetails,
|
|
1663
|
-
payeeName: payeeResult.payeeDetails?.name ?? null,
|
|
1664
|
-
payeeId: payeeResult.payeeDetails?.payeeId ?? null,
|
|
1665
|
-
isPayeeLoading: payeeResult.isFetching,
|
|
1666
|
-
intentExpiryTime,
|
|
1667
|
-
isIntentExpired: payeeResult.isPruned,
|
|
1668
|
-
indexedIntentStatus: payeeResult.intentStatus,
|
|
1669
|
-
canSubmit,
|
|
1670
|
-
validationMessage,
|
|
1671
|
-
submitOrder,
|
|
1672
|
-
confirmPayment,
|
|
1673
|
-
reset,
|
|
1674
|
-
intentHash,
|
|
1675
|
-
intentStatus: signalIntent.status,
|
|
1676
|
-
intentError: errorMessage ?? signalIntent.message,
|
|
1677
|
-
isSubmitting: signalIntent.isLoading,
|
|
1678
|
-
chainId
|
|
1679
|
-
};
|
|
1680
|
-
}
|
|
1681
|
-
var ProvexBuyContext = createContext(null);
|
|
1682
|
-
function useProvexBuyContext() {
|
|
1683
|
-
const ctx = useContext(ProvexBuyContext);
|
|
1684
|
-
if (!ctx) {
|
|
1685
|
-
throw new Error(
|
|
1686
|
-
"useProvexBuyContext must be used within a <ProvexBuyProvider>. Wrap your component tree with <ProvexBuyProvider> or use useProvexBuy() directly."
|
|
1687
|
-
);
|
|
1688
|
-
}
|
|
1689
|
-
return ctx;
|
|
1690
|
-
}
|
|
1691
|
-
function ProvexBuyProvider({
|
|
1692
|
-
children,
|
|
1693
|
-
...options
|
|
1694
|
-
}) {
|
|
1695
|
-
const buy = useProvexBuy(options);
|
|
1696
|
-
return /* @__PURE__ */ jsx(ProvexBuyContext.Provider, { value: buy, children });
|
|
1697
|
-
}
|
|
1698
|
-
var STATUS_MESSAGES = {
|
|
1699
|
-
input: "",
|
|
1700
|
-
loading_payee: "Loading payment details...",
|
|
1701
|
-
loading_intent: "Requesting signature...",
|
|
1702
|
-
loading_orchestrator: "Loading orchestrator...",
|
|
1703
|
-
prompt_wallet_confirm: "Confirm in your wallet...",
|
|
1704
|
-
writing_intent: "Submitting transaction...",
|
|
1705
|
-
success: "Order placed successfully!",
|
|
1706
|
-
error: "Something went wrong."
|
|
1707
|
-
};
|
|
1708
|
-
function BrowsePhase({
|
|
1709
|
-
className,
|
|
1710
|
-
style,
|
|
1711
|
-
render
|
|
1712
|
-
}) {
|
|
1713
|
-
const ctx = useProvexBuyContext();
|
|
1714
|
-
if (ctx.phase !== "browse") return null;
|
|
1715
|
-
const state = {
|
|
1716
|
-
amount: ctx.amount,
|
|
1717
|
-
setAmount: ctx.setAmount,
|
|
1718
|
-
selectedPaymentMethod: ctx.selectedPaymentMethod,
|
|
1719
|
-
setSelectedPaymentMethod: ctx.setSelectedPaymentMethod,
|
|
1720
|
-
availablePaymentMethods: ctx.availablePaymentMethods,
|
|
1721
|
-
chainId: ctx.chainId,
|
|
1722
|
-
rateDisplay: ctx.rateDisplay,
|
|
1723
|
-
tokenAmountDisplay: ctx.tokenAmountDisplay,
|
|
1724
|
-
token: ctx.token,
|
|
1725
|
-
currency: ctx.currency,
|
|
1726
|
-
canSubmit: ctx.canSubmit,
|
|
1727
|
-
isSubmitting: ctx.isSubmitting,
|
|
1728
|
-
validationMessage: ctx.validationMessage,
|
|
1729
|
-
intentError: ctx.intentError,
|
|
1730
|
-
intentStatus: ctx.intentStatus,
|
|
1731
|
-
isLoadingDeposits: ctx.isLoadingDeposits,
|
|
1732
|
-
deposits: ctx.deposits,
|
|
1733
|
-
submitOrder: ctx.submitOrder
|
|
1734
|
-
};
|
|
1735
|
-
if (render) return /* @__PURE__ */ jsx(Fragment, { children: render(state) });
|
|
1736
|
-
const tokenSymbol = ctx.token?.symbol ?? "USDC";
|
|
1737
|
-
const matchCount = ctx.deposits.length;
|
|
1738
|
-
const statusMessage = STATUS_MESSAGES[ctx.intentStatus] ?? "";
|
|
1739
|
-
return /* @__PURE__ */ jsxs(
|
|
1740
|
-
"div",
|
|
1741
|
-
{
|
|
1742
|
-
"data-provex-phase": "browse",
|
|
1743
|
-
"data-provex-section": "browse",
|
|
1744
|
-
className,
|
|
1745
|
-
style,
|
|
1746
|
-
children: [
|
|
1747
|
-
/* @__PURE__ */ jsxs("div", { "data-provex-field": "payment-method", children: [
|
|
1748
|
-
/* @__PURE__ */ jsx("label", { "data-provex-label": "payment-method", htmlFor: "provex-payment-method", children: "Payment Method" }),
|
|
1749
|
-
/* @__PURE__ */ jsx(
|
|
1750
|
-
"select",
|
|
1751
|
-
{
|
|
1752
|
-
"data-provex-select": "payment-method",
|
|
1753
|
-
id: "provex-payment-method",
|
|
1754
|
-
value: ctx.selectedPaymentMethod || (ctx.availablePaymentMethods[0] ?? ""),
|
|
1755
|
-
onChange: (e) => ctx.setSelectedPaymentMethod(e.target.value),
|
|
1756
|
-
children: ctx.availablePaymentMethods.map((pm) => /* @__PURE__ */ jsx("option", { value: pm, children: getPaymentMethodName(ctx.chainId, pm) }, pm))
|
|
1757
|
-
}
|
|
1758
|
-
)
|
|
1759
|
-
] }),
|
|
1760
|
-
/* @__PURE__ */ jsxs("div", { "data-provex-field": "amount", children: [
|
|
1761
|
-
/* @__PURE__ */ jsxs("label", { "data-provex-label": "amount", htmlFor: "provex-amount", children: [
|
|
1762
|
-
"Amount (",
|
|
1763
|
-
ctx.currency?.ticker ?? "USD",
|
|
1764
|
-
")"
|
|
1765
|
-
] }),
|
|
1766
|
-
/* @__PURE__ */ jsxs("div", { "data-provex-input-group": "amount", children: [
|
|
1767
|
-
/* @__PURE__ */ jsx("span", { "data-provex-input-prefix": "", children: ctx.currency?.symbol ?? "$" }),
|
|
1768
|
-
/* @__PURE__ */ jsx(
|
|
1769
|
-
"input",
|
|
1770
|
-
{
|
|
1771
|
-
"data-provex-input": "amount",
|
|
1772
|
-
id: "provex-amount",
|
|
1773
|
-
type: "text",
|
|
1774
|
-
inputMode: "decimal",
|
|
1775
|
-
placeholder: "0.00",
|
|
1776
|
-
value: ctx.amount,
|
|
1777
|
-
onChange: (e) => ctx.setAmount(e.target.value),
|
|
1778
|
-
autoComplete: "off"
|
|
1779
|
-
}
|
|
1780
|
-
)
|
|
1781
|
-
] })
|
|
1782
|
-
] }),
|
|
1783
|
-
ctx.rateDisplay && /* @__PURE__ */ jsxs("div", { "data-provex-info": "rate", children: [
|
|
1784
|
-
/* @__PURE__ */ jsx("span", { "data-provex-label": "rate", children: "Rate" }),
|
|
1785
|
-
/* @__PURE__ */ jsx("span", { "data-provex-value": "rate", children: ctx.rateDisplay })
|
|
1786
|
-
] }),
|
|
1787
|
-
ctx.tokenAmountDisplay && /* @__PURE__ */ jsxs("div", { "data-provex-info": "receive", children: [
|
|
1788
|
-
/* @__PURE__ */ jsx("span", { "data-provex-label": "receive", children: "You receive" }),
|
|
1789
|
-
/* @__PURE__ */ jsxs("span", { "data-provex-value": "receive", children: [
|
|
1790
|
-
ctx.tokenAmountDisplay,
|
|
1791
|
-
" ",
|
|
1792
|
-
tokenSymbol
|
|
1793
|
-
] })
|
|
1794
|
-
] }),
|
|
1795
|
-
ctx.isLoadingDeposits && ctx.amount && /* @__PURE__ */ jsx("div", { "data-provex-info": "loading", children: /* @__PURE__ */ jsx("span", { "data-provex-status": "loading", children: "Searching for orders..." }) }),
|
|
1796
|
-
!ctx.isLoadingDeposits && ctx.amount && matchCount > 0 && /* @__PURE__ */ jsx("div", { "data-provex-info": "match-count", children: /* @__PURE__ */ jsxs("span", { "data-provex-value": "match-count", children: [
|
|
1797
|
-
matchCount,
|
|
1798
|
-
" order",
|
|
1799
|
-
matchCount !== 1 ? "s" : "",
|
|
1800
|
-
" available"
|
|
1801
|
-
] }) }),
|
|
1802
|
-
ctx.validationMessage && /* @__PURE__ */ jsx("p", { "data-provex-message": "validation", children: ctx.validationMessage }),
|
|
1803
|
-
ctx.intentError && /* @__PURE__ */ jsx("p", { "data-provex-message": "error", children: ctx.intentError }),
|
|
1804
|
-
ctx.isSubmitting && statusMessage && /* @__PURE__ */ jsx("p", { "data-provex-message": "status", children: statusMessage }),
|
|
1805
|
-
/* @__PURE__ */ jsx(
|
|
1806
|
-
"button",
|
|
1807
|
-
{
|
|
1808
|
-
"data-provex-button": "buy",
|
|
1809
|
-
type: "button",
|
|
1810
|
-
disabled: !ctx.canSubmit,
|
|
1811
|
-
onClick: ctx.submitOrder,
|
|
1812
|
-
children: ctx.isSubmitting ? "Processing..." : "Buy"
|
|
1813
|
-
}
|
|
1814
|
-
)
|
|
1815
|
-
]
|
|
1816
|
-
}
|
|
1817
|
-
);
|
|
1818
|
-
}
|
|
1819
|
-
function CommittedPhase({
|
|
1820
|
-
className,
|
|
1821
|
-
style,
|
|
1822
|
-
render
|
|
1823
|
-
}) {
|
|
1824
|
-
const ctx = useProvexBuyContext();
|
|
1825
|
-
if (ctx.phase !== "committed") return null;
|
|
1826
|
-
const state = {
|
|
1827
|
-
intentHash: ctx.intentHash,
|
|
1828
|
-
amount: ctx.amount,
|
|
1829
|
-
currency: ctx.currency,
|
|
1830
|
-
selectedPaymentMethod: ctx.selectedPaymentMethod,
|
|
1831
|
-
chainId: ctx.chainId,
|
|
1832
|
-
tokenAmountDisplay: ctx.tokenAmountDisplay,
|
|
1833
|
-
token: ctx.token,
|
|
1834
|
-
confirmPayment: ctx.confirmPayment,
|
|
1835
|
-
payeeDetails: ctx.payeeDetails,
|
|
1836
|
-
payeeName: ctx.payeeName,
|
|
1837
|
-
payeeId: ctx.payeeId,
|
|
1838
|
-
isPayeeLoading: ctx.isPayeeLoading,
|
|
1839
|
-
intentExpiryTime: ctx.intentExpiryTime
|
|
1840
|
-
};
|
|
1841
|
-
if (render) return /* @__PURE__ */ jsx(Fragment, { children: render(state) });
|
|
1842
|
-
const tokenSymbol = ctx.token?.symbol ?? "USDC";
|
|
1843
|
-
const paymentName = ctx.selectedPaymentMethod ? getPaymentMethodName(ctx.chainId, ctx.selectedPaymentMethod) : "Unknown";
|
|
1844
|
-
return /* @__PURE__ */ jsxs(
|
|
1845
|
-
"div",
|
|
1846
|
-
{
|
|
1847
|
-
"data-provex-phase": "committed",
|
|
1848
|
-
"data-provex-section": "committed",
|
|
1849
|
-
className,
|
|
1850
|
-
style,
|
|
1851
|
-
children: [
|
|
1852
|
-
/* @__PURE__ */ jsxs("div", { "data-provex-info": "order-summary", children: [
|
|
1853
|
-
/* @__PURE__ */ jsx("p", { "data-provex-heading": "committed", children: "Order Placed" }),
|
|
1854
|
-
/* @__PURE__ */ jsxs("div", { "data-provex-detail": "amount", children: [
|
|
1855
|
-
/* @__PURE__ */ jsx("span", { "data-provex-label": "amount", children: "Amount" }),
|
|
1856
|
-
/* @__PURE__ */ jsxs("span", { "data-provex-value": "amount", children: [
|
|
1857
|
-
ctx.currency?.symbol,
|
|
1858
|
-
ctx.amount
|
|
1859
|
-
] })
|
|
1860
|
-
] }),
|
|
1861
|
-
/* @__PURE__ */ jsxs("div", { "data-provex-detail": "receive", children: [
|
|
1862
|
-
/* @__PURE__ */ jsx("span", { "data-provex-label": "receive", children: "You receive" }),
|
|
1863
|
-
/* @__PURE__ */ jsxs("span", { "data-provex-value": "receive", children: [
|
|
1864
|
-
ctx.tokenAmountDisplay,
|
|
1865
|
-
" ",
|
|
1866
|
-
tokenSymbol
|
|
1867
|
-
] })
|
|
1868
|
-
] }),
|
|
1869
|
-
/* @__PURE__ */ jsxs("div", { "data-provex-detail": "payment-method", children: [
|
|
1870
|
-
/* @__PURE__ */ jsx("span", { "data-provex-label": "payment-method", children: "Pay via" }),
|
|
1871
|
-
/* @__PURE__ */ jsx("span", { "data-provex-value": "payment-method", children: paymentName })
|
|
1872
|
-
] }),
|
|
1873
|
-
ctx.intentHash && /* @__PURE__ */ jsxs("div", { "data-provex-detail": "intent-hash", children: [
|
|
1874
|
-
/* @__PURE__ */ jsx("span", { "data-provex-label": "intent-hash", children: "Order ID" }),
|
|
1875
|
-
/* @__PURE__ */ jsxs("span", { "data-provex-value": "intent-hash", title: ctx.intentHash, children: [
|
|
1876
|
-
ctx.intentHash.slice(0, 10),
|
|
1877
|
-
"...",
|
|
1878
|
-
ctx.intentHash.slice(-8)
|
|
1879
|
-
] })
|
|
1880
|
-
] })
|
|
1881
|
-
] }),
|
|
1882
|
-
ctx.isPayeeLoading && /* @__PURE__ */ jsx("div", { "data-provex-info": "payee-loading", children: /* @__PURE__ */ jsx("span", { "data-provex-status": "loading", children: "Loading seller details..." }) }),
|
|
1883
|
-
!ctx.isPayeeLoading && ctx.payeeId && /* @__PURE__ */ jsxs("div", { "data-provex-info": "payee", children: [
|
|
1884
|
-
ctx.payeeName && /* @__PURE__ */ jsxs("div", { "data-provex-detail": "payee-name", children: [
|
|
1885
|
-
/* @__PURE__ */ jsx("span", { "data-provex-label": "payee-name", children: "Seller" }),
|
|
1886
|
-
/* @__PURE__ */ jsx("span", { "data-provex-value": "payee-name", children: ctx.payeeName })
|
|
1887
|
-
] }),
|
|
1888
|
-
/* @__PURE__ */ jsxs("div", { "data-provex-detail": "payee-id", children: [
|
|
1889
|
-
/* @__PURE__ */ jsx("span", { "data-provex-label": "payee-id", children: "Send to" }),
|
|
1890
|
-
/* @__PURE__ */ jsx("span", { "data-provex-value": "payee-id", children: ctx.payeeId })
|
|
1891
|
-
] })
|
|
1892
|
-
] }),
|
|
1893
|
-
/* @__PURE__ */ jsx("div", { "data-provex-info": "instructions", children: /* @__PURE__ */ jsxs("p", { "data-provex-text": "instructions", children: [
|
|
1894
|
-
"Send ",
|
|
1895
|
-
ctx.currency?.symbol,
|
|
1896
|
-
ctx.amount,
|
|
1897
|
-
" via ",
|
|
1898
|
-
paymentName,
|
|
1899
|
-
" to the seller, then verify your payment to release the ",
|
|
1900
|
-
tokenSymbol,
|
|
1901
|
-
"."
|
|
1902
|
-
] }) }),
|
|
1903
|
-
/* @__PURE__ */ jsx(
|
|
1904
|
-
"button",
|
|
1905
|
-
{
|
|
1906
|
-
"data-provex-button": "prove",
|
|
1907
|
-
type: "button",
|
|
1908
|
-
disabled: ctx.isPayeeLoading,
|
|
1909
|
-
onClick: ctx.confirmPayment,
|
|
1910
|
-
children: "I have paid"
|
|
1911
|
-
}
|
|
1912
|
-
)
|
|
1913
|
-
]
|
|
1914
|
-
}
|
|
1915
|
-
);
|
|
1916
|
-
}
|
|
1917
|
-
function ProvingPhase({
|
|
1918
|
-
className,
|
|
1919
|
-
style,
|
|
1920
|
-
render
|
|
1921
|
-
}) {
|
|
1922
|
-
const ctx = useProvexBuyContext();
|
|
1923
|
-
if (ctx.phase !== "proving") return null;
|
|
1924
|
-
const state = {
|
|
1925
|
-
intentHash: ctx.intentHash,
|
|
1926
|
-
intentExpiryTime: ctx.intentExpiryTime,
|
|
1927
|
-
isIntentExpired: ctx.isIntentExpired,
|
|
1928
|
-
indexedIntentStatus: ctx.indexedIntentStatus
|
|
1929
|
-
};
|
|
1930
|
-
if (render) return /* @__PURE__ */ jsx(Fragment, { children: render(state) });
|
|
1931
|
-
const statusText = ctx.indexedIntentStatus === "fulfilled" ? "Payment verified!" : "Generating zero-knowledge proof of your payment...";
|
|
1932
|
-
return /* @__PURE__ */ jsxs(
|
|
1933
|
-
"div",
|
|
1934
|
-
{
|
|
1935
|
-
"data-provex-phase": "proving",
|
|
1936
|
-
"data-provex-section": "proving",
|
|
1937
|
-
className,
|
|
1938
|
-
style,
|
|
1939
|
-
children: [
|
|
1940
|
-
/* @__PURE__ */ jsx("p", { "data-provex-heading": "proving", children: "Verifying Payment" }),
|
|
1941
|
-
/* @__PURE__ */ jsx("p", { "data-provex-text": "proving", children: statusText }),
|
|
1942
|
-
ctx.intentHash && /* @__PURE__ */ jsxs("div", { "data-provex-detail": "intent-hash", children: [
|
|
1943
|
-
/* @__PURE__ */ jsx("span", { "data-provex-label": "intent-hash", children: "Order ID" }),
|
|
1944
|
-
/* @__PURE__ */ jsxs("span", { "data-provex-value": "intent-hash", title: ctx.intentHash, children: [
|
|
1945
|
-
ctx.intentHash.slice(0, 10),
|
|
1946
|
-
"...",
|
|
1947
|
-
ctx.intentHash.slice(-8)
|
|
1948
|
-
] })
|
|
1949
|
-
] }),
|
|
1950
|
-
/* @__PURE__ */ jsx("div", { "data-provex-info": "status", children: /* @__PURE__ */ jsx("span", { "data-provex-status": ctx.indexedIntentStatus ?? "proving", children: ctx.indexedIntentStatus === "fulfilled" ? "Complete" : "Processing..." }) })
|
|
1951
|
-
]
|
|
1952
|
-
}
|
|
1953
|
-
);
|
|
1954
|
-
}
|
|
1955
|
-
function CompletePhase({
|
|
1956
|
-
className,
|
|
1957
|
-
style,
|
|
1958
|
-
render
|
|
1959
|
-
}) {
|
|
1960
|
-
const ctx = useProvexBuyContext();
|
|
1961
|
-
if (ctx.phase !== "complete") return null;
|
|
1962
|
-
const state = {
|
|
1963
|
-
intentHash: ctx.intentHash,
|
|
1964
|
-
chainId: ctx.chainId,
|
|
1965
|
-
reset: ctx.reset
|
|
1966
|
-
};
|
|
1967
|
-
if (render) return /* @__PURE__ */ jsx(Fragment, { children: render(state) });
|
|
1968
|
-
return /* @__PURE__ */ jsxs(
|
|
1969
|
-
"div",
|
|
1970
|
-
{
|
|
1971
|
-
"data-provex-phase": "complete",
|
|
1972
|
-
"data-provex-section": "complete",
|
|
1973
|
-
className,
|
|
1974
|
-
style,
|
|
1975
|
-
children: [
|
|
1976
|
-
/* @__PURE__ */ jsx("p", { "data-provex-heading": "complete", children: "Purchase Complete" }),
|
|
1977
|
-
/* @__PURE__ */ jsx("p", { "data-provex-text": "complete", children: "Your tokens have been released to your wallet." }),
|
|
1978
|
-
ctx.intentHash && /* @__PURE__ */ jsxs("div", { "data-provex-detail": "intent-hash", children: [
|
|
1979
|
-
/* @__PURE__ */ jsx("span", { "data-provex-label": "intent-hash", children: "Order ID" }),
|
|
1980
|
-
/* @__PURE__ */ jsxs("span", { "data-provex-value": "intent-hash", title: ctx.intentHash, children: [
|
|
1981
|
-
ctx.intentHash.slice(0, 10),
|
|
1982
|
-
"...",
|
|
1983
|
-
ctx.intentHash.slice(-8)
|
|
1984
|
-
] })
|
|
1985
|
-
] }),
|
|
1986
|
-
/* @__PURE__ */ jsx(
|
|
1987
|
-
"button",
|
|
1988
|
-
{
|
|
1989
|
-
"data-provex-button": "buy-more",
|
|
1990
|
-
type: "button",
|
|
1991
|
-
onClick: ctx.reset,
|
|
1992
|
-
children: "Buy More"
|
|
1993
|
-
}
|
|
1994
|
-
)
|
|
1995
|
-
]
|
|
1996
|
-
}
|
|
1997
|
-
);
|
|
1998
|
-
}
|
|
1999
|
-
function applyTheme(baseStyle, theme) {
|
|
2000
|
-
if (!theme) return baseStyle;
|
|
2001
|
-
const vars = {};
|
|
2002
|
-
const themeEntries = [
|
|
2003
|
-
["accent", theme.accent],
|
|
2004
|
-
["background", theme.background],
|
|
2005
|
-
["backgroundCard", theme.backgroundCard],
|
|
2006
|
-
["text", theme.text],
|
|
2007
|
-
["textMuted", theme.textMuted],
|
|
2008
|
-
["border", theme.border],
|
|
2009
|
-
["error", theme.error],
|
|
2010
|
-
["radius", theme.radius],
|
|
2011
|
-
["font", theme.font]
|
|
2012
|
-
];
|
|
2013
|
-
for (const [key, value] of themeEntries) {
|
|
2014
|
-
if (value === void 0) continue;
|
|
2015
|
-
const kebab = key.replace(/[A-Z]/g, (ch) => `-${ch.toLowerCase()}`);
|
|
2016
|
-
vars[`--provex-${kebab}`] = value;
|
|
2017
|
-
}
|
|
2018
|
-
if (Object.keys(vars).length === 0) return baseStyle;
|
|
2019
|
-
return { ...baseStyle, ...vars };
|
|
2020
|
-
}
|
|
2021
|
-
function ProvexBuy({
|
|
2022
|
-
wallet,
|
|
2023
|
-
onIntentSignaled,
|
|
2024
|
-
onComplete,
|
|
2025
|
-
paymentMethods,
|
|
2026
|
-
className,
|
|
2027
|
-
style,
|
|
2028
|
-
theme
|
|
2029
|
-
}) {
|
|
2030
|
-
return /* @__PURE__ */ jsx(
|
|
2031
|
-
ProvexBuyProvider,
|
|
2032
|
-
{
|
|
2033
|
-
wallet,
|
|
2034
|
-
onIntentSignaled,
|
|
2035
|
-
onComplete,
|
|
2036
|
-
paymentMethods,
|
|
2037
|
-
children: /* @__PURE__ */ jsx(
|
|
2038
|
-
ProvexBuyRoot,
|
|
2039
|
-
{
|
|
2040
|
-
className,
|
|
2041
|
-
style: applyTheme(style, theme)
|
|
2042
|
-
}
|
|
2043
|
-
)
|
|
2044
|
-
}
|
|
2045
|
-
);
|
|
2046
|
-
}
|
|
2047
|
-
function ProvexBuyRoot({
|
|
2048
|
-
className,
|
|
2049
|
-
style
|
|
2050
|
-
}) {
|
|
2051
|
-
const { phase } = useProvexBuyContext();
|
|
2052
|
-
return /* @__PURE__ */ jsxs(
|
|
2053
|
-
"div",
|
|
2054
|
-
{
|
|
2055
|
-
className,
|
|
2056
|
-
style,
|
|
2057
|
-
"data-provex-root": "",
|
|
2058
|
-
"data-provex-phase": phase,
|
|
2059
|
-
children: [
|
|
2060
|
-
/* @__PURE__ */ jsx(BrowsePhase, {}),
|
|
2061
|
-
/* @__PURE__ */ jsx(CommittedPhase, {}),
|
|
2062
|
-
/* @__PURE__ */ jsx(ProvingPhase, {}),
|
|
2063
|
-
/* @__PURE__ */ jsx(CompletePhase, {})
|
|
2064
|
-
]
|
|
2065
|
-
}
|
|
2066
|
-
);
|
|
2067
|
-
}
|
|
2068
|
-
function useWagmiWallet() {
|
|
2069
|
-
const { address } = useAccount();
|
|
2070
|
-
const { data: walletClient } = useWalletClient();
|
|
2071
|
-
return useMemo(() => {
|
|
2072
|
-
if (!walletClient || !address) return null;
|
|
2073
|
-
return {
|
|
2074
|
-
address,
|
|
2075
|
-
async sendTransaction(tx) {
|
|
2076
|
-
return walletClient.sendTransaction({
|
|
2077
|
-
to: tx.to,
|
|
2078
|
-
data: tx.data,
|
|
2079
|
-
value: tx.value ?? 0n,
|
|
2080
|
-
chain: walletClient.chain,
|
|
2081
|
-
maxFeePerGas: tx.maxFeePerGas,
|
|
2082
|
-
maxPriorityFeePerGas: tx.maxPriorityFeePerGas
|
|
2083
|
-
});
|
|
2084
|
-
}
|
|
2085
|
-
};
|
|
2086
|
-
}, [walletClient, address]);
|
|
2087
|
-
}
|
|
2088
|
-
var DISCONNECTED_WALLET = {
|
|
2089
|
-
address: void 0,
|
|
2090
|
-
sendTransaction: () => Promise.reject(new Error("Wallet not connected"))
|
|
2091
|
-
};
|
|
2092
|
-
function ProvexBuyWagmi({
|
|
2093
|
-
onIntentSignaled,
|
|
2094
|
-
onComplete,
|
|
2095
|
-
paymentMethods,
|
|
2096
|
-
className,
|
|
2097
|
-
style,
|
|
2098
|
-
theme
|
|
2099
|
-
}) {
|
|
2100
|
-
const wallet = useWagmiWallet() ?? DISCONNECTED_WALLET;
|
|
2101
|
-
return /* @__PURE__ */ jsx(
|
|
2102
|
-
ProvexBuy,
|
|
2103
|
-
{
|
|
2104
|
-
wallet,
|
|
2105
|
-
onIntentSignaled,
|
|
2106
|
-
onComplete,
|
|
2107
|
-
paymentMethods,
|
|
2108
|
-
className,
|
|
2109
|
-
style,
|
|
2110
|
-
theme
|
|
2111
|
-
}
|
|
2112
|
-
);
|
|
2113
|
-
}
|
|
2114
9
|
function useNullifierRegistry({
|
|
2115
10
|
escrowAddress,
|
|
2116
11
|
paymentMethodId,
|
|
2117
12
|
chainId
|
|
2118
13
|
}) {
|
|
2119
|
-
const
|
|
2120
|
-
const { data: orchestratorAddress, isLoading: isLoadingOrchestrator } =
|
|
14
|
+
const publicClient = useOptionalProvexPublicClient(chainId);
|
|
15
|
+
const { data: orchestratorAddress, isLoading: isLoadingOrchestrator } = useContractRead({
|
|
2121
16
|
address: escrowAddress,
|
|
2122
17
|
abi: V3EscrowAbi,
|
|
2123
18
|
functionName: "orchestrator",
|
|
@@ -2126,7 +21,7 @@ function useNullifierRegistry({
|
|
|
2126
21
|
enabled: !!escrowAddress
|
|
2127
22
|
}
|
|
2128
23
|
});
|
|
2129
|
-
const { data: paymentVerifierRegistryAddress, isLoading: isLoadingRegistry } =
|
|
24
|
+
const { data: paymentVerifierRegistryAddress, isLoading: isLoadingRegistry } = useContractRead({
|
|
2130
25
|
address: orchestratorAddress,
|
|
2131
26
|
abi: OrchestratorAbi,
|
|
2132
27
|
functionName: "paymentVerifierRegistry",
|
|
@@ -2135,7 +30,7 @@ function useNullifierRegistry({
|
|
|
2135
30
|
enabled: !!orchestratorAddress
|
|
2136
31
|
}
|
|
2137
32
|
});
|
|
2138
|
-
const { data: verifierAddress, isLoading: isLoadingVerifier } =
|
|
33
|
+
const { data: verifierAddress, isLoading: isLoadingVerifier } = useContractRead({
|
|
2139
34
|
address: paymentVerifierRegistryAddress,
|
|
2140
35
|
abi: PaymentVerifierRegistryAbi,
|
|
2141
36
|
functionName: "getVerifier",
|
|
@@ -2145,7 +40,7 @@ function useNullifierRegistry({
|
|
|
2145
40
|
enabled: !!paymentVerifierRegistryAddress && !!paymentMethodId
|
|
2146
41
|
}
|
|
2147
42
|
});
|
|
2148
|
-
const { data: nullifierRegistryAddress, isLoading: isLoadingNullifierRegistry } =
|
|
43
|
+
const { data: nullifierRegistryAddress, isLoading: isLoadingNullifierRegistry } = useContractRead({
|
|
2149
44
|
address: verifierAddress,
|
|
2150
45
|
abi: UnifiedPaymentVerifierAbi,
|
|
2151
46
|
functionName: "nullifierRegistry",
|
|
@@ -2157,11 +52,11 @@ function useNullifierRegistry({
|
|
|
2157
52
|
const isLoading = isLoadingOrchestrator || isLoadingRegistry || isLoadingVerifier || isLoadingNullifierRegistry;
|
|
2158
53
|
const checkNullifierUsed = useCallback(
|
|
2159
54
|
async (nullifier) => {
|
|
2160
|
-
if (!nullifierRegistryAddress || !
|
|
55
|
+
if (!nullifierRegistryAddress || !publicClient) {
|
|
2161
56
|
return null;
|
|
2162
57
|
}
|
|
2163
58
|
try {
|
|
2164
|
-
const isUsed = await
|
|
59
|
+
const isUsed = await publicClient.readContract({
|
|
2165
60
|
address: nullifierRegistryAddress,
|
|
2166
61
|
abi: NullifierRegistryAbi,
|
|
2167
62
|
functionName: "isNullified",
|
|
@@ -2173,7 +68,7 @@ function useNullifierRegistry({
|
|
|
2173
68
|
return null;
|
|
2174
69
|
}
|
|
2175
70
|
},
|
|
2176
|
-
[nullifierRegistryAddress,
|
|
71
|
+
[nullifierRegistryAddress, publicClient]
|
|
2177
72
|
);
|
|
2178
73
|
return {
|
|
2179
74
|
orchestratorAddress,
|
|
@@ -2200,25 +95,19 @@ var useAllowance = ({
|
|
|
2200
95
|
}
|
|
2201
96
|
return maxUint256;
|
|
2202
97
|
}, [defaultAllowance, balance]);
|
|
2203
|
-
const
|
|
2204
|
-
const
|
|
2205
|
-
const
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
args: [account, spender]
|
|
2215
|
-
});
|
|
2216
|
-
return result;
|
|
2217
|
-
},
|
|
2218
|
-
enabled: queryEnabled
|
|
98
|
+
const publicClient = useOptionalProvexPublicClient(token.chainId);
|
|
99
|
+
const wallet = useOptionalProvexWallet();
|
|
100
|
+
const { data, isLoading, error, refetch } = useContractRead({
|
|
101
|
+
address: token.address,
|
|
102
|
+
abi: erc20Abi,
|
|
103
|
+
functionName: "allowance",
|
|
104
|
+
args: account && spender ? [account, spender] : void 0,
|
|
105
|
+
chainId: token.chainId,
|
|
106
|
+
query: {
|
|
107
|
+
enabled: !!account && !!spender && !!token.address
|
|
108
|
+
}
|
|
2219
109
|
});
|
|
2220
110
|
const [approvalPhase, setApprovalPhase] = useState("idle");
|
|
2221
|
-
const { mutateAsync } = useWriteContract();
|
|
2222
111
|
const isWritingApproval = approvalPhase !== "idle";
|
|
2223
112
|
const approvalLoadingText = approvalPhase === "confirming" ? "Confirming..." : `Approve ${token.symbol}`;
|
|
2224
113
|
return {
|
|
@@ -2229,25 +118,27 @@ var useAllowance = ({
|
|
|
2229
118
|
approvalLoadingText,
|
|
2230
119
|
error,
|
|
2231
120
|
writeApproval: async () => {
|
|
2232
|
-
if (!account || !spender || !token.address || !
|
|
121
|
+
if (!account || !spender || !token.address || !publicClient || !wallet) {
|
|
2233
122
|
return;
|
|
2234
123
|
}
|
|
2235
124
|
setApprovalPhase("submitting");
|
|
2236
125
|
try {
|
|
2237
|
-
if (currentChain?.id !== token.chainId) {
|
|
2238
|
-
await switchChainAsync({ chainId: token.chainId });
|
|
2239
|
-
}
|
|
2240
126
|
const gasInputs = await getTransactionGasInputs(token.chainId);
|
|
2241
|
-
const
|
|
2242
|
-
chainId: token.chainId,
|
|
2243
|
-
address: token.address,
|
|
127
|
+
const callData = encodeFunctionData({
|
|
2244
128
|
abi: erc20Abi,
|
|
2245
129
|
functionName: "approve",
|
|
2246
|
-
...gasInputs,
|
|
2247
130
|
args: [spender, targetAllowance]
|
|
2248
131
|
});
|
|
132
|
+
const hash = await wallet.sendTransaction({
|
|
133
|
+
to: token.address,
|
|
134
|
+
data: callData,
|
|
135
|
+
value: 0n,
|
|
136
|
+
chainId: token.chainId,
|
|
137
|
+
maxFeePerGas: gasInputs.maxFeePerGas,
|
|
138
|
+
maxPriorityFeePerGas: gasInputs.maxPriorityFeePerGas
|
|
139
|
+
});
|
|
2249
140
|
setApprovalPhase("confirming");
|
|
2250
|
-
await
|
|
141
|
+
await publicClient.waitForTransactionReceipt({ hash });
|
|
2251
142
|
await refetch();
|
|
2252
143
|
onSuccess?.(hash);
|
|
2253
144
|
} catch (err) {
|
|
@@ -2269,7 +160,8 @@ var useCancelIntent = ({
|
|
|
2269
160
|
version: explicitVersion
|
|
2270
161
|
}) => {
|
|
2271
162
|
const provex = useOptionalProvex();
|
|
2272
|
-
const wallet =
|
|
163
|
+
const wallet = useOptionalProvexWallet();
|
|
164
|
+
const publicClient = useOptionalProvexPublicClient(chainId ?? void 0);
|
|
2273
165
|
const [status, setStatus] = useState("idle");
|
|
2274
166
|
const [errorMessage, setErrorMessage] = useState(null);
|
|
2275
167
|
const isLoading = useMemo(() => status === "prompt_wallet_confirm" || status === "writing_tx", [status]);
|
|
@@ -2291,13 +183,11 @@ var useCancelIntent = ({
|
|
|
2291
183
|
return createProveXClient({
|
|
2292
184
|
chain: provex.config.chain,
|
|
2293
185
|
apiUrl: provex.config.apiUrl,
|
|
2294
|
-
wallet
|
|
186
|
+
wallet,
|
|
2295
187
|
indexer: provex.indexer,
|
|
2296
188
|
escrowAddress: escrowAddress ?? void 0
|
|
2297
189
|
});
|
|
2298
190
|
}, [provex, chainId, version, wallet, escrowAddress]);
|
|
2299
|
-
const { mutateAsync: writeContractAsync } = useWriteContract();
|
|
2300
|
-
const publicClient2 = usePublicClient();
|
|
2301
191
|
const cancelIntent = useCallback(async (intentHash) => {
|
|
2302
192
|
if (!intentHash || !chainId) return;
|
|
2303
193
|
setStatus("prompt_wallet_confirm");
|
|
@@ -2308,15 +198,22 @@ var useCancelIntent = ({
|
|
|
2308
198
|
await client.cancelIntent({ intentHash });
|
|
2309
199
|
} else {
|
|
2310
200
|
if (!escrowAddress) throw new Error("Missing escrow address");
|
|
201
|
+
if (!wallet) throw new Error("No wallet configured on ProvexProvider");
|
|
2311
202
|
const gasInputs = await getTransactionGasInputs(chainId);
|
|
2312
|
-
const
|
|
2313
|
-
address: escrowAddress,
|
|
203
|
+
const data = encodeFunctionData({
|
|
2314
204
|
abi: V2EscrowAbi,
|
|
2315
205
|
functionName: "cancelIntent",
|
|
2316
|
-
args: [intentHash]
|
|
2317
|
-
...gasInputs
|
|
206
|
+
args: [intentHash]
|
|
2318
207
|
});
|
|
2319
|
-
|
|
208
|
+
const hash = await wallet.sendTransaction({
|
|
209
|
+
to: escrowAddress,
|
|
210
|
+
data,
|
|
211
|
+
value: 0n,
|
|
212
|
+
chainId,
|
|
213
|
+
maxFeePerGas: gasInputs.maxFeePerGas,
|
|
214
|
+
maxPriorityFeePerGas: gasInputs.maxPriorityFeePerGas
|
|
215
|
+
});
|
|
216
|
+
if (publicClient) await publicClient.waitForTransactionReceipt({ hash });
|
|
2320
217
|
if (provex?.indexer) {
|
|
2321
218
|
await checkTransactionIndexed({ queryTransaction: provex.indexer.getTransactionByHash, hash });
|
|
2322
219
|
}
|
|
@@ -2335,7 +232,7 @@ var useCancelIntent = ({
|
|
|
2335
232
|
} finally {
|
|
2336
233
|
onSettled?.();
|
|
2337
234
|
}
|
|
2338
|
-
}, [chainId, escrowAddress, version, client,
|
|
235
|
+
}, [chainId, escrowAddress, version, client, publicClient, wallet, provex, onSuccess, onMutate, onError, onSettled]);
|
|
2339
236
|
return {
|
|
2340
237
|
cancelIntent,
|
|
2341
238
|
status,
|
|
@@ -2352,7 +249,8 @@ var useReleaseFundsToPayer = ({
|
|
|
2352
249
|
version: explicitVersion
|
|
2353
250
|
}) => {
|
|
2354
251
|
const provex = useOptionalProvex();
|
|
2355
|
-
const wallet =
|
|
252
|
+
const wallet = useOptionalProvexWallet();
|
|
253
|
+
const publicClient = useOptionalProvexPublicClient(chainId ?? void 0);
|
|
2356
254
|
const [status, setStatus] = useState("idle");
|
|
2357
255
|
const [errorMessage, setErrorMessage] = useState(null);
|
|
2358
256
|
const isLoading = useMemo(
|
|
@@ -2377,13 +275,11 @@ var useReleaseFundsToPayer = ({
|
|
|
2377
275
|
return createProveXClient({
|
|
2378
276
|
chain: provex.config.chain,
|
|
2379
277
|
apiUrl: provex.config.apiUrl,
|
|
2380
|
-
wallet
|
|
278
|
+
wallet,
|
|
2381
279
|
indexer: provex.indexer,
|
|
2382
280
|
escrowAddress: escrowAddress ?? void 0
|
|
2383
281
|
});
|
|
2384
282
|
}, [provex, chainId, version, wallet, escrowAddress]);
|
|
2385
|
-
const { mutateAsync: writeContractAsync } = useWriteContract();
|
|
2386
|
-
const publicClient2 = usePublicClient();
|
|
2387
283
|
const releaseFundsToPayer = useCallback(async (intentHash) => {
|
|
2388
284
|
if (!intentHash || !chainId) return;
|
|
2389
285
|
setStatus("prompt_wallet_confirm");
|
|
@@ -2393,15 +289,22 @@ var useReleaseFundsToPayer = ({
|
|
|
2393
289
|
await client.releaseFundsToPayer({ intentHash });
|
|
2394
290
|
} else {
|
|
2395
291
|
if (!escrowAddress) throw new Error("Missing escrow address");
|
|
292
|
+
if (!wallet) throw new Error("No wallet configured on ProvexProvider");
|
|
2396
293
|
const gasInputs = await getTransactionGasInputs(chainId);
|
|
2397
|
-
const
|
|
2398
|
-
address: escrowAddress,
|
|
294
|
+
const data = encodeFunctionData({
|
|
2399
295
|
abi: V2EscrowAbi,
|
|
2400
296
|
functionName: "releaseFundsToPayer",
|
|
2401
|
-
args: [intentHash]
|
|
2402
|
-
...gasInputs
|
|
297
|
+
args: [intentHash]
|
|
2403
298
|
});
|
|
2404
|
-
|
|
299
|
+
const hash = await wallet.sendTransaction({
|
|
300
|
+
to: escrowAddress,
|
|
301
|
+
data,
|
|
302
|
+
value: 0n,
|
|
303
|
+
chainId,
|
|
304
|
+
maxFeePerGas: gasInputs.maxFeePerGas,
|
|
305
|
+
maxPriorityFeePerGas: gasInputs.maxPriorityFeePerGas
|
|
306
|
+
});
|
|
307
|
+
if (publicClient) await publicClient.waitForTransactionReceipt({ hash });
|
|
2405
308
|
if (provex?.indexer) {
|
|
2406
309
|
await checkTransactionIndexed({ queryTransaction: provex.indexer.getTransactionByHash, hash });
|
|
2407
310
|
}
|
|
@@ -2420,7 +323,7 @@ var useReleaseFundsToPayer = ({
|
|
|
2420
323
|
} finally {
|
|
2421
324
|
onSettled?.();
|
|
2422
325
|
}
|
|
2423
|
-
}, [chainId, escrowAddress, version, client,
|
|
326
|
+
}, [chainId, escrowAddress, version, client, publicClient, wallet, provex, onSuccess, onSettled]);
|
|
2424
327
|
return {
|
|
2425
328
|
releaseFundsToPayer,
|
|
2426
329
|
status,
|
|
@@ -2437,7 +340,7 @@ var useV3Escrow = ({
|
|
|
2437
340
|
onError
|
|
2438
341
|
}) => {
|
|
2439
342
|
const provex = useOptionalProvex();
|
|
2440
|
-
const wallet =
|
|
343
|
+
const wallet = useOptionalProvexWallet();
|
|
2441
344
|
const [status, setStatus] = useState("idle");
|
|
2442
345
|
const [error, setError] = useState(null);
|
|
2443
346
|
const [txHash, setTxHash] = useState(null);
|
|
@@ -2455,7 +358,7 @@ var useV3Escrow = ({
|
|
|
2455
358
|
return createProveXClient({
|
|
2456
359
|
chain: provex.config.chain,
|
|
2457
360
|
apiUrl: provex.config.apiUrl,
|
|
2458
|
-
wallet
|
|
361
|
+
wallet,
|
|
2459
362
|
indexer: provex.indexer,
|
|
2460
363
|
escrowAddress: escrow ?? void 0,
|
|
2461
364
|
onTransactionHash: (hash) => {
|
|
@@ -2468,16 +371,18 @@ var useV3Escrow = ({
|
|
|
2468
371
|
}
|
|
2469
372
|
});
|
|
2470
373
|
}, [provex, chainId, wallet, escrow, onSlowSync]);
|
|
2471
|
-
const { data: orchestratorAddress, refetch: refetchOrchestrator } =
|
|
374
|
+
const { data: orchestratorAddress, refetch: refetchOrchestrator } = useContractRead({
|
|
2472
375
|
address: escrow ?? void 0,
|
|
2473
376
|
abi: V3EscrowAbi,
|
|
2474
377
|
functionName: "orchestrator",
|
|
378
|
+
chainId: chainId ?? void 0,
|
|
2475
379
|
query: { enabled: !!escrow }
|
|
2476
380
|
});
|
|
2477
|
-
const { data: depositCounter, refetch: refetchDepositCounter } =
|
|
381
|
+
const { data: depositCounter, refetch: refetchDepositCounter } = useContractRead({
|
|
2478
382
|
address: escrow ?? void 0,
|
|
2479
383
|
abi: V3EscrowAbi,
|
|
2480
384
|
functionName: "depositCounter",
|
|
385
|
+
chainId: chainId ?? void 0,
|
|
2481
386
|
query: { enabled: !!escrow }
|
|
2482
387
|
});
|
|
2483
388
|
const executeClientMethod = useCallback(async (method, action) => {
|
|
@@ -2625,7 +530,7 @@ var useTransactionWithIndexer = (options = {}) => {
|
|
|
2625
530
|
const provex = useOptionalProvex();
|
|
2626
531
|
const indexer = indexerParam ?? provex?.indexer;
|
|
2627
532
|
const [phase, setPhase] = useState("idle");
|
|
2628
|
-
const
|
|
533
|
+
const publicClient = useOptionalProvexPublicClient();
|
|
2629
534
|
const waitForTransaction = useCallback(async ({
|
|
2630
535
|
hash,
|
|
2631
536
|
chainId,
|
|
@@ -2633,7 +538,7 @@ var useTransactionWithIndexer = (options = {}) => {
|
|
|
2633
538
|
}) => {
|
|
2634
539
|
try {
|
|
2635
540
|
setPhase("confirming");
|
|
2636
|
-
await
|
|
541
|
+
await publicClient?.waitForTransactionReceipt({ hash });
|
|
2637
542
|
if (indexer) {
|
|
2638
543
|
setPhase("syncing");
|
|
2639
544
|
await checkTransactionIndexed({
|
|
@@ -2652,7 +557,7 @@ var useTransactionWithIndexer = (options = {}) => {
|
|
|
2652
557
|
onError?.(error);
|
|
2653
558
|
throw e;
|
|
2654
559
|
}
|
|
2655
|
-
}, [
|
|
560
|
+
}, [publicClient, indexer, onSuccess, onError, onSlowSync, onTransactionConfirmed, onTransactionError]);
|
|
2656
561
|
const waitForMutation = useCallback(async ({
|
|
2657
562
|
hash,
|
|
2658
563
|
depositId,
|
|
@@ -2662,7 +567,7 @@ var useTransactionWithIndexer = (options = {}) => {
|
|
|
2662
567
|
}) => {
|
|
2663
568
|
try {
|
|
2664
569
|
setPhase("confirming");
|
|
2665
|
-
await
|
|
570
|
+
await publicClient?.waitForTransactionReceipt({ hash });
|
|
2666
571
|
if (indexer) {
|
|
2667
572
|
setPhase("syncing");
|
|
2668
573
|
const escrow = getLatestContract(chainId, "escrow");
|
|
@@ -2688,7 +593,7 @@ var useTransactionWithIndexer = (options = {}) => {
|
|
|
2688
593
|
onError?.(error);
|
|
2689
594
|
throw e;
|
|
2690
595
|
}
|
|
2691
|
-
}, [
|
|
596
|
+
}, [publicClient, indexer, onSuccess, onError, onSlowSync, onTransactionConfirmed, onTransactionError]);
|
|
2692
597
|
const reset = useCallback(() => {
|
|
2693
598
|
setPhase("idle");
|
|
2694
599
|
}, []);
|
|
@@ -2717,6 +622,6 @@ function useProveXClient(wallet) {
|
|
|
2717
622
|
);
|
|
2718
623
|
}
|
|
2719
624
|
|
|
2720
|
-
export {
|
|
625
|
+
export { useAllowance, useCancelIntent, useNullifierRegistry, useProveXClient, useReleaseFundsToPayer, useTransactionWithIndexer, useV3Escrow };
|
|
2721
626
|
//# sourceMappingURL=index.js.map
|
|
2722
627
|
//# sourceMappingURL=index.js.map
|