@b3dotfun/sdk 0.0.9-alpha.1 → 0.0.9-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,735 @@
1
+ # Error Handling & Troubleshooting
2
+
3
+ Comprehensive guide to handling errors gracefully and debugging common issues with AnySpend.
4
+
5
+ ## 📊 Order Status Lifecycle
6
+
7
+ Understanding order states is crucial for proper error handling and user experience.
8
+
9
+ ### Order Status Types
10
+
11
+ ```typescript
12
+ enum OrderStatus {
13
+ // Initial States
14
+ SCANNING_DEPOSIT_TRANSACTION = "scanning_deposit_transaction",
15
+ WAITING_STRIPE_PAYMENT = "waiting_stripe_payment",
16
+ OBTAIN_TOKEN = "obtain_token",
17
+
18
+ // Processing States
19
+ SENDING_TOKEN_FROM_VAULT = "sending_token_from_vault",
20
+ RELAY = "relay",
21
+
22
+ // Success States
23
+ EXECUTED = "executed",
24
+
25
+ // Failure States
26
+ OBTAIN_FAILED = "obtain_failed",
27
+ EXPIRED = "expired",
28
+ REFUNDING = "refunding",
29
+ REFUNDED = "refunded",
30
+ FAILURE = "failure",
31
+ }
32
+ ```
33
+
34
+ ### Status Descriptions
35
+
36
+ | Status | Description | User Action Required |
37
+ |--------|-------------|---------------------|
38
+ | `scanning_deposit_transaction` | Waiting for payment confirmation | None - wait for blockchain confirmation |
39
+ | `waiting_stripe_payment` | Processing credit card payment | May need to complete 3D Secure |
40
+ | `obtain_token` | Getting source tokens from vault | None - automatic process |
41
+ | `sending_token_from_vault` | Sending tokens for swap | None - automatic process |
42
+ | `relay` | Cross-chain transaction in progress | None - wait for completion |
43
+ | `executed` | Transaction completed successfully | None - success! |
44
+ | `obtain_failed` | Failed to obtain source tokens | Check payment method/balance |
45
+ | `expired` | Order expired before completion | Create new order |
46
+ | `refunding` | Automatic refund in progress | None - wait for refund |
47
+ | `refunded` | Refund completed | Check wallet for refunded tokens |
48
+ | `failure` | Transaction failed | Review error details, retry |
49
+
50
+ ## ⚠️ Common Error Codes
51
+
52
+ ### Payment Errors
53
+
54
+ | Error Code | Description | Solution |
55
+ |------------|-------------|----------|
56
+ | `INSUFFICIENT_BALANCE` | User doesn't have enough tokens | Request user to add funds |
57
+ | `INVALID_TOKEN_ADDRESS` | Token contract not supported | Verify token is supported on target chain |
58
+ | `MINIMUM_AMOUNT_NOT_MET` | Amount below minimum threshold | Increase transaction amount |
59
+ | `MAXIMUM_AMOUNT_EXCEEDED` | Amount above maximum limit | Reduce transaction amount or split |
60
+
61
+ ### Network Errors
62
+
63
+ | Error Code | Description | Solution |
64
+ |------------|-------------|----------|
65
+ | `SLIPPAGE` | Price moved beyond tolerance | Retry with higher slippage or wait |
66
+ | `NETWORK_ERROR` | RPC or connectivity issues | Retry after delay |
67
+ | `QUOTE_EXPIRED` | Price quote no longer valid | Get fresh quote |
68
+ | `CHAIN_NOT_SUPPORTED` | Blockchain not supported | Use supported chain |
69
+
70
+ ### Contract Errors
71
+
72
+ | Error Code | Description | Solution |
73
+ |------------|-------------|----------|
74
+ | `CONTRACT_CALL_FAILED` | Smart contract execution failed | Check contract parameters |
75
+ | `INSUFFICIENT_GAS` | Gas limit too low | Increase gas limit |
76
+ | `NONCE_TOO_LOW` | Transaction nonce issue | Wait and retry |
77
+ | `TRANSACTION_REVERTED` | Contract reverted transaction | Check contract state and parameters |
78
+
79
+ ## 🛠️ Error Handling Patterns
80
+
81
+ ### Component-Level Error Handling
82
+
83
+ ```tsx
84
+ import { useAnyspendCreateOrder } from "@b3dotfun/sdk/anyspend";
85
+
86
+ function PaymentComponent() {
87
+ const [error, setError] = useState<string | null>(null);
88
+ const [retryCount, setRetryCount] = useState(0);
89
+
90
+ const { createOrder, isCreatingOrder } = useAnyspendCreateOrder({
91
+ onError: (error) => {
92
+ console.error("Payment failed:", error);
93
+
94
+ // Handle specific errors
95
+ switch (error.message) {
96
+ case "INSUFFICIENT_BALANCE":
97
+ setError("Insufficient balance. Please add funds to your wallet.");
98
+ break;
99
+
100
+ case "SLIPPAGE":
101
+ if (retryCount < 3) {
102
+ setError("Price moved unfavorably. Retrying...");
103
+ setTimeout(() => {
104
+ setRetryCount(prev => prev + 1);
105
+ retryPayment();
106
+ }, 2000);
107
+ } else {
108
+ setError("Price too volatile. Please try again later.");
109
+ }
110
+ break;
111
+
112
+ case "NETWORK_ERROR":
113
+ setError("Network issue. Please check your connection and try again.");
114
+ break;
115
+
116
+ case "QUOTE_EXPIRED":
117
+ setError("Price quote expired. Getting fresh quote...");
118
+ refreshQuote();
119
+ break;
120
+
121
+ default:
122
+ setError("Payment failed. Please try again or contact support.");
123
+ }
124
+
125
+ // Track errors for monitoring
126
+ analytics.track("payment_error", {
127
+ error: error.message,
128
+ retryCount,
129
+ timestamp: new Date().toISOString(),
130
+ });
131
+ },
132
+
133
+ onSuccess: () => {
134
+ setError(null);
135
+ setRetryCount(0);
136
+ },
137
+ });
138
+
139
+ return (
140
+ <div className="payment-component">
141
+ {error && (
142
+ <div className="error-banner">
143
+ <span className="error-icon">⚠️</span>
144
+ <span>{error}</span>
145
+ <button onClick={() => setError(null)}>Dismiss</button>
146
+ </div>
147
+ )}
148
+
149
+ <button
150
+ onClick={handlePayment}
151
+ disabled={isCreatingOrder}
152
+ >
153
+ {isCreatingOrder ? "Processing..." : "Pay Now"}
154
+ </button>
155
+ </div>
156
+ );
157
+ }
158
+ ```
159
+
160
+ ### Order Status Monitoring
161
+
162
+ ```tsx
163
+ import { useAnyspendOrderAndTransactions } from "@b3dotfun/sdk/anyspend";
164
+
165
+ function OrderStatusMonitor({ orderId }: { orderId: string }) {
166
+ const { orderAndTransactions, getOrderAndTransactionsError } =
167
+ useAnyspendOrderAndTransactions(true, orderId);
168
+
169
+ if (getOrderAndTransactionsError) {
170
+ return (
171
+ <div className="error-state">
172
+ <h3>Unable to load order status</h3>
173
+ <p>Please check your connection and try again.</p>
174
+ <button onClick={() => window.location.reload()}>
175
+ Retry
176
+ </button>
177
+ </div>
178
+ );
179
+ }
180
+
181
+ if (!orderAndTransactions) {
182
+ return <div>Loading order status...</div>;
183
+ }
184
+
185
+ const { order, depositTxs, executeTx, refundTxs } = orderAndTransactions.data;
186
+
187
+ const renderStatusMessage = () => {
188
+ switch (order.status) {
189
+ case "scanning_deposit_transaction":
190
+ return (
191
+ <div className="status-pending">
192
+ <div className="spinner" />
193
+ <div>
194
+ <h3>⏳ Waiting for payment confirmation</h3>
195
+ <p>This usually takes 1-2 minutes. Please don't close this window.</p>
196
+ {depositTxs.length > 0 && (
197
+ <a
198
+ href={getExplorerUrl(depositTxs[0].txHash, depositTxs[0].chainId)}
199
+ target="_blank"
200
+ rel="noopener noreferrer"
201
+ >
202
+ View payment transaction
203
+ </a>
204
+ )}
205
+ </div>
206
+ </div>
207
+ );
208
+
209
+ case "relay":
210
+ return (
211
+ <div className="status-processing">
212
+ <div className="spinner" />
213
+ <div>
214
+ <h3>🔄 Processing cross-chain transaction</h3>
215
+ <p>Your payment is being processed. This may take a few minutes.</p>
216
+ </div>
217
+ </div>
218
+ );
219
+
220
+ case "executed":
221
+ return (
222
+ <div className="status-success">
223
+ <div className="success-icon">✅</div>
224
+ <div>
225
+ <h3>Transaction completed successfully!</h3>
226
+ <p>Your order has been processed.</p>
227
+ {executeTx && (
228
+ <a
229
+ href={getExplorerUrl(executeTx.txHash, executeTx.chainId)}
230
+ target="_blank"
231
+ rel="noopener noreferrer"
232
+ >
233
+ View transaction
234
+ </a>
235
+ )}
236
+ </div>
237
+ </div>
238
+ );
239
+
240
+ case "failure":
241
+ case "obtain_failed":
242
+ return (
243
+ <div className="status-error">
244
+ <div className="error-icon">❌</div>
245
+ <div>
246
+ <h3>Transaction failed</h3>
247
+ <p>{order.errorDetails || "An error occurred while processing your order."}</p>
248
+ <div className="error-actions">
249
+ <button onClick={() => createNewOrder()}>
250
+ Try Again
251
+ </button>
252
+ <button onClick={() => contactSupport(orderId)}>
253
+ Contact Support
254
+ </button>
255
+ </div>
256
+ </div>
257
+ </div>
258
+ );
259
+
260
+ case "refunded":
261
+ return (
262
+ <div className="status-refunded">
263
+ <div className="refund-icon">↩️</div>
264
+ <div>
265
+ <h3>Refund processed</h3>
266
+ <p>Your payment has been refunded automatically.</p>
267
+ {refundTxs.length > 0 && (
268
+ <a
269
+ href={getExplorerUrl(refundTxs[0].txHash, refundTxs[0].chainId)}
270
+ target="_blank"
271
+ rel="noopener noreferrer"
272
+ >
273
+ View refund transaction
274
+ </a>
275
+ )}
276
+ </div>
277
+ </div>
278
+ );
279
+
280
+ case "expired":
281
+ return (
282
+ <div className="status-expired">
283
+ <div className="expired-icon">⏰</div>
284
+ <div>
285
+ <h3>Order expired</h3>
286
+ <p>This order expired before payment was received.</p>
287
+ <button onClick={() => createNewOrder()}>
288
+ Create New Order
289
+ </button>
290
+ </div>
291
+ </div>
292
+ );
293
+
294
+ default:
295
+ return (
296
+ <div className="status-unknown">
297
+ <div className="spinner" />
298
+ <div>
299
+ <h3>Processing...</h3>
300
+ <p>Order status: {order.status}</p>
301
+ </div>
302
+ </div>
303
+ );
304
+ }
305
+ };
306
+
307
+ return (
308
+ <div className="order-status-monitor">
309
+ <div className="order-header">
310
+ <h2>Order #{orderId.slice(0, 8)}</h2>
311
+ <div className="order-meta">
312
+ <span>Created: {new Date(order.createdAt).toLocaleString()}</span>
313
+ <span>Status: {order.status}</span>
314
+ </div>
315
+ </div>
316
+
317
+ {renderStatusMessage()}
318
+
319
+ {/* Debug information in development */}
320
+ {process.env.NODE_ENV === "development" && (
321
+ <details className="debug-info">
322
+ <summary>Debug Information</summary>
323
+ <pre>{JSON.stringify(order, null, 2)}</pre>
324
+ </details>
325
+ )}
326
+ </div>
327
+ );
328
+ }
329
+ ```
330
+
331
+ ### Global Error Boundary
332
+
333
+ ```tsx
334
+ import React, { Component, ErrorInfo } from "react";
335
+
336
+ interface Props {
337
+ children: React.ReactNode;
338
+ fallback?: React.ComponentType<{ error: Error; resetError: () => void }>;
339
+ }
340
+
341
+ interface State {
342
+ hasError: boolean;
343
+ error?: Error;
344
+ }
345
+
346
+ class AnySpendErrorBoundary extends Component<Props, State> {
347
+ constructor(props: Props) {
348
+ super(props);
349
+ this.state = { hasError: false };
350
+ }
351
+
352
+ static getDerivedStateFromError(error: Error): State {
353
+ return { hasError: true, error };
354
+ }
355
+
356
+ componentDidCatch(error: Error, errorInfo: ErrorInfo) {
357
+ console.error("AnySpend Error Boundary caught an error:", error, errorInfo);
358
+
359
+ // Report to error tracking service
360
+ if (typeof window !== "undefined") {
361
+ // Example: Sentry.captureException(error, { contexts: { errorInfo } });
362
+ }
363
+ }
364
+
365
+ resetError = () => {
366
+ this.setState({ hasError: false, error: undefined });
367
+ };
368
+
369
+ render() {
370
+ if (this.state.hasError) {
371
+ const FallbackComponent = this.props.fallback || DefaultErrorFallback;
372
+ return (
373
+ <FallbackComponent
374
+ error={this.state.error!}
375
+ resetError={this.resetError}
376
+ />
377
+ );
378
+ }
379
+
380
+ return this.props.children;
381
+ }
382
+ }
383
+
384
+ function DefaultErrorFallback({ error, resetError }: { error: Error; resetError: () => void }) {
385
+ return (
386
+ <div className="error-fallback">
387
+ <h2>Something went wrong</h2>
388
+ <p>An unexpected error occurred in the payment component.</p>
389
+ <details className="error-details">
390
+ <summary>Error details</summary>
391
+ <pre>{error.message}</pre>
392
+ </details>
393
+ <div className="error-actions">
394
+ <button onClick={resetError}>Try Again</button>
395
+ <button onClick={() => window.location.reload()}>
396
+ Reload Page
397
+ </button>
398
+ </div>
399
+ </div>
400
+ );
401
+ }
402
+
403
+ // Usage
404
+ function App() {
405
+ return (
406
+ <AnySpendErrorBoundary>
407
+ <AnySpendProvider>
408
+ {/* Your app components */}
409
+ </AnySpendProvider>
410
+ </AnySpendErrorBoundary>
411
+ );
412
+ }
413
+ ```
414
+
415
+ ## 🐛 Troubleshooting Common Issues
416
+
417
+ ### Issue: "Get rate error" when trying to swap
418
+
419
+ **Symptoms:**
420
+ - Quote request fails
421
+ - Unable to get pricing information
422
+ - Network requests timeout
423
+
424
+ **Solutions:**
425
+
426
+ ```tsx
427
+ function DiagnoseQuoteIssue() {
428
+ const [quoteRequest, setQuoteRequest] = useState(null);
429
+ const [diagnosis, setDiagnosis] = useState("");
430
+
431
+ const diagnoseIssue = async () => {
432
+ try {
433
+ // Check if tokens are valid
434
+ const srcTokenValid = await validateToken(quoteRequest.srcTokenAddress, quoteRequest.srcChain);
435
+ const dstTokenValid = await validateToken(quoteRequest.dstTokenAddress, quoteRequest.dstChain);
436
+
437
+ if (!srcTokenValid) {
438
+ setDiagnosis("Source token address is invalid or not supported");
439
+ return;
440
+ }
441
+
442
+ if (!dstTokenValid) {
443
+ setDiagnosis("Destination token address is invalid or not supported");
444
+ return;
445
+ }
446
+
447
+ // Check if amount is within limits
448
+ const amount = parseFloat(quoteRequest.amount);
449
+ if (amount < MIN_SWAP_AMOUNT) {
450
+ setDiagnosis(`Amount too small. Minimum: ${MIN_SWAP_AMOUNT}`);
451
+ return;
452
+ }
453
+
454
+ if (amount > MAX_SWAP_AMOUNT) {
455
+ setDiagnosis(`Amount too large. Maximum: ${MAX_SWAP_AMOUNT}`);
456
+ return;
457
+ }
458
+
459
+ // Check if chain pair is supported
460
+ const chainPairSupported = await checkChainPairSupport(
461
+ quoteRequest.srcChain,
462
+ quoteRequest.dstChain
463
+ );
464
+
465
+ if (!chainPairSupported) {
466
+ setDiagnosis("This chain pair is not currently supported");
467
+ return;
468
+ }
469
+
470
+ setDiagnosis("All checks passed. Try refreshing the quote.");
471
+
472
+ } catch (error) {
473
+ setDiagnosis(`Network error: ${error.message}`);
474
+ }
475
+ };
476
+
477
+ return (
478
+ <div className="quote-diagnostics">
479
+ <button onClick={diagnoseIssue}>Diagnose Quote Issue</button>
480
+ {diagnosis && <p>{diagnosis}</p>}
481
+ </div>
482
+ );
483
+ }
484
+ ```
485
+
486
+ ### Issue: Order stuck in "scanning_deposit_transaction"
487
+
488
+ **Symptoms:**
489
+ - Order remains in pending state for over 10 minutes
490
+ - Payment transaction confirmed on blockchain
491
+ - No progress in AnySpend system
492
+
493
+ **Solutions:**
494
+
495
+ ```tsx
496
+ function DepositDiagnostics({ orderId }: { orderId: string }) {
497
+ const [depositDiag, setDepositDiag] = useState(null);
498
+
499
+ const diagnoseDespositIssue = async () => {
500
+ try {
501
+ const order = await anyspendService.getOrder(true, orderId);
502
+
503
+ if (!order.depositAddress) {
504
+ setDepositDiag({
505
+ issue: "No deposit address generated",
506
+ solution: "Contact support with order ID"
507
+ });
508
+ return;
509
+ }
510
+
511
+ // Check if payment was sent to correct address
512
+ const expectedAddress = order.depositAddress;
513
+ const userTxs = await getTransactionsToAddress(expectedAddress);
514
+
515
+ if (userTxs.length === 0) {
516
+ setDepositDiag({
517
+ issue: "No payment received at deposit address",
518
+ solution: "Ensure you sent payment to: " + expectedAddress
519
+ });
520
+ return;
521
+ }
522
+
523
+ // Check if amount matches
524
+ const expectedAmount = order.srcAmount;
525
+ const receivedAmount = userTxs[0].amount;
526
+
527
+ if (receivedAmount !== expectedAmount) {
528
+ setDepositDiag({
529
+ issue: `Amount mismatch. Expected: ${expectedAmount}, Received: ${receivedAmount}`,
530
+ solution: "Send the exact amount specified"
531
+ });
532
+ return;
533
+ }
534
+
535
+ // Check transaction confirmations
536
+ const confirmations = await getTransactionConfirmations(userTxs[0].hash);
537
+ const requiredConfirmations = getRequiredConfirmations(order.srcChain);
538
+
539
+ if (confirmations < requiredConfirmations) {
540
+ setDepositDiag({
541
+ issue: `Waiting for confirmations: ${confirmations}/${requiredConfirmations}`,
542
+ solution: "Wait for more blockchain confirmations"
543
+ });
544
+ return;
545
+ }
546
+
547
+ setDepositDiag({
548
+ issue: "Payment detected but not processed",
549
+ solution: "This may be a system delay. Contact support if it persists."
550
+ });
551
+
552
+ } catch (error) {
553
+ setDepositDiag({
554
+ issue: "Unable to diagnose",
555
+ solution: "Check your network connection and try again"
556
+ });
557
+ }
558
+ };
559
+
560
+ return (
561
+ <div className="deposit-diagnostics">
562
+ <button onClick={diagnoseDespositIssue}>
563
+ Diagnose Deposit Issue
564
+ </button>
565
+
566
+ {depositDiag && (
567
+ <div className="diagnosis-result">
568
+ <h4>Issue: {depositDiag.issue}</h4>
569
+ <p>Solution: {depositDiag.solution}</p>
570
+ </div>
571
+ )}
572
+ </div>
573
+ );
574
+ }
575
+ ```
576
+
577
+ ### Issue: React Native Build Problems
578
+
579
+ **Symptoms:**
580
+ - Metro bundler errors
581
+ - Module resolution failures
582
+ - Platform-specific component issues
583
+
584
+ **Solutions:**
585
+
586
+ 1. **Correct Import Paths:**
587
+ ```tsx
588
+ // ✅ Correct for React Native
589
+ import { anyspendService } from "@b3dotfun/sdk/anyspend";
590
+ import { useAnyspendQuote } from "@b3dotfun/sdk/anyspend";
591
+
592
+ // ❌ Incorrect for React Native (web-only components)
593
+ import { AnySpend } from "@b3dotfun/sdk/anyspend/react";
594
+ ```
595
+
596
+ 2. **Metro Configuration:**
597
+ ```javascript
598
+ // metro.config.js
599
+ module.exports = {
600
+ resolver: {
601
+ alias: {
602
+ '@b3dotfun/sdk': require.resolve('@b3dotfun/sdk/index.native.js'),
603
+ },
604
+ },
605
+ };
606
+ ```
607
+
608
+ 3. **Platform-Specific Code:**
609
+ ```tsx
610
+ import { Platform } from "react-native";
611
+
612
+ function PaymentComponent() {
613
+ if (Platform.OS === "web") {
614
+ // Use web components
615
+ const { AnySpend } = require("@b3dotfun/sdk/anyspend/react");
616
+ return <AnySpend {...props} />;
617
+ } else {
618
+ // Use service layer for native
619
+ return <CustomNativePaymentFlow />;
620
+ }
621
+ }
622
+ ```
623
+
624
+ ## 🔧 Debug Mode
625
+
626
+ Enable comprehensive logging for troubleshooting:
627
+
628
+ ```typescript
629
+ // Browser
630
+ localStorage.setItem("debug", "anyspend:*");
631
+
632
+ // Node.js/React Native
633
+ process.env.DEBUG = "anyspend:*";
634
+
635
+ // Or programmatically
636
+ import { anyspendService } from "@b3dotfun/sdk/anyspend";
637
+
638
+ // Enable debug logging
639
+ anyspendService.setDebugMode(true);
640
+ ```
641
+
642
+ ### Debug Information Collection
643
+
644
+ ```tsx
645
+ function DebugInfo({ orderId }: { orderId: string }) {
646
+ const [debugData, setDebugData] = useState(null);
647
+
648
+ const collectDebugInfo = async () => {
649
+ const debugInfo = {
650
+ timestamp: new Date().toISOString(),
651
+ userAgent: navigator.userAgent,
652
+ url: window.location.href,
653
+ orderId,
654
+
655
+ // Network info
656
+ connection: (navigator as any).connection,
657
+
658
+ // Order data
659
+ order: await anyspendService.getOrder(true, orderId),
660
+
661
+ // Browser storage
662
+ localStorage: { ...localStorage },
663
+
664
+ // Console errors
665
+ recentErrors: getRecentConsoleErrors(),
666
+
667
+ // SDK version
668
+ sdkVersion: process.env.REACT_APP_SDK_VERSION,
669
+ };
670
+
671
+ setDebugData(debugInfo);
672
+ };
673
+
674
+ const copyDebugInfo = () => {
675
+ navigator.clipboard.writeText(JSON.stringify(debugData, null, 2));
676
+ toast.success("Debug info copied to clipboard");
677
+ };
678
+
679
+ return (
680
+ <div className="debug-info">
681
+ <button onClick={collectDebugInfo}>
682
+ Collect Debug Info
683
+ </button>
684
+
685
+ {debugData && (
686
+ <div>
687
+ <button onClick={copyDebugInfo}>
688
+ Copy to Clipboard
689
+ </button>
690
+ <pre className="debug-output">
691
+ {JSON.stringify(debugData, null, 2)}
692
+ </pre>
693
+ </div>
694
+ )}
695
+ </div>
696
+ );
697
+ }
698
+ ```
699
+
700
+ ## 📞 Support Channels
701
+
702
+ When you need additional help:
703
+
704
+ - **Documentation**: [View latest docs](../README.md)
705
+ - **GitHub Issues**: [Report bugs](https://github.com/b3-fun/b3/issues)
706
+ - **Discord**: [Join community](https://discord.gg/b3dotfun)
707
+ - **Email Support**: Include debug information and order IDs
708
+
709
+ ### Creating Effective Bug Reports
710
+
711
+ ```typescript
712
+ interface BugReport {
713
+ title: string;
714
+ description: string;
715
+ stepsToReproduce: string[];
716
+ expectedBehavior: string;
717
+ actualBehavior: string;
718
+ environment: {
719
+ sdkVersion: string;
720
+ browser: string;
721
+ platform: string;
722
+ networkType: "mainnet" | "testnet";
723
+ };
724
+ orderId?: string;
725
+ transactionHash?: string;
726
+ errorMessage?: string;
727
+ debugInfo?: object;
728
+ }
729
+ ```
730
+
731
+ ## Next Steps
732
+
733
+ - [View Installation Guide →](./installation.md)
734
+ - [Explore Components →](./components.md)
735
+ - [See Examples →](./examples.md)