@ensofinance/checkout-widget 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/checkout-widget.es.js +24133 -25422
  2. package/dist/checkout-widget.umd.js +59 -65
  3. package/dist/index.d.ts +1 -3
  4. package/package.json +2 -2
  5. package/src/assets/usdc.webp +0 -0
  6. package/src/assets/usdt.webp +0 -0
  7. package/src/components/AmountInput.tsx +25 -41
  8. package/src/components/ChakraProvider.tsx +13 -36
  9. package/src/components/Checkout.tsx +0 -3
  10. package/src/components/CurrencySwapDisplay.tsx +22 -59
  11. package/src/components/DepositProcessing.tsx +1 -1
  12. package/src/components/ExchangeConfirmSecurity.tsx +1 -1
  13. package/src/components/QuoteParameters.tsx +1 -1
  14. package/src/components/TransactionDetailRow.tsx +2 -2
  15. package/src/components/cards/ExchangeCard.tsx +1 -1
  16. package/src/components/cards/OptionCard.tsx +1 -2
  17. package/src/components/cards/WalletCard.tsx +1 -1
  18. package/src/components/modal.tsx +3 -3
  19. package/src/components/steps/ExchangeFlow.tsx +1404 -231
  20. package/src/components/steps/FlowSelector.tsx +60 -117
  21. package/src/components/steps/WalletFlow/WalletAmountStep.tsx +2 -2
  22. package/src/components/steps/WalletFlow/WalletConfirmStep.tsx +51 -92
  23. package/src/components/steps/WalletFlow/WalletFlow.tsx +16 -17
  24. package/src/components/steps/WalletFlow/WalletQuoteStep.tsx +2 -2
  25. package/src/components/steps/WalletFlow/WalletTokenStep.tsx +4 -6
  26. package/src/components/ui/index.tsx +6 -23
  27. package/src/components/ui/toaster.tsx +1 -2
  28. package/src/types/index.ts +0 -97
  29. package/src/util/constants.tsx +0 -27
  30. package/src/util/enso-hooks.tsx +61 -75
  31. package/dist/checkout-widget.es.js.map +0 -1
  32. package/dist/checkout-widget.umd.js.map +0 -1
  33. package/src/assets/providers/alchemypay.svg +0 -21
  34. package/src/assets/providers/banxa.svg +0 -21
  35. package/src/assets/providers/binanceconnect.svg +0 -14
  36. package/src/assets/providers/kryptonim.svg +0 -6
  37. package/src/assets/providers/mercuryo.svg +0 -21
  38. package/src/assets/providers/moonpay.svg +0 -14
  39. package/src/assets/providers/stripe.svg +0 -16
  40. package/src/assets/providers/swapped.svg +0 -1
  41. package/src/assets/providers/topper.svg +0 -14
  42. package/src/assets/providers/transak.svg +0 -21
  43. package/src/assets/providers/unlimit.svg +0 -21
  44. package/src/components/steps/CardBuyFlow/CardBuyFlow.tsx +0 -412
  45. package/src/components/steps/CardBuyFlow/ChooseAmountStep.tsx +0 -352
  46. package/src/components/steps/CardBuyFlow/OpenWidgetStep.tsx +0 -193
  47. package/src/components/steps/SmartAccountFlow.tsx +0 -372
  48. package/src/components/steps/shared/ChooseAmountStep.tsx +0 -325
  49. package/src/components/steps/shared/SignUserOpStep.tsx +0 -117
  50. package/src/components/steps/shared/TrackUserOpStep.tsx +0 -625
  51. package/src/components/steps/shared/exchangeIntegration.ts +0 -19
  52. package/src/components/steps/shared/types.ts +0 -22
  53. package/src/components/ui/transitions.tsx +0 -16
  54. package/src/enso-api/model/bridgeTransactionResponse.ts +0 -37
  55. package/src/enso-api/model/bridgeTransactionResponseStatus.ts +0 -25
  56. package/src/enso-api/model/ensoEvent.ts +0 -30
  57. package/src/enso-api/model/ensoMetadata.ts +0 -23
  58. package/src/enso-api/model/layerZeroControllerCheckBridgeTransactionParams.ts +0 -21
  59. package/src/enso-api/model/layerZeroMessageStatus.ts +0 -39
  60. package/src/enso-api/model/refundDetails.ts +0 -21
  61. package/src/util/meld-hooks.tsx +0 -533
@@ -56,12 +56,10 @@ export const Button = chakra(ChakraButton, {
56
56
  width: "100%",
57
57
  justifyContent: "center",
58
58
  alignItems: "center",
59
- borderRadius: "control",
59
+ borderRadius: "md",
60
60
  flexShrink: "initial",
61
- transition: "transform 0.12s ease, opacity 0.12s ease",
62
- _active: {
63
- transform: "scale(0.98)",
64
- },
61
+ // cursor: "pointer",
62
+ // transition: "all 0.2s ease-in-out",
65
63
  },
66
64
  variants: {
67
65
  visual: {
@@ -76,24 +74,10 @@ export const Button = chakra(ChakraButton, {
76
74
  grayFilled: {
77
75
  bg: "bg.emphasized",
78
76
  color: "customWhite",
79
- // Override Chakra's default solid hover.
80
- _hover: {
81
- bg: "bg.emphasized",
82
- },
83
- _active: {
84
- bg: "bg.emphasized",
85
- },
86
77
  },
87
78
  lightGray: {
88
79
  bg: "bg.subtle",
89
80
  color: "fg",
90
- // Override Chakra's default solid hover.
91
- _hover: {
92
- bg: "bg.emphasized",
93
- },
94
- _active: {
95
- bg: "bg.emphasized",
96
- },
97
81
  },
98
82
  },
99
83
  size: {
@@ -146,7 +130,7 @@ export const Tab = chakra("div", {
146
130
  justifyContent: "center",
147
131
  alignItems: "center",
148
132
  gap: "8px",
149
- borderRadius: "control",
133
+ borderRadius: "6px",
150
134
  cursor: "pointer",
151
135
  color: "fg.muted",
152
136
  fontSize: "14px",
@@ -315,13 +299,12 @@ export const Card: React.FC<CardProps> & {
315
299
  return (
316
300
  <Box
317
301
  p={padding}
318
- borderRadius="card"
302
+ borderRadius="md"
319
303
  border="1px solid"
320
304
  borderColor={selected ? "primary" : "border"}
321
305
  bg="bg"
322
306
  cursor={onClick && !disabled ? "pointer" : "default"}
323
307
  opacity={disabled ? 0.5 : 1}
324
- transition="border-color 0.15s ease, opacity 0.15s ease"
325
308
  _hover={
326
309
  selected
327
310
  ? undefined
@@ -393,7 +376,7 @@ export const Helper: React.FC<HelperProps> = ({ children, type = "info" }) => {
393
376
  <Flex
394
377
  gap={1}
395
378
  p={3}
396
- borderRadius="card"
379
+ borderRadius="md"
397
380
  border="1px solid"
398
381
  fontSize="sm"
399
382
  {...style}
@@ -9,12 +9,11 @@ import {
9
9
  createToaster,
10
10
  } from "@chakra-ui/react"
11
11
 
12
- export const toaster: ReturnType<typeof createToaster> = createToaster({
12
+ export const toaster = createToaster({
13
13
  placement: "bottom-end",
14
14
  pauseOnPageIdle: true,
15
15
  })
16
16
 
17
-
18
17
  export const Toaster = () => {
19
18
  return (
20
19
  <Portal>
@@ -16,8 +16,6 @@ export type CheckoutConfig = {
16
16
  apiKey: string;
17
17
  theme?: WidgetTheme;
18
18
  enableExchange?: SupportedExchanges[];
19
- /** Enable card purchases via MELD onramp */
20
- enableCardBuy?: boolean;
21
19
  /** Override the default CEX bridge chain mapping (maps target chains to intermediate chains for withdrawal + bridge) */
22
20
  cexBridgeChainMapping?: Record<number, number>;
23
21
  /** Override recipient address (defaults to connected wallet's smart account) */
@@ -35,100 +33,5 @@ export type CheckoutModalProps = {
35
33
  onClose?: () => void;
36
34
  };
37
35
 
38
- // MELD Types
39
- export interface MeldQuote {
40
- serviceProvider: string;
41
- serviceProviderName: string;
42
- transactionType: "BUY" | "SELL";
43
- sourceAmount: number;
44
- sourceCurrencyCode: string;
45
- destinationAmount: number;
46
- destinationCurrencyCode: string;
47
- exchangeRate: number;
48
- paymentMethodType: string;
49
- customerScore?: number;
50
- rampIntelligence?: {
51
- rampScore?: number;
52
- [key: string]: unknown;
53
- };
54
- totalFee: number;
55
- networkFee: number;
56
- transactionFee: number;
57
- lowKyc?: boolean;
58
- }
59
-
60
- export interface MeldQuotesResponse {
61
- quotes: MeldQuote[];
62
- message?: string;
63
- error?: string;
64
- }
65
-
66
- export interface MeldSessionRequest {
67
- countryCode: string;
68
- sourceCurrencyCode: string;
69
- destinationCurrencyCode: string;
70
- sourceAmount: number;
71
- walletAddress: string;
72
- serviceProvider?: string;
73
- paymentMethodType?: string;
74
- externalCustomerId?: string;
75
- externalSessionId?: string;
76
- }
77
-
78
- export interface MeldSessionResponse {
79
- widgetUrl: string;
80
- sessionId: string;
81
- token?: string;
82
- }
83
-
84
- export type MeldTransactionStatus =
85
- | "PENDING_CREATED"
86
- | "PENDING"
87
- | "PROCESSING"
88
- | "AUTHORIZED"
89
- | "AUTHORIZATION_EXPIRED"
90
- | "SETTLING"
91
- | "SETTLED"
92
- | "REFUNDED"
93
- | "DECLINED"
94
- | "CANCELLED"
95
- | "FAILED"
96
- | "ERROR"
97
- | "VOIDED"
98
- | "TWO_FA_REQUIRED"
99
- | "TWO_FA_PROVIDED";
100
-
101
- export interface MeldTransaction {
102
- transactionId: string;
103
- externalCustomerId?: string;
104
- externalSessionId?: string;
105
- status: MeldTransactionStatus;
106
- transactionType: "BUY" | "SELL";
107
- sourceAmount: number;
108
- sourceCurrencyCode: string;
109
- destinationAmount: number;
110
- destinationCurrencyCode: string;
111
- destinationAddress: string;
112
- transactionHash?: string;
113
- serviceProvider: string;
114
- paymentMethod?: string;
115
- createdAt: string;
116
- updatedAt: string;
117
- }
118
-
119
- export interface MeldSupportedCrypto {
120
- currencyCode: string;
121
- name: string;
122
- chainCode: string;
123
- chainId?: number;
124
- contractAddress?: string;
125
- }
126
-
127
- export interface MeldSupportedCryptoResponse {
128
- currencies: MeldSupportedCrypto[];
129
- message?: string;
130
- error?: string;
131
- }
132
-
133
36
  export type { WidgetTheme };
134
37
  export { SupportedExchanges };
@@ -3,30 +3,6 @@ import { Token } from "@/util/common";
3
3
  export const ETH_ADDRESS = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
4
4
  export const VITALIK_ADDRESS = "0xd8da6bf26964af9d7eed9e03e53415d37aa96045";
5
5
  export const DEFAULT_SLIPPAGE = 200;
6
- // Backend-for-frontend used for Mesh + MELD integrations.
7
- // export const CHECKOUT_BFF_URL = "http://localhost:3001/api";
8
- export const CHECKOUT_BFF_URL = "https://checkout-api.enso.build/api";
9
- // export const CHECKOUT_BFF_URL = "https://checkout-api.vercel.app/api";
10
-
11
- // Hardcoded USDC contract addresses for supported chains (native USDC where applicable).
12
- // Used by CardBuyFlow (MELD) as the fixed onramp asset.
13
- export const USDC_ADDRESS_BY_CHAIN_ID: Record<number, string> = {
14
- 1: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // Ethereum
15
- 8453: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // Base
16
- 42161: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // Arbitrum One
17
- 137: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", // Polygon
18
- 10: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85", // Optimism
19
- 43114: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E", // Avalanche C-Chain
20
- 56: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d", // BSC
21
- };
22
-
23
- export function getUsdcAddress(chainId: number): string {
24
- const addr = USDC_ADDRESS_BY_CHAIN_ID[chainId];
25
- if (!addr) {
26
- throw new Error(`USDC is not configured for chainId ${chainId}`);
27
- }
28
- return addr;
29
- }
30
6
 
31
7
  enum MESH_SYMBOLS {
32
8
  ETH = "ETH",
@@ -249,6 +225,3 @@ export const CHAINS_ETHERSCAN: Record<SupportedChainId, string> = {
249
225
  [SupportedChainId.HYPERLIQUID]: "https://www.hyperscan.com/",
250
226
  [SupportedChainId.KATANA]: "https://explorer-katana.t.conduit.xyz/",
251
227
  };
252
-
253
- export const ENTRY_POINT_ADDRESS: `0x${string}` =
254
- "0x0000000071727de22e5e9d8baf0edac6f37da032";
@@ -1,9 +1,4 @@
1
- import {
2
- useAccount,
3
- useWalletClient,
4
- useReadContract,
5
- usePublicClient,
6
- } from "wagmi";
1
+ import { useAccount, useWalletClient, useReadContract } from "wagmi";
7
2
  import { useCapabilities, useSendCalls } from "wagmi/experimental";
8
3
  import { Address, parseAbiItem } from "viem";
9
4
  import { useCallback, useMemo } from "react";
@@ -29,9 +24,11 @@ const GET_SMART_ADDRESS = parseAbiItem(
29
24
  "function getAddress(address) external view returns (address)",
30
25
  );
31
26
 
32
- export const useSmartAccountAddress = (chainId = 1) => {
27
+ export const useSmartAccountAddress = (
28
+ ownerAddress?: Address,
29
+ chainId?: number,
30
+ ) => {
33
31
  const factoryAddress = getERC4337CloneFactory(chainId);
34
- const { address } = useAccount();
35
32
 
36
33
  const {
37
34
  data: smartAccountAddress,
@@ -41,10 +38,10 @@ export const useSmartAccountAddress = (chainId = 1) => {
41
38
  address: factoryAddress as Address,
42
39
  abi: [GET_SMART_ADDRESS],
43
40
  functionName: "getAddress",
44
- args: address ? [address] : undefined,
41
+ args: ownerAddress ? [ownerAddress] : undefined,
45
42
  chainId,
46
43
  query: {
47
- enabled: !!(factoryAddress && address && chainId),
44
+ enabled: !!(factoryAddress && ownerAddress && chainId),
48
45
  },
49
46
  });
50
47
 
@@ -55,9 +52,11 @@ export const useSmartAccountAddress = (chainId = 1) => {
55
52
  };
56
53
 
57
54
  export const useSmartAccountBalances = (chainId: number = 1) => {
55
+ const { address } = useAccount();
56
+
58
57
  // Get smart account address for the given chain
59
58
  const { smartAccountAddress, isLoading: isLoadingSmartAccount } =
60
- useSmartAccountAddress(chainId);
59
+ useSmartAccountAddress(address, chainId);
61
60
 
62
61
  // Get balances from smart account
63
62
  const {
@@ -160,12 +159,6 @@ export const useAppDetails = () => {
160
159
  };
161
160
  };
162
161
 
163
- export type TxStep =
164
- | { type: "approving" }
165
- | { type: "executing" }
166
- | { type: "confirmed"; hash: string }
167
- | { type: "atomic"; bundleId: string };
168
-
169
162
  export const useSendTxns = ({
170
163
  address,
171
164
  chainId,
@@ -175,90 +168,83 @@ export const useSendTxns = ({
175
168
  chainId: number;
176
169
  calls: any[];
177
170
  }) => {
178
- const { sendCallsAsync } = useSendCalls();
179
- const { data: caps, isFetched: capsFetched } = useCapabilities();
180
- const atomicStatus = caps?.[chainId]?.atomic?.status;
181
- const atomicOkay =
182
- caps?.[chainId]?.atomicBatch?.supported === true ||
183
- atomicStatus === "ready" ||
184
- atomicStatus === "supported"; // metmask
185
- console.log(
186
- caps,
187
- caps?.[chainId]?.atomicBatch?.supported,
188
- caps?.[chainId]?.atomic?.status,
189
- );
190
-
171
+ const { sendCalls } = useSendCalls();
172
+ const { data: caps } = useCapabilities();
173
+ // const atomicOkay = caps?.[chainId]?.atomic?.status === "ready";
174
+ const atomicOkay = false;
175
+ // const useFallback = !atomicOkay; // one-line policy; tweak to taste
191
176
  const wallet = useWalletClient();
192
- const publicClient = usePublicClient({ chainId });
177
+
178
+ console.log(caps, atomicOkay, wallet.data);
193
179
 
194
180
  const sendTxns = useCallback(
195
- async ({
196
- onStep,
197
- onFail,
198
- }: {
199
- onStep: (step: TxStep) => void;
200
- onFail: (error: any) => void;
201
- }) => {
181
+ async (
182
+ onTxSend: (hash: string) => void,
183
+ onFail: (error: any) => void,
184
+ ) => {
202
185
  if (!atomicOkay) {
203
- try {
204
- for (let i = 0; i < calls.length; i++) {
205
- const call = calls[i];
206
- const isFinal = i === calls.length - 1;
186
+ // Send transactions sequentially when atomic is not supported
187
+ console.log(
188
+ "Atomic not supported, sending transactions sequentially",
189
+ );
207
190
 
208
- onStep(
209
- isFinal
210
- ? { type: "executing" }
211
- : { type: "approving" },
212
- );
191
+ try {
192
+ for (const call of calls) {
193
+ console.log("Sending individual transaction:", call);
213
194
 
214
- const hash = await wallet.data?.sendTransaction({
195
+ const result = await wallet.data?.sendTransaction({
215
196
  ...call,
216
197
  account: address as Address,
217
198
  chainId,
218
199
  });
219
200
 
220
- if (!hash) {
221
- throw new Error("Transaction returned no hash");
222
- }
201
+ console.log("Sequential transaction result:", result);
223
202
 
224
- if (!isFinal) {
225
- const receipt =
226
- await publicClient!.waitForTransactionReceipt({
227
- hash,
228
- });
229
- if (receipt.status === "reverted") {
230
- throw new Error("Approve transaction reverted");
231
- }
203
+ // Check if transaction failed and stop execution
204
+ if (!result) {
205
+ throw new Error(
206
+ `Transaction failed for call: ${JSON.stringify(call)}`,
207
+ );
232
208
  }
233
209
 
234
- if (isFinal) {
235
- onStep({ type: "confirmed", hash });
210
+ if (call === calls[calls.length - 1]) {
211
+ onTxSend(result);
236
212
  }
237
213
  }
214
+
215
+ console.log("All sequential transactions completed");
238
216
  } catch (err) {
217
+ console.error("Error in sequential transaction:", err);
239
218
  onFail(err);
219
+ throw err;
240
220
  }
241
221
  return;
242
222
  }
243
223
 
244
- try {
245
- const result = await sendCallsAsync({
246
- calls: calls.map((call) => ({
247
- ...call,
248
- chainId,
249
- })),
250
- account: address as Address,
224
+ // Use atomic transactions when supported
225
+ wallet.data
226
+ ?.sendCalls(
227
+ // @ts-ignore
228
+ {
229
+ calls,
230
+ account: address as Address,
231
+ forceAtomic: true, // request atomic only when possible
232
+ },
233
+ )
234
+ .then((result) => {
235
+ debugger;
236
+ console.log(result);
237
+ })
238
+ .catch((err) => {
239
+ debugger;
240
+ console.error(err);
241
+ onFail(err);
251
242
  });
252
- onStep({ type: "atomic", bundleId: result.id });
253
- } catch (err) {
254
- onFail(err);
255
- }
256
243
  },
257
- [sendCallsAsync, calls, atomicOkay, chainId, wallet.data, publicClient],
244
+ [sendCalls, calls, atomicOkay, chainId, wallet.data],
258
245
  );
259
246
 
260
- const ready =
261
- calls.length > 0 && !!wallet.data && !!publicClient && capsFetched;
247
+ const ready = calls.length > 0 && wallet.data;
262
248
 
263
249
  return {
264
250
  ready,