@ensofinance/checkout-widget 0.0.19 → 0.0.20
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 +22890 -16731
- package/dist/checkout-widget.es.js.map +1 -1
- package/dist/checkout-widget.umd.js +62 -54
- package/dist/checkout-widget.umd.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/Checkout.tsx +22 -2
- package/src/components/steps/ExchangeFlow.tsx +36 -29
- package/src/components/steps/FlowSelector.tsx +119 -16
- package/src/components/steps/WalletFlow/WalletFlow.tsx +22 -14
- package/src/types/index.ts +4 -0
- package/src/components/steps/CardBuyFlow.tsx +0 -778
- package/src/util/meld-hooks.tsx +0 -319
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { ComponentType } from 'react';
|
|
|
4
4
|
import { JSX as JSX_2 } from 'react/jsx-runtime';
|
|
5
5
|
import { SystemConfig as WidgetTheme } from '@chakra-ui/react';
|
|
6
6
|
|
|
7
|
-
export declare const Checkout: ({ config: { apiKey, tokenOut, chainIdOut, theme, enableExchange, cexBridgeChainMapping, recipient }, onClose, wrapper, }: {
|
|
7
|
+
export declare const Checkout: ({ config: { apiKey, tokenOut, chainIdOut, theme, enableExchange, cexBridgeChainMapping, recipient, enforceFlow, }, onClose, wrapper, }: {
|
|
8
8
|
config: CheckoutConfig;
|
|
9
9
|
wrapper?: ComponentType;
|
|
10
10
|
onClose?: () => void;
|
package/package.json
CHANGED
|
@@ -4,18 +4,33 @@ import FlowSelector from "./steps/FlowSelector";
|
|
|
4
4
|
import { useAppStore } from "@/store";
|
|
5
5
|
import { TxTracker } from "@/util/tx-tracker";
|
|
6
6
|
import ChakraProvider from "./ChakraProvider";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
type CheckoutConfig,
|
|
9
|
+
type SupportedExchanges,
|
|
10
|
+
type EnforceFlow,
|
|
11
|
+
} from "@/types";
|
|
12
|
+
import posthog from "posthog-js";
|
|
8
13
|
|
|
9
14
|
type ICheckoutContext = {
|
|
10
15
|
handleClose: () => void;
|
|
11
16
|
enableExchange?: SupportedExchanges[];
|
|
12
17
|
cexBridgeChainMapping?: Record<number, number>;
|
|
18
|
+
enforceFlow?: EnforceFlow;
|
|
13
19
|
};
|
|
14
20
|
|
|
15
21
|
const CheckoutContext = createContext<ICheckoutContext>({} as ICheckoutContext);
|
|
16
22
|
|
|
17
23
|
const Checkout = ({
|
|
18
|
-
config: {
|
|
24
|
+
config: {
|
|
25
|
+
apiKey,
|
|
26
|
+
tokenOut,
|
|
27
|
+
chainIdOut,
|
|
28
|
+
theme,
|
|
29
|
+
enableExchange,
|
|
30
|
+
cexBridgeChainMapping,
|
|
31
|
+
recipient,
|
|
32
|
+
enforceFlow,
|
|
33
|
+
},
|
|
19
34
|
onClose,
|
|
20
35
|
wrapper,
|
|
21
36
|
}: {
|
|
@@ -47,6 +62,10 @@ const Checkout = ({
|
|
|
47
62
|
}, [tokenOut, chainIdOut, recipient]);
|
|
48
63
|
|
|
49
64
|
useEffect(() => {
|
|
65
|
+
posthog.init("phc_capPDVae4W7y6QIqVTugTtx5geVthX4YVswtXa6DrjM", {
|
|
66
|
+
api_host: "https://eu.i.posthog.com",
|
|
67
|
+
person_profiles: "always", // or 'always' to create profiles for anonymous users as well
|
|
68
|
+
});
|
|
50
69
|
if (!apiKey) alert("Please provide an API key");
|
|
51
70
|
setEnsoApiToken(apiKey);
|
|
52
71
|
}, [apiKey]);
|
|
@@ -68,6 +87,7 @@ const Checkout = ({
|
|
|
68
87
|
handleClose,
|
|
69
88
|
enableExchange,
|
|
70
89
|
cexBridgeChainMapping,
|
|
90
|
+
enforceFlow,
|
|
71
91
|
}}
|
|
72
92
|
>
|
|
73
93
|
<ChakraProvider themeConfig={theme}>
|
|
@@ -294,9 +294,9 @@ const ChooseExchangeStep = ({
|
|
|
294
294
|
|
|
295
295
|
return (
|
|
296
296
|
<BodyWrapper>
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
297
|
+
{/*<Box mb={4} width="100%" textAlign="left">*/}
|
|
298
|
+
{/* <HeaderTitle>Choose Exchange</HeaderTitle>*/}
|
|
299
|
+
{/*</Box>*/}
|
|
300
300
|
|
|
301
301
|
{integrations?.length > 0 ? (
|
|
302
302
|
<ListWrapper>
|
|
@@ -478,7 +478,6 @@ const DEVICE_ID_KEY = "meshDeviceId";
|
|
|
478
478
|
const useDeviceId = () => {
|
|
479
479
|
return useMemo(() => {
|
|
480
480
|
let deviceId = localStorage.getItem(DEVICE_ID_KEY);
|
|
481
|
-
console.log(deviceId);
|
|
482
481
|
|
|
483
482
|
if (!deviceId) {
|
|
484
483
|
deviceId = `device_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
|
|
@@ -1967,7 +1966,7 @@ const ExchangeFlow = ({
|
|
|
1967
1966
|
setFlow: (string) => void;
|
|
1968
1967
|
initialStep?: WithdrawalStep;
|
|
1969
1968
|
}) => {
|
|
1970
|
-
const { handleClose } = useContext(CheckoutContext);
|
|
1969
|
+
const { handleClose, enforceFlow } = useContext(CheckoutContext);
|
|
1971
1970
|
const [currentStep, setCurrentStep] = useState(initialStep);
|
|
1972
1971
|
const [selectedToken, setSelectedToken] = useState<MatchedToken | null>(
|
|
1973
1972
|
null,
|
|
@@ -2047,30 +2046,38 @@ const ExchangeFlow = ({
|
|
|
2047
2046
|
<>
|
|
2048
2047
|
<Modal.Header>
|
|
2049
2048
|
<HeaderWrapper>
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2049
|
+
{!(
|
|
2050
|
+
enforceFlow &&
|
|
2051
|
+
(currentStep === WithdrawalStep.ChooseExchange ||
|
|
2052
|
+
currentStep === WithdrawalStep.ChooseBalanceAsset)
|
|
2053
|
+
) && (
|
|
2054
|
+
<IconButton
|
|
2055
|
+
minWidth={"16px"}
|
|
2056
|
+
minHeight={"16px"}
|
|
2057
|
+
maxWidth={"16px"}
|
|
2058
|
+
onClick={() => {
|
|
2059
|
+
const index =
|
|
2060
|
+
(selectedIntegration?.type === "delayed"
|
|
2061
|
+
? balanceSteps
|
|
2062
|
+
: withdrawalSteps
|
|
2063
|
+
).findIndex(
|
|
2064
|
+
(step) => step === currentStep,
|
|
2065
|
+
) - 1;
|
|
2066
|
+
if (index >= 0) {
|
|
2067
|
+
setCurrentStep(withdrawalSteps[index]);
|
|
2068
|
+
} else {
|
|
2069
|
+
setFlow("");
|
|
2070
|
+
}
|
|
2071
|
+
}}
|
|
2072
|
+
>
|
|
2073
|
+
<Icon
|
|
2074
|
+
as={ChevronLeft}
|
|
2075
|
+
color="gray"
|
|
2076
|
+
width={"16px"}
|
|
2077
|
+
height={"16px"}
|
|
2078
|
+
/>
|
|
2079
|
+
</IconButton>
|
|
2080
|
+
)}
|
|
2074
2081
|
|
|
2075
2082
|
<Box
|
|
2076
2083
|
display="flex"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Box, Icon, Skeleton } from "@chakra-ui/react";
|
|
2
|
-
import { X } from "lucide-react";
|
|
3
|
-
import { useContext, useMemo, useState } from "react";
|
|
1
|
+
import { Box, Icon, Skeleton, Text } from "@chakra-ui/react";
|
|
2
|
+
import { X, AlertCircle } from "lucide-react";
|
|
3
|
+
import { useContext, useEffect, useMemo, useState } from "react";
|
|
4
4
|
import { useAccount } from "wagmi";
|
|
5
5
|
import { IconButton } from "../ui";
|
|
6
6
|
import {
|
|
@@ -22,17 +22,21 @@ import ExchangeFlow, {
|
|
|
22
22
|
EXCHANGE_ICON_BY_TYPE,
|
|
23
23
|
ExchangeToIntegrationType,
|
|
24
24
|
} from "@/components/steps/ExchangeFlow";
|
|
25
|
-
import WalletFlow
|
|
25
|
+
import WalletFlow, {
|
|
26
|
+
WalletFlowStep,
|
|
27
|
+
} from "@/components/steps/WalletFlow/WalletFlow";
|
|
26
28
|
|
|
27
29
|
const FLOWS = {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
exchange: ExchangeFlow,
|
|
31
|
+
wallet: WalletFlow,
|
|
30
32
|
};
|
|
31
33
|
|
|
32
34
|
const FlowSelector = () => {
|
|
33
|
-
const { handleClose, enableExchange } =
|
|
35
|
+
const { handleClose, enableExchange, enforceFlow } =
|
|
36
|
+
useContext(CheckoutContext);
|
|
34
37
|
const [flow, setFlow] = useState("");
|
|
35
38
|
const [initialStep, setInitialStep] = useState<string | number>("");
|
|
39
|
+
const [enforceError, setEnforceError] = useState<string | null>(null);
|
|
36
40
|
|
|
37
41
|
const { total, isLoading } = useWalletBalance();
|
|
38
42
|
const { address } = useAccount();
|
|
@@ -43,6 +47,28 @@ const FlowSelector = () => {
|
|
|
43
47
|
const { total: smartAccountTotal, isLoading: isLoadingSmartAccount } =
|
|
44
48
|
useSmartAccountBalances(1);
|
|
45
49
|
|
|
50
|
+
// Handle enforceFlow on mount
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (!enforceFlow) return;
|
|
53
|
+
|
|
54
|
+
if (enforceFlow === "exchange") {
|
|
55
|
+
if (!Array.isArray(enableExchange) || enableExchange.length === 0) {
|
|
56
|
+
setEnforceError(
|
|
57
|
+
"No exchanges configured. Please enable at least one exchange in the widget configuration.",
|
|
58
|
+
);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
setFlow("exchange");
|
|
62
|
+
setInitialStep(WithdrawalStep.ChooseExchange);
|
|
63
|
+
} else if (enforceFlow === "wallet") {
|
|
64
|
+
if (address) {
|
|
65
|
+
setFlow("wallet");
|
|
66
|
+
setInitialStep(WalletFlowStep.SelectToken);
|
|
67
|
+
}
|
|
68
|
+
// If no address, we'll show the wallet connection prompt in the UI
|
|
69
|
+
}
|
|
70
|
+
}, [enforceFlow, enableExchange, address]);
|
|
71
|
+
|
|
46
72
|
const formattedBalance = useMemo(() => {
|
|
47
73
|
if (isLoading)
|
|
48
74
|
return (
|
|
@@ -100,16 +126,10 @@ const FlowSelector = () => {
|
|
|
100
126
|
limit: formatUSD(smartAccountTotal),
|
|
101
127
|
delay: "2 min",
|
|
102
128
|
icons: [],
|
|
103
|
-
flow: "
|
|
129
|
+
flow: "exchange",
|
|
104
130
|
firstStep: WithdrawalStep.ChooseBalanceAsset,
|
|
105
131
|
});
|
|
106
132
|
}
|
|
107
|
-
console.log(
|
|
108
|
-
enableExchange,
|
|
109
|
-
enableExchange.map(
|
|
110
|
-
(integration) => EXCHANGE_ICON_BY_TYPE[integration],
|
|
111
|
-
),
|
|
112
|
-
);
|
|
113
133
|
|
|
114
134
|
if (Array.isArray(enableExchange) && enableExchange.length > 0)
|
|
115
135
|
options.unshift({
|
|
@@ -125,7 +145,7 @@ const FlowSelector = () => {
|
|
|
125
145
|
],
|
|
126
146
|
)
|
|
127
147
|
.filter(Boolean),
|
|
128
|
-
flow: "
|
|
148
|
+
flow: "exchange",
|
|
129
149
|
// Start at ChooseExchange to allow picking among multiple integrations
|
|
130
150
|
firstStep: WithdrawalStep.ChooseExchange,
|
|
131
151
|
});
|
|
@@ -138,6 +158,89 @@ const FlowSelector = () => {
|
|
|
138
158
|
return <FlowComponent setFlow={setFlow} initialStep={initialStep} />;
|
|
139
159
|
}
|
|
140
160
|
|
|
161
|
+
// Error state for enforced exchange mode with no exchanges configured
|
|
162
|
+
if (enforceError) {
|
|
163
|
+
return (
|
|
164
|
+
<>
|
|
165
|
+
<Modal.Header>
|
|
166
|
+
<InitialStepHeaderWrapper>
|
|
167
|
+
<Box display="flex" flexDirection="column" gap={"4px"}>
|
|
168
|
+
<HeaderTitle>Configuration Error</HeaderTitle>
|
|
169
|
+
</Box>
|
|
170
|
+
{handleClose && (
|
|
171
|
+
<IconButton onClick={handleClose} width={"40px"}>
|
|
172
|
+
<Icon
|
|
173
|
+
as={X}
|
|
174
|
+
color="fg.muted"
|
|
175
|
+
width={"16px"}
|
|
176
|
+
height={"16px"}
|
|
177
|
+
/>
|
|
178
|
+
</IconButton>
|
|
179
|
+
)}
|
|
180
|
+
</InitialStepHeaderWrapper>
|
|
181
|
+
</Modal.Header>
|
|
182
|
+
<Modal.Body>
|
|
183
|
+
<BodyWrapper>
|
|
184
|
+
<Box
|
|
185
|
+
display="flex"
|
|
186
|
+
flexDirection="column"
|
|
187
|
+
alignItems="center"
|
|
188
|
+
gap="4"
|
|
189
|
+
p="6"
|
|
190
|
+
textAlign="center"
|
|
191
|
+
>
|
|
192
|
+
<Icon
|
|
193
|
+
as={AlertCircle}
|
|
194
|
+
color="red.500"
|
|
195
|
+
width="48px"
|
|
196
|
+
height="48px"
|
|
197
|
+
/>
|
|
198
|
+
<Text color="fg.muted">{enforceError}</Text>
|
|
199
|
+
</Box>
|
|
200
|
+
</BodyWrapper>
|
|
201
|
+
</Modal.Body>
|
|
202
|
+
</>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Wallet connection prompt for enforced wallet mode without wallet connected
|
|
207
|
+
if (enforceFlow === "wallet" && !address) {
|
|
208
|
+
return (
|
|
209
|
+
<>
|
|
210
|
+
<Modal.Header>
|
|
211
|
+
<InitialStepHeaderWrapper>
|
|
212
|
+
<Box display="flex" flexDirection="column" gap={"4px"}>
|
|
213
|
+
<HeaderTitle>Connect Wallet</HeaderTitle>
|
|
214
|
+
</Box>
|
|
215
|
+
{handleClose && (
|
|
216
|
+
<IconButton onClick={handleClose} width={"40px"}>
|
|
217
|
+
<Icon
|
|
218
|
+
as={X}
|
|
219
|
+
color="fg.muted"
|
|
220
|
+
width={"16px"}
|
|
221
|
+
height={"16px"}
|
|
222
|
+
/>
|
|
223
|
+
</IconButton>
|
|
224
|
+
)}
|
|
225
|
+
</InitialStepHeaderWrapper>
|
|
226
|
+
</Modal.Header>
|
|
227
|
+
<Modal.Body>
|
|
228
|
+
<BodyWrapper>
|
|
229
|
+
<ListWrapper>
|
|
230
|
+
<WalletCard
|
|
231
|
+
icon={walletIcon}
|
|
232
|
+
walletHash="Not Connected"
|
|
233
|
+
balance="Connect your wallet to continue"
|
|
234
|
+
delay=""
|
|
235
|
+
status={WalletStatus.NONE}
|
|
236
|
+
/>
|
|
237
|
+
</ListWrapper>
|
|
238
|
+
</BodyWrapper>
|
|
239
|
+
</Modal.Body>
|
|
240
|
+
</>
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
141
244
|
return (
|
|
142
245
|
<>
|
|
143
246
|
<Modal.Header>
|
|
@@ -172,7 +275,7 @@ const FlowSelector = () => {
|
|
|
172
275
|
status={WalletStatus.CONNECTED}
|
|
173
276
|
badge={walletDisplayName}
|
|
174
277
|
onClick={() => {
|
|
175
|
-
setFlow("
|
|
278
|
+
setFlow("wallet");
|
|
176
279
|
}}
|
|
177
280
|
/>
|
|
178
281
|
}
|
|
@@ -32,7 +32,7 @@ const WalletFlow = ({
|
|
|
32
32
|
setFlow?: (step: string) => void;
|
|
33
33
|
}) => {
|
|
34
34
|
const [currentStep, setCurrentStep] = useState<WalletFlowStep>(initialStep);
|
|
35
|
-
const { handleClose } = useContext(CheckoutContext);
|
|
35
|
+
const { handleClose, enforceFlow } = useContext(CheckoutContext);
|
|
36
36
|
|
|
37
37
|
const handleSetStep = (step: WalletFlowStep | string) => {
|
|
38
38
|
setCurrentStep(step as WalletFlowStep);
|
|
@@ -62,23 +62,31 @@ const WalletFlow = ({
|
|
|
62
62
|
}
|
|
63
63
|
})();
|
|
64
64
|
|
|
65
|
+
const enforcedInitialStep =
|
|
66
|
+
enforceFlow && currentStep === WalletFlowStep.SelectToken;
|
|
67
|
+
|
|
65
68
|
return (
|
|
66
69
|
<>
|
|
67
70
|
<Modal.Header>
|
|
68
71
|
<HeaderWrapper>
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
72
|
+
{!(
|
|
73
|
+
enforceFlow &&
|
|
74
|
+
currentStep === WalletFlowStep.SelectToken
|
|
75
|
+
) && (
|
|
76
|
+
<IconButton
|
|
77
|
+
minWidth={"16px"}
|
|
78
|
+
minHeight={"16px"}
|
|
79
|
+
maxWidth={"16px"}
|
|
80
|
+
onClick={handleBackClick}
|
|
81
|
+
>
|
|
82
|
+
<Icon
|
|
83
|
+
as={ChevronLeft}
|
|
84
|
+
color="gray"
|
|
85
|
+
width={"16px"}
|
|
86
|
+
height={"16px"}
|
|
87
|
+
/>
|
|
88
|
+
</IconButton>
|
|
89
|
+
)}
|
|
82
90
|
|
|
83
91
|
<Box
|
|
84
92
|
display="flex"
|
package/src/types/index.ts
CHANGED
|
@@ -8,6 +8,8 @@ enum SupportedExchanges {
|
|
|
8
8
|
Bybit = "bybit",
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
export type EnforceFlow = "exchange" | "wallet";
|
|
12
|
+
|
|
11
13
|
export type CheckoutConfig = {
|
|
12
14
|
tokenOut: string;
|
|
13
15
|
chainIdOut: number;
|
|
@@ -18,6 +20,8 @@ export type CheckoutConfig = {
|
|
|
18
20
|
cexBridgeChainMapping?: Record<number, number>;
|
|
19
21
|
/** Override recipient address (defaults to connected wallet's smart account) */
|
|
20
22
|
recipient?: string;
|
|
23
|
+
/** Force the widget to open in a specific flow, bypassing the selector */
|
|
24
|
+
enforceFlow?: EnforceFlow;
|
|
21
25
|
};
|
|
22
26
|
|
|
23
27
|
export type CheckoutModalProps = {
|