@ensofinance/checkout-widget 0.0.17 → 0.0.19
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/checkout-widget.es.js +22053 -33949
- package/dist/checkout-widget.es.js.map +1 -1
- package/dist/checkout-widget.umd.js +61 -46
- package/dist/checkout-widget.umd.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/package.json +2 -2
- package/src/components/ChakraProvider.tsx +3 -0
- package/src/components/Checkout.tsx +6 -3
- package/src/components/steps/CardBuyFlow.tsx +778 -0
- package/src/components/steps/ExchangeFlow.tsx +526 -155
- package/src/enso-api/index.ts +276 -1
- package/src/enso-api/model/action.ts +1 -1
- package/src/enso-api/model/actionAction.ts +1 -1
- package/src/enso-api/model/actionInputs.ts +1 -1
- package/src/enso-api/model/actionToBundle.ts +1 -1
- package/src/enso-api/model/actionToBundleAction.ts +1 -1
- package/src/enso-api/model/actionToBundleArgs.ts +1 -1
- package/src/enso-api/model/approveActionDto.ts +1 -1
- package/src/enso-api/model/approveArgsDto.ts +1 -1
- package/src/enso-api/model/approveArgsDtoAmount.ts +1 -1
- package/src/enso-api/model/balanceActionDto.ts +1 -1
- package/src/enso-api/model/balanceArgsDto.ts +1 -1
- package/src/enso-api/model/borrowActionDto.ts +1 -1
- package/src/enso-api/model/borrowArgsDto.ts +1 -1
- package/src/enso-api/model/borrowArgsDtoAmountOut.ts +1 -1
- package/src/enso-api/model/bridgeActionDto.ts +1 -1
- package/src/enso-api/model/bridgeArgsDto.ts +1 -1
- package/src/enso-api/model/bridgeArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/bridgeArgsDtoCallbackItem.ts +1 -1
- package/src/enso-api/model/bridgeLatencyEstimate.ts +1 -1
- package/src/enso-api/model/bridgeTransactionResponse.ts +37 -0
- package/src/enso-api/model/bridgeTransactionResponseStatus.ts +25 -0
- package/src/enso-api/model/bundleControllerBundleShortcutTransactionBodyItem.ts +1 -1
- package/src/enso-api/model/bundleControllerBundleShortcutTransactionParams.ts +1 -1
- package/src/enso-api/model/bundleControllerBundleShortcutTransactionRoutingStrategy.ts +1 -1
- package/src/enso-api/model/bundleShortcutTransaction.ts +1 -1
- package/src/enso-api/model/bundleShortcutTransactionAmountsOut.ts +1 -1
- package/src/enso-api/model/bundleShortcutTransactionFeeAmount.ts +1 -1
- package/src/enso-api/model/bundleShortcutTransactionMinAmountsOut.ts +1 -1
- package/src/enso-api/model/callActionDto.ts +1 -1
- package/src/enso-api/model/callArgsDto.ts +1 -1
- package/src/enso-api/model/callArgsDtoArgsItem.ts +1 -1
- package/src/enso-api/model/callArgsDtoArgsItemAnyOf.ts +1 -1
- package/src/enso-api/model/callArgsDtoValue.ts +1 -1
- package/src/enso-api/model/callOutput.ts +1 -1
- package/src/enso-api/model/connectedNetwork.ts +1 -1
- package/src/enso-api/model/depositActionDto.ts +1 -1
- package/src/enso-api/model/depositArgsDto.ts +1 -1
- package/src/enso-api/model/depositArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/depositArgsDtoAmountInOneOfItem.ts +1 -1
- package/src/enso-api/model/depositArgsDtoTokenIn.ts +1 -1
- package/src/enso-api/model/depositArgsDtoTokenOut.ts +1 -1
- package/src/enso-api/model/depositCLMMActionDto.ts +1 -1
- package/src/enso-api/model/depositCLMMArgsDto.ts +1 -1
- package/src/enso-api/model/depositCLMMArgsDtoAmountInItem.ts +1 -1
- package/src/enso-api/model/depositCLMMArgsDtoAmountInItemAnyOf.ts +1 -1
- package/src/enso-api/model/ensoEvent.ts +30 -0
- package/src/enso-api/model/ensoFeeActionDto.ts +1 -1
- package/src/enso-api/model/ensoFeeArgsDto.ts +1 -1
- package/src/enso-api/model/ensoFeeArgsDtoAmount.ts +1 -1
- package/src/enso-api/model/ensoMetadata.ts +23 -0
- package/src/enso-api/model/feeActionDto.ts +1 -1
- package/src/enso-api/model/feeArgsDto.ts +1 -1
- package/src/enso-api/model/feeArgsDtoAmount.ts +1 -1
- package/src/enso-api/model/harvestActionDto.ts +1 -1
- package/src/enso-api/model/harvestArgsDto.ts +1 -1
- package/src/enso-api/model/hop.ts +1 -1
- package/src/enso-api/model/hopArgs.ts +1 -1
- package/src/enso-api/model/index.ts +8 -1
- package/src/enso-api/model/iporControllerIporShortcutTransactionParams.ts +1 -1
- package/src/enso-api/model/iporShortcutInput.ts +1 -1
- package/src/enso-api/model/iporShortcutTransaction.ts +1 -1
- package/src/enso-api/model/lZDestinationTokenData.ts +1 -1
- package/src/enso-api/model/lZPoolLookupResponse.ts +1 -1
- package/src/enso-api/model/layerZeroControllerCheckBridgeTransactionParams.ts +21 -0
- package/src/enso-api/model/layerZeroControllerGetPoolAddressParams.ts +1 -1
- package/src/enso-api/model/layerZeroMessageStatus.ts +39 -0
- package/src/enso-api/model/mergeActionDto.ts +1 -1
- package/src/enso-api/model/mergeArgsDto.ts +1 -1
- package/src/enso-api/model/mergeArgsDtoAmountInItem.ts +1 -1
- package/src/enso-api/model/minAmountOutActionDto.ts +1 -1
- package/src/enso-api/model/minAmountOutArgsDto.ts +1 -1
- package/src/enso-api/model/minAmountOutArgsDtoAmountOut.ts +1 -1
- package/src/enso-api/model/minAmountOutArgsDtoMinAmountOut.ts +1 -1
- package/src/enso-api/model/multiDepositActionDto.ts +1 -1
- package/src/enso-api/model/multiDepositArgsDto.ts +1 -1
- package/src/enso-api/model/multiDepositArgsDtoAmountInItem.ts +1 -1
- package/src/enso-api/model/multiDepositArgsDtoAmountInItemAnyOf.ts +1 -1
- package/src/enso-api/model/multiOutSingleDepositActionDto.ts +1 -1
- package/src/enso-api/model/multiOutSingleDepositArgsDto.ts +1 -1
- package/src/enso-api/model/multiOutSingleDepositArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/multiRedeemActionDto.ts +1 -1
- package/src/enso-api/model/multiRedeemArgs2Dto.ts +1 -1
- package/src/enso-api/model/multiRedeemArgs2DtoAmountIn.ts +1 -1
- package/src/enso-api/model/network.ts +1 -1
- package/src/enso-api/model/networksControllerNetworksParams.ts +1 -1
- package/src/enso-api/model/nonTokenizedControllerTokens200.ts +1 -1
- package/src/enso-api/model/nonTokenizedControllerTokens200AllOf.ts +1 -1
- package/src/enso-api/model/nonTokenizedControllerTokensParams.ts +1 -1
- package/src/enso-api/model/nonTokenizedModel.ts +1 -1
- package/src/enso-api/model/nontokenizedControllerRouteNontokenizedShorcutTransactionParams.ts +1 -1
- package/src/enso-api/model/nontokenizedControllerRouteNontokenizedShorcutTransactionRoutingStrategy.ts +1 -1
- package/src/enso-api/model/nontokenizedRouteShortcutTransaction.ts +1 -1
- package/src/enso-api/model/paginatedResult.ts +1 -1
- package/src/enso-api/model/paginationMeta.ts +1 -1
- package/src/enso-api/model/paymasterFeeActionDto.ts +1 -1
- package/src/enso-api/model/paymasterFeeArgsDto.ts +1 -1
- package/src/enso-api/model/paymasterFeeArgsDtoAmount.ts +1 -1
- package/src/enso-api/model/permitTransferFromActionDto.ts +1 -1
- package/src/enso-api/model/permitTransferFromArgsDto.ts +1 -1
- package/src/enso-api/model/permitTransferFromArgsDtoAmount.ts +1 -1
- package/src/enso-api/model/permitTransferFromArgsDtoAmountOneOfItem.ts +1 -1
- package/src/enso-api/model/permitTransferFromArgsDtoToken.ts +1 -1
- package/src/enso-api/model/positionModel.ts +1 -1
- package/src/enso-api/model/price.ts +1 -1
- package/src/enso-api/model/pricesControllerGetPricesParams.ts +1 -1
- package/src/enso-api/model/project.ts +1 -1
- package/src/enso-api/model/protocol.ts +1 -1
- package/src/enso-api/model/protocolModel.ts +1 -1
- package/src/enso-api/model/protocolsControllerFindAllParams.ts +1 -1
- package/src/enso-api/model/redeemActionDto.ts +1 -1
- package/src/enso-api/model/redeemArgsDto.ts +1 -1
- package/src/enso-api/model/redeemArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/redeemArgsDtoTokenOut.ts +1 -1
- package/src/enso-api/model/redeemCLMMActionDto.ts +1 -1
- package/src/enso-api/model/redeemCLMMArgsDto.ts +1 -1
- package/src/enso-api/model/redeemCLMMArgsDtoLiquidity.ts +1 -1
- package/src/enso-api/model/refundDetails.ts +21 -0
- package/src/enso-api/model/repayActionDto.ts +1 -1
- package/src/enso-api/model/repayArgsDto.ts +1 -1
- package/src/enso-api/model/repayArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/routeActionDto.ts +1 -1
- package/src/enso-api/model/routeArgsDto.ts +1 -1
- package/src/enso-api/model/routeArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/routeShortcutTransaction.ts +1 -1
- package/src/enso-api/model/routeShortcutVariableInputs.ts +1 -1
- package/src/enso-api/model/routeShortcutVariableInputsRoutingStrategy.ts +1 -1
- package/src/enso-api/model/routeShortcutVariableInputsVariableEstimates.ts +1 -1
- package/src/enso-api/model/routerControllerRouteShortcutTransactionParams.ts +1 -1
- package/src/enso-api/model/routerControllerRouteShortcutTransactionRoutingStrategy.ts +1 -1
- package/src/enso-api/model/singleDepositActionDto.ts +1 -1
- package/src/enso-api/model/singleDepositArgsDto.ts +1 -1
- package/src/enso-api/model/singleDepositArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/singleRedeemActionDto.ts +1 -1
- package/src/enso-api/model/singleRedeemArgs2Dto.ts +1 -1
- package/src/enso-api/model/singleRedeemArgs2DtoAmountIn.ts +1 -1
- package/src/enso-api/model/slippageActionDto.ts +1 -1
- package/src/enso-api/model/slippageArgsDto.ts +1 -1
- package/src/enso-api/model/slippageArgsDtoAmountOut.ts +1 -1
- package/src/enso-api/model/splitActionDto.ts +1 -1
- package/src/enso-api/model/splitArgsDto.ts +1 -1
- package/src/enso-api/model/splitArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/standard.ts +1 -1
- package/src/enso-api/model/standardAction.ts +1 -1
- package/src/enso-api/model/standardActionAction.ts +1 -1
- package/src/enso-api/model/swapActionDto.ts +1 -1
- package/src/enso-api/model/swapArgsDto.ts +1 -1
- package/src/enso-api/model/swapArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/tokenModel.ts +1 -1
- package/src/enso-api/model/tokenizedMultiDepositActionDto.ts +1 -1
- package/src/enso-api/model/tokenizedMultiDepositArgsDto.ts +1 -1
- package/src/enso-api/model/tokenizedMultiDepositArgsDtoAmountInItem.ts +1 -1
- package/src/enso-api/model/tokenizedMultiDepositArgsDtoAmountInItemAnyOf.ts +1 -1
- package/src/enso-api/model/tokenizedMultiRedeemActionDto.ts +1 -1
- package/src/enso-api/model/tokenizedMultiRedeemArgsDto.ts +1 -1
- package/src/enso-api/model/tokenizedMultiRedeemArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/tokenizedSingleDepositActionDto.ts +1 -1
- package/src/enso-api/model/tokenizedSingleDepositArgsDto.ts +1 -1
- package/src/enso-api/model/tokenizedSingleDepositArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/tokenizedSingleRedeemActionDto.ts +1 -1
- package/src/enso-api/model/tokenizedSingleRedeemArgsDto.ts +1 -1
- package/src/enso-api/model/tokenizedSingleRedeemArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/tokensControllerTokens200.ts +1 -1
- package/src/enso-api/model/tokensControllerTokens200AllOf.ts +1 -1
- package/src/enso-api/model/tokensControllerTokensLiquidityType.ts +1 -1
- package/src/enso-api/model/tokensControllerTokensParams.ts +1 -1
- package/src/enso-api/model/tokensControllerTokensType.ts +1 -1
- package/src/enso-api/model/transaction.ts +1 -1
- package/src/enso-api/model/transferActionDto.ts +1 -1
- package/src/enso-api/model/transferArgsDto.ts +1 -1
- package/src/enso-api/model/transferArgsDtoAmount.ts +1 -1
- package/src/enso-api/model/transferFromActionDto.ts +1 -1
- package/src/enso-api/model/transferFromArgsDto.ts +1 -1
- package/src/enso-api/model/transferFromArgsDtoAmount.ts +1 -1
- package/src/enso-api/model/userOperation.ts +1 -1
- package/src/enso-api/model/walletApproveTransaction.ts +1 -1
- package/src/enso-api/model/walletApproveTransactionTx.ts +1 -1
- package/src/enso-api/model/walletBalance.ts +1 -1
- package/src/enso-api/model/walletControllerCreateApproveTransactionParams.ts +1 -1
- package/src/enso-api/model/walletControllerCreateApproveTransactionRoutingStrategy.ts +1 -1
- package/src/enso-api/model/walletControllerWalletBalancesParams.ts +1 -1
- package/src/index.ts +3 -0
- package/src/store.ts +8 -0
- package/src/types/index.ts +4 -0
- package/src/util/constants.tsx +12 -1
- package/src/util/enso-hooks.tsx +12 -5
- package/src/util/meld-hooks.tsx +319 -0
- package/src/util/tx-tracker.tsx +162 -1
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
|
2
|
+
import { useCallback, useState, useEffect } from "react";
|
|
3
|
+
import type {
|
|
4
|
+
MeldQuote,
|
|
5
|
+
MeldQuotesResponse,
|
|
6
|
+
MeldSessionRequest,
|
|
7
|
+
MeldSessionResponse,
|
|
8
|
+
MeldTransaction,
|
|
9
|
+
MeldTransactionStatus,
|
|
10
|
+
} from "@/types";
|
|
11
|
+
|
|
12
|
+
// BFF URL - proxies requests to MELD API with authentication
|
|
13
|
+
const MELD_BFF_URL = "https://meld-bff.enso-checkout.workers.dev";
|
|
14
|
+
|
|
15
|
+
// Chain ID to MELD chain code mapping
|
|
16
|
+
export const MELD_CHAIN_CODES: Record<number, string> = {
|
|
17
|
+
1: "ETH", // Ethereum
|
|
18
|
+
8453: "BASE", // Base
|
|
19
|
+
42161: "ARBITRUM_ONE", // Arbitrum
|
|
20
|
+
137: "POLYGON", // Polygon
|
|
21
|
+
10: "OPTIMISM", // Optimism
|
|
22
|
+
43114: "AVAX_CCHAIN", // Avalanche
|
|
23
|
+
56: "BSC", // BNB Chain
|
|
24
|
+
146: "SONIC", // Sonic
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// Native token symbols by chain
|
|
28
|
+
export const NATIVE_TOKEN_SYMBOLS: Record<number, string> = {
|
|
29
|
+
1: "ETH",
|
|
30
|
+
8453: "ETH",
|
|
31
|
+
42161: "ETH",
|
|
32
|
+
137: "MATIC",
|
|
33
|
+
10: "ETH",
|
|
34
|
+
43114: "AVAX",
|
|
35
|
+
56: "BNB",
|
|
36
|
+
146: "S",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Common tokens across chains
|
|
40
|
+
export const COMMON_TOKENS = ["ETH", "USDC", "USDT", "DAI"];
|
|
41
|
+
|
|
42
|
+
export const MELD_SUPPORTED_CHAINS = Object.keys(MELD_CHAIN_CODES).map(Number);
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Check if a chain is supported by MELD
|
|
46
|
+
*/
|
|
47
|
+
export function isMeldSupportedChain(chainId: number): boolean {
|
|
48
|
+
return chainId in MELD_CHAIN_CODES;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get the destination crypto code for MELD
|
|
53
|
+
* Format: SYMBOL_CHAINCODE (e.g., ETH_BASE, USDC_POLYGON)
|
|
54
|
+
*/
|
|
55
|
+
export function getMeldCryptoCode(symbol: string, chainId: number): string {
|
|
56
|
+
const chainCode = MELD_CHAIN_CODES[chainId];
|
|
57
|
+
if (!chainCode) {
|
|
58
|
+
throw new Error(`Chain ${chainId} not supported by MELD`);
|
|
59
|
+
}
|
|
60
|
+
return `${symbol}_${chainCode}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Hook to fetch quotes from MELD
|
|
65
|
+
*/
|
|
66
|
+
export function useMeldQuotes(params: {
|
|
67
|
+
sourceCurrency: string;
|
|
68
|
+
destinationCurrency: string; // Should be in format SYMBOL_CHAINCODE
|
|
69
|
+
amount: number;
|
|
70
|
+
countryCode: string;
|
|
71
|
+
enabled?: boolean;
|
|
72
|
+
}) {
|
|
73
|
+
const { sourceCurrency, destinationCurrency, amount, countryCode, enabled = true } = params;
|
|
74
|
+
|
|
75
|
+
return useQuery({
|
|
76
|
+
queryKey: ["meld-quotes", sourceCurrency, destinationCurrency, amount, countryCode],
|
|
77
|
+
queryFn: async (): Promise<MeldQuote[]> => {
|
|
78
|
+
const searchParams = new URLSearchParams({
|
|
79
|
+
sourceCurrencyCode: sourceCurrency,
|
|
80
|
+
destinationCurrencyCode: destinationCurrency,
|
|
81
|
+
sourceAmount: String(amount),
|
|
82
|
+
countryCode,
|
|
83
|
+
paymentMethodType: "CREDIT_DEBIT_CARD",
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const res = await fetch(`${MELD_BFF_URL}/quotes?${searchParams}`);
|
|
87
|
+
|
|
88
|
+
if (!res.ok) {
|
|
89
|
+
const error = await res.json().catch(() => ({ error: "Failed to fetch quotes" }));
|
|
90
|
+
throw new Error(error.error || error.message || "Failed to fetch quotes");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const data: MeldQuotesResponse = await res.json();
|
|
94
|
+
|
|
95
|
+
if (data.error) {
|
|
96
|
+
throw new Error(data.error);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Sort by best rate (highest destination amount)
|
|
100
|
+
return (data.quotes || []).sort((a, b) => b.destinationAmount - a.destinationAmount);
|
|
101
|
+
},
|
|
102
|
+
enabled: enabled && amount > 0 && !!destinationCurrency && !!countryCode,
|
|
103
|
+
staleTime: 30000, // 30 seconds
|
|
104
|
+
refetchInterval: 60000, // Refresh every minute
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Hook to create a MELD session
|
|
110
|
+
*/
|
|
111
|
+
export function useCreateMeldSession() {
|
|
112
|
+
const queryClient = useQueryClient();
|
|
113
|
+
|
|
114
|
+
return useMutation({
|
|
115
|
+
mutationFn: async (params: MeldSessionRequest): Promise<MeldSessionResponse> => {
|
|
116
|
+
const res = await fetch(`${MELD_BFF_URL}/session`, {
|
|
117
|
+
method: "POST",
|
|
118
|
+
headers: { "Content-Type": "application/json" },
|
|
119
|
+
body: JSON.stringify(params),
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
if (!res.ok) {
|
|
123
|
+
const error = await res.json().catch(() => ({ error: "Failed to create session" }));
|
|
124
|
+
throw new Error(error.error || error.message || "Failed to create session");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return res.json();
|
|
128
|
+
},
|
|
129
|
+
onSuccess: (data) => {
|
|
130
|
+
// Store session for tracking
|
|
131
|
+
if (data.sessionId) {
|
|
132
|
+
queryClient.setQueryData(["meld-session", data.sessionId], data);
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Hook to track a MELD transaction
|
|
140
|
+
*/
|
|
141
|
+
export function useMeldTransaction(sessionId: string | null) {
|
|
142
|
+
return useQuery({
|
|
143
|
+
queryKey: ["meld-transaction", sessionId],
|
|
144
|
+
queryFn: async (): Promise<MeldTransaction | null> => {
|
|
145
|
+
if (!sessionId) return null;
|
|
146
|
+
|
|
147
|
+
const res = await fetch(`${MELD_BFF_URL}/transaction/${sessionId}`);
|
|
148
|
+
|
|
149
|
+
if (!res.ok) {
|
|
150
|
+
if (res.status === 404) {
|
|
151
|
+
return null; // Transaction not found yet
|
|
152
|
+
}
|
|
153
|
+
const error = await res.json().catch(() => ({ error: "Failed to fetch transaction" }));
|
|
154
|
+
throw new Error(error.error || error.message || "Failed to fetch transaction");
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return res.json();
|
|
158
|
+
},
|
|
159
|
+
enabled: !!sessionId,
|
|
160
|
+
refetchInterval: (query) => {
|
|
161
|
+
const data = query.state.data;
|
|
162
|
+
// Stop polling when transaction is complete or failed
|
|
163
|
+
if (
|
|
164
|
+
data?.status === "COMPLETED" ||
|
|
165
|
+
data?.status === "FAILED" ||
|
|
166
|
+
data?.status === "REFUNDED" ||
|
|
167
|
+
data?.status === "CANCELLED"
|
|
168
|
+
) {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
return 3000; // Poll every 3 seconds
|
|
172
|
+
},
|
|
173
|
+
staleTime: 0, // Always refetch
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Terminal status check
|
|
179
|
+
*/
|
|
180
|
+
export function isTerminalStatus(status: MeldTransactionStatus): boolean {
|
|
181
|
+
return ["COMPLETED", "FAILED", "REFUNDED", "CANCELLED"].includes(status);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Success status check
|
|
186
|
+
*/
|
|
187
|
+
export function isSuccessStatus(status: MeldTransactionStatus): boolean {
|
|
188
|
+
return status === "COMPLETED";
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Hook for detecting user's country code
|
|
193
|
+
*/
|
|
194
|
+
export function useCountryCode() {
|
|
195
|
+
const [countryCode, setCountryCode] = useState<string>("US");
|
|
196
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
197
|
+
|
|
198
|
+
useEffect(() => {
|
|
199
|
+
// Try to detect country from timezone
|
|
200
|
+
const detectCountry = async () => {
|
|
201
|
+
try {
|
|
202
|
+
// Simple timezone-based detection (can be enhanced)
|
|
203
|
+
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
204
|
+
|
|
205
|
+
// Basic mapping of common timezones
|
|
206
|
+
const tzToCountry: Record<string, string> = {
|
|
207
|
+
"America/New_York": "US",
|
|
208
|
+
"America/Los_Angeles": "US",
|
|
209
|
+
"America/Chicago": "US",
|
|
210
|
+
"Europe/London": "GB",
|
|
211
|
+
"Europe/Paris": "FR",
|
|
212
|
+
"Europe/Berlin": "DE",
|
|
213
|
+
"Asia/Tokyo": "JP",
|
|
214
|
+
"Asia/Singapore": "SG",
|
|
215
|
+
"Australia/Sydney": "AU",
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const detected = tzToCountry[timezone];
|
|
219
|
+
if (detected) {
|
|
220
|
+
setCountryCode(detected);
|
|
221
|
+
}
|
|
222
|
+
} catch {
|
|
223
|
+
// Keep default
|
|
224
|
+
} finally {
|
|
225
|
+
setIsLoading(false);
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
detectCountry();
|
|
230
|
+
}, []);
|
|
231
|
+
|
|
232
|
+
return { countryCode, setCountryCode, isLoading };
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Hook to manage the full MELD card buy flow state
|
|
237
|
+
*/
|
|
238
|
+
export function useMeldCardBuyFlow() {
|
|
239
|
+
const [sessionId, setSessionId] = useState<string | null>(null);
|
|
240
|
+
const [widgetUrl, setWidgetUrl] = useState<string | null>(null);
|
|
241
|
+
const [widgetOpen, setWidgetOpen] = useState(false);
|
|
242
|
+
|
|
243
|
+
const createSession = useCreateMeldSession();
|
|
244
|
+
const { data: transaction, isLoading: isTrackingLoading } = useMeldTransaction(sessionId);
|
|
245
|
+
|
|
246
|
+
const startSession = useCallback(
|
|
247
|
+
async (params: MeldSessionRequest) => {
|
|
248
|
+
const result = await createSession.mutateAsync(params);
|
|
249
|
+
setSessionId(result.sessionId);
|
|
250
|
+
setWidgetUrl(result.widgetUrl);
|
|
251
|
+
return result;
|
|
252
|
+
},
|
|
253
|
+
[createSession]
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
const openWidget = useCallback(() => {
|
|
257
|
+
if (widgetUrl) {
|
|
258
|
+
setWidgetOpen(true);
|
|
259
|
+
// Open in new window/tab
|
|
260
|
+
window.open(widgetUrl, "_blank", "width=500,height=700");
|
|
261
|
+
}
|
|
262
|
+
}, [widgetUrl]);
|
|
263
|
+
|
|
264
|
+
const reset = useCallback(() => {
|
|
265
|
+
setSessionId(null);
|
|
266
|
+
setWidgetUrl(null);
|
|
267
|
+
setWidgetOpen(false);
|
|
268
|
+
}, []);
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
// Session management
|
|
272
|
+
sessionId,
|
|
273
|
+
widgetUrl,
|
|
274
|
+
widgetOpen,
|
|
275
|
+
startSession,
|
|
276
|
+
openWidget,
|
|
277
|
+
reset,
|
|
278
|
+
|
|
279
|
+
// Session creation state
|
|
280
|
+
isCreatingSession: createSession.isPending,
|
|
281
|
+
sessionError: createSession.error,
|
|
282
|
+
|
|
283
|
+
// Transaction tracking
|
|
284
|
+
transaction,
|
|
285
|
+
isTrackingLoading,
|
|
286
|
+
isComplete: transaction ? isSuccessStatus(transaction.status) : false,
|
|
287
|
+
isFailed: transaction
|
|
288
|
+
? ["FAILED", "REFUNDED", "CANCELLED"].includes(transaction.status)
|
|
289
|
+
: false,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Format MELD provider name for display
|
|
295
|
+
*/
|
|
296
|
+
export function formatProviderName(provider: string): string {
|
|
297
|
+
const names: Record<string, string> = {
|
|
298
|
+
TRANSAK: "Transak",
|
|
299
|
+
MOONPAY: "MoonPay",
|
|
300
|
+
BANXA: "Banxa",
|
|
301
|
+
RAMP: "Ramp",
|
|
302
|
+
SARDINE: "Sardine",
|
|
303
|
+
STRIPE: "Stripe",
|
|
304
|
+
};
|
|
305
|
+
return names[provider] || provider;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Get provider icon URL
|
|
310
|
+
*/
|
|
311
|
+
export function getProviderIcon(provider: string): string {
|
|
312
|
+
const icons: Record<string, string> = {
|
|
313
|
+
TRANSAK: "https://assets.transak.com/images/website/transak-logo.svg",
|
|
314
|
+
MOONPAY: "https://www.moonpay.com/assets/logo-full-white.svg",
|
|
315
|
+
BANXA: "https://banxa.com/wp-content/uploads/2022/07/banxa-logo.svg",
|
|
316
|
+
RAMP: "https://ramp.network/assets/images/Logo.svg",
|
|
317
|
+
};
|
|
318
|
+
return icons[provider] || "";
|
|
319
|
+
}
|
package/src/util/tx-tracker.tsx
CHANGED
|
@@ -52,7 +52,7 @@ export const useTrackTx = () => {
|
|
|
52
52
|
return { track };
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
-
enum LayerZeroStatus {
|
|
55
|
+
export enum LayerZeroStatus {
|
|
56
56
|
Pending = "PENDING",
|
|
57
57
|
Success = "SUCCEEDED",
|
|
58
58
|
Failed = "FAILED",
|
|
@@ -61,6 +61,167 @@ enum LayerZeroStatus {
|
|
|
61
61
|
Delivered = "DELIVERED",
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
// Types for Enso bridge check API response
|
|
65
|
+
export interface BridgeCheckResponse {
|
|
66
|
+
sourceChainId: number;
|
|
67
|
+
sourceTxHash: string;
|
|
68
|
+
status: "pending" | "success" | "failed";
|
|
69
|
+
layerZeroMessage?: {
|
|
70
|
+
srcEid: number;
|
|
71
|
+
dstEid: number;
|
|
72
|
+
srcChainId: number;
|
|
73
|
+
dstChainId: number;
|
|
74
|
+
status: LayerZeroStatus;
|
|
75
|
+
srcTxHash: string;
|
|
76
|
+
dstTxHash: string;
|
|
77
|
+
srcBlockNumber: string;
|
|
78
|
+
dstBlockNumber: number;
|
|
79
|
+
sender: string;
|
|
80
|
+
receiver: string;
|
|
81
|
+
};
|
|
82
|
+
destinationChainId?: number;
|
|
83
|
+
destinationTxHash?: string;
|
|
84
|
+
ensoSourceEvent?: {
|
|
85
|
+
accountId: string;
|
|
86
|
+
requestId: string;
|
|
87
|
+
blockNumber: number;
|
|
88
|
+
transactionHash: string;
|
|
89
|
+
chainId: number;
|
|
90
|
+
success: boolean;
|
|
91
|
+
};
|
|
92
|
+
ensoDestinationEvent?: {
|
|
93
|
+
blockNumber: number;
|
|
94
|
+
transactionHash: string;
|
|
95
|
+
chainId: number;
|
|
96
|
+
success: boolean;
|
|
97
|
+
error?: string;
|
|
98
|
+
refundDetails?: {
|
|
99
|
+
token: string;
|
|
100
|
+
amount: string;
|
|
101
|
+
recipient: string;
|
|
102
|
+
isNative: boolean;
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Hook for bridge status using Enso API (includes destination execution verification)
|
|
108
|
+
export const useBridgeStatus = (
|
|
109
|
+
hash?: `0x${string}`,
|
|
110
|
+
chainId?: number,
|
|
111
|
+
enabled = true,
|
|
112
|
+
) => {
|
|
113
|
+
const { data, isLoading } = useQuery({
|
|
114
|
+
queryKey: ["bridgeStatus", hash || "none", chainId],
|
|
115
|
+
queryFn: async (): Promise<BridgeCheckResponse | null> => {
|
|
116
|
+
if (!hash || !chainId) return null;
|
|
117
|
+
const res = await fetch(
|
|
118
|
+
`https://api.enso.finance/api/v1/layerzero/bridge/check?chainId=${chainId}&txHash=${hash}`,
|
|
119
|
+
);
|
|
120
|
+
if (!res.ok) return null;
|
|
121
|
+
return res.json();
|
|
122
|
+
},
|
|
123
|
+
refetchInterval: 3000,
|
|
124
|
+
enabled: enabled && !!hash && !!chainId,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const lzStatus = data?.layerZeroMessage?.status;
|
|
128
|
+
const overallStatus = data?.status;
|
|
129
|
+
const destinationSuccess = data?.ensoDestinationEvent?.success;
|
|
130
|
+
const refundDetails = data?.ensoDestinationEvent?.refundDetails;
|
|
131
|
+
|
|
132
|
+
let step = 0;
|
|
133
|
+
let message = "Waiting for bridge transaction...";
|
|
134
|
+
|
|
135
|
+
if (!data) {
|
|
136
|
+
step = 0;
|
|
137
|
+
message = "Waiting for bridge transaction...";
|
|
138
|
+
} else if (lzStatus === LayerZeroStatus.Inflight) {
|
|
139
|
+
step = 1;
|
|
140
|
+
message = "Funds in transit to destination...";
|
|
141
|
+
} else if (lzStatus === LayerZeroStatus.Confirming) {
|
|
142
|
+
step = 2;
|
|
143
|
+
message = "Confirming on destination chain...";
|
|
144
|
+
} else if (lzStatus === LayerZeroStatus.Delivered) {
|
|
145
|
+
if (overallStatus === "success" || destinationSuccess === true) {
|
|
146
|
+
step = 4;
|
|
147
|
+
message = "Bridge completed successfully!";
|
|
148
|
+
} else if (overallStatus === "failed" || destinationSuccess === false) {
|
|
149
|
+
step = 4;
|
|
150
|
+
message = refundDetails
|
|
151
|
+
? "Destination execution failed. Funds refunded."
|
|
152
|
+
: "Destination execution failed.";
|
|
153
|
+
} else {
|
|
154
|
+
step = 3;
|
|
155
|
+
message = "Verifying destination execution...";
|
|
156
|
+
}
|
|
157
|
+
} else if (lzStatus === LayerZeroStatus.Failed) {
|
|
158
|
+
step = 4;
|
|
159
|
+
message = "Bridge transaction failed.";
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
data,
|
|
164
|
+
isLoading,
|
|
165
|
+
lzStatus,
|
|
166
|
+
overallStatus,
|
|
167
|
+
destinationSuccess,
|
|
168
|
+
refundDetails,
|
|
169
|
+
step,
|
|
170
|
+
message,
|
|
171
|
+
isComplete: overallStatus === "success",
|
|
172
|
+
isFailed: overallStatus === "failed" || lzStatus === LayerZeroStatus.Failed,
|
|
173
|
+
destinationTxHash: data?.destinationTxHash,
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// Legacy hook for LayerZero status polling (kept for backward compatibility)
|
|
178
|
+
export const useLayerZeroStatus = (hash?: `0x${string}`, enabled = true) => {
|
|
179
|
+
const { data, isLoading } = useQuery({
|
|
180
|
+
queryKey: ["layerZeroStatus", hash || "none"],
|
|
181
|
+
queryFn: async () => {
|
|
182
|
+
if (!hash) return null;
|
|
183
|
+
return fetch(
|
|
184
|
+
`https://scan.layerzero-api.com/v1/messages/tx/${hash}`,
|
|
185
|
+
)
|
|
186
|
+
.then((res) => res.json())
|
|
187
|
+
.then((res) => res.data?.[0] ?? null);
|
|
188
|
+
},
|
|
189
|
+
refetchInterval: 2000,
|
|
190
|
+
enabled: enabled && !!hash,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
const statusName = data?.status?.name as LayerZeroStatus | undefined;
|
|
194
|
+
const sourceStatus = data?.source?.status as LayerZeroStatus | undefined;
|
|
195
|
+
|
|
196
|
+
let step = 0;
|
|
197
|
+
let message = "Waiting for bridge transaction...";
|
|
198
|
+
|
|
199
|
+
if (sourceStatus && sourceStatus !== LayerZeroStatus.Success) {
|
|
200
|
+
step = 1;
|
|
201
|
+
message = "Waiting for funds to be sent on destination";
|
|
202
|
+
} else if (statusName === LayerZeroStatus.Inflight) {
|
|
203
|
+
step = 2;
|
|
204
|
+
message = "Waiting for funds to be delivered on destination";
|
|
205
|
+
} else if (statusName === LayerZeroStatus.Confirming) {
|
|
206
|
+
step = 3;
|
|
207
|
+
message = "Waiting for destination execution";
|
|
208
|
+
} else if (statusName === LayerZeroStatus.Delivered) {
|
|
209
|
+
step = 4;
|
|
210
|
+
message = "Bridging is complete";
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
data,
|
|
215
|
+
isLoading,
|
|
216
|
+
status: statusName,
|
|
217
|
+
sourceStatus,
|
|
218
|
+
step,
|
|
219
|
+
message,
|
|
220
|
+
isComplete: statusName === LayerZeroStatus.Delivered,
|
|
221
|
+
isFailed: statusName === LayerZeroStatus.Failed,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
64
225
|
const useLayerZeroUrl = (hash?: `0x${string}`, reset?: () => void) => {
|
|
65
226
|
// const [loadingToastId, setLoadingToastId] = useState<string>();
|
|
66
227
|
const updateTx = useTrackingStore((state) => state.updateTx);
|